From 4c89c718b555be6ac0b3bfb47f73255b637e16e5 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Thu, 11 Feb 2016 17:57:18 +0100 Subject: [PATCH] Imported Upstream version 229 --- .dir-locals.el | 20 +- .editorconfig | 20 + .gitignore | 11 +- .vimrc | 15 + CODING_STYLE | 2 +- CONTRIBUTING.md | 37 + Makefile-man.am | 261 +- Makefile.am | 446 +- NEWS | 227 + README | 13 +- README.md | 13 +- TODO | 61 +- catalog/systemd.catalog | 54 + catalog/systemd.hu.catalog | 262 + catalog/systemd.ru.catalog | 62 +- coccinelle/xsprintf.cocci | 6 + configure.ac | 85 +- hwdb/20-OUI.hwdb | 15661 +++++++++------- hwdb/20-bluetooth-vendor-product.hwdb | 171 +- hwdb/20-pci-vendor-model.hwdb | 838 +- hwdb/20-usb-vendor-model.hwdb | 459 +- hwdb/60-evdev.hwdb | 32 +- hwdb/60-keyboard.hwdb | 15 +- hwdb/70-mouse.hwdb | 7 +- hwdb/70-pointingstick.hwdb | 7 +- m4/attributes.m4 | 2 +- man/.gitignore | 1 + man/busctl.xml | 2 +- man/custom-html.xsl | 3 +- man/dnssec-trust-anchors.d.xml | 200 + man/file-hierarchy.xml | 2 +- man/hostname.xml | 4 - man/hostnamectl.xml | 8 +- man/journal-remote.conf.xml | 9 +- man/journalctl.xml | 17 +- man/kernel-command-line.xml | 1 + man/logind.conf.xml | 16 +- man/machine-id.xml | 6 + man/machinectl.xml | 79 +- man/nss-myhostname.xml | 6 +- man/resolved.conf.xml | 134 +- man/sd-bus.xml | 123 + man/sd-daemon.xml | 4 +- man/sd-event.xml | 187 + man/sd-journal.xml | 12 +- man/sd_bus_creds_get_pid.xml | 2 +- man/sd_bus_creds_new_from_pid.xml | 21 + man/sd_bus_new.xml | 48 +- man/sd_event_add_child.xml | 132 +- man/sd_event_add_defer.xml | 101 +- man/sd_event_add_io.xml | 300 + man/sd_event_add_signal.xml | 125 +- man/sd_event_add_time.xml | 188 +- man/sd_event_exit.xml | 163 + man/sd_event_get_fd.xml | 43 +- man/sd_event_new.xml | 100 +- man/sd_event_now.xml | 146 + man/sd_event_run.xml | 93 +- man/sd_event_set_name.xml | 151 - man/sd_event_set_watchdog.xml | 177 + man/sd_event_source_get_event.xml | 100 + man/sd_event_source_get_pending.xml | 167 + man/sd_event_source_set_description.xml | 170 + man/sd_event_source_set_enabled.xml | 179 + man/sd_event_source_set_prepare.xml | 171 + man/sd_event_source_set_priority.xml | 189 + man/sd_event_source_set_userdata.xml | 119 + man/sd_event_source_unref.xml | 142 + man/sd_event_wait.xml | 271 +- man/sd_journal_enumerate_fields.xml | 161 + man/sd_journal_has_runtime_files.xml | 95 + man/sd_journal_query_unique.xml | 42 +- man/sd_login_monitor_new.xml | 31 + man/sd_notify.xml | 2 +- man/sd_seat_get_active.xml | 2 +- man/sd_watchdog_enabled.xml | 8 +- man/systemctl.xml | 76 +- man/systemd-activate.xml | 52 +- man/systemd-ask-password.xml | 4 +- man/systemd-detect-virt.xml | 13 +- man/systemd-escape.xml | 2 +- man/systemd-journal-gatewayd.service.xml | 2 +- man/systemd-journal-remote.xml | 15 +- man/systemd-journald.service.xml | 7 - man/systemd-nspawn.xml | 76 +- man/systemd-path.xml | 2 +- man/systemd-resolve.xml | 277 + man/systemd-resolved.service.xml | 45 +- man/systemd-system.conf.xml | 27 +- man/systemd.exec.xml | 57 +- man/systemd.generator.xml | 17 +- man/systemd.mount.xml | 3 +- man/systemd.netdev.xml | 19 + man/systemd.network.xml | 112 +- man/systemd.nspawn.xml | 34 +- man/systemd.resource-control.xml | 23 +- man/systemd.service.xml | 181 +- man/systemd.socket.xml | 9 + man/systemd.special.xml | 55 +- man/systemd.time.xml | 5 + man/systemd.timer.xml | 58 +- man/systemd.unit.xml | 152 +- man/systemd.xml | 24 + man/sysusers.d.xml | 2 +- man/timesyncd.conf.xml | 2 + man/tmpfiles.d.xml | 5 +- man/udev_device_new_from_syspath.xml | 7 +- po/el.po | 100 +- po/es.po | 101 +- po/hu.po | 156 +- po/it.po | 91 +- po/pt_BR.po | 101 +- po/ru.po | 112 +- po/sv.po | 101 +- po/uk.po | 201 +- po/zh_TW.po | 101 +- shell-completion/bash/journalctl | 13 +- shell-completion/bash/loginctl | 3 +- shell-completion/bash/machinectl | 5 +- shell-completion/bash/systemctl.in | 5 +- shell-completion/bash/systemd-nspawn | 6 +- shell-completion/zsh/_busctl | 2 +- shell-completion/zsh/_journalctl | 5 +- shell-completion/zsh/_machinectl | 4 +- shell-completion/zsh/_systemctl.in | 6 +- shell-completion/zsh/_systemd | 2 +- src/ac-power/ac-power.c | 2 - src/activate/activate.c | 256 +- src/analyze/analyze-verify.c | 66 +- src/analyze/analyze-verify.h | 2 - src/analyze/analyze.c | 32 +- src/ask-password/ask-password.c | 2 - src/backlight/backlight.c | 4 +- src/basic/af-list.c | 4 +- src/basic/af-list.h | 2 - src/basic/alloc-util.c | 6 +- src/basic/alloc-util.h | 3 +- src/basic/arphrd-list.c | 4 +- src/basic/arphrd-list.h | 2 - src/basic/async.c | 5 +- src/basic/async.h | 2 - src/basic/audit-util.c | 5 +- src/basic/audit-util.h | 4 +- src/basic/barrier.c | 4 +- src/basic/barrier.h | 4 +- src/basic/bitmap.c | 23 +- src/basic/bitmap.h | 6 +- src/basic/blkid-util.h | 2 - src/basic/btrfs-ctree.h | 2 - src/basic/btrfs-util.c | 24 +- src/basic/btrfs-util.h | 5 +- src/basic/build.h | 2 - src/basic/bus-label.c | 3 - src/basic/bus-label.h | 3 +- src/basic/c-rbtree.c | 679 + src/basic/c-rbtree.h | 297 + src/basic/calendarspec.c | 256 +- src/basic/calendarspec.h | 6 +- src/basic/cap-list.c | 4 +- src/basic/cap-list.h | 2 - src/basic/capability-util.c | 74 +- src/basic/capability-util.h | 20 +- src/basic/cgroup-util.c | 21 +- src/basic/cgroup-util.h | 14 +- src/basic/chattr-util.c | 6 +- src/basic/chattr-util.h | 2 - src/basic/clock-util.c | 22 +- src/basic/clock-util.h | 3 +- src/basic/conf-files.c | 25 +- src/basic/conf-files.h | 2 - src/basic/copy.c | 15 +- src/basic/copy.h | 3 +- src/basic/cpu-set-util.c | 9 +- src/basic/cpu-set-util.h | 2 - src/basic/def.h | 2 - src/basic/device-nodes.c | 4 +- src/basic/device-nodes.h | 3 +- src/basic/dirent-util.c | 5 +- src/basic/dirent-util.h | 5 +- src/basic/env-util.c | 10 +- src/basic/env-util.h | 3 +- src/basic/errno-list.c | 9 +- src/basic/errno-list.h | 2 - src/basic/escape.c | 84 +- src/basic/escape.h | 13 +- src/basic/ether-addr-util.c | 4 +- src/basic/ether-addr-util.h | 2 - src/basic/exit-status.c | 2 - src/basic/exit-status.h | 4 +- src/basic/extract-word.c | 25 +- src/basic/extract-word.h | 2 - src/basic/fd-util.c | 13 +- src/basic/fd-util.h | 8 +- src/basic/fdset.c | 8 +- src/basic/fdset.h | 6 +- src/basic/fileio-label.c | 6 +- src/basic/fileio-label.h | 3 +- src/basic/fileio.c | 48 +- src/basic/fileio.h | 4 +- src/basic/fs-util.c | 21 +- src/basic/fs-util.h | 6 +- src/basic/glob-util.c | 10 +- src/basic/glob-util.h | 3 +- src/basic/gunicode.c | 2 + src/basic/gunicode.h | 2 +- src/basic/hash-funcs.c | 81 + src/basic/hash-funcs.h | 65 + src/basic/hashmap.c | 66 +- src/basic/hashmap.h | 47 +- src/basic/hexdecoct.c | 69 +- src/basic/hexdecoct.h | 8 +- src/basic/hostname-util.c | 13 +- src/basic/hostname-util.h | 2 - src/basic/in-addr-util.c | 27 +- src/basic/in-addr-util.h | 10 +- src/basic/io-util.c | 7 +- src/basic/io-util.h | 23 +- src/basic/ioprio.h | 2 +- src/basic/json.c | 11 +- src/basic/json.h | 6 +- src/basic/label.c | 8 +- src/basic/label.h | 2 - src/basic/list.h | 2 - src/basic/locale-util.c | 13 +- src/basic/locale-util.h | 2 - src/basic/lockfile-util.c | 10 +- src/basic/lockfile-util.h | 4 +- src/basic/log.c | 104 +- src/basic/log.h | 12 +- src/basic/login-util.c | 5 +- src/basic/login-util.h | 2 - src/basic/macro.h | 55 +- src/basic/memfd-util.c | 7 +- src/basic/memfd-util.h | 6 +- src/basic/mempool.c | 5 +- src/basic/mempool.h | 2 - src/basic/missing.h | 47 +- src/basic/mkdir-label.c | 3 +- src/basic/mkdir.c | 6 +- src/basic/mkdir.h | 2 - src/basic/mount-util.c | 8 +- src/basic/mount-util.h | 4 +- src/{shared => basic}/nss-util.h | 11 +- src/basic/ordered-set.c | 64 + src/basic/ordered-set.h | 19 +- src/basic/parse-util.c | 70 +- src/basic/parse-util.h | 7 +- src/basic/path-util.c | 14 +- src/basic/path-util.h | 4 +- src/basic/prioq.c | 7 +- src/basic/prioq.h | 5 +- src/basic/proc-cmdline.c | 6 +- src/basic/proc-cmdline.h | 2 - src/basic/process-util.c | 39 +- src/basic/process-util.h | 10 +- src/basic/random-util.c | 24 +- src/basic/random-util.h | 1 + src/basic/ratelimit.c | 5 +- src/basic/ratelimit.h | 5 +- src/basic/refcnt.h | 2 - src/basic/replace-var.c | 6 +- src/basic/replace-var.h | 2 - src/basic/rlimit-util.c | 207 +- src/basic/rlimit-util.h | 7 +- src/basic/rm-rf.c | 16 +- src/basic/rm-rf.h | 2 - src/basic/selinux-util.c | 32 +- src/basic/selinux-util.h | 6 +- src/basic/set.h | 3 - src/basic/sigbus.c | 4 +- src/basic/sigbus.h | 2 - src/basic/signal-util.c | 13 +- src/basic/signal-util.h | 13 +- src/basic/siphash24.c | 3 +- src/basic/siphash24.h | 4 + src/basic/smack-util.c | 9 +- src/basic/smack-util.h | 3 +- src/basic/socket-label.c | 14 +- src/basic/socket-util.c | 31 +- src/basic/socket-util.h | 19 +- src/basic/special.h | 2 - src/basic/stat-util.c | 6 +- src/basic/stat-util.h | 9 +- src/basic/stdio-util.h | 2 - src/basic/strbuf.c | 4 +- src/basic/strbuf.h | 4 +- src/basic/string-table.c | 3 +- src/basic/string-table.h | 21 +- src/basic/string-util.c | 75 +- src/basic/string-util.h | 11 +- src/basic/strv.c | 25 +- src/basic/strv.h | 7 +- src/basic/strxcpyx.c | 3 +- src/basic/strxcpyx.h | 4 +- src/basic/syslog-util.c | 5 +- src/basic/syslog-util.h | 2 - src/basic/terminal-util.c | 37 +- src/basic/terminal-util.h | 20 +- src/basic/time-util.c | 114 +- src/basic/time-util.h | 35 +- src/basic/umask-util.h | 2 - src/basic/unaligned.h | 2 - src/basic/unit-name.c | 53 +- src/basic/unit-name.h | 2 - src/basic/user-util.c | 16 +- src/basic/user-util.h | 4 +- src/basic/utf8.c | 53 +- src/basic/utf8.h | 18 +- src/basic/util.c | 59 +- src/basic/util.h | 5 +- src/basic/verbs.c | 16 +- src/basic/verbs.h | 5 +- src/basic/virt.c | 17 +- src/basic/virt.h | 2 - src/basic/web-util.c | 2 - src/basic/web-util.h | 2 - src/basic/xattr-util.c | 11 +- src/basic/xattr-util.h | 3 +- src/basic/xml.c | 6 +- src/basic/xml.h | 2 - src/binfmt/binfmt.c | 2 - src/boot/bootctl.c | 24 +- src/boot/efi/boot.c | 2 - src/boot/efi/console.c | 2 - src/boot/efi/console.h | 2 - src/boot/efi/disk.c | 2 - src/boot/efi/disk.h | 2 - src/boot/efi/graphics.c | 2 - src/boot/efi/graphics.h | 2 - src/boot/efi/linux.c | 2 - src/boot/efi/linux.h | 2 - src/boot/efi/pefile.c | 2 - src/boot/efi/pefile.h | 2 - src/boot/efi/splash.c | 2 - src/boot/efi/splash.h | 2 - src/boot/efi/stub.c | 2 - src/boot/efi/util.c | 2 - src/boot/efi/util.h | 2 - src/bootchart/bootchart.c | 2 - src/bootchart/bootchart.h | 3 +- src/bootchart/store.c | 2 - src/bootchart/store.h | 3 +- src/bootchart/svg.c | 5 +- src/bootchart/svg.h | 2 - src/bus-proxyd/bus-proxyd.c | 2 - src/bus-proxyd/bus-xml-policy.c | 2 - src/bus-proxyd/bus-xml-policy.h | 4 +- src/bus-proxyd/driver.c | 38 +- src/bus-proxyd/driver.h | 3 +- src/bus-proxyd/proxy.c | 14 +- src/bus-proxyd/proxy.h | 2 - src/bus-proxyd/stdio-bridge.c | 4 +- src/bus-proxyd/synthesize.c | 16 +- src/bus-proxyd/synthesize.h | 2 - src/bus-proxyd/test-bus-xml-policy.c | 2 - src/cgls/cgls.c | 10 +- src/cgroups-agent/cgroups-agent.c | 4 +- src/cgtop/cgtop.c | 11 +- src/core/audit-fd.c | 2 - src/core/audit-fd.h | 2 - src/core/automount.c | 31 +- src/core/automount.h | 2 - src/core/bus-endpoint.h | 4 +- src/core/bus-policy.h | 4 +- src/core/busname.c | 56 +- src/core/busname.h | 4 +- src/core/cgroup.c | 119 +- src/core/cgroup.h | 28 +- src/core/dbus-automount.c | 2 - src/core/dbus-automount.h | 2 - src/core/dbus-busname.c | 2 - src/core/dbus-busname.h | 2 - src/core/dbus-cgroup.c | 2 - src/core/dbus-cgroup.h | 2 - src/core/dbus-device.c | 2 - src/core/dbus-device.h | 2 - src/core/dbus-execute.c | 102 +- src/core/dbus-execute.h | 2 - src/core/dbus-job.c | 6 +- src/core/dbus-job.h | 2 - src/core/dbus-kill.c | 2 - src/core/dbus-kill.h | 4 +- src/core/dbus-manager.c | 58 +- src/core/dbus-manager.h | 2 - src/core/dbus-mount.c | 2 - src/core/dbus-mount.h | 2 - src/core/dbus-path.c | 2 - src/core/dbus-path.h | 2 - src/core/dbus-scope.c | 4 +- src/core/dbus-scope.h | 3 +- src/core/dbus-service.c | 27 +- src/core/dbus-service.h | 3 +- src/core/dbus-slice.c | 2 - src/core/dbus-slice.h | 3 +- src/core/dbus-socket.c | 3 +- src/core/dbus-socket.h | 3 +- src/core/dbus-swap.c | 2 - src/core/dbus-swap.h | 3 +- src/core/dbus-target.c | 2 - src/core/dbus-target.h | 2 - src/core/dbus-timer.c | 27 +- src/core/dbus-timer.h | 3 +- src/core/dbus-unit.c | 51 +- src/core/dbus-unit.h | 5 +- src/core/dbus.c | 84 +- src/core/dbus.h | 4 +- src/core/device.c | 23 +- src/core/device.h | 2 - src/core/execute.c | 212 +- src/core/execute.h | 18 +- src/core/failure-action.c | 2 - src/core/failure-action.h | 2 - src/core/hostname-setup.c | 2 - src/core/hostname-setup.h | 2 - src/core/ima-setup.c | 2 - src/core/ima-setup.h | 2 - src/core/job.c | 52 +- src/core/job.h | 10 +- src/core/kill.c | 2 - src/core/kill.h | 2 - src/core/killall.c | 23 +- src/core/killall.h | 2 - src/core/kmod-setup.c | 2 - src/core/kmod-setup.h | 2 - src/core/load-dropin.c | 3 +- src/core/load-dropin.h | 4 +- src/core/load-fragment-gperf.gperf.m4 | 48 +- src/core/load-fragment.c | 427 +- src/core/load-fragment.h | 9 +- src/core/locale-setup.c | 2 - src/core/locale-setup.h | 2 - src/core/loopback-setup.c | 8 +- src/core/loopback-setup.h | 2 - src/core/machine-id-setup.c | 25 +- src/core/machine-id-setup.h | 4 +- src/core/macros.systemd.in | 2 +- src/core/main.c | 134 +- src/core/manager.c | 38 +- src/core/manager.h | 9 +- src/core/mount-setup.c | 60 +- src/core/mount-setup.h | 2 - src/core/mount.c | 45 +- src/core/mount.h | 4 +- src/core/namespace.c | 2 - src/core/namespace.h | 2 - src/core/path.c | 20 +- src/core/path.h | 2 - src/core/scope.c | 47 +- src/core/scope.h | 2 - src/core/selinux-access.c | 89 +- src/core/selinux-access.h | 3 +- src/core/selinux-setup.c | 2 - src/core/selinux-setup.h | 2 - src/core/service.c | 281 +- src/core/service.h | 12 +- src/core/show-status.c | 2 - src/core/show-status.h | 2 - src/core/shutdown.c | 2 - src/core/slice.c | 2 - src/core/slice.h | 2 - src/core/smack-setup.c | 103 +- src/core/smack-setup.h | 2 - src/core/socket.c | 137 +- src/core/socket.h | 8 +- src/core/swap.c | 40 +- src/core/swap.h | 2 - src/core/target.c | 2 - src/core/target.h | 2 - src/core/timer.c | 62 +- src/core/timer.h | 3 +- src/core/transaction.c | 52 +- src/core/transaction.h | 8 +- src/core/triggers.systemd.in | 46 +- src/core/umount.c | 2 - src/core/umount.h | 2 - src/core/unit-printf.c | 2 - src/core/unit-printf.h | 2 - src/core/unit.c | 129 +- src/core/unit.h | 38 +- src/{resolve-host => coredump}/Makefile | 0 src/{journal => coredump}/coredump-vacuum.c | 2 - src/{journal => coredump}/coredump-vacuum.h | 2 - src/{journal => coredump}/coredump.c | 935 +- src/{journal => coredump}/coredump.conf | 0 src/{journal => coredump}/coredumpctl.c | 4 +- src/{journal => coredump}/stacktrace.c | 2 - src/{journal => coredump}/stacktrace.h | 2 - .../test-coredump-vacuum.c | 2 - src/cryptsetup/cryptsetup-generator.c | 2 - src/cryptsetup/cryptsetup.c | 4 +- src/dbus1-generator/dbus1-generator.c | 2 - src/debug-generator/debug-generator.c | 2 - src/delta/delta.c | 45 +- src/detect-virt/detect-virt.c | 2 - src/escape/escape.c | 2 - src/firstboot/firstboot.c | 4 +- src/fsck/fsck.c | 8 +- src/fstab-generator/fstab-generator.c | 16 +- src/getty-generator/getty-generator.c | 4 +- src/gpt-auto-generator/gpt-auto-generator.c | 18 +- .../hibernate-resume-generator.c | 2 - src/hibernate-resume/hibernate-resume.c | 2 - src/hostname/hostnamectl.c | 10 +- src/hostname/hostnamed.c | 17 +- src/hwdb/hwdb.c | 2 +- src/import/aufs-util.c | 4 +- src/import/aufs-util.h | 2 - src/import/curl-util.c | 2 - src/import/curl-util.h | 4 +- src/import/export-raw.c | 2 - src/import/export-raw.h | 5 +- src/import/export-tar.c | 2 - src/import/export-tar.h | 5 +- src/import/export.c | 7 +- src/import/import-common.c | 6 +- src/import/import-common.h | 2 - src/import/import-compress.c | 2 - src/import/import-compress.h | 9 +- src/import/import-raw.c | 2 - src/import/import-raw.h | 5 +- src/import/import-tar.c | 2 - src/import/import-tar.h | 5 +- src/import/import.c | 7 +- src/import/importd.c | 127 +- src/import/org.freedesktop.import1.conf | 4 - src/import/pull-common.c | 2 - src/import/pull-common.h | 4 +- src/import/pull-dkr.c | 1346 -- src/import/pull-job.c | 2 - src/import/pull-job.h | 4 +- src/import/pull-raw.c | 2 - src/import/pull-raw.h | 5 +- src/import/pull-tar.c | 2 - src/import/pull-tar.h | 5 +- src/import/pull.c | 135 +- src/import/qcow2-util.c | 2 - src/import/qcow2-util.h | 2 - src/import/test-qcow2.c | 2 - src/initctl/initctl.c | 4 +- src/journal-remote/journal-gatewayd.c | 16 +- src/journal-remote/journal-remote-parse.c | 2 - src/journal-remote/journal-remote-parse.h | 3 +- src/journal-remote/journal-remote-write.c | 2 - src/journal-remote/journal-remote-write.h | 2 - src/journal-remote/journal-remote.c | 61 +- src/journal-remote/journal-remote.conf.in | 1 + src/journal-remote/journal-remote.h | 6 +- src/journal-remote/journal-upload-journal.c | 9 +- src/journal-remote/journal-upload.c | 2 - src/journal-remote/journal-upload.h | 2 +- src/journal-remote/microhttpd-util.c | 2 - src/journal-remote/microhttpd-util.h | 13 +- src/journal/audit-type.c | 2 - src/journal/audit-type.h | 2 - src/journal/cat.c | 12 +- src/journal/catalog.c | 148 +- src/journal/catalog.h | 5 +- src/journal/compress.c | 120 +- src/journal/compress.h | 15 +- src/journal/fsprg.c | 2 - src/journal/fsprg.h | 4 +- src/journal/journal-authenticate.c | 2 - src/journal/journal-authenticate.h | 2 - src/journal/journal-def.h | 2 - src/journal/journal-file.c | 149 +- src/journal/journal-file.h | 11 +- src/journal/journal-internal.h | 30 +- src/journal/journal-qrcode.c | 2 - src/journal/journal-qrcode.h | 2 - src/journal/journal-send.c | 13 +- src/journal/journal-vacuum.c | 2 - src/journal/journal-vacuum.h | 2 - src/journal/journal-verify.c | 2 - src/journal/journal-verify.h | 2 - src/journal/journalctl.c | 176 +- src/journal/journald-audit.c | 6 +- src/journal/journald-audit.h | 4 +- src/journal/journald-console.c | 2 - src/journal/journald-console.h | 2 - src/journal/journald-kmsg.c | 8 +- src/journal/journald-kmsg.h | 2 - src/journal/journald-native.c | 8 +- src/journal/journald-native.h | 2 - src/journal/journald-rate-limit.c | 2 - src/journal/journald-rate-limit.h | 2 - src/journal/journald-server.c | 194 +- src/journal/journald-server.h | 6 +- src/journal/journald-stream.c | 16 +- src/journal/journald-stream.h | 2 - src/journal/journald-syslog.c | 19 +- src/journal/journald-syslog.h | 2 - src/journal/journald-wall.c | 2 - src/journal/journald-wall.h | 2 - src/journal/journald.c | 10 +- src/journal/lookup3.h | 2 - src/journal/mmap-cache.c | 84 +- src/journal/mmap-cache.h | 2 - src/journal/sd-journal.c | 200 +- src/journal/test-audit-type.c | 2 - src/journal/test-catalog.c | 134 +- src/journal/test-compress-benchmark.c | 9 +- src/journal/test-compress.c | 121 +- src/journal/test-journal-enum.c | 4 +- src/journal/test-journal-flush.c | 2 - src/journal/test-journal-init.c | 2 - src/journal/test-journal-interleaving.c | 2 - src/journal/test-journal-match.c | 4 +- src/journal/test-journal-send.c | 85 +- src/journal/test-journal-stream.c | 4 +- src/journal/test-journal-syslog.c | 2 - src/journal/test-journal-verify.c | 2 - src/journal/test-journal.c | 2 - src/journal/test-mmap-cache.c | 2 - src/libsystemd-network/arp-util.h | 4 +- src/libsystemd-network/dhcp-identifier.c | 2 - src/libsystemd-network/dhcp-identifier.h | 2 - src/libsystemd-network/dhcp-internal.h | 10 +- src/libsystemd-network/dhcp-lease-internal.h | 12 +- src/libsystemd-network/dhcp-option.c | 123 +- src/libsystemd-network/dhcp-packet.c | 2 +- src/libsystemd-network/dhcp-protocol.h | 47 +- src/libsystemd-network/dhcp-server-internal.h | 14 +- src/libsystemd-network/dhcp6-internal.h | 2 - src/libsystemd-network/dhcp6-lease-internal.h | 6 +- src/libsystemd-network/dhcp6-option.c | 36 +- src/libsystemd-network/dhcp6-protocol.h | 37 - src/libsystemd-network/icmp6-util.c | 44 +- src/libsystemd-network/icmp6-util.h | 2 - src/libsystemd-network/lldp-internal.c | 4 +- src/libsystemd-network/lldp-internal.h | 2 - src/libsystemd-network/lldp-network.c | 2 - src/libsystemd-network/lldp-network.h | 2 - src/libsystemd-network/lldp-port.c | 2 - src/libsystemd-network/lldp-port.h | 2 - src/libsystemd-network/lldp-tlv.c | 2 - src/libsystemd-network/lldp-tlv.h | 13 +- src/libsystemd-network/lldp.h | 2 - src/libsystemd-network/network-internal.c | 17 +- src/libsystemd-network/network-internal.h | 8 +- src/libsystemd-network/sd-dhcp-client.c | 180 +- src/libsystemd-network/sd-dhcp-lease.c | 167 +- src/libsystemd-network/sd-dhcp-server.c | 57 +- src/libsystemd-network/sd-dhcp6-client.c | 83 +- src/libsystemd-network/sd-dhcp6-lease.c | 4 +- src/libsystemd-network/sd-ipv4acd.c | 8 +- src/libsystemd-network/sd-ipv4ll.c | 8 +- src/libsystemd-network/sd-lldp.c | 98 +- src/libsystemd-network/sd-ndisc.c | 128 +- src/libsystemd-network/test-acd.c | 9 +- src/libsystemd-network/test-dhcp-client.c | 37 +- src/libsystemd-network/test-dhcp-option.c | 68 +- src/libsystemd-network/test-dhcp-server.c | 25 +- src/libsystemd-network/test-dhcp6-client.c | 69 +- src/libsystemd-network/test-ipv4ll-manual.c | 9 +- src/libsystemd-network/test-ipv4ll.c | 4 +- src/libsystemd-network/test-lldp.c | 11 +- src/libsystemd-network/test-ndisc-rs.c | 2 - src/libsystemd/libsystemd.sym | 8 + src/libsystemd/sd-bus/bus-bloom.c | 2 - src/libsystemd/sd-bus/bus-bloom.h | 2 - src/libsystemd/sd-bus/bus-common-errors.c | 14 +- src/libsystemd/sd-bus/bus-common-errors.h | 10 +- src/libsystemd/sd-bus/bus-container.c | 2 - src/libsystemd/sd-bus/bus-container.h | 2 - src/libsystemd/sd-bus/bus-control.c | 22 +- src/libsystemd/sd-bus/bus-control.h | 3 +- src/libsystemd/sd-bus/bus-convenience.c | 28 +- src/libsystemd/sd-bus/bus-creds.c | 8 +- src/libsystemd/sd-bus/bus-creds.h | 2 - src/libsystemd/sd-bus/bus-dump.c | 2 - src/libsystemd/sd-bus/bus-dump.h | 4 +- src/libsystemd/sd-bus/bus-error.c | 59 +- src/libsystemd/sd-bus/bus-error.h | 3 +- src/libsystemd/sd-bus/bus-gvariant.c | 2 - src/libsystemd/sd-bus/bus-gvariant.h | 2 - src/libsystemd/sd-bus/bus-internal.c | 2 - src/libsystemd/sd-bus/bus-internal.h | 4 +- src/libsystemd/sd-bus/bus-introspect.c | 2 - src/libsystemd/sd-bus/bus-introspect.h | 3 +- src/libsystemd/sd-bus/bus-kernel.c | 43 +- src/libsystemd/sd-bus/bus-kernel.h | 2 - src/libsystemd/sd-bus/bus-match.c | 4 +- src/libsystemd/sd-bus/bus-match.h | 2 - src/libsystemd/sd-bus/bus-message.c | 14 +- src/libsystemd/sd-bus/bus-message.h | 2 - src/libsystemd/sd-bus/bus-objects.c | 42 +- src/libsystemd/sd-bus/bus-objects.h | 2 - src/libsystemd/sd-bus/bus-protocol.h | 2 - src/libsystemd/sd-bus/bus-signature.c | 2 - src/libsystemd/sd-bus/bus-signature.h | 2 - src/libsystemd/sd-bus/bus-slot.c | 6 +- src/libsystemd/sd-bus/bus-slot.h | 3 +- src/libsystemd/sd-bus/bus-socket.c | 4 +- src/libsystemd/sd-bus/bus-socket.h | 2 - src/libsystemd/sd-bus/bus-track.c | 10 +- src/libsystemd/sd-bus/bus-track.h | 2 - src/libsystemd/sd-bus/bus-type.c | 2 - src/libsystemd/sd-bus/bus-type.h | 2 - src/libsystemd/sd-bus/busctl-introspect.c | 2 - src/libsystemd/sd-bus/busctl-introspect.h | 2 - src/libsystemd/sd-bus/busctl.c | 30 +- src/libsystemd/sd-bus/sd-bus.c | 34 +- src/libsystemd/sd-bus/test-bus-benchmark.c | 10 +- src/libsystemd/sd-bus/test-bus-chat.c | 20 +- src/libsystemd/sd-bus/test-bus-cleanup.c | 18 +- src/libsystemd/sd-bus/test-bus-creds.c | 6 +- src/libsystemd/sd-bus/test-bus-error.c | 35 +- src/libsystemd/sd-bus/test-bus-gvariant.c | 6 +- src/libsystemd/sd-bus/test-bus-introspect.c | 2 - src/libsystemd/sd-bus/test-bus-kernel-bloom.c | 4 +- src/libsystemd/sd-bus/test-bus-kernel.c | 6 +- src/libsystemd/sd-bus/test-bus-marshal.c | 8 +- src/libsystemd/sd-bus/test-bus-match.c | 6 +- src/libsystemd/sd-bus/test-bus-objects.c | 8 +- src/libsystemd/sd-bus/test-bus-proxy.c | 4 +- src/libsystemd/sd-bus/test-bus-server.c | 8 +- src/libsystemd/sd-bus/test-bus-signature.c | 2 - src/libsystemd/sd-bus/test-bus-zero-copy.c | 2 - src/libsystemd/sd-daemon/sd-daemon.c | 2 - .../sd-device/device-enumerator-private.h | 2 - src/libsystemd/sd-device/device-enumerator.c | 8 +- src/libsystemd/sd-device/device-private.c | 10 +- src/libsystemd/sd-device/device-private.h | 2 - src/libsystemd/sd-device/device-util.h | 8 - src/libsystemd/sd-device/sd-device.c | 8 +- src/libsystemd/sd-event/sd-event.c | 150 +- src/libsystemd/sd-event/test-event.c | 48 +- src/libsystemd/sd-hwdb/hwdb-util.h | 5 - src/libsystemd/sd-hwdb/sd-hwdb.c | 2 +- src/libsystemd/sd-id128/sd-id128.c | 2 - src/libsystemd/sd-login/sd-login.c | 7 +- src/libsystemd/sd-login/test-login.c | 2 - src/libsystemd/sd-netlink/local-addresses.c | 10 +- src/libsystemd/sd-netlink/local-addresses.h | 3 +- src/libsystemd/sd-netlink/netlink-internal.h | 6 +- src/libsystemd/sd-netlink/netlink-message.c | 17 +- src/libsystemd/sd-netlink/netlink-socket.c | 8 +- src/libsystemd/sd-netlink/netlink-types.c | 11 - src/libsystemd/sd-netlink/netlink-types.h | 2 - src/libsystemd/sd-netlink/netlink-util.c | 6 +- src/libsystemd/sd-netlink/netlink-util.h | 8 - src/libsystemd/sd-netlink/rtnl-message.c | 2 - src/libsystemd/sd-netlink/sd-netlink.c | 26 +- .../sd-netlink/test-local-addresses.c | 2 - src/libsystemd/sd-netlink/test-netlink.c | 31 +- src/libsystemd/sd-network/network-util.c | 2 - src/libsystemd/sd-network/network-util.h | 5 - src/libsystemd/sd-network/sd-network.c | 207 +- src/libsystemd/sd-resolve/sd-resolve.c | 5 +- src/libsystemd/sd-resolve/test-resolve.c | 15 +- src/libsystemd/sd-utf8/sd-utf8.c | 2 - src/libudev/libudev-device-private.c | 8 +- src/libudev/libudev-enumerate.c | 2 +- src/libudev/libudev-hwdb.c | 2 +- src/libudev/libudev-private.h | 2 +- src/locale/localectl.c | 12 +- src/locale/localed.c | 15 +- src/login/inhibit.c | 10 +- src/login/loginctl.c | 56 +- src/login/logind-acl.c | 2 - src/login/logind-acl.h | 4 +- src/login/logind-action.c | 4 +- src/login/logind-action.h | 4 +- src/login/logind-button.c | 2 - src/login/logind-button.h | 2 - src/login/logind-core.c | 6 +- src/login/logind-dbus.c | 159 +- src/login/logind-device.c | 2 - src/login/logind-device.h | 2 - src/login/logind-inhibit.c | 2 - src/login/logind-inhibit.h | 2 - src/login/logind-seat-dbus.c | 6 +- src/login/logind-seat.c | 5 +- src/login/logind-seat.h | 2 - src/login/logind-session-dbus.c | 12 +- src/login/logind-session-device.c | 4 +- src/login/logind-session-device.h | 2 - src/login/logind-session.c | 6 +- src/login/logind-session.h | 4 +- src/login/logind-user-dbus.c | 6 +- src/login/logind-user.c | 23 +- src/login/logind-user.h | 2 - src/login/logind-utmp.c | 2 - src/login/logind.c | 13 +- src/login/logind.conf | 2 +- src/login/logind.h | 2 - src/login/pam_systemd.c | 12 +- src/login/sysfs-show.c | 2 - src/login/sysfs-show.h | 2 - src/login/test-inhibit.c | 12 +- src/login/test-login-shared.c | 2 - src/machine-id-setup/machine-id-setup-main.c | 4 +- src/machine/image-dbus.c | 5 +- src/machine/image-dbus.h | 2 - src/machine/machine-dbus.c | 26 +- src/machine/machine-dbus.h | 2 - src/machine/machine.c | 4 +- src/machine/machine.h | 2 - src/machine/machinectl.c | 191 +- src/machine/machined-dbus.c | 52 +- src/machine/machined.c | 4 +- src/machine/machined.h | 6 +- src/modules-load/modules-load.c | 2 - src/network/networkctl.c | 109 +- src/network/networkd-address-pool.c | 2 - src/network/networkd-address-pool.h | 3 +- src/network/networkd-address.c | 6 +- src/network/networkd-address.h | 6 +- src/network/networkd-dhcp4.c | 63 +- src/network/networkd-dhcp6.c | 2 - src/network/networkd-fdb.c | 4 +- src/network/networkd-fdb.h | 4 +- src/network/networkd-ipv4ll.c | 2 - src/network/networkd-link-bus.c | 15 +- src/network/networkd-link.c | 169 +- src/network/networkd-link.h | 6 +- src/network/networkd-manager-bus.c | 2 - src/network/networkd-manager.c | 84 +- src/network/networkd-ndisc.c | 4 +- src/network/networkd-netdev-bond.c | 2 - src/network/networkd-netdev-bond.h | 2 - src/network/networkd-netdev-bridge.c | 4 +- src/network/networkd-netdev-bridge.h | 2 - src/network/networkd-netdev-dummy.c | 2 - src/network/networkd-netdev-dummy.h | 2 - src/network/networkd-netdev-gperf.gperf | 2 + src/network/networkd-netdev-ipvlan.c | 2 - src/network/networkd-netdev-ipvlan.h | 2 - src/network/networkd-netdev-macvlan.c | 2 - src/network/networkd-netdev-macvlan.h | 2 - src/network/networkd-netdev-tunnel.c | 38 +- src/network/networkd-netdev-tunnel.h | 2 - src/network/networkd-netdev-tuntap.c | 2 - src/network/networkd-netdev-tuntap.h | 2 - src/network/networkd-netdev-veth.c | 2 - src/network/networkd-netdev-veth.h | 2 - src/network/networkd-netdev-vlan.c | 2 - src/network/networkd-netdev-vlan.h | 2 - src/network/networkd-netdev-vxlan.c | 102 +- src/network/networkd-netdev-vxlan.h | 30 +- src/network/networkd-netdev.c | 10 +- src/network/networkd-netdev.h | 18 +- src/network/networkd-network-bus.c | 2 - src/network/networkd-network-gperf.gperf | 35 +- src/network/networkd-network.c | 191 +- src/network/networkd-network.h | 46 +- src/network/networkd-route.c | 9 +- src/network/networkd-route.h | 4 +- src/network/networkd-util.c | 53 - src/network/networkd-util.h | 14 - src/network/networkd-wait-online-link.c | 2 - src/network/networkd-wait-online-link.h | 2 - src/network/networkd-wait-online-manager.c | 4 +- src/network/networkd-wait-online.h | 2 - src/network/networkd.c | 2 - src/network/networkd.h | 8 +- src/network/test-network.c | 2 - src/notify/notify.c | 2 - src/nspawn/nspawn-cgroup.c | 3 +- src/nspawn/nspawn-cgroup.h | 4 +- src/nspawn/nspawn-expose-ports.c | 4 +- src/nspawn/nspawn-expose-ports.h | 5 +- src/nspawn/nspawn-gperf.gperf | 4 +- src/nspawn/nspawn-mount.c | 2 - src/nspawn/nspawn-mount.h | 2 - src/nspawn/nspawn-network.c | 24 +- src/nspawn/nspawn-network.h | 5 +- src/nspawn/nspawn-register.c | 26 +- src/nspawn/nspawn-register.h | 2 - src/nspawn/nspawn-settings.c | 96 +- src/nspawn/nspawn-settings.h | 45 +- src/nspawn/nspawn-setuid.c | 6 +- src/nspawn/nspawn-setuid.h | 2 - src/nspawn/nspawn-stub-pid1.c | 170 + src/nspawn/nspawn-stub-pid1.h | 22 + src/nspawn/nspawn.c | 143 +- src/nss-myhostname/nss-myhostname.c | 9 +- src/nss-mymachines/nss-mymachines.c | 74 +- src/nss-resolve/nss-resolve.c | 178 +- src/path/path.c | 2 - src/quotacheck/quotacheck.c | 2 - src/random-seed/random-seed.c | 24 +- src/rc-local-generator/rc-local-generator.c | 2 - src/remount-fs/remount-fs.c | 2 - src/reply-password/reply-password.c | 2 - src/resolve-host/resolve-host.c | 657 - src/resolve/RFCs | 59 + src/resolve/dns-type.c | 272 +- src/resolve/dns-type.h | 45 +- src/resolve/resolve-tool.c | 1272 ++ src/resolve/resolved-bus.c | 1316 +- src/resolve/resolved-bus.h | 3 +- src/resolve/resolved-conf.c | 170 +- src/resolve/resolved-conf.h | 14 +- src/resolve/resolved-def.h | 24 +- src/resolve/resolved-dns-answer.c | 703 +- src/resolve/resolved-dns-answer.h | 99 +- src/resolve/resolved-dns-cache.c | 704 +- src/resolve/resolved-dns-cache.h | 20 +- src/resolve/resolved-dns-dnssec.c | 2211 +++ src/resolve/resolved-dns-dnssec.h | 102 + src/resolve/resolved-dns-packet.c | 737 +- src/resolve/resolved-dns-packet.h | 114 +- src/resolve/resolved-dns-query.c | 1383 +- src/resolve/resolved-dns-query.h | 76 +- src/resolve/resolved-dns-question.c | 297 +- src/resolve/resolved-dns-question.h | 34 +- src/resolve/resolved-dns-rr.c | 877 +- src/resolve/resolved-dns-rr.h | 189 +- src/resolve/resolved-dns-scope.c | 338 +- src/resolve/resolved-dns-scope.h | 38 +- src/resolve/resolved-dns-search-domain.c | 227 + src/resolve/resolved-dns-search-domain.h | 74 + src/resolve/resolved-dns-server.c | 665 +- src/resolve/resolved-dns-server.h | 86 +- src/resolve/resolved-dns-stream.c | 11 +- src/resolve/resolved-dns-stream.h | 2 - src/resolve/resolved-dns-synthesize.c | 413 + .../resolved-dns-synthesize.h} | 18 +- src/resolve/resolved-dns-transaction.c | 2713 ++- src/resolve/resolved-dns-transaction.h | 105 +- src/resolve/resolved-dns-trust-anchor.c | 743 + src/resolve/resolved-dns-trust-anchor.h | 43 + src/resolve/resolved-dns-zone.c | 317 +- src/resolve/resolved-dns-zone.h | 10 +- src/resolve/resolved-etc-hosts.c | 448 + .../resolved-etc-hosts.h} | 25 +- src/resolve/resolved-gperf.gperf | 8 +- src/resolve/resolved-link-bus.c | 550 + src/resolve/resolved-link-bus.h | 38 + src/resolve/resolved-link.c | 466 +- src/resolve/resolved-link.h | 34 +- src/resolve/resolved-llmnr.c | 24 +- src/resolve/resolved-llmnr.h | 2 - src/resolve/resolved-manager.c | 622 +- src/resolve/resolved-manager.h | 74 +- src/resolve/resolved-mdns.c | 287 + .../lldp-util.h => resolve/resolved-mdns.h} | 16 +- src/resolve/resolved-resolv-conf.c | 267 + .../resolved-resolv-conf.h} | 15 +- src/resolve/resolved.c | 9 +- src/resolve/resolved.conf.in | 2 + src/resolve/test-dnssec-complex.c | 236 + src/resolve/test-dnssec.c | 336 + src/resolve/test-resolve-tables.c | 27 + src/rfkill/rfkill.c | 2 - src/run/run.c | 29 +- src/shared/acl-util.c | 47 +- src/shared/acl-util.h | 5 +- src/shared/acpi-fpdt.c | 6 +- src/shared/acpi-fpdt.h | 2 - src/shared/apparmor-util.c | 5 +- src/shared/apparmor-util.h | 2 - src/shared/architecture.c | 3 +- src/shared/architecture.h | 3 +- src/shared/ask-password-api.c | 30 +- src/shared/ask-password-api.h | 2 - src/shared/base-filesystem.c | 5 +- src/shared/base-filesystem.h | 2 - src/shared/boot-timestamps.c | 4 +- src/shared/boot-timestamps.h | 2 - src/shared/bus-util.c | 207 +- src/shared/bus-util.h | 26 +- src/shared/cgroup-show.c | 6 +- src/shared/cgroup-show.h | 4 +- src/shared/clean-ipc.c | 11 +- src/shared/clean-ipc.h | 2 - src/shared/condition.c | 10 +- src/shared/condition.h | 2 - src/shared/conf-parser.c | 10 +- src/shared/conf-parser.h | 9 +- src/shared/dev-setup.c | 3 +- src/shared/dev-setup.h | 2 - src/shared/dns-domain.c | 889 +- src/shared/dns-domain.h | 53 +- src/shared/dropin.c | 16 +- src/shared/dropin.h | 3 +- src/shared/efivars.c | 12 +- src/shared/efivars.h | 5 +- src/shared/firewall-util.c | 12 +- src/shared/firewall-util.h | 5 +- src/shared/fstab-util.c | 9 +- src/shared/fstab-util.h | 2 - src/shared/generator.c | 12 +- src/shared/generator.h | 2 - src/shared/gpt.h | 9 +- src/shared/ima-util.c | 2 - src/shared/ima-util.h | 2 - src/shared/import-util.c | 59 +- src/shared/import-util.h | 8 - src/shared/install-printf.c | 11 +- src/shared/install-printf.h | 2 - src/shared/install.c | 12 +- src/shared/install.h | 5 +- src/shared/logs-show.c | 44 +- src/shared/logs-show.h | 8 +- src/shared/machine-image.c | 17 +- src/shared/machine-image.h | 10 +- src/shared/machine-pool.c | 21 +- src/shared/machine-pool.h | 4 +- src/shared/output-mode.h | 2 - src/shared/pager.c | 10 +- src/shared/pager.h | 2 - src/shared/path-lookup.c | 4 +- src/shared/path-lookup.h | 3 +- src/shared/ptyfwd.c | 16 +- src/shared/ptyfwd.h | 4 +- src/shared/resolve-util.c | 39 + src/shared/resolve-util.h | 60 + src/shared/seccomp-util.c | 6 +- src/shared/seccomp-util.h | 3 +- src/shared/sleep-config.c | 10 +- src/shared/sleep-config.h | 2 - src/shared/spawn-ask-password-agent.c | 2 - src/shared/spawn-ask-password-agent.h | 2 - src/shared/spawn-polkit-agent.c | 4 +- src/shared/spawn-polkit-agent.h | 2 - src/shared/specifier.c | 9 +- src/shared/specifier.h | 2 - src/shared/switch-root.c | 9 +- src/shared/switch-root.h | 3 +- src/shared/sysctl-util.c | 9 +- src/shared/sysctl-util.h | 2 - src/shared/test-tables.h | 15 +- src/shared/udev-util.h | 2 - src/shared/uid-range.c | 8 +- src/shared/uid-range.h | 2 - src/shared/utmp-wtmp.c | 8 +- src/shared/utmp-wtmp.h | 6 +- src/shared/watchdog.c | 4 +- src/shared/watchdog.h | 5 +- src/sleep/sleep.c | 2 - src/socket-proxy/socket-proxyd.c | 4 +- src/sysctl/sysctl.c | 2 - .../system-update-generator.c | 2 - src/systemctl/systemctl.c | 417 +- src/systemd/_sd-common.h | 17 +- src/systemd/sd-bus-protocol.h | 2 - src/systemd/sd-bus-vtable.h | 2 - src/systemd/sd-bus.h | 13 +- src/systemd/sd-daemon.h | 4 +- src/systemd/sd-device.h | 7 +- src/systemd/sd-dhcp-client.h | 49 +- src/systemd/sd-dhcp-lease.h | 12 +- src/systemd/sd-dhcp-server.h | 5 +- src/systemd/sd-dhcp6-client.h | 41 +- src/systemd/sd-dhcp6-lease.h | 4 +- src/systemd/sd-event.h | 19 +- src/systemd/sd-hwdb.h | 4 +- src/systemd/sd-id128.h | 2 - src/systemd/sd-ipv4acd.h | 9 +- src/systemd/sd-ipv4ll.h | 7 +- src/systemd/sd-journal.h | 23 +- src/systemd/sd-lldp.h | 10 +- src/systemd/sd-login.h | 6 +- src/systemd/sd-messages.h | 7 +- src/systemd/sd-ndisc.h | 5 +- src/systemd/sd-netlink.h | 9 +- src/systemd/sd-network.h | 45 +- src/systemd/sd-path.h | 2 - src/systemd/sd-resolve.h | 12 +- src/systemd/sd-utf8.h | 2 - src/sysusers/sysusers.c | 15 +- src/sysv-generator/sysv-generator.c | 27 +- src/test/test-acl-util.c | 85 + src/test/test-architecture.c | 2 - src/test/test-ask-password-api.c | 38 + src/test/test-barrier.c | 2 - src/test/test-boot-timestamps.c | 2 - src/test/test-btrfs.c | 2 - src/test/test-calendarspec.c | 15 +- src/test/test-cap-list.c | 2 - src/test/test-capability.c | 68 +- src/test/test-cgroup-mask.c | 3 +- src/test/test-cgroup-util.c | 2 - src/test/test-cgroup.c | 2 - src/test/test-condition.c | 2 +- src/test/test-conf-files.c | 2 - src/test/test-daemon.c | 2 - src/test/test-date.c | 8 +- src/test/test-device-nodes.c | 2 - src/test/test-dns-domain.c | 407 +- src/test/test-ellipsize.c | 2 - src/test/test-engine.c | 9 +- src/test/test-env-replace.c | 2 - src/test/test-execute.c | 21 +- src/test/test-extract-word.c | 2 - src/test/test-fileio.c | 2 - src/test/test-firewall-util.c | 2 - src/test/test-fstab-util.c | 2 - src/test/test-helper.h | 14 +- src/test/test-hostname-util.c | 2 - src/test/test-hostname.c | 2 - src/test/test-id128.c | 2 - src/test/test-install-root.c | 2 - src/test/test-install.c | 2 - src/test/test-ipcrm.c | 2 - src/test/test-job-type.c | 2 - src/test/test-json.c | 2 - src/test/test-libudev.c | 4 +- src/test/test-log.c | 2 - src/test/test-loopback.c | 2 - src/test/test-namespace.c | 2 - src/test/test-netlink-manual.c | 2 - src/test/test-ns.c | 2 - src/test/test-parse-util.c | 2 - src/test/test-path-lookup.c | 2 - src/test/test-path-util.c | 2 - src/test/test-path.c | 5 +- src/test/test-prioq.c | 2 - src/test/test-rbtree.c | 362 + src/test/test-replace-var.c | 2 - src/test/test-rlimit-util.c | 104 + src/test/test-sched-prio.c | 7 +- src/test/test-sigbus.c | 2 - src/test/test-signal-util.c | 49 + src/test/test-siphash24.c | 8 +- src/test/test-sleep.c | 2 - src/test/test-strbuf.c | 2 - src/test/test-string-util.c | 48 +- src/test/test-strip-tab-ansi.c | 2 - src/test/test-strv.c | 2 - src/test/test-strxcpyx.c | 2 - src/test/test-time.c | 40 +- src/test/test-tmpfiles.c | 19 +- src/test/test-uid-range.c | 2 - src/test/test-unit-file.c | 199 +- src/test/test-unit-name.c | 127 +- src/test/test-user-util.c | 2 - src/test/test-utf8.c | 2 - src/test/test-util.c | 23 +- src/test/test-watchdog.c | 2 - src/test/test-xml.c | 2 - src/timedate/timedatectl.c | 12 +- src/timedate/timedated.c | 13 +- src/timesync/timesyncd-conf.c | 2 - src/timesync/timesyncd-conf.h | 3 - src/timesync/timesyncd-manager.c | 5 +- src/timesync/timesyncd-manager.h | 5 +- src/timesync/timesyncd-server.c | 2 - src/timesync/timesyncd-server.h | 4 +- src/timesync/timesyncd.c | 2 - src/tmpfiles/tmpfiles.c | 27 +- .../tty-ask-password-agent.c | 125 +- src/udev/collect/collect.c | 3 +- src/udev/net/ethtool-util.c | 2 - src/udev/net/ethtool-util.h | 2 - src/udev/net/link-config.c | 2 - src/udev/net/link-config.h | 2 - src/udev/scsi_id/scsi.h | 62 +- src/udev/scsi_id/scsi_serial.c | 75 +- src/udev/udev-builtin-blkid.c | 2 +- src/udev/udev-builtin-input_id.c | 14 +- src/udev/udev-builtin-net_id.c | 35 +- src/udev/udev-builtin-net_setup_link.c | 2 - src/udev/udev-builtin-path_id.c | 6 + src/udev/udev-event.c | 11 +- src/udev/udev-node.c | 11 +- src/udev/udev-watch.c | 7 +- src/udev/udevadm-hwdb.c | 2 +- src/udev/udevadm.c | 1 - src/udev/udevd.c | 6 +- src/update-done/update-done.c | 2 - src/update-utmp/update-utmp.c | 6 +- src/user-sessions/user-sessions.c | 10 +- src/vconsole/vconsole-setup.c | 7 +- sysctl.d/50-coredump.conf.in | 2 +- sysusers.d/.gitignore | 1 + sysusers.d/basic.conf.in | 1 - ...emd-remote.conf => systemd-remote.conf.m4} | 4 + sysusers.d/systemd.conf.m4 | 3 + test/README.testsuite | 2 +- test/TEST-01-BASIC/test.sh | 11 +- test/TEST-02-CRYPTSETUP/test.sh | 5 +- test/TEST-03-JOBS/test-jobs.sh | 8 +- test/TEST-03-JOBS/test.sh | 2 +- test/TEST-04-JOURNAL/Makefile | 1 + test/TEST-04-JOURNAL/test-journal.sh | 62 + test/TEST-04-JOURNAL/test.sh | 85 + test/TEST-05-RLIMITS/Makefile | 1 + test/TEST-05-RLIMITS/test-rlimits.sh | 16 + test/TEST-05-RLIMITS/test.sh | 81 + test/TEST-06-SELINUX/Makefile | 10 + test/TEST-06-SELINUX/systemd_test.if | 8 + test/TEST-06-SELINUX/systemd_test.te | 50 + test/TEST-06-SELINUX/test-selinux-checks.sh | 12 + test/TEST-06-SELINUX/test.sh | 135 + test/TEST-07-ISSUE-1981/Makefile | 1 + test/TEST-07-ISSUE-1981/test-segfault.sh | 36 + test/TEST-07-ISSUE-1981/test.sh | 58 + test/networkd-test.py | 371 + test/sys.tar.xz | Bin 165116 -> 261380 bytes test/sysv-generator-test.py | 18 +- .../exec-capabilityambientset-merge.service | 9 + .../exec-capabilityambientset.service | 8 + test/test-functions | 122 +- test/udev-test.pl | 4 +- tmpfiles.d/legacy.conf | 8 - tmpfiles.d/systemd-remote.conf | 6 +- tmpfiles.d/systemd.conf.m4 | 4 + tools/make-directive-index.py | 1 + units/.gitignore | 1 + units/basic.target | 9 +- units/console-shell.service.m4.in | 2 +- units/dev-mqueue.mount | 1 + units/emergency.service.in | 2 +- units/kmod-static-nodes.service.in | 2 +- units/rescue.service.in | 4 +- units/sys-fs-fuse-connections.mount | 1 + units/systemd-coredump.socket | 17 + units/systemd-coredump@.service.in | 24 + units/systemd-journal-gatewayd.service.in | 1 + units/systemd-journal-gatewayd.socket | 1 + units/systemd-journal-remote.service.in | 1 + units/systemd-journal-upload.service.in | 2 + units/user@.service.m4.in | 1 + 1216 files changed, 48516 insertions(+), 21379 deletions(-) create mode 100644 .editorconfig create mode 100644 CONTRIBUTING.md create mode 100644 catalog/systemd.hu.catalog create mode 100644 coccinelle/xsprintf.cocci create mode 100644 man/dnssec-trust-anchors.d.xml create mode 100644 man/sd-bus.xml create mode 100644 man/sd-event.xml create mode 100644 man/sd_event_add_io.xml create mode 100644 man/sd_event_exit.xml create mode 100644 man/sd_event_now.xml delete mode 100644 man/sd_event_set_name.xml create mode 100644 man/sd_event_set_watchdog.xml create mode 100644 man/sd_event_source_get_event.xml create mode 100644 man/sd_event_source_get_pending.xml create mode 100644 man/sd_event_source_set_description.xml create mode 100644 man/sd_event_source_set_enabled.xml create mode 100644 man/sd_event_source_set_prepare.xml create mode 100644 man/sd_event_source_set_priority.xml create mode 100644 man/sd_event_source_set_userdata.xml create mode 100644 man/sd_event_source_unref.xml create mode 100644 man/sd_journal_enumerate_fields.xml create mode 100644 man/sd_journal_has_runtime_files.xml create mode 100644 man/systemd-resolve.xml create mode 100644 src/basic/c-rbtree.c create mode 100644 src/basic/c-rbtree.h create mode 100644 src/basic/hash-funcs.c create mode 100644 src/basic/hash-funcs.h rename src/{shared => basic}/nss-util.h (98%) create mode 100644 src/basic/ordered-set.c rename src/{resolve-host => coredump}/Makefile (100%) rename src/{journal => coredump}/coredump-vacuum.c (99%) rename src/{journal => coredump}/coredump-vacuum.h (93%) rename src/{journal => coredump}/coredump.c (52%) rename src/{journal => coredump}/coredump.conf (100%) rename src/{journal => coredump}/coredumpctl.c (99%) rename src/{journal => coredump}/stacktrace.c (98%) rename src/{journal => coredump}/stacktrace.h (92%) rename src/{journal => coredump}/test-coredump-vacuum.c (93%) delete mode 100644 src/import/pull-dkr.c create mode 100644 src/nspawn/nspawn-stub-pid1.c create mode 100644 src/nspawn/nspawn-stub-pid1.h delete mode 100644 src/resolve-host/resolve-host.c create mode 100644 src/resolve/RFCs create mode 100644 src/resolve/resolve-tool.c create mode 100644 src/resolve/resolved-dns-dnssec.c create mode 100644 src/resolve/resolved-dns-dnssec.h create mode 100644 src/resolve/resolved-dns-search-domain.c create mode 100644 src/resolve/resolved-dns-search-domain.h create mode 100644 src/resolve/resolved-dns-synthesize.c rename src/{libsystemd/sd-event/event-util.h => resolve/resolved-dns-synthesize.h} (63%) create mode 100644 src/resolve/resolved-dns-trust-anchor.c create mode 100644 src/resolve/resolved-dns-trust-anchor.h create mode 100644 src/resolve/resolved-etc-hosts.c rename src/{import/pull-dkr.h => resolve/resolved-etc-hosts.h} (50%) create mode 100644 src/resolve/resolved-link-bus.c create mode 100644 src/resolve/resolved-link-bus.h create mode 100644 src/resolve/resolved-mdns.c rename src/{libsystemd-network/lldp-util.h => resolve/resolved-mdns.h} (74%) create mode 100644 src/resolve/resolved-resolv-conf.c rename src/{libsystemd/sd-resolve/resolve-util.h => resolve/resolved-resolv-conf.h} (63%) create mode 100644 src/resolve/test-dnssec-complex.c create mode 100644 src/resolve/test-dnssec.c create mode 100644 src/resolve/test-resolve-tables.c create mode 100644 src/shared/resolve-util.c create mode 100644 src/shared/resolve-util.h create mode 100644 src/test/test-acl-util.c create mode 100644 src/test/test-ask-password-api.c create mode 100644 src/test/test-rbtree.c create mode 100644 src/test/test-rlimit-util.c create mode 100644 src/test/test-signal-util.c rename sysusers.d/{systemd-remote.conf => systemd-remote.conf.m4} (86%) create mode 120000 test/TEST-04-JOURNAL/Makefile create mode 100755 test/TEST-04-JOURNAL/test-journal.sh create mode 100755 test/TEST-04-JOURNAL/test.sh create mode 120000 test/TEST-05-RLIMITS/Makefile create mode 100755 test/TEST-05-RLIMITS/test-rlimits.sh create mode 100755 test/TEST-05-RLIMITS/test.sh create mode 100644 test/TEST-06-SELINUX/Makefile create mode 100644 test/TEST-06-SELINUX/systemd_test.if create mode 100644 test/TEST-06-SELINUX/systemd_test.te create mode 100755 test/TEST-06-SELINUX/test-selinux-checks.sh create mode 100755 test/TEST-06-SELINUX/test.sh create mode 120000 test/TEST-07-ISSUE-1981/Makefile create mode 100755 test/TEST-07-ISSUE-1981/test-segfault.sh create mode 100755 test/TEST-07-ISSUE-1981/test.sh create mode 100755 test/networkd-test.py create mode 100644 test/test-execute/exec-capabilityambientset-merge.service create mode 100644 test/test-execute/exec-capabilityambientset.service create mode 100644 units/systemd-coredump.socket create mode 100644 units/systemd-coredump@.service.in diff --git a/.dir-locals.el b/.dir-locals.el index 9d9f8cd17..3e1b2d76c 100644 --- a/.dir-locals.el +++ b/.dir-locals.el @@ -2,6 +2,22 @@ ; A list of (major-mode . ((var1 . value1) (var2 . value2))) ; Mode can be nil, which gives default values. +; Note that we set a line width of 119 for .c and XML files, but for everything +; else (such as journal catalog files, unit files, README files) we stick to a +; more conservative 79 characters. + +; NOTE: If you update this file make sure to update .vimrc and .editorconfig, +; too. + ((nil . ((indent-tabs-mode . nil) - (tab-width . 8))) -) + (tab-width . 8) + (fill-column . 79))) + (c-mode . ((fill-column . 119) + (c-basic-offset . 8) + (eval . (c-set-offset 'substatement-open 0)) + (eval . (c-set-offset 'statement-case-open 0)) + (eval . (c-set-offset 'case-label 0)) + (eval . (c-set-offset 'arglist-intro '++)) + (eval . (c-set-offset 'arglist-close 0)))) + (nxml-mode . ((nxml-child-indent . 2) + (fill-column . 119)))) diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..e98007c4e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +# EditorConfig configuration for systemd +# http://EditorConfig.org + +# NOTE: If you update this file make sure to update .dir-locals.el and .vimrc, +# too. + +# Top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file, utf-8 charset +[*] +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +charset = utf-8 + +# Match config files, set indent to spaces with width of eight +[*.{c,h}] +indent_style = space +indent_size = 8 diff --git a/.gitignore b/.gitignore index b0abc0d4e..586b3796b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,5 @@ *.a *.cache -*.html *.la *.lo *.log @@ -110,7 +109,7 @@ /systemd-remount-api-vfs /systemd-remount-fs /systemd-reply-password -/systemd-resolve-host +/systemd-resolve /systemd-resolved /systemd-rfkill /systemd-run @@ -134,9 +133,11 @@ /systemd-vconsole-setup /tags /test-acd +/test-acl-util /test-af-list /test-architecture /test-arphrd-list +/test-ask-password-api /test-async /test-audit-type /test-barrier @@ -177,11 +178,13 @@ /test-daemon /test-date /test-device-nodes +/test-dnssec-complex /test-dhcp-client /test-dhcp-option /test-dhcp-server /test-dhcp6-client /test-dns-domain +/test-dnssec /test-efi-disk.img /test-ellipsize /test-engine @@ -245,12 +248,16 @@ /test-pty /test-qcow2 /test-ratelimit +/test-rbtree /test-replace-var /test-resolve +/test-resolve-tables /test-ring +/test-rlimit-util /test-sched-prio /test-set /test-sigbus +/test-signal-util /test-siphash24 /test-sleep /test-socket-util diff --git a/.vimrc b/.vimrc index b802c908f..7b436bd37 100644 --- a/.vimrc +++ b/.vimrc @@ -1,5 +1,20 @@ " 'set exrc' in ~/.vimrc will read .vimrc from the current directory +" Warning: Enabling exrc is dangerous! You can do nearly everything from a +" vimrc configuration file, including write operations and shell execution. +" You should consider setting 'set secure' as well, which is highly +" recommended! + +" Note that we set a line width of 119 for .c and XML files, but for everything +" else (such as journal catalog files, unit files, README files) we stick to a +" more conservative 79 characters. + +" NOTE: If you update this file make sure to update .dir-locals.el and +" .editorconfig, too. + set tabstop=8 set shiftwidth=8 set expandtab set makeprg=GCC_COLORS=\ make +set tw=79 +au FileType xml set tw=119 +au FileType c set tw=119 diff --git a/CODING_STYLE b/CODING_STYLE index 006430320..46e366898 100644 --- a/CODING_STYLE +++ b/CODING_STYLE @@ -7,7 +7,7 @@ - Don't break code lines too eagerly. We do *not* force line breaks at 80ch, all of today's screens should be much larger than that. But - then again, don't overdo it, ~140ch should be enough really. + then again, don't overdo it, ~119ch should be enough really. - Variables and functions *must* be static, unless they have a prototype, and are supposed to be exported. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..18081cbb4 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,37 @@ +# Contributing + +We welcome contributions from everyone. However, please follow the following guidelines when posting a GitHub Pull +Request or filing a GitHub Issue on the systemd project: + +## Filing Issues + +* We use GitHub Issues **exclusively** for tracking **bugs** and **feature** **requests** of systemd. If you are + looking for help, please contact our [mailing list](http://lists.freedesktop.org/mailman/listinfo/systemd-devel) + instead. +* We only track bugs in the **two** **most** **recently** **released** **versions** of systemd in the GitHub Issue + tracker. If you are using an older version of systemd, please contact your distribution's bug tracker instead. +* When filing an issue, specify the **systemd** **version** you are experiencing the issue with. Also, indicate which + **distribution** you are using. +* Please include an explanation how to reproduce the issue you are pointing out. + +Following these guidelines makes it easier for us to process your issue, and ensures we won't close your issue +right-away for being misfiled. + +## Posting Pull Requests + +* Make sure to post PRs only relative to a very recent git master. +* Follow our [Coding Style](https://raw.githubusercontent.com/systemd/systemd/master/CODING_STYLE) when contributing + code. This is a requirement for all code we merge. +* Make sure to run "make check" locally, before posting your PR. We use a CI system, meaning we don't even look at your + PR, if the build and tests don't pass. +* If you need to update the code in an existing PR, please consider opening a new PR (mentioning in it which old PR it + replaces) and closing the old PR. This is much preferable over force-pushing a new patch set into the PR's branch, as + commit comments aren't lost that way. That said, we don't follow this rule ourselves quite often, hence this is + really just a say as we say, not say as we do... + +## Final Words + +We'd like to apologize in advance if we are not able to process and reply to your issue or PR right-away. We have a lot +of work to do, but we are trying our best! + +Thank you very much for your contributions! diff --git a/Makefile-man.am b/Makefile-man.am index c792c8932..28b5fb6ad 100644 --- a/Makefile-man.am +++ b/Makefile-man.am @@ -25,7 +25,9 @@ MANPAGES += \ man/machine-info.5 \ man/os-release.5 \ man/sd-bus-errors.3 \ + man/sd-bus.3 \ man/sd-daemon.3 \ + man/sd-event.3 \ man/sd-id128.3 \ man/sd-journal.3 \ man/sd_booted.3 \ @@ -47,18 +49,30 @@ MANPAGES += \ man/sd_bus_request_name.3 \ man/sd_event_add_child.3 \ man/sd_event_add_defer.3 \ + man/sd_event_add_io.3 \ man/sd_event_add_signal.3 \ man/sd_event_add_time.3 \ + man/sd_event_exit.3 \ man/sd_event_get_fd.3 \ man/sd_event_new.3 \ + man/sd_event_now.3 \ man/sd_event_run.3 \ - man/sd_event_set_name.3 \ + man/sd_event_set_watchdog.3 \ + man/sd_event_source_get_event.3 \ + man/sd_event_source_get_pending.3 \ + man/sd_event_source_set_description.3 \ + man/sd_event_source_set_enabled.3 \ + man/sd_event_source_set_prepare.3 \ + man/sd_event_source_set_priority.3 \ + man/sd_event_source_set_userdata.3 \ + man/sd_event_source_unref.3 \ man/sd_event_wait.3 \ man/sd_id128_get_machine.3 \ man/sd_id128_randomize.3 \ man/sd_id128_to_string.3 \ man/sd_is_fifo.3 \ man/sd_journal_add_match.3 \ + man/sd_journal_enumerate_fields.3 \ man/sd_journal_get_catalog.3 \ man/sd_journal_get_cursor.3 \ man/sd_journal_get_cutoff_realtime_usec.3 \ @@ -66,6 +80,7 @@ MANPAGES += \ man/sd_journal_get_fd.3 \ man/sd_journal_get_realtime_usec.3 \ man/sd_journal_get_usage.3 \ + man/sd_journal_has_runtime_files.3 \ man/sd_journal_next.3 \ man/sd_journal_open.3 \ man/sd_journal_print.3 \ @@ -108,6 +123,7 @@ MANPAGES += \ man/systemd-nspawn.1 \ man/systemd-path.1 \ man/systemd-remount-fs.service.8 \ + man/systemd-resolve.1 \ man/systemd-run.1 \ man/systemd-sleep.conf.5 \ man/systemd-socket-proxyd.8 \ @@ -199,6 +215,19 @@ MANPAGES_ALIAS += \ man/SD_DEBUG.3 \ man/SD_EMERG.3 \ man/SD_ERR.3 \ + man/SD_EVENT_ARMED.3 \ + man/SD_EVENT_EXITING.3 \ + man/SD_EVENT_FINISHED.3 \ + man/SD_EVENT_INITIAL.3 \ + man/SD_EVENT_OFF.3 \ + man/SD_EVENT_ON.3 \ + man/SD_EVENT_ONESHOT.3 \ + man/SD_EVENT_PENDING.3 \ + man/SD_EVENT_PREPARING.3 \ + man/SD_EVENT_PRIORITY_IDLE.3 \ + man/SD_EVENT_PRIORITY_IMPORTANT.3 \ + man/SD_EVENT_PRIORITY_NORMAL.3 \ + man/SD_EVENT_RUNNING.3 \ man/SD_ID128_CONST_STR.3 \ man/SD_ID128_FORMAT_STR.3 \ man/SD_ID128_FORMAT_VAL.3 \ @@ -209,6 +238,7 @@ MANPAGES_ALIAS += \ man/SD_JOURNAL_FOREACH.3 \ man/SD_JOURNAL_FOREACH_BACKWARDS.3 \ man/SD_JOURNAL_FOREACH_DATA.3 \ + man/SD_JOURNAL_FOREACH_FIELD.3 \ man/SD_JOURNAL_FOREACH_UNIQUE.3 \ man/SD_JOURNAL_INVALIDATE.3 \ man/SD_JOURNAL_LOCAL_ONLY.3 \ @@ -260,6 +290,7 @@ MANPAGES_ALIAS += \ man/sd_bus_creds_has_permitted_cap.3 \ man/sd_bus_creds_ref.3 \ man/sd_bus_creds_unref.3 \ + man/sd_bus_creds_unrefp.3 \ man/sd_bus_default_system.3 \ man/sd_bus_default_user.3 \ man/sd_bus_error_copy.3 \ @@ -295,22 +326,45 @@ MANPAGES_ALIAS += \ man/sd_bus_ref.3 \ man/sd_bus_release_name.3 \ man/sd_bus_unref.3 \ + man/sd_bus_unrefp.3 \ + man/sd_event.3 \ man/sd_event_add_exit.3 \ man/sd_event_add_post.3 \ + man/sd_event_child_handler_t.3 \ man/sd_event_default.3 \ man/sd_event_dispatch.3 \ - man/sd_event_get_name.3 \ + man/sd_event_get_exit_code.3 \ + man/sd_event_get_state.3 \ + man/sd_event_get_tid.3 \ + man/sd_event_get_watchdog.3 \ + man/sd_event_handler_t.3 \ + man/sd_event_io_handler_t.3 \ man/sd_event_loop.3 \ man/sd_event_prepare.3 \ man/sd_event_ref.3 \ + man/sd_event_signal_handler_t.3 \ + man/sd_event_source.3 \ man/sd_event_source_get_child_pid.3 \ + man/sd_event_source_get_description.3 \ + man/sd_event_source_get_enabled.3 \ + man/sd_event_source_get_io_events.3 \ + man/sd_event_source_get_io_fd.3 \ + man/sd_event_source_get_io_revents.3 \ + man/sd_event_source_get_priority.3 \ man/sd_event_source_get_signal.3 \ man/sd_event_source_get_time.3 \ man/sd_event_source_get_time_accuracy.3 \ man/sd_event_source_get_time_clock.3 \ + man/sd_event_source_get_userdata.3 \ + man/sd_event_source_ref.3 \ + man/sd_event_source_set_io_events.3 \ + man/sd_event_source_set_io_fd.3 \ man/sd_event_source_set_time.3 \ man/sd_event_source_set_time_accuracy.3 \ + man/sd_event_source_unrefp.3 \ + man/sd_event_time_handler_t.3 \ man/sd_event_unref.3 \ + man/sd_event_unrefp.3 \ man/sd_id128_equal.3 \ man/sd_id128_from_string.3 \ man/sd_id128_get_boot.3 \ @@ -333,6 +387,7 @@ MANPAGES_ALIAS += \ man/sd_journal_get_events.3 \ man/sd_journal_get_monotonic_usec.3 \ man/sd_journal_get_timeout.3 \ + man/sd_journal_has_persistent_files.3 \ man/sd_journal_next_skip.3 \ man/sd_journal_open_container.3 \ man/sd_journal_open_directory.3 \ @@ -344,6 +399,7 @@ MANPAGES_ALIAS += \ man/sd_journal_process.3 \ man/sd_journal_reliable_fd.3 \ man/sd_journal_restart_data.3 \ + man/sd_journal_restart_fields.3 \ man/sd_journal_restart_unique.3 \ man/sd_journal_seek_cursor.3 \ man/sd_journal_seek_monotonic_usec.3 \ @@ -489,6 +545,19 @@ man/SD_CRIT.3: man/sd-daemon.3 man/SD_DEBUG.3: man/sd-daemon.3 man/SD_EMERG.3: man/sd-daemon.3 man/SD_ERR.3: man/sd-daemon.3 +man/SD_EVENT_ARMED.3: man/sd_event_wait.3 +man/SD_EVENT_EXITING.3: man/sd_event_wait.3 +man/SD_EVENT_FINISHED.3: man/sd_event_wait.3 +man/SD_EVENT_INITIAL.3: man/sd_event_wait.3 +man/SD_EVENT_OFF.3: man/sd_event_source_set_enabled.3 +man/SD_EVENT_ON.3: man/sd_event_source_set_enabled.3 +man/SD_EVENT_ONESHOT.3: man/sd_event_source_set_enabled.3 +man/SD_EVENT_PENDING.3: man/sd_event_wait.3 +man/SD_EVENT_PREPARING.3: man/sd_event_wait.3 +man/SD_EVENT_PRIORITY_IDLE.3: man/sd_event_source_set_priority.3 +man/SD_EVENT_PRIORITY_IMPORTANT.3: man/sd_event_source_set_priority.3 +man/SD_EVENT_PRIORITY_NORMAL.3: man/sd_event_source_set_priority.3 +man/SD_EVENT_RUNNING.3: man/sd_event_wait.3 man/SD_ID128_CONST_STR.3: man/sd-id128.3 man/SD_ID128_FORMAT_STR.3: man/sd-id128.3 man/SD_ID128_FORMAT_VAL.3: man/sd-id128.3 @@ -499,6 +568,7 @@ man/SD_JOURNAL_CURRENT_USER.3: man/sd_journal_open.3 man/SD_JOURNAL_FOREACH.3: man/sd_journal_next.3 man/SD_JOURNAL_FOREACH_BACKWARDS.3: man/sd_journal_next.3 man/SD_JOURNAL_FOREACH_DATA.3: man/sd_journal_get_data.3 +man/SD_JOURNAL_FOREACH_FIELD.3: man/sd_journal_enumerate_fields.3 man/SD_JOURNAL_FOREACH_UNIQUE.3: man/sd_journal_query_unique.3 man/SD_JOURNAL_INVALIDATE.3: man/sd_journal_get_fd.3 man/SD_JOURNAL_LOCAL_ONLY.3: man/sd_journal_open.3 @@ -550,6 +620,7 @@ man/sd_bus_creds_has_inheritable_cap.3: man/sd_bus_creds_get_pid.3 man/sd_bus_creds_has_permitted_cap.3: man/sd_bus_creds_get_pid.3 man/sd_bus_creds_ref.3: man/sd_bus_creds_new_from_pid.3 man/sd_bus_creds_unref.3: man/sd_bus_creds_new_from_pid.3 +man/sd_bus_creds_unrefp.3: man/sd_bus_creds_new_from_pid.3 man/sd_bus_default_system.3: man/sd_bus_default.3 man/sd_bus_default_user.3: man/sd_bus_default.3 man/sd_bus_error_copy.3: man/sd_bus_error.3 @@ -585,22 +656,45 @@ man/sd_bus_path_encode_many.3: man/sd_bus_path_encode.3 man/sd_bus_ref.3: man/sd_bus_new.3 man/sd_bus_release_name.3: man/sd_bus_request_name.3 man/sd_bus_unref.3: man/sd_bus_new.3 +man/sd_bus_unrefp.3: man/sd_bus_new.3 +man/sd_event.3: man/sd_event_new.3 man/sd_event_add_exit.3: man/sd_event_add_defer.3 man/sd_event_add_post.3: man/sd_event_add_defer.3 +man/sd_event_child_handler_t.3: man/sd_event_add_child.3 man/sd_event_default.3: man/sd_event_new.3 man/sd_event_dispatch.3: man/sd_event_wait.3 -man/sd_event_get_name.3: man/sd_event_set_name.3 +man/sd_event_get_exit_code.3: man/sd_event_exit.3 +man/sd_event_get_state.3: man/sd_event_wait.3 +man/sd_event_get_tid.3: man/sd_event_new.3 +man/sd_event_get_watchdog.3: man/sd_event_set_watchdog.3 +man/sd_event_handler_t.3: man/sd_event_add_defer.3 +man/sd_event_io_handler_t.3: man/sd_event_add_io.3 man/sd_event_loop.3: man/sd_event_run.3 man/sd_event_prepare.3: man/sd_event_wait.3 man/sd_event_ref.3: man/sd_event_new.3 +man/sd_event_signal_handler_t.3: man/sd_event_add_signal.3 +man/sd_event_source.3: man/sd_event_add_io.3 man/sd_event_source_get_child_pid.3: man/sd_event_add_child.3 +man/sd_event_source_get_description.3: man/sd_event_source_set_description.3 +man/sd_event_source_get_enabled.3: man/sd_event_source_set_enabled.3 +man/sd_event_source_get_io_events.3: man/sd_event_add_io.3 +man/sd_event_source_get_io_fd.3: man/sd_event_add_io.3 +man/sd_event_source_get_io_revents.3: man/sd_event_add_io.3 +man/sd_event_source_get_priority.3: man/sd_event_source_set_priority.3 man/sd_event_source_get_signal.3: man/sd_event_add_signal.3 man/sd_event_source_get_time.3: man/sd_event_add_time.3 man/sd_event_source_get_time_accuracy.3: man/sd_event_add_time.3 man/sd_event_source_get_time_clock.3: man/sd_event_add_time.3 +man/sd_event_source_get_userdata.3: man/sd_event_source_set_userdata.3 +man/sd_event_source_ref.3: man/sd_event_source_unref.3 +man/sd_event_source_set_io_events.3: man/sd_event_add_io.3 +man/sd_event_source_set_io_fd.3: man/sd_event_add_io.3 man/sd_event_source_set_time.3: man/sd_event_add_time.3 man/sd_event_source_set_time_accuracy.3: man/sd_event_add_time.3 +man/sd_event_source_unrefp.3: man/sd_event_source_unref.3 +man/sd_event_time_handler_t.3: man/sd_event_add_time.3 man/sd_event_unref.3: man/sd_event_new.3 +man/sd_event_unrefp.3: man/sd_event_new.3 man/sd_id128_equal.3: man/sd-id128.3 man/sd_id128_from_string.3: man/sd_id128_to_string.3 man/sd_id128_get_boot.3: man/sd_id128_get_machine.3 @@ -623,6 +717,7 @@ man/sd_journal_get_data_threshold.3: man/sd_journal_get_data.3 man/sd_journal_get_events.3: man/sd_journal_get_fd.3 man/sd_journal_get_monotonic_usec.3: man/sd_journal_get_realtime_usec.3 man/sd_journal_get_timeout.3: man/sd_journal_get_fd.3 +man/sd_journal_has_persistent_files.3: man/sd_journal_has_runtime_files.3 man/sd_journal_next_skip.3: man/sd_journal_next.3 man/sd_journal_open_container.3: man/sd_journal_open.3 man/sd_journal_open_directory.3: man/sd_journal_open.3 @@ -634,6 +729,7 @@ man/sd_journal_printv.3: man/sd_journal_print.3 man/sd_journal_process.3: man/sd_journal_get_fd.3 man/sd_journal_reliable_fd.3: man/sd_journal_get_fd.3 man/sd_journal_restart_data.3: man/sd_journal_get_data.3 +man/sd_journal_restart_fields.3: man/sd_journal_enumerate_fields.3 man/sd_journal_restart_unique.3: man/sd_journal_query_unique.3 man/sd_journal_seek_cursor.3: man/sd_journal_seek_head.3 man/sd_journal_seek_monotonic_usec.3: man/sd_journal_seek_head.3 @@ -857,6 +953,45 @@ man/SD_EMERG.html: man/sd-daemon.html man/SD_ERR.html: man/sd-daemon.html $(html-alias) +man/SD_EVENT_ARMED.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_EXITING.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_FINISHED.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_INITIAL.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_OFF.html: man/sd_event_source_set_enabled.html + $(html-alias) + +man/SD_EVENT_ON.html: man/sd_event_source_set_enabled.html + $(html-alias) + +man/SD_EVENT_ONESHOT.html: man/sd_event_source_set_enabled.html + $(html-alias) + +man/SD_EVENT_PENDING.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_PREPARING.html: man/sd_event_wait.html + $(html-alias) + +man/SD_EVENT_PRIORITY_IDLE.html: man/sd_event_source_set_priority.html + $(html-alias) + +man/SD_EVENT_PRIORITY_IMPORTANT.html: man/sd_event_source_set_priority.html + $(html-alias) + +man/SD_EVENT_PRIORITY_NORMAL.html: man/sd_event_source_set_priority.html + $(html-alias) + +man/SD_EVENT_RUNNING.html: man/sd_event_wait.html + $(html-alias) + man/SD_ID128_CONST_STR.html: man/sd-id128.html $(html-alias) @@ -887,6 +1022,9 @@ man/SD_JOURNAL_FOREACH_BACKWARDS.html: man/sd_journal_next.html man/SD_JOURNAL_FOREACH_DATA.html: man/sd_journal_get_data.html $(html-alias) +man/SD_JOURNAL_FOREACH_FIELD.html: man/sd_journal_enumerate_fields.html + $(html-alias) + man/SD_JOURNAL_FOREACH_UNIQUE.html: man/sd_journal_query_unique.html $(html-alias) @@ -1040,6 +1178,9 @@ man/sd_bus_creds_ref.html: man/sd_bus_creds_new_from_pid.html man/sd_bus_creds_unref.html: man/sd_bus_creds_new_from_pid.html $(html-alias) +man/sd_bus_creds_unrefp.html: man/sd_bus_creds_new_from_pid.html + $(html-alias) + man/sd_bus_default_system.html: man/sd_bus_default.html $(html-alias) @@ -1145,19 +1286,43 @@ man/sd_bus_release_name.html: man/sd_bus_request_name.html man/sd_bus_unref.html: man/sd_bus_new.html $(html-alias) +man/sd_bus_unrefp.html: man/sd_bus_new.html + $(html-alias) + +man/sd_event.html: man/sd_event_new.html + $(html-alias) + man/sd_event_add_exit.html: man/sd_event_add_defer.html $(html-alias) man/sd_event_add_post.html: man/sd_event_add_defer.html $(html-alias) +man/sd_event_child_handler_t.html: man/sd_event_add_child.html + $(html-alias) + man/sd_event_default.html: man/sd_event_new.html $(html-alias) man/sd_event_dispatch.html: man/sd_event_wait.html $(html-alias) -man/sd_event_get_name.html: man/sd_event_set_name.html +man/sd_event_get_exit_code.html: man/sd_event_exit.html + $(html-alias) + +man/sd_event_get_state.html: man/sd_event_wait.html + $(html-alias) + +man/sd_event_get_tid.html: man/sd_event_new.html + $(html-alias) + +man/sd_event_get_watchdog.html: man/sd_event_set_watchdog.html + $(html-alias) + +man/sd_event_handler_t.html: man/sd_event_add_defer.html + $(html-alias) + +man/sd_event_io_handler_t.html: man/sd_event_add_io.html $(html-alias) man/sd_event_loop.html: man/sd_event_run.html @@ -1169,9 +1334,33 @@ man/sd_event_prepare.html: man/sd_event_wait.html man/sd_event_ref.html: man/sd_event_new.html $(html-alias) +man/sd_event_signal_handler_t.html: man/sd_event_add_signal.html + $(html-alias) + +man/sd_event_source.html: man/sd_event_add_io.html + $(html-alias) + man/sd_event_source_get_child_pid.html: man/sd_event_add_child.html $(html-alias) +man/sd_event_source_get_description.html: man/sd_event_source_set_description.html + $(html-alias) + +man/sd_event_source_get_enabled.html: man/sd_event_source_set_enabled.html + $(html-alias) + +man/sd_event_source_get_io_events.html: man/sd_event_add_io.html + $(html-alias) + +man/sd_event_source_get_io_fd.html: man/sd_event_add_io.html + $(html-alias) + +man/sd_event_source_get_io_revents.html: man/sd_event_add_io.html + $(html-alias) + +man/sd_event_source_get_priority.html: man/sd_event_source_set_priority.html + $(html-alias) + man/sd_event_source_get_signal.html: man/sd_event_add_signal.html $(html-alias) @@ -1184,15 +1373,36 @@ man/sd_event_source_get_time_accuracy.html: man/sd_event_add_time.html man/sd_event_source_get_time_clock.html: man/sd_event_add_time.html $(html-alias) +man/sd_event_source_get_userdata.html: man/sd_event_source_set_userdata.html + $(html-alias) + +man/sd_event_source_ref.html: man/sd_event_source_unref.html + $(html-alias) + +man/sd_event_source_set_io_events.html: man/sd_event_add_io.html + $(html-alias) + +man/sd_event_source_set_io_fd.html: man/sd_event_add_io.html + $(html-alias) + man/sd_event_source_set_time.html: man/sd_event_add_time.html $(html-alias) man/sd_event_source_set_time_accuracy.html: man/sd_event_add_time.html $(html-alias) +man/sd_event_source_unrefp.html: man/sd_event_source_unref.html + $(html-alias) + +man/sd_event_time_handler_t.html: man/sd_event_add_time.html + $(html-alias) + man/sd_event_unref.html: man/sd_event_new.html $(html-alias) +man/sd_event_unrefp.html: man/sd_event_new.html + $(html-alias) + man/sd_id128_equal.html: man/sd-id128.html $(html-alias) @@ -1259,6 +1469,9 @@ man/sd_journal_get_monotonic_usec.html: man/sd_journal_get_realtime_usec.html man/sd_journal_get_timeout.html: man/sd_journal_get_fd.html $(html-alias) +man/sd_journal_has_persistent_files.html: man/sd_journal_has_runtime_files.html + $(html-alias) + man/sd_journal_next_skip.html: man/sd_journal_next.html $(html-alias) @@ -1292,6 +1505,9 @@ man/sd_journal_reliable_fd.html: man/sd_journal_get_fd.html man/sd_journal_restart_data.html: man/sd_journal_get_data.html $(html-alias) +man/sd_journal_restart_fields.html: man/sd_journal_enumerate_fields.html + $(html-alias) + man/sd_journal_restart_unique.html: man/sd_journal_query_unique.html $(html-alias) @@ -1793,16 +2009,21 @@ endif if ENABLE_RESOLVED MANPAGES += \ + man/dnssec-trust-anchors.d.5 \ man/nss-resolve.8 \ man/resolved.conf.5 \ man/systemd-resolved.service.8 MANPAGES_ALIAS += \ man/libnss_resolve.so.2.8 \ man/resolved.conf.d.5 \ - man/systemd-resolved.8 + man/systemd-resolved.8 \ + man/systemd.negative.5 \ + man/systemd.positive.5 man/libnss_resolve.so.2.8: man/nss-resolve.8 man/resolved.conf.d.5: man/resolved.conf.5 man/systemd-resolved.8: man/systemd-resolved.service.8 +man/systemd.negative.5: man/dnssec-trust-anchors.d.5 +man/systemd.positive.5: man/dnssec-trust-anchors.d.5 man/libnss_resolve.so.2.html: man/nss-resolve.html $(html-alias) @@ -1812,6 +2033,12 @@ man/resolved.conf.d.html: man/resolved.conf.html man/systemd-resolved.html: man/systemd-resolved.service.html $(html-alias) +man/systemd.negative.html: man/dnssec-trust-anchors.d.html + $(html-alias) + +man/systemd.positive.html: man/dnssec-trust-anchors.d.html + $(html-alias) + endif if ENABLE_RFKILL @@ -1961,6 +2188,7 @@ MANPAGES_ALIAS += \ man/sd_login_monitor_get_fd.3 \ man/sd_login_monitor_get_timeout.3 \ man/sd_login_monitor_unref.3 \ + man/sd_login_monitor_unrefp.3 \ man/sd_peer_get_cgroup.3 \ man/sd_peer_get_machine_name.3 \ man/sd_peer_get_owner_uid.3 \ @@ -2007,6 +2235,7 @@ man/sd_login_monitor_get_events.3: man/sd_login_monitor_new.3 man/sd_login_monitor_get_fd.3: man/sd_login_monitor_new.3 man/sd_login_monitor_get_timeout.3: man/sd_login_monitor_new.3 man/sd_login_monitor_unref.3: man/sd_login_monitor_new.3 +man/sd_login_monitor_unrefp.3: man/sd_login_monitor_new.3 man/sd_peer_get_cgroup.3: man/sd_pid_get_session.3 man/sd_peer_get_machine_name.3: man/sd_pid_get_session.3 man/sd_peer_get_owner_uid.3: man/sd_pid_get_session.3 @@ -2071,6 +2300,9 @@ man/sd_login_monitor_get_timeout.html: man/sd_login_monitor_new.html man/sd_login_monitor_unref.html: man/sd_login_monitor_new.html $(html-alias) +man/sd_login_monitor_unrefp.html: man/sd_login_monitor_new.html + $(html-alias) + man/sd_peer_get_cgroup.html: man/sd_pid_get_session.html $(html-alias) @@ -2232,6 +2464,7 @@ EXTRA_DIST += \ man/coredumpctl.xml \ man/crypttab.xml \ man/daemon.xml \ + man/dnssec-trust-anchors.d.xml \ man/file-hierarchy.xml \ man/halt.xml \ man/hostname.xml \ @@ -2263,7 +2496,9 @@ EXTRA_DIST += \ man/resolved.conf.xml \ man/runlevel.xml \ man/sd-bus-errors.xml \ + man/sd-bus.xml \ man/sd-daemon.xml \ + man/sd-event.xml \ man/sd-id128.xml \ man/sd-journal.xml \ man/sd-login.xml \ @@ -2286,12 +2521,23 @@ EXTRA_DIST += \ man/sd_bus_request_name.xml \ man/sd_event_add_child.xml \ man/sd_event_add_defer.xml \ + man/sd_event_add_io.xml \ man/sd_event_add_signal.xml \ man/sd_event_add_time.xml \ + man/sd_event_exit.xml \ man/sd_event_get_fd.xml \ man/sd_event_new.xml \ + man/sd_event_now.xml \ man/sd_event_run.xml \ - man/sd_event_set_name.xml \ + man/sd_event_set_watchdog.xml \ + man/sd_event_source_get_event.xml \ + man/sd_event_source_get_pending.xml \ + man/sd_event_source_set_description.xml \ + man/sd_event_source_set_enabled.xml \ + man/sd_event_source_set_prepare.xml \ + man/sd_event_source_set_priority.xml \ + man/sd_event_source_set_userdata.xml \ + man/sd_event_source_unref.xml \ man/sd_event_wait.xml \ man/sd_get_seats.xml \ man/sd_id128_get_machine.xml \ @@ -2299,6 +2545,7 @@ EXTRA_DIST += \ man/sd_id128_to_string.xml \ man/sd_is_fifo.xml \ man/sd_journal_add_match.xml \ + man/sd_journal_enumerate_fields.xml \ man/sd_journal_get_catalog.xml \ man/sd_journal_get_cursor.xml \ man/sd_journal_get_cutoff_realtime_usec.xml \ @@ -2306,6 +2553,7 @@ EXTRA_DIST += \ man/sd_journal_get_fd.xml \ man/sd_journal_get_realtime_usec.xml \ man/sd_journal_get_usage.xml \ + man/sd_journal_has_runtime_files.xml \ man/sd_journal_next.xml \ man/sd_journal_open.xml \ man/sd_journal_print.xml \ @@ -2375,6 +2623,7 @@ EXTRA_DIST += \ man/systemd-quotacheck.service.xml \ man/systemd-random-seed.service.xml \ man/systemd-remount-fs.service.xml \ + man/systemd-resolve.xml \ man/systemd-resolved.service.xml \ man/systemd-rfkill.service.xml \ man/systemd-run.xml \ diff --git a/Makefile.am b/Makefile.am index 437905ce0..3b7cc1e33 100644 --- a/Makefile.am +++ b/Makefile.am @@ -42,9 +42,9 @@ LIBUDEV_CURRENT=7 LIBUDEV_REVISION=4 LIBUDEV_AGE=6 -LIBSYSTEMD_CURRENT=13 +LIBSYSTEMD_CURRENT=14 LIBSYSTEMD_REVISION=0 -LIBSYSTEMD_AGE=13 +LIBSYSTEMD_AGE=14 # The following four libraries only exist for compatibility reasons, # their version info should not be bumped anymore @@ -147,6 +147,7 @@ tests= manual_tests = TEST_EXTENSIONS = .py PY_LOG_COMPILER = $(PYTHON) +DISABLE_HARD_ERRORS = yes if ENABLE_TESTS noinst_PROGRAMS = $(manual_tests) $(tests) TESTS = $(tests) @@ -154,6 +155,14 @@ else noinst_PROGRAMS = TESTS = endif +if ENABLE_BASH_COMPLETION +dist_bashcompletion_DATA = $(dist_bashcompletion_data) +nodist_bashcompletion_DATA = $(nodist_bashcompletion_data) +endif +if ENABLE_ZSH_COMPLETION +dist_zshcompletion_DATA = $(dist_zshcompletion_data) +nodist_zshcompletion_DATA = $(nodist_zshcompletion_data) +endif udevlibexec_PROGRAMS = gperf_gperf_sources = @@ -164,6 +173,8 @@ m4_files = $(filter %.m4,$(EXTRA_DIST) $(in_files:.m4.in=.m4)) CLEANFILES = $(BUILT_SOURCES) \ $(pkgconfigdata_DATA) \ $(pkgconfiglib_DATA) \ + $(nodist_bashcompletion_data) \ + $(nodist_zshcompletion_data) \ $(in_files:.in=) $(in_in_files:.in.in=) \ $(m4_files:.m4=) @@ -415,8 +426,7 @@ systemgenerator_PROGRAMS = \ systemd-system-update-generator \ systemd-debug-generator -if ENABLE_BASH_COMPLETION -dist_bashcompletion_DATA = \ +dist_bashcompletion_data = \ shell-completion/bash/busctl \ shell-completion/bash/journalctl \ shell-completion/bash/systemd-analyze \ @@ -426,16 +436,15 @@ dist_bashcompletion_DATA = \ shell-completion/bash/systemd-delta \ shell-completion/bash/systemd-detect-virt \ shell-completion/bash/systemd-nspawn \ + shell-completion/bash/systemd-path \ shell-completion/bash/systemd-run \ shell-completion/bash/udevadm \ shell-completion/bash/kernel-install -nodist_bashcompletion_DATA = \ +nodist_bashcompletion_data = \ shell-completion/bash/systemctl -endif -if ENABLE_ZSH_COMPLETION -dist_zshcompletion_DATA = \ +dist_zshcompletion_data = \ shell-completion/zsh/_busctl \ shell-completion/zsh/_journalctl \ shell-completion/zsh/_udevadm \ @@ -449,18 +458,13 @@ dist_zshcompletion_DATA = \ shell-completion/zsh/_systemd-delta \ shell-completion/zsh/_systemd -nodist_zshcompletion_DATA = \ +nodist_zshcompletion_data = \ shell-completion/zsh/_systemctl -endif EXTRA_DIST += \ shell-completion/bash/systemctl.in \ shell-completion/zsh/_systemctl.in -CLEANFILES += \ - $(nodist_bashcompletion_DATA) \ - $(nodist_zshcompletion_DATA) - dist_sysctl_DATA = \ sysctl.d/50-default.conf @@ -660,6 +664,7 @@ EXTRA_DIST += \ README.md \ autogen.sh \ .dir-locals.el \ + .editorconfig \ .vimrc \ .ycm_extra_conf.py \ .travis.yml \ @@ -691,29 +696,27 @@ man_MANS = \ noinst_DATA += \ $(HTML_FILES) \ - $(HTML_ALIAS) + $(HTML_ALIAS) \ + docs/html/man +endif CLEANFILES += \ $(man_MANS) \ $(HTML_FILES) \ - $(HTML_ALIAS) + $(HTML_ALIAS) \ + docs/html/man docs/html/man: $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_LN)$(LN_S) -f ../../man $@ -noinst_DATA += \ - docs/html/man - -CLEANFILES += \ - docs/html/man - -if HAVE_PYTHON man/index.html: man/systemd.index.html $(AM_V_LN)$(LN_S) -f systemd.index.html $@ +if HAVE_PYTHON noinst_DATA += \ man/index.html +endif CLEANFILES += \ man/index.html @@ -742,16 +745,10 @@ CLEANFILES += \ man/systemd.index.xml \ man/systemd.directives.xml -EXTRA_DIST += \ - tools/make-man-rules.py - -endif - -endif - EXTRA_DIST += \ $(filter-out man/systemd.directives.xml man/systemd.index.xml,$(XML_FILES)) \ tools/make-man-index.py \ + tools/make-man-rules.py \ tools/make-directive-index.py \ tools/xml_helper.py \ man/glib-event-glue.c @@ -764,6 +761,8 @@ libbasic_la_SOURCES = \ src/basic/missing.h \ src/basic/capability-util.c \ src/basic/capability-util.h \ + src/basic/c-rbtree.c \ + src/basic/c-rbtree.h \ src/basic/conf-files.c \ src/basic/conf-files.h \ src/basic/stdio-util.h \ @@ -837,10 +836,13 @@ libbasic_la_SOURCES = \ src/basic/mempool.h \ src/basic/hashmap.c \ src/basic/hashmap.h \ + src/basic/hash-funcs.c \ + src/basic/hash-funcs.h \ src/basic/siphash24.c \ src/basic/siphash24.h \ src/basic/set.h \ src/basic/ordered-set.h \ + src/basic/ordered-set.c \ src/basic/bitmap.c \ src/basic/bitmap.h \ src/basic/fdset.c \ @@ -945,7 +947,8 @@ libbasic_la_SOURCES = \ src/basic/copy.h \ src/basic/alloc-util.h \ src/basic/alloc-util.c \ - src/basic/formats-util.h + src/basic/formats-util.h \ + src/basic/nss-util.h nodist_libbasic_la_SOURCES = \ src/basic/errno-from-name.h \ @@ -1005,7 +1008,6 @@ libshared_la_SOURCES = \ src/shared/base-filesystem.h \ src/shared/uid-range.c \ src/shared/uid-range.h \ - src/shared/nss-util.h \ src/shared/install.c \ src/shared/install.h \ src/shared/install-printf.c \ @@ -1050,7 +1052,9 @@ libshared_la_SOURCES = \ src/shared/machine-image.c \ src/shared/machine-image.h \ src/shared/machine-pool.c \ - src/shared/machine-pool.h + src/shared/machine-pool.h \ + src/shared/resolve-util.c \ + src/shared/resolve-util.h if HAVE_UTMP libshared_la_SOURCES += \ @@ -1416,7 +1420,8 @@ manual_tests += \ test-ipcrm \ test-btrfs \ test-acd \ - test-ipv4ll-manual + test-ipv4ll-manual \ + test-ask-password-api if HAVE_LIBIPTC manual_tests += \ @@ -1491,11 +1496,20 @@ tests += \ test-copy \ test-cap-list \ test-sigbus \ + test-rbtree \ test-verbs \ test-af-list \ test-arphrd-list \ test-dns-domain \ - test-install-root + test-resolve-tables \ + test-install-root \ + test-rlimit-util \ + test-signal-util + +if HAVE_ACL +tests += \ + test-acl-util +endif EXTRA_DIST += \ test/a.service \ @@ -1652,6 +1666,17 @@ test_dns_domain_LDADD = \ libsystemd-network.la \ libshared.la +test_resolve_tables_SOURCES = \ + src/resolve/test-resolve-tables.c \ + src/shared/test-tables.h \ + src/resolve/dns-type.c \ + src/resolve/dns-type.h \ + src/resolve/dns_type-from-name.h \ + src/resolve/dns_type-to-name.h + +test_resolve_tables_LDADD = \ + libshared.la + if ENABLE_EFI manual_tests += \ test-boot-timestamp @@ -1721,6 +1746,12 @@ test_sigbus_SOURCES = \ test_sigbus_LDADD = \ libshared.la +test_rbtree_SOURCES = \ + src/test/test-rbtree.c + +test_rbtree_LDADD = \ + libshared.la + test_condition_SOURCES = \ src/test/test-condition.c @@ -1844,9 +1875,33 @@ test_install_root_SOURCES = \ test_install_root_LDADD = \ libshared.la +test_acl_util_SOURCES = \ + src/test/test-acl-util.c + +test_acl_util_LDADD = \ + libshared.la + test_namespace_LDADD = \ libcore.la +test_rlimit_util_SOURCES = \ + src/test/test-rlimit-util.c + +test_rlimit_util_LDADD = \ + libshared.la + +test_ask_password_api_SOURCES = \ + src/test/test-ask-password-api.c + +test_ask_password_api_LDADD = \ + libshared.la + +test_signal_util_SOURCES = \ + src/test/test-signal-util.c + +test_signal_util_LDADD = \ + libshared.la + BUILT_SOURCES += \ src/test/test-hashmap-ordered.c @@ -2343,10 +2398,8 @@ SYSINIT_TARGET_WANTS += \ systemd-tmpfiles-setup-dev.service \ systemd-tmpfiles-setup.service -if ENABLE_ZSH_COMPLETION -dist_zshcompletion_DATA += \ +dist_zshcompletion_data += \ shell-completion/zsh/_systemd-tmpfiles -endif TIMERS_TARGET_WANTS += \ systemd-tmpfiles-clean.timer @@ -2384,6 +2437,11 @@ nodist_sysusers_DATA = \ sysusers.d/systemd.conf \ sysusers.d/basic.conf +if HAVE_REMOTE +nodist_sysusers_DATA += \ + sysusers.d/systemd-remote.conf +endif + INSTALL_DIRS += \ $(sysusersdir) endif @@ -2391,6 +2449,7 @@ endif EXTRA_DIST += \ units/systemd-sysusers.service.in \ sysusers.d/systemd.conf.m4 \ + sysusers.d/systemd-remote.conf.m4 \ sysusers.d/basic.conf.in # ------------------------------------------------------------------------------ @@ -2568,16 +2627,12 @@ bootctl_LDADD = \ bin_PROGRAMS += \ bootctl -if ENABLE_BASH_COMPLETION -dist_bashcompletion_DATA += \ +dist_bashcompletion_data += \ shell-completion/bash/bootctl -endif -if ENABLE_ZSH_COMPLETION -dist_zshcompletion_DATA += \ +dist_zshcompletion_data += \ shell-completion/zsh/_bootctl endif -endif # ------------------------------------------------------------------------------ if HAVE_GNUEFI @@ -2658,14 +2713,13 @@ systemd_boot_sources = \ EXTRA_DIST += $(systemd_boot_sources) $(systemd_boot_headers) -if ENABLE_EFI -if HAVE_GNUEFI systemd_boot_objects = $(addprefix $(top_builddir)/,$(systemd_boot_sources:.c=.o)) systemd_boot_solib = $(top_builddir)/src/boot/efi/systemd_boot.so systemd_boot = systemd-boot$(EFI_MACHINE_TYPE_NAME).efi +if ENABLE_EFI +if HAVE_GNUEFI bootlib_DATA = $(systemd_boot) -CLEANFILES += $(systemd_boot_objects) $(systemd_boot_solib) $(systemd_boot) $(top_builddir)/src/boot/efi/%.o: $(top_srcdir)/src/boot/efi/%.c $(addprefix $(top_srcdir)/,$(systemd_boot_headers)) @$(MKDIR_P) $(top_builddir)/src/boot/efi/ @@ -2682,6 +2736,8 @@ $(systemd_boot): $(systemd_boot_solib) endif endif +CLEANFILES += $(systemd_boot_objects) $(systemd_boot_solib) $(systemd_boot) + # ------------------------------------------------------------------------------ stub_headers = \ src/boot/efi/util.h \ @@ -2705,14 +2761,13 @@ EXTRA_DIST += \ $(stub_headers) \ test/splash.bmp -if ENABLE_EFI -if HAVE_GNUEFI stub_objects = $(addprefix $(top_builddir)/,$(stub_sources:.c=.o)) stub_solib = $(top_builddir)/src/boot/efi/stub.so stub = linux$(EFI_MACHINE_TYPE_NAME).efi.stub +if ENABLE_EFI +if HAVE_GNUEFI bootlib_DATA += $(stub) -CLEANFILES += $(stub_objects) $(stub_solib) $(stub) $(top_builddir)/src/boot/efi/%.o: $(top_srcdir)/src/boot/efi/%.c $(addprefix $(top_srcdir)/,$(stub_headers)) @$(MKDIR_P) $(top_builddir)/src/boot/efi/ @@ -2726,6 +2781,11 @@ $(stub_solib): $(stub_objects) $(stub): $(stub_solib) $(AM_V_GEN)$(OBJCOPY) -j .text -j .sdata -j .data -j .dynamic \ -j .dynsym -j .rel -j .rela -j .reloc $(EFI_FORMAT) $< $@ +endif +endif + +CLEANFILES += $(stub_objects) $(stub_solib) $(stub) + # ------------------------------------------------------------------------------ CLEANFILES += test-efi-disk.img @@ -2735,8 +2795,6 @@ test-efi-disk.img: $(systemd_boot) $(stub) test/test-efi-create-disk.sh test-efi: test-efi-disk.img $(QEMU) -machine accel=kvm -m 1024 -bios $(QEMU_BIOS) -snapshot test-efi-disk.img -endif -endif EXTRA_DIST += test/test-efi-create-disk.sh @@ -2885,6 +2943,8 @@ systemd_nspawn_SOURCES = \ src/nspawn/nspawn-register.h \ src/nspawn/nspawn-setuid.c \ src/nspawn/nspawn-setuid.h \ + src/nspawn/nspawn-stub-pid1.c \ + src/nspawn/nspawn-stub-pid1.h \ src/core/mount-setup.c \ src/core/mount-setup.h \ src/core/loopback-setup.c \ @@ -3039,7 +3099,6 @@ libsystemd_internal_la_SOURCES = \ src/libsystemd/sd-bus/bus-dump.h \ src/libsystemd/sd-utf8/sd-utf8.c \ src/libsystemd/sd-event/sd-event.c \ - src/libsystemd/sd-event/event-util.h \ src/libsystemd/sd-netlink/sd-netlink.c \ src/libsystemd/sd-netlink/netlink-internal.h \ src/libsystemd/sd-netlink/netlink-message.c \ @@ -3068,8 +3127,7 @@ libsystemd_internal_la_SOURCES = \ src/libsystemd/sd-device/sd-device.c \ src/libsystemd/sd-device/device-private.c \ src/libsystemd/sd-device/device-private.h \ - src/libsystemd/sd-resolve/sd-resolve.c \ - src/libsystemd/sd-resolve/resolve-util.h + src/libsystemd/sd-resolve/sd-resolve.c libsystemd_internal_la_LIBADD = \ libbasic.la \ @@ -3351,7 +3409,6 @@ libsystemd_network_la_SOURCES = \ src/libsystemd-network/lldp-port.c \ src/libsystemd-network/lldp-internal.h \ src/libsystemd-network/lldp-internal.c \ - src/libsystemd-network/lldp-util.h \ src/libsystemd-network/sd-lldp.c libsystemd_network_la_LIBADD = \ @@ -3712,6 +3769,7 @@ EXTRA_DIST += \ hwdb/sdio.ids # ------------------------------------------------------------------------------ +if ENABLE_TESTS TESTS += \ test/udev-test.pl @@ -3724,6 +3782,7 @@ TESTS += \ test/sysv-generator-test.py endif endif +endif manual_tests += \ test-libudev \ @@ -3743,8 +3802,10 @@ test_udev_LDADD = \ $(BLKID_LIBS) \ $(KMOD_LIBS) +if ENABLE_TESTS check_DATA += \ test/sys +endif # packed sysfs test tree test/sys: @@ -3898,11 +3959,6 @@ systemd_journal_remote_CFLAGS = \ systemd_journal_remote_LDADD += \ $(MICROHTTPD_LIBS) -if ENABLE_SYSUSERS -dist_sysusers_DATA += \ - sysusers.d/systemd-remote.conf -endif - if ENABLE_TMPFILES dist_tmpfiles_DATA += \ tmpfiles.d/systemd-remote.conf @@ -3972,7 +4028,8 @@ journalctl_SOURCES = \ src/journal/journalctl.c journalctl_LDADD = \ - libshared.la + libshared.la \ + libudev-core.la if HAVE_QRENCODE journalctl_SOURCES += \ @@ -4340,30 +4397,39 @@ systemd_socket_proxyd_LDADD = \ # ------------------------------------------------------------------------------ if ENABLE_COREDUMP systemd_coredump_SOURCES = \ - src/journal/coredump.c \ - src/journal/coredump-vacuum.c \ - src/journal/coredump-vacuum.h + src/coredump/coredump.c \ + src/coredump/coredump-vacuum.c \ + src/coredump/coredump-vacuum.h systemd_coredump_LDADD = \ libshared.la if HAVE_ELFUTILS systemd_coredump_SOURCES += \ - src/journal/stacktrace.c \ - src/journal/stacktrace.h + src/coredump/stacktrace.c \ + src/coredump/stacktrace.h systemd_coredump_LDADD += \ $(ELFUTILS_LIBS) endif +nodist_systemunit_DATA += \ + units/systemd-coredump@.service + +dist_systemunit_DATA += \ + units/systemd-coredump.socket + +SOCKETS_TARGET_WANTS += \ + systemd-coredump.socket + rootlibexec_PROGRAMS += \ systemd-coredump dist_pkgsysconf_DATA += \ - src/journal/coredump.conf + src/coredump/coredump.conf coredumpctl_SOURCES = \ - src/journal/coredumpctl.c + src/coredump/coredumpctl.c coredumpctl_LDADD = \ libshared.la @@ -4375,22 +4441,18 @@ manual_tests += \ test-coredump-vacuum test_coredump_vacuum_SOURCES = \ - src/journal/test-coredump-vacuum.c \ - src/journal/coredump-vacuum.c \ - src/journal/coredump-vacuum.h + src/coredump/test-coredump-vacuum.c \ + src/coredump/coredump-vacuum.c \ + src/coredump/coredump-vacuum.h test_coredump_vacuum_LDADD = \ libshared.la -if ENABLE_BASH_COMPLETION -dist_bashcompletion_DATA += \ +dist_bashcompletion_data += \ shell-completion/bash/coredumpctl -endif -if ENABLE_ZSH_COMPLETION -dist_zshcompletion_DATA += \ +dist_zshcompletion_data += \ shell-completion/zsh/_coredumpctl -endif nodist_sysctl_DATA = \ sysctl.d/50-coredump.conf @@ -4400,7 +4462,8 @@ CLEANFILES += \ endif EXTRA_DIST += \ - sysctl.d/50-coredump.conf.in + sysctl.d/50-coredump.conf.in \ + units/systemd-coredump@.service.in # ------------------------------------------------------------------------------ if ENABLE_BINFMT @@ -4641,16 +4704,12 @@ hostnamectl_LDADD = \ bin_PROGRAMS += \ hostnamectl -if ENABLE_BASH_COMPLETION -dist_bashcompletion_DATA += \ +dist_bashcompletion_data += \ shell-completion/bash/hostnamectl -endif -if ENABLE_ZSH_COMPLETION -dist_zshcompletion_DATA += \ +dist_zshcompletion_data += \ shell-completion/zsh/_hostnamectl endif -endif polkitpolicy_in_files += \ src/hostname/org.freedesktop.hostname1.policy.in @@ -4715,16 +4774,12 @@ localectl_LDADD = \ bin_PROGRAMS += \ localectl -if ENABLE_BASH_COMPLETION -dist_bashcompletion_DATA += \ +dist_bashcompletion_data += \ shell-completion/bash/localectl -endif -if ENABLE_ZSH_COMPLETION -dist_zshcompletion_DATA += \ +dist_zshcompletion_data += \ shell-completion/zsh/_localectl endif -endif .PHONY: update-kbd-model-map @@ -4775,16 +4830,12 @@ timedatectl_LDADD = \ bin_PROGRAMS += \ timedatectl -if ENABLE_BASH_COMPLETION -dist_bashcompletion_DATA += \ +dist_bashcompletion_data += \ shell-completion/bash/timedatectl -endif -if ENABLE_ZSH_COMPLETION -dist_zshcompletion_DATA += \ +dist_zshcompletion_data += \ shell-completion/zsh/_timedatectl endif -endif polkitpolicy_in_files += \ src/timedate/org.freedesktop.timedate1.policy.in @@ -4806,9 +4857,6 @@ systemd_timesyncd_SOURCES = \ nodist_systemd_timesyncd_SOURCES = \ src/timesync/timesyncd-gperf.c -gperf_gperf_sources += \ - src/timesync/timesyncd-gperf.gperf - systemd_timesyncd_LDADD = \ libsystemd-network.la \ libshared.la @@ -4822,16 +4870,18 @@ nodist_systemunit_DATA += \ GENERAL_ALIASES += \ $(systemunitdir)/systemd-timesyncd.service $(pkgsysconfdir)/system/sysinit.target.wants/systemd-timesyncd.service -EXTRA_DIST += \ - units/systemd-timesyncd.service.in - nodist_pkgsysconf_DATA += \ src/timesync/timesyncd.conf -EXTRA_DIST += \ - src/timesync/timesyncd.conf.in endif +gperf_gperf_sources += \ + src/timesync/timesyncd-gperf.gperf + +EXTRA_DIST += \ + units/systemd-timesyncd.service.in \ + src/timesync/timesyncd.conf.in + # ------------------------------------------------------------------------------ if HAVE_MYHOSTNAME libnss_myhostname_la_SOURCES = \ @@ -4848,7 +4898,7 @@ libnss_myhostname_la_LDFLAGS = \ -Wl,--version-script=$(top_srcdir)/src/nss-myhostname/nss-myhostname.sym libnss_myhostname_la_LIBADD = \ - libshared.la + libsystemd-internal.la lib_LTLIBRARIES += \ libnss_myhostname.la @@ -4890,11 +4940,6 @@ machinectl_LDADD = \ rootbin_PROGRAMS += \ machinectl -if ENABLE_BASH_COMPLETION -dist_bashcompletion_DATA += \ - shell-completion/bash/machinectl -endif - test_machine_tables_SOURCES = \ src/machine/test-machine-tables.c @@ -4922,11 +4967,12 @@ dist_dbuspolicy_DATA += \ polkitpolicy_files += \ src/machine/org.freedesktop.machine1.policy -if ENABLE_ZSH_COMPLETION -dist_zshcompletion_DATA += \ +dist_bashcompletion_data += \ + shell-completion/bash/machinectl + +dist_zshcompletion_data += \ shell-completion/zsh/_machinectl \ shell-completion/zsh/_sd_machines -endif SYSTEM_UNIT_ALIASES += \ systemd-machined.service dbus-org.freedesktop.machine1.service @@ -4948,7 +4994,7 @@ libnss_mymachines_la_LDFLAGS = \ -Wl,--version-script=$(top_srcdir)/src/nss-mymachines/nss-mymachines.sym libnss_mymachines_la_LIBADD = \ - libshared.la + libsystemd-internal.la lib_LTLIBRARIES += \ libnss_mymachines.la @@ -4994,8 +5040,6 @@ systemd_pull_SOURCES = \ src/import/pull-raw.h \ src/import/pull-tar.c \ src/import/pull-tar.h \ - src/import/pull-dkr.c \ - src/import/pull-dkr.h \ src/import/pull-job.c \ src/import/pull-job.h \ src/import/pull-common.c \ @@ -5126,24 +5170,30 @@ polkitpolicy_in_files += \ src/import/org.freedesktop.import1.policy.in EXTRA_DIST += \ - units/systemd-importd.service.in \ - src/resolve/resolved.conf.in + units/systemd-importd.service.in # ------------------------------------------------------------------------------ if ENABLE_RESOLVED + systemd_resolved_SOURCES = \ src/resolve/resolved.c \ src/resolve/resolved-manager.c \ src/resolve/resolved-manager.h \ src/resolve/resolved-conf.c \ src/resolve/resolved-conf.h \ + src/resolve/resolved-resolv-conf.c \ + src/resolve/resolved-resolv-conf.h \ src/resolve/resolved-bus.c \ src/resolve/resolved-bus.h \ src/resolve/resolved-link.h \ src/resolve/resolved-link.c \ + src/resolve/resolved-link-bus.c \ + src/resolve/resolved-link-bus.h \ src/resolve/resolved-llmnr.h \ src/resolve/resolved-llmnr.c \ + src/resolve/resolved-mdns.h \ + src/resolve/resolved-mdns.c \ src/resolve/resolved-def.h \ src/resolve/resolved-dns-rr.h \ src/resolve/resolved-dns-rr.c \ @@ -5155,18 +5205,28 @@ systemd_resolved_SOURCES = \ src/resolve/resolved-dns-packet.c \ src/resolve/resolved-dns-query.h \ src/resolve/resolved-dns-query.c \ + src/resolve/resolved-dns-synthesize.h \ + src/resolve/resolved-dns-synthesize.c \ src/resolve/resolved-dns-transaction.h \ src/resolve/resolved-dns-transaction.c \ src/resolve/resolved-dns-scope.h \ src/resolve/resolved-dns-scope.c \ src/resolve/resolved-dns-server.h \ src/resolve/resolved-dns-server.c \ + src/resolve/resolved-dns-search-domain.h \ + src/resolve/resolved-dns-search-domain.c \ src/resolve/resolved-dns-cache.h \ src/resolve/resolved-dns-cache.c \ src/resolve/resolved-dns-zone.h \ src/resolve/resolved-dns-zone.c \ src/resolve/resolved-dns-stream.h \ src/resolve/resolved-dns-stream.c \ + src/resolve/resolved-dns-dnssec.h \ + src/resolve/resolved-dns-dnssec.c \ + src/resolve/resolved-dns-trust-anchor.h \ + src/resolve/resolved-dns-trust-anchor.c \ + src/resolve/resolved-etc-hosts.h \ + src/resolve/resolved-etc-hosts.c \ src/resolve/dns-type.c \ src/resolve/dns-type.h @@ -5175,12 +5235,6 @@ nodist_systemd_resolved_SOURCES = \ src/resolve/dns_type-to-name.h \ src/resolve/resolved-gperf.c -gperf_gperf_sources += \ - src/resolve/resolved-gperf.gperf - -gperf_txt_sources += \ - src/resolve/dns_type-list.txt - systemd_resolved_LDADD = \ libsystemd-network.la \ libshared.la @@ -5212,9 +5266,6 @@ GENERAL_ALIASES += \ nodist_pkgsysconf_DATA += \ src/resolve/resolved.conf -tests += \ - test-dns-domain - libnss_resolve_la_SOURCES = \ src/nss-resolve/nss-resolve.sym \ src/nss-resolve/nss-resolve.c @@ -5229,14 +5280,16 @@ libnss_resolve_la_LDFLAGS = \ -Wl,--version-script=$(top_srcdir)/src/nss-resolve/nss-resolve.sym libnss_resolve_la_LIBADD = \ - libshared.la \ + libsystemd-internal.la \ -ldl lib_LTLIBRARIES += \ libnss_resolve.la -systemd_resolve_host_SOURCES = \ - src/resolve-host/resolve-host.c \ +systemd_resolve_SOURCES = \ + src/resolve/resolve-tool.c \ + src/resolve/resolved-dns-dnssec.c \ + src/resolve/resolved-dns-dnssec.h \ src/resolve/resolved-dns-packet.c \ src/resolve/resolved-dns-packet.h \ src/resolve/resolved-dns-rr.c \ @@ -5248,20 +5301,60 @@ systemd_resolve_host_SOURCES = \ src/resolve/dns-type.c \ src/resolve/dns-type.h -nodist_systemd_resolve_host_SOURCES = \ +nodist_systemd_resolve_SOURCES = \ src/resolve/dns_type-from-name.h \ src/resolve/dns_type-to-name.h -systemd_resolve_host_LDADD = \ +systemd_resolve_LDADD = \ libshared.la -rootlibexec_PROGRAMS += \ - systemd-resolve-host +bin_PROGRAMS += \ + systemd-resolve + +tests += \ + test-dns-domain \ + test-dnssec + +manual_tests += \ + test-dnssec-complex + +test_dnssec_SOURCES = \ + src/resolve/test-dnssec.c \ + src/resolve/resolved-dns-packet.c \ + src/resolve/resolved-dns-packet.h \ + src/resolve/resolved-dns-rr.c \ + src/resolve/resolved-dns-rr.h \ + src/resolve/resolved-dns-answer.c \ + src/resolve/resolved-dns-answer.h \ + src/resolve/resolved-dns-question.c \ + src/resolve/resolved-dns-question.h \ + src/resolve/resolved-dns-dnssec.c \ + src/resolve/resolved-dns-dnssec.h \ + src/resolve/dns-type.c \ + src/resolve/dns-type.h + +test_dnssec_LDADD = \ + libshared.la + +test_dnssec_complex_SOURCES = \ + src/resolve/test-dnssec-complex.c \ + src/resolve/dns-type.c \ + src/resolve/dns-type.h + +test_dnssec_complex_LDADD = \ + libshared.la endif +gperf_txt_sources += \ + src/resolve/dns_type-list.txt + +gperf_gperf_sources += \ + src/resolve/resolved-gperf.gperf + EXTRA_DIST += \ - units/systemd-resolved.service.m4.in + units/systemd-resolved.service.m4.in \ + src/resolve/resolved.conf.in # ------------------------------------------------------------------------------ if ENABLE_NETWORKD @@ -5369,6 +5462,9 @@ networkctl_LDADD = \ libshared.la \ libsystemd-network.la +dist_bashcompletion_data += \ + shell-completion/bash/networkctl + test_network_SOURCES = \ src/network/test-network.c @@ -5424,14 +5520,16 @@ SYSTEM_UNIT_ALIASES += \ BUSNAMES_TARGET_WANTS += \ org.freedesktop.network1.busname +endif + gperf_gperf_sources += \ src/network/networkd-network-gperf.gperf \ src/network/networkd-netdev-gperf.gperf -endif EXTRA_DIST += \ units/systemd-networkd.service.m4.in \ - units/systemd-networkd-wait-online.service.in + units/systemd-networkd-wait-online.service.in \ + test/networkd-test.py # ------------------------------------------------------------------------------ if ENABLE_LOGIND @@ -5495,16 +5593,12 @@ loginctl_LDADD = \ rootbin_PROGRAMS += \ loginctl -if ENABLE_BASH_COMPLETION -dist_bashcompletion_DATA += \ +dist_bashcompletion_data += \ shell-completion/bash/loginctl -endif -if ENABLE_ZSH_COMPLETION -dist_zshcompletion_DATA += \ +dist_zshcompletion_data += \ shell-completion/zsh/_loginctl \ shell-completion/zsh/_systemd-inhibit -endif systemd_inhibit_SOURCES = \ src/login/inhibit.c @@ -5669,6 +5763,20 @@ EXTRA_DIST += \ test/TEST-03-JOBS/Makefile \ test/TEST-03-JOBS/test-jobs.sh \ test/TEST-03-JOBS/test.sh \ + test/TEST-04-JOURNAL/Makefile \ + test/TEST-04-JOURNAL/test-journal.sh \ + test/TEST-04-JOURNAL/test.sh \ + test/TEST-05-RLIMITS/Makefile \ + test/TEST-05-RLIMITS/test-rlimits.sh \ + test/TEST-05-RLIMITS/test.sh \ + test/TEST-06-SELINUX/Makefile \ + test/TEST-06-SELINUX/test-selinux-checks.sh \ + test/TEST-06-SELINUX/test.sh \ + test/TEST-06-SELINUX/systemd_test.te \ + test/TEST-06-SELINUX/systemd_test.if \ + test/TEST-07-ISSUE-1981/Makefile \ + test/TEST-07-ISSUE-1981/test-segfault.sh \ + test/TEST-07-ISSUE-1981/test.sh \ test/test-functions EXTRA_DIST += \ @@ -5904,24 +6012,24 @@ src/%.c: src/%.gperf $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_GPERF)$(GPERF) < $< > $@ -src/%: src/%.m4 +src/%: src/%.m4 $(top_builddir)/config.status $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_M4)$(M4) -P $(M4_DEFINES) < $< > $@ -sysusers.d/%: sysusers.d/%.m4 +sysusers.d/%: sysusers.d/%.m4 $(top_builddir)/config.status $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_M4)$(M4) -P $(M4_DEFINES) < $< > $@ -tmpfiles.d/%: tmpfiles.d/%.m4 +tmpfiles.d/%: tmpfiles.d/%.m4 $(top_builddir)/config.status $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_M4)$(M4) -P $(M4_DEFINES) < $< > $@ -units/%: units/%.m4 +units/%: units/%.m4 $(top_builddir)/config.status $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_M4)$(M4) -P $(M4_DEFINES) -DFOR_SYSTEM=1 < $< > $@ -units/user/%: units/user/%.m4 +units/user/%: units/user/%.m4 $(top_builddir)/config.status $(AM_V_at)$(MKDIR_P) $(dir $@) $(AM_V_M4)$(M4) -P $(M4_DEFINES) -DFOR_USER=1 < $< > $@ @@ -5936,7 +6044,6 @@ EXTRA_DIST += \ $(polkitpolicy_in_in_files) # ------------------------------------------------------------------------------ -if ENABLE_MANPAGES man/custom-entities.ent: configure.ac $(AM_V_GEN)$(MKDIR_P) $(dir $@) $(AM_V_GEN)(echo '' && \ @@ -5956,11 +6063,12 @@ XSLTPROC_FLAGS = \ --stringparam systemd.version $(VERSION) \ --path '$(builddir)/man:$(srcdir)/man' +XSLT = $(if $(XSLTPROC), $(XSLTPROC), xsltproc) XSLTPROC_PROCESS_MAN = \ - $(AM_V_XSLT)$(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(srcdir)/man/custom-man.xsl $< + $(AM_V_XSLT)$(XSLT) -o $@ $(XSLTPROC_FLAGS) $(srcdir)/man/custom-man.xsl $< XSLTPROC_PROCESS_HTML = \ - $(AM_V_XSLT)$(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(srcdir)/man/custom-html.xsl $< + $(AM_V_XSLT)$(XSLT) -o $@ $(XSLTPROC_FLAGS) $(srcdir)/man/custom-html.xsl $< man/%.1: man/%.xml man/custom-man.xsl man/custom-entities.ent $(XSLTPROC_PROCESS_MAN) @@ -5984,8 +6092,6 @@ define html-alias $(AM_V_LN)$(LN_S) -f $(notdir $<) $@ endef -endif - EXTRA_DIST += \ man/custom-html.xsl \ man/custom-man.xsl @@ -6159,21 +6265,7 @@ DISTCHECK_CONFIGURE_FLAGS += \ --disable-split-usr endif -# -# Require python when making dist -# -.PHONY: dist-check-python dist-check-compat-libs dist-check-help -dist-check-python: -if !HAVE_PYTHON - @echo "*** python and python-lxml module must be installed and enabled in order to make dist" - @false -endif - -dist-check-compat-libs: -if !ENABLE_COMPAT_LIBS - @echo "*** compat-libs must be enabled in order to make dist" - @false -endif +.PHONY: dist-check-help dist-check-help: $(rootbin_PROGRAMS) $(bin_PROGRAMS) for i in $(abspath $^); do \ @@ -6183,8 +6275,6 @@ dist-check-help: $(rootbin_PROGRAMS) $(bin_PROGRAMS) exit 1; \ fi; done -dist: dist-check-python dist-check-compat-libs - .PHONY: hwdb-update hwdb-update: ( cd $(top_srcdir)/hwdb && \ @@ -6212,14 +6302,6 @@ www_target = www.freedesktop.org:/srv/www.freedesktop.org/www/software/systemd doc-sync: all rsync -rlv --delete-excluded --include="*.html" --exclude="*" --omit-dir-times man/ $(www_target)/man/ -.PHONY: gardel -gardel: - scp man/*.html gardel:public/systemd-man/ - -.PHONY: lennart-fedora -lennart-fedora: - cp -v systemd-$(VERSION).tar.xz /home/lennart/git.fedora/systemd/ - .PHONY: install-tree install-tree: all rm -rf $(abs_srcdir)/install-tree @@ -6227,14 +6309,14 @@ install-tree: all tree $(abs_srcdir)/install-tree # Let's run all tests of the test suite, but under valgrind. Let's -# exclude the one perl script we have in there +# exclude perl/python/shell scripts we have in there .PHONY: valgrind-tests valgrind-tests: $(TESTS) - $(AM_V_GEN)for f in $(filter-out %.pl, $^); do \ + $(AM_V_GEN)for f in $(filter-out %.pl %.py, $^); do \ if file $$f | grep -q shell; then \ echo -e "$${x}Skipping non-binary $$f"; else \ echo -e "$${x}Running $$f"; \ - libtool --mode=execute valgrind -q --leak-check=full --max-stackframe=5242880 --error-exitcode=55 $(builddir)/$$f ; fi; \ + $(LIBTOOL) --mode=execute valgrind -q --leak-check=full --max-stackframe=5242880 --error-exitcode=55 $(builddir)/$$f ; fi; \ x="\n\n"; \ done diff --git a/NEWS b/NEWS index 006aef5e1..e7f6bb459 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,224 @@ systemd System and Service Manager +CHANGES WITH 229: + + * The systemd-resolved DNS resolver service has gained a substantial + set of new features, most prominently it may now act as a DNSSEC + validating stub resolver. DNSSEC mode is currently turned off by + default, but it is expected that this is turned on by default in one + of the next releases. For now, we invite everybody to test the DNSSEC + logic by setting DNSSEC=allow-downgrade in + /etc/systemd/resolved.conf. The service also gained a full set of + D-Bus interfaces, including calls to configure DNS and DNSSEC + settings per link (for consumption by external network management + software). systemd-resolved (and systemd-networkd along with it) now + know to distinguish between "search" and "routing" domains. The + former are used to qualify single-label names, the latter are purely + used for routing lookups within certain domains to specific + links. resolved will now also synthesize RRs for all entries from + /etc/hosts. + + * The systemd-resolve tool (which is a client utility for + systemd-resolved, and previously experimental) has been improved + considerably and is now fully supported and documented. Hence it has + moved from /usr/lib/systemd to /usr/bin. + + * /dev/disk/by-path/ symlink support has been (re-)added for virtio + devices. + + * The coredump collection logic has been reworked: when a coredump is + collected it is now written to disk, compressed and processed + (including stacktrace extraction) from a new instantiated service + systemd-coredump@.service, instead of directly from the + /proc/sys/kernel/core_pattern hook we provide. This is beneficial as + processing large coredumps can take up a substantial amount of + resources and time, and this previously happened entirely outside of + systemd's service supervision. With the new logic the core_pattern + hook only does minimal metadata collection before passing off control + to the new instantiated service, which is configured with a time + limit, a nice level and other settings to minimize negative impact on + the rest of the system. Also note that the new logic will honour the + RLIMIT_CORE setting of the crashed process, which now allows users + and processes to turn off coredumping for their processes by setting + this limit. + + * The RLIMIT_CORE resource limit now defaults to "unlimited" for PID 1 + and all forked processes by default. Previously, PID 1 would leave + the setting at "0" for all processes, as set by the kernel. Note that + the resource limit traditionally has no effect on the generated + coredumps on the system if the /proc/sys/kernel/core_pattern hook + logic is used. Since the limit is now honoured (see above) its + default has been changed so that the coredumping logic is enabled by + default for all processes, while allowing specific opt-out. + + * When the stacktrace is extracted from processes of system users, this + is now done as "systemd-coredump" user, in order to sandbox this + potentially security sensitive parsing operation. (Note that when + processing coredumps of normal users this is done under the user ID + of process that crashed, as before.) Packagers should take notice + that it is now necessary to create the "systemd-coredump" system user + and group at package installation time. + + * The systemd-activate socket activation testing tool gained support + for SOCK_DGRAM and SOCK_SEQPACKET sockets using the new --datagram + and --seqpacket switches. It also has been extended to support both + new-style and inetd-style file descriptor passing. Use the new + --inetd switch to request inetd-style file descriptor passing. + + * Most systemd tools now honor a new $SYSTEMD_COLORS environment + variable, which takes a boolean value. If set to false, ANSI color + output is disabled in the tools even when run on a terminal that + supports it. + + * The VXLAN support in networkd now supports two new settings + DestinationPort= and PortRange=. + + * A new systemd.machine_id= kernel command line switch has been added, + that may be used to set the machine ID in /etc/machine-id if it is + not initialized yet. This command line option has no effect if the + file is already initialized. + + * systemd-nspawn gained a new --as-pid2 switch that invokes any + specified command line as PID 2 rather than PID 1 in the + container. In this mode PID 1 will be a minimal stub init process + that implements the special POSIX and Linux semantics of PID 1 + regarding signal and child process management. Note that this stub + init process is implemented in nspawn itself and requires no support + from the container image. This new logic is useful to support running + arbitrary command lines in the container, as normal processes are + generally not prepared to run as PID 1. + + * systemd-nspawn gained a new --chdir= switch for setting the current + working directory for the process started in the container. + + * "journalctl /dev/sda" will now output all kernel log messages from + the specified device, in addition to all devices that are parents of + it. This should make log output about devices pretty useful, as long + as kernel drivers attach enough metadata to the log messages. (The + usual SATA drivers do.) + + * The sd-journal API gained two new calls + sd_journal_has_runtime_files() and sd_journal_has_persistent_files() + that report whether log data from /run or /var has been found. + + * journalctl gained a new switch "--fields" that prints all journal + record field names currently in use in the journal. This is backed + by two new sd-journal API calls sd_journal_enumerate_fields() and + sd_journal_restart_fields(). + + * Most configurable timeouts in systemd now expect an argument of + "infinity" to turn them off, instead of "0" as before. The semantics + from now on is that a timeout of "0" means "now", and "infinity" + means "never". To maintain backwards compatibility, "0" continues to + turn off previously existing timeout settings. + + * "systemctl reload-or-try-restart" has been renamed to "systemctl + try-reload-or-restart" to clarify what it actually does: the "try" + logic applies to both reloading and restarting, not just restarting. + The old name continues to be accepted for compatibility. + + * On boot-up, when PID 1 detects that the system clock is behind the + release date of the systemd version in use, the clock is now set + to the latter. Previously, this was already done in timesyncd, in order + to avoid running with clocks set to the various clock epochs such as + 1902, 1938 or 1970. With this change the logic is now done in PID 1 + in addition to timesyncd during early boot-up, so that it is enforced + before the first process is spawned by systemd. Note that the logic + in timesyncd remains, as it is more comprehensive and ensures + montonic clocks by maintaining a persistant timestamp file in + /var. Since /var is generally not available in earliest boot or the + initrd, this part of the logic remains in timesyncd, and is not done + by PID 1. + + * Support for tweaking details in net_cls.class_id through the + NetClass= configuration directive has been removed, as the kernel + people have decided to deprecate that controller in cgroup v2. + Userspace tools such as nftables are moving over to setting rules + that are specific to the full cgroup path of a task, which obsoletes + these controllers anyway. The NetClass= directive is kept around for + legacy compatibility reasons. For a more in-depth description of the + kernel change, please refer to the respective upstream commit: + + https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=bd1060a1d671 + + * A new service setting RuntimeMaxSec= has been added that may be used + to specify a maximum runtime for a service. If the timeout is hit, the + service is terminated and put into a failure state. + + * A new service setting AmbientCapabilities= has been added. It allows + configuration of additional Linux process capabilities that are + passed to the activated processes. This is only available on very + recent kernels. + + * The process resource limit settings in service units may now be used + to configure hard and soft limits individually. + + * The various libsystemd APIs such as sd-bus or sd-event now publicly + expose support for gcc's __attribute__((cleanup())) C + extension. Specifically, for many object destructor functions + alternative versions whose names are suffixed with "p" have been + added, which take a pointer to a pointer to the object to destroy, + instead of just a pointer to the object itself. This is useful because + these destructor functions may be used directly as parameters to the + cleanup construct. Internally, systemd has been a heavy user of the + GCC extension since a long time, and with this change similar support + is now available to consumers of the library outside of systemd. Note + that by using this extension in your sources compatibility with old + and strictly ANSI compatible C compilers is lost. However, any gcc or + LLVM version of recent years have supported this extension. + + * Timer units gained support for a new setting RandomizedDelaySec= that + allows configuring some additional randomized delay to the configured + time. This is useful to spread out timer events to avoid load peaks in + clusters or larger setups. + + * Calendar time specifications now support sub-second accuracy. + + * Socket units now support listening on SCTP and UDP-lite protocol + sockets. + + * The sd-event API now comes with a full set of man pages. + + * Older versions of systemd contained experimental support for + compressing journal files and coredumps with the LZ4 compressor that + was not compatible with the lz4 binary (due to API limitations of the + lz4 library). This support has been removed; only support for files + compatible with the lz4 binary remains. This LZ4 logic is now + officially supported and no longer considered experimental. + + * The dkr image import logic has been removed again from importd. dkr's + micro-services focus doesn't fit into the machine image focus of + importd, and quickly got out of date with the upstream dkr API. + + * Creation of the /run/lock/lockdev/ directory was dropped from + tmpfiles.d/legacy.conf. Better locking mechanisms like flock() have + been available for many years. If you still need this, you need to + create your own tmpfiles.d config file with: + + d /run/lock/lockdev 0775 root lock - + + Contributions from: Abdo Roig-Maranges, Alban Crequy, Aleksander + Adamowski, Alexander Kuleshov, Andreas Pokorny, Andrei Borzenkov, + Andrew Wilcox, Arthur Clement, Beniamino Galvani, Casey Schaufler, + Chris Atkinson, Chris Mayo, Christian Hesse, Damjan Georgievski, Dan + Dedrick, Daniele Medri, Daniel J Walsh, Daniel Korostil, Daniel Mack, + David Herrmann, Dimitri John Ledkov, Dominik Hannen, Douglas Christman, + Evgeny Vereshchagin, Filipe Brandenburger, Franck Bui, Gabor Kelemen, + Harald Hoyer, Hayden Walles, Helmut Grohne, Henrik Kaare Poulsen, + Hristo Venev, Hui Wang, Indrajit Raychaudhuri, Ismo Puustinen, Jakub + Wilk, Jan Alexander Steffens (heftig), Jan Engelhardt, Jan Synacek, + Joost Bremmer, Jorgen Schaefer, Karel Zak, Klearchos Chaloulos, + lc85446, Lennart Poettering, Lukas Nykryn, Mantas Mikulėnas, Marcel + Holtmann, Martin Pitt, Michael Biebl, Michael Olbrich, Michael Scherer, + Michał Górny, Michal Sekletar, Nicolas Cornu, Nicolas Iooss, Nils + Carlson, nmartensen, nnz1024, Patrick Ohly, Peter Hutterer, Phillip Sz, + Ronny Chevalier, Samu Kallio, Shawn Landden, Stef Walter, Susant + Sahani, Sylvain Plantefève, Tadej Janež, Thomas Hindoe Paaboel + Andersen, Tom Gundersen, Torstein Husebø, Umut Tezduyar Lindskog, Vito + Caputo, WaLyong Cho, Yu Watanabe, Zbigniew Jędrzejewski-Szmek + + -- Berlin, 2016-02-11 + CHANGES WITH 228: * A number of properties previously only settable in unit @@ -88,6 +307,14 @@ CHANGES WITH 228: from PID1's environment block into the environment block of the service. + * Timer units gained support for a new RemainAfterElapse= + setting which takes a boolean argument. It defaults on on, + exposing behaviour unchanged to previous releases. If set to + off, timer units are unloaded after they elapsed if they + cannot elapse again. This is particularly useful for + transient timer units, which shall not stay around longer + than until they first elapse. + * systemd will now bump the net.unix.max_dgram_qlen to 512 by default now (the kernel default is 16). This is beneficial for avoiding blocking on AF_UNIX/SOCK_DGRAM sockets since it diff --git a/README b/README index bc7068a66..0a2c0df47 100644 --- a/README +++ b/README @@ -15,7 +15,6 @@ GITWEB: MAILING LIST: http://lists.freedesktop.org/mailman/listinfo/systemd-devel - http://lists.freedesktop.org/mailman/listinfo/systemd-commits IRC: #systemd on irc.freenode.org @@ -204,6 +203,9 @@ USERS AND GROUPS: Similarly, the kdbus dbus1 proxy daemon requires the "systemd-bus-proxy" system user and group to exist. + Similarly, the coredump support requires the + "systemd-coredump" system user and group to exist. + NSS: systemd ships with three NSS modules: @@ -237,10 +239,6 @@ SYSV INIT.D SCRIPTS: needs to look like, and provide an implementation at the marked places. WARNINGS: - systemd will freeze execution during boot if /etc/mtab exists - but is not a symlink to /proc/mounts. Please ensure that - /etc/mtab is a proper symlink. - systemd will warn you during boot if /usr is on a different file system than /. While in systemd itself very little will break if /usr is on a separate partition, many of its @@ -267,3 +265,8 @@ WARNINGS: servers if not specified otherwise at configure time. You really should not ship an OS or device with this default setting. See DISTRO_PORTING for details. + +ENGINEERING AND CONSULTING SERVICES: + Kinvolk (https://kinvolk.io) offers professional engineering + and consulting services for systemd. Please contact Chris Kühl + for more information. diff --git a/README.md b/README.md index 5abe2073c..dcd14ba94 100644 --- a/README.md +++ b/README.md @@ -5,5 +5,14 @@ ## Details - * General information about systemd can be found in the [systemd Wiki](http://www.freedesktop.org/wiki/Software/systemd) - * Information about build requirements are provided in the [README file](../master/README) +General information about systemd can be found in the [systemd Wiki](http://www.freedesktop.org/wiki/Software/systemd). + +Information about build requirements are provided in the [README file](../master/README). + +Consult our [NEWS file](../master/NEWS) for information about what's new in the most recent systemd versions. + +Please see our [Contribution Guidelines](../master/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests. + +When preparing patches for systemd, please follow our [Coding Style Guidelines](../master/CODING_STYLE). + +If you are looking for support, please contact our [mailing list](http://lists.freedesktop.org/mailman/listinfo/systemd-devel) or join our [IRC channel](irc://irc.freenode.org/%23systemd). diff --git a/TODO b/TODO index 10a20758b..7437938bf 100644 --- a/TODO +++ b/TODO @@ -33,6 +33,19 @@ Janitorial Clean-ups: Features: +* delay activation of logind until somebody logs in, or when /dev/tty0 pulls it + in or lingering is on (so that containers don't bother with it until PAM is used). also exit-on-idle + +* cache sd_event_now() result from before the first iteration... + +* remove Capabilities=, after all AmbientCapabilities= and CapabilityBoundingSet= should be enough. + +* support for the new copy_file_range() syscall + +* add systemctl stop --job-mode=triggering that follows TRIGGERED_BY deps and adds them to the same transaction + +* Maybe add a way how users can "pin" units into memory, so that they are not subject to automatic GC? + * PID1: find a way how we can reload unit file configuration for specific units only, without reloading the whole of systemd @@ -58,8 +71,6 @@ Features: * consider throwing a warning if a service declares it wants to be "Before=" a .device unit. -* "systemctl edit" should know a mode to create a new unit file - * there's probably something wrong with having user mounts below /sys, as we have for debugfs. for exmaple, src/core/mount.c handles mounts prefixed with /sys generally special. @@ -67,12 +78,8 @@ Features: * man: document that unless you use StandardError=null the shell >/dev/stderr won't work in shell scripts in services -* "systemctl daemon-reload" should result in /etc/systemd/system.conf being reloaded by systemd - * install: include generator dirs in unit file search paths -* invent a better systemd-run scheme for naming scopes, that works with remoting - * rework C11 utf8.[ch] to use char32_t instead of uint32_t when referring to unicode chars, to make things more expressive. @@ -103,7 +110,7 @@ Features: * Rework systemctl's GetAll property parsing to use the generic bus_map_all_properties() API -* core/cgroup: support net_cls modules, and support automatically allocating class ids, then add support for making firewall changes depending on it, to implement a per-service firewall +* implement a per-service firewall based on net_cls * Port various tools to make use of verbs.[ch], where applicable @@ -155,8 +162,6 @@ Features: * maybe provide an API to allow migration of foreign PIDs into existing scopes. -* maybe support a new very "soft" reboot mode, that simply kills all processes, disassembles everything, flushes /run and sysvipc, and then reexecs systemd again - * man: maybe use the word "inspect" rather than "introspect"? * systemctl: if some operation fails, show log output? @@ -166,9 +171,9 @@ Features: - use equvalent of cat() to insert existing config as a comment, prepended with #. Upon editor exit, lines with one # are removed, lines with two # are left with one #, etc. -* exponential backoff in timesyncd and resolved when we cannot reach a server +* exponential backoff in timesyncd when we cannot reach a server -* timesyncd + resolved: add ugly bus calls to set NTP and DNS servers per-interface, for usage by NM +* timesyncd: add ugly bus calls to set NTP servers per-interface, for usage by NM * extract_many_words() should probably be used by a lot of code that currently uses FOREACH_WORD and friends. For example, most conf @@ -183,23 +188,16 @@ Features: (throughout the codebase, not only PID1) * resolved: - - put networkd events and rtnl events at a higher priority, so that - we always process them before we process client requests - - DNSSEC - - add display of private key types (http://tools.ietf.org/html/rfc4034#appendix-A.1.1)? - - DNS - - search paths - mDNS/DNS-SD + - service registration + - service/domain/types browsing - avahi compat - DNS-SD service registration from socket units - - edns0 - - dname: Not necessary for plain DNS as synthesized cname is handed out instead if we do not - announce dname support. However, for DNSSEC it is necessary as the synthesized cname - will not be signed. - - cname on PTR (?) - resolved should optionally register additional per-interface LLMNR names, so that for the container case we can establish the same name (maybe "host") for referencing the server, everywhere. + - enable DNSSEC by default + - allow clients to request DNSSEC for a single lookup even if DNSSEC is off (?) * refcounting in sd-resolve is borked @@ -213,8 +211,6 @@ Features: * generator that automatically discovers btrfs subvolumes, identifies their purpose based on some xattr on them. -* timer units: actually add extra delays to timer units with high AccuracySec values, don't start them already when we are awake... - * a way for container managers to turn off getty starting via $container_headless= or so... * figure out a nice way how we can let the admin know what child/sibling unit causes cgroup membership for a specific unit @@ -339,10 +335,6 @@ Features: - generate a failure of a default event loop is executed out-of-thread - maybe add support for inotify events -* in the final killing spree, detect processes from the root directory, and - complain loudly if they have argv[0][0] == '@' set. - https://bugzilla.redhat.com/show_bug.cgi?id=961044 - * investigate endianness issues of UUID vs. GUID * dbus: when a unit failed to load (i.e. is in UNIT_ERROR state), we @@ -491,10 +483,6 @@ Features: - journal-or-kmsg is currently broken? See reverted commit 4a01181e460686d8b4a543b1dfa7f77c9e3c5ab8. - man: document that corrupted journal files is nothing to act on - - systemd-journal-upload (or a new, related tool): allow pushing out - journal messages onto the network in BSD syslog protocol, - continuously. Default to some link-local IP mcast group, to make this - useful as a one-stop debugging tool. - rework journald sigbus stuff to use mutex - Set RLIMIT_NPROC for systemd-journal-xyz, and all other of our services that run under their own user ids, and use User= (but only @@ -609,8 +597,6 @@ Features: removed or added to an existing machine - "machinectl migrate" or similar to copy a container from or to a difference host, via ssh - - man: document how update dkr images works with machinectl - http://lists.freedesktop.org/archives/systemd-devel/2015-February/028630.html - introduce systemd-nspawn-ephemeral@.service, and hook it into "machinectl start" with a new --ephemeral switch - "machinectl status" should also show internal logs of the container in @@ -623,8 +609,6 @@ Features: shell in it, and marks it read-only after use * importd: - - dkr: support tarsum checksum verification, if it becomes reality one day... - - dkr: convert json bits to nspawn configuration - generate a nice warning if mkfs.btrfs is missing * cryptsetup: @@ -661,10 +645,6 @@ Features: * coredump: - save coredump in Windows/Mozilla minidump format - move PID 1 segfaults to /var/lib/systemd/coredump? - - make the handler check /proc/$PID/rlimits for RLIMIT_CORE, - and supress coredump if turned off. Then change RLIMIT_CORE to - infinity by default for all services. This then allows per-service - control of coredumping. * support crash reporting operation modes (https://live.gnome.org/GnomeOS/Design/Whiteboards/ProblemReporting) @@ -736,7 +716,6 @@ Features: - Support --test based on current system state - If we show an error about a unit (such as not showing up) and it has no Description string, then show a description string generated form the reverse of unit_name_mangle(). - after deserializing sockets in socket.c we should reapply sockopts and things - - make timer units go away after they elapsed - drop PID 1 reloading, only do reexecing (difficult: Reload() currently is properly synchronous, Reexec() is weird, because we cannot delay the response properly until we are back, so instead of diff --git a/catalog/systemd.catalog b/catalog/systemd.catalog index 4488c835a..077f182a5 100644 --- a/catalog/systemd.catalog +++ b/catalog/systemd.catalog @@ -38,6 +38,21 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel The system journal process has shut down and closed all currently active journal files. +-- ec387f577b844b8fa948f33cad9a75e6 +Subject: Disk space used by the journal +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@JOURNAL_NAME@ (@JOURNAL_PATH@) is currently using @CURRENT_USE_PRETTY@. +Maximum allowed usage is set to @MAX_USE_PRETTY@. +Leaving at least @DISK_KEEP_FREE_PRETTY@ free (of currently available @DISK_AVAILABLE_PRETTY@ of disk space). +Enforced usage limit is thus @LIMIT_PRETTY@, of which @AVAILABLE_PRETTY@ are still available. + +The limits controlling how much disk space is used by the journal may +be configured with SystemMaxUse=, SystemKeepFree=, SystemMaxFileSize=, +RuntimeMaxUse=, RuntimeKeepFree=, RuntimeMaxFileSize= settings in +/etc/systemd/journald.conf. See journald.conf(5) for details. + -- a596d6fe7bfa4994828e72309e95d61e Subject: Messages from a service have been suppressed Defined-By: systemd @@ -278,3 +293,42 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel The virtual machine @NAME@ with its leader PID @LEADER@ has been shut down. + +-- 36db2dfa5a9045e1bd4af5f93e1cf057 +Subject: DNSSEC mode has been turned off, as server doesn't support it +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:systemd-resolved.service(8) resolved.conf(5) + +The resolver service (systemd-resolved.service) has detected that the +configured DNS server does not support DNSSEC, and DNSSEC validation has been +turned off as result. + +This event will take place if DNSSEC=allow-downgrade is configured in +resolved.conf and the configured DNS server is incompatible with DNSSEC. Note +that using this mode permits DNSSEC downgrade attacks, as an attacker might be +able turn off DNSSEC validation on the system by inserting DNS replies in the +communication channel that result in a downgrade like this. + +This event might be indication that the DNS server is indeed incompatible with +DNSSEC or that an attacker has successfully managed to stage such a downgrade +attack. + +-- 1675d7f172174098b1108bf8c7dc8f5d +Subject: DNSSEC validation failed +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:systemd-resolved.service(8) + +A DNS query or resource record set failed DNSSEC validation. This is usually +indication that the communication channel used was tampered with. + +-- 4d4408cfd0d144859184d1e65d7c8a65 +Subject: A DNSSEC trust anchor has been revoked +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:systemd-resolved.service(8) + +A DNSSEC trust anchor has been revoked. A new trust anchor has to be +configured, or the operating system needs to be updated, to provide an updated +DNSSEC trust anchor. diff --git a/catalog/systemd.hu.catalog b/catalog/systemd.hu.catalog new file mode 100644 index 000000000..30d76916c --- /dev/null +++ b/catalog/systemd.hu.catalog @@ -0,0 +1,262 @@ +# This file is part of systemd. +# +# Copyright 2012 Lennart Poettering +# Copyright 2016 Gabor Kelemen +# +# 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 . + +# Message catalog for systemd's own messages + +# The catalog format is documented on +# http://www.freedesktop.org/wiki/Software/systemd/catalog + +# For an explanation why we do all this, see https://xkcd.com/1024/ + +-- f77379a8490b408bbe5f6940505a777b +Subject: A napló elindult +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A rendszernapló folyamat elindult, megnyitotta írásra a naplófájlokat, +és most készen áll kérések feldolgozására. + +-- d93fb3c9c24d451a97cea615ce59c00b +Subject: A napló leállt +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A rendszernapló folyamat leállt, és bezárt minden jelenleg aktív naplófájlt. + +-- a596d6fe7bfa4994828e72309e95d61e +Subject: Egy szolgáltatás üzenetei elnémítva +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:journald.conf(5) + +Egy szolgáltatás túl sok üzenetet naplózott adott idő alatt. A +szolgáltatástól származó üzenetek eldobásra kerültek. + +Ne feledje, hogy csak a kérdéses szolgáltatás üzenetei kerültek eldobásra, + más szolgáltatások üzeneteit ez nem befolyásolja. + +Az üzenetek eldobását vezérlő korlátok az /etc/systemd/journald.conf +RateLimitInterval= és RateLimitBurst= beállításaival adhatók meg. +Részletekért lásd a journald.conf(5) man oldalt. + +-- e9bf28e6e834481bb6f48f548ad13606 +Subject: Naplóüzenetek vesztek el +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Kernelüzenetek vesztek el, mert a naplózó rendszer nem tudta elég gyorsan +feldolgozni azokat. + +-- fc2e22bc6ee647b6b90729ab34a250b1 +Subject: Egy folyamat összeomlott: @COREDUMP_PID@ (@COREDUMP_COMM@) +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:core(5) + +Ez a folyamat: @COREDUMP_PID@ (@COREDUMP_COMM@) összeomlott, és core fájlt + írt ki. + +Ez általában programozási hibát jelez az összeomló programban, és +a szállítója felé kell bejelenteni. + +-- 8d45620c1a4348dbb17410da57c60c66 +Subject: Új munkamenet (@SESSION_ID@) létrehozva, felhasználója: @USER_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Létrejött egy új munkamenet @SESSION_ID@ azonosítóval ezen felhasználóhoz: +@USER_ID@. + +A munkamenet vezető folyamata: @LEADER@. + +-- 3354939424b4456d9802ca8333ed424a +Subject: Munkamenet (@SESSION_ID@) befejezve +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +A következő azonosítójú munkamenet befejeződött: @SESSION_ID@. + +-- fcbefc5da23d428093f97c82a9290f7b +Subject: Elérhető egy új munkaállomás: @SEAT_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +Beállításra kerül és használható egy új munkaállomás: @SEAT_ID@. + +-- e7852bfe46784ed0accde04bc864c2d5 +Subject: A munkaállomás eltávolítva: @SEAT_ID@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: http://www.freedesktop.org/wiki/Software/systemd/multiseat + +A munkaállomás el lett távolítva, és már nem érhető el: @SEAT_ID@ + +-- c7a787079b354eaaa9e77b371893cd27 +Subject: Időmódosítás +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A rendszeróra beállítva @REALTIME@ ezredmásodpercre 1970. január 1. után. + +-- 45f82f4aef7a4bbf942ce861d1f20990 +Subject: Időzóna-módosítás erre: @TIMEZONE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A rendszer időzónája módosítva lett erre: @TIMEZONE@. + +-- b07a249cd024414a82dd00cd181378ff +Subject: A rendszer indítása kész +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A rendszerindításkor szükséges indításhoz sorba állított összes +rendszerszolgáltatás elindult. Ne feledje, hogy ez nem jelenti, hogy a +gép üresjáratban van, mivel egyes szolgáltatások még az indítás +befejezésével lehetnek elfoglalva. + +A kernel indítása @KERNEL_USEC@ ezredmásodpercet igényelt. + +A kiinduló RAM lemez indítása @INITRD_USEC@ ezredmásodpercet igényelt. + +A felhasználói programok indítása @USERSPACE_USEC@ ezredmásodpercet igényelt. + +-- 6bbd95ee977941e497c48be27c254128 +Subject: A rendszer „@SLEEP@” alvási állapotba lépett +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A rendszer belépett ebbe az alvási állapotba: @SLEEP@. + +-- 8811e6df2a8e40f58a94cea26f8ebf14 +Subject: A rendszer „@SLEEP@” alvási állapotból kilépett +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A rendszer kilépett ebből az alvási állapotból: @SLEEP@. + +-- 98268866d1d54a499c4e98921d93bc40 +Subject: Rendszer leállítása kezdeményezve +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A systemd leállítása kezdeményezve. A leállítás megkezdődött, minden +rendszerszolgáltatás befejeződik, minden fájlrendszer leválasztásra kerül. + +-- 7d4958e842da4a758f6c1cdc7b36dcc5 +Subject: A(z) @UNIT@ egység indítása megkezdődött +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A(z) @UNIT@ egység megkezdte az indulást. + +-- 39f53479d3a045ac8e11786248231fbf +Subject: A(z) @UNIT@ egység befejezte az indulást +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A(z) @UNIT@ egység befejezte az indulást + +Az indítás eredménye: @RESULT@. + +-- de5b426a63be47a7b6ac3eaac82e2f6f +Subject: A(z) @UNIT@ egység megkezdte a leállást +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A(z) @UNIT@ egység megkezdte a leállást. + +-- 9d1aaa27d60140bd96365438aad20286 +Subject: A(z) @UNIT@ egység befejezte a leállást +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A(z) @UNIT@ egység befejezte a leállást. + +-- be02cf6855d2428ba40df7e9d022f03d +Subject: A(z) @UNIT@ egység hibát jelzett +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A(z) @UNIT@ egység hibát jelzett. + +Az eredmény: @RESULT@. + +-- d34d037fff1847e6ae669a370e694725 +Subject: A(z) @UNIT@ egység megkezdte a beállításainak újratöltését +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A(z) @UNIT@ egység megkezdte a beállításainak újratöltését. + +-- 7b05ebc668384222baa8881179cfda54 +Subject: A(z) @UNIT@ egység befejezte a beállításainak újratöltését +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A(z) @UNIT@ egység befejezte a beállításainak újratöltését. + +Az eredmény: @RESULT@. + +-- 641257651c1b4ec9a8624d7a40a9e1e7 +Subject: A folyamat végrehajtása sikertelen: @EXECUTABLE@ +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A folyamat végrehajtása sikertelen volt, és hibát jelzett: @EXECUTABLE@. + +A folyamat által visszaadott hibaszám: @ERRNO@. + +-- 0027229ca0644181a76c4e92458afa2e +Subject: Legalább egy üzenet nem továbbítható a rendszernaplónak +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +Legalább egy üzenet nem volt továbbítható a journald-vel párhuzamosan futó +syslog szolgáltatásnak. Ez általában azt jelenti, hogy a syslog +megvalósítás nem volt képes lépést tartani a sorba állított +üzenetek sebességével. + +-- 1dee0369c7fc4736b7099b38ecb46ee7 +Subject: A csatolási pont nem üres +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A csatolási pontként megadott @WHERE@ könyvtár (második mező az /etc/fstab +fájlban, vagy a Where= sor a systemd egységfájlban) nem üres. Ez nem +akadályozza meg a csatolást, de a könyvtárban már meglévő fájlok +elérhetetlenné válnak. A fájlok láthatóvá tételéhez csatolja +az azokat tartalmazó fájlrendszert egy másodlagos helyre. + +-- 24d8d4452573402496068381a6312df2 +Subject: Egy virtuális gép vagy konténer elindult +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A(z) @NAME@ nevű virtuális gép (vezető PID: @LEADER@) elindult, és +használatra kész. + +-- 58432bd3bace477cb514b56381b8a758 +Subject: Egy virtuális gép vagy konténer befejeződött +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +A(z) @NAME@ nevű virtuális gép (vezető PID: @LEADER@) leállt. diff --git a/catalog/systemd.ru.catalog b/catalog/systemd.ru.catalog index 03eea04c9..eedbb8aa9 100644 --- a/catalog/systemd.ru.catalog +++ b/catalog/systemd.ru.catalog @@ -1,7 +1,7 @@ # This file is part of systemd. # # Copyright 2012 Lennart Poettering -# Copyright 2013 Sergey Ptashnick +# Copyright 2013-2016 Sergey Ptashnick # # 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 @@ -43,6 +43,25 @@ Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel Процесс, отвечающий за журналирование системных событий, завершил работу и закрыл все свои файлы. +# Subject: Disk space used by the journal +-- ec387f577b844b8fa948f33cad9a75e6 +Subject: Место на диске, занятое журналом +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel + +@JOURNAL_NAME@ (@JOURNAL_PATH@) сейчас занимает @CURRENT_USE_PRETTY@. +Максимальный разрешенный размер составляет @MAX_USE_PRETTY@. +Оставляем свободными как минимум @DISK_KEEP_FREE_PRETTY@ (сейчас на диске +свободно @DISK_AVAILABLE_PRETTY@). +Таким образом, предел использования составляет @LIMIT_PRETTY@, из которых +@AVAILABLE_PRETTY@ пока свободно. + +Ограничения на размер журнала настраиваются при помощи параметров +SystemMaxUse=, SystemKeepFree=, SystemMaxFileSize=, RuntimeMaxUse=, +RuntimeKeepFree=, RuntimeMaxFileSize= в файле /etc/systemd/journald.conf. +Более подробные сведения вы можете получить на справочной странице +journald.conf(5). + # Subject: Messages from a service have been suppressed -- a596d6fe7bfa4994828e72309e95d61e Subject: Часть сообщений от службы пропущена @@ -292,3 +311,44 @@ Defined-By: systemd Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel Виртуальная машина @NAME@ (идентификатор главного процесса: @LEADER@) выключена. + +# Subject: DNSSEC mode has been turned off, as server doesn't support it +-- 36db2dfa5a9045e1bd4af5f93e1cf057 +Subject: Механизм DNSSEC был отключен, так как DNS-сервер его не поддерживает +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:systemd-resolved.service(8) resolved.conf(5) + +Служба разрешения имен хостов (systemd-resolved.service) определила, что +указанный в настойках DNS-сервер не поддерживает технологию DNSSEC, и +автоматически отключила DNSSEC-проверки. + +Данное событие возникает, если в файле resolved.conf указан параметр +DNSSEC=allow-downgrade, и вышестоящий DNS-сервер не поддерживает DNSSEC. +Обратите внимание, что режим allow-downgrade допускает возможность атаки +"DNSSEC downgrade", в ходе которой атакующий хакер блокирует проверки DNSSEC +путем отправки ложных сообщений от имени DNS-сервера. + +Возникновение данного события может свидетельствовать как о том, что ваш +DNS-сервер не поддерживает DNSSEC, так и о том, что некий хакер успешно провел +против вас атаку, направленную на блокировку DNSSEC-проверок. + +# Subject: DNSSEC validation failed +-- 1675d7f172174098b1108bf8c7dc8f5d +Subject: Проверка DNSSEC провалена +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:systemd-resolved.service(8) + +DNS-запрос или отдельная ресурсная запись не прошла проверку DNSSEC. +Как правило, это свидетельствует о постороннем вмешательстве в канал связи. + +# Subject: A DNSSEC trust anchor has been revoked +-- 4d4408cfd0d144859184d1e65d7c8a65 +Subject: Открытый ключ DNSSEC был отозван +Defined-By: systemd +Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel +Documentation: man:systemd-resolved.service(8) + +Открытый ключ (trust ahcnor) DNSSEC был отозван. Необходимо настроить новый +открытый ключ, либо обновить систему, чтобы получить обновленный открытый ключ. diff --git a/coccinelle/xsprintf.cocci b/coccinelle/xsprintf.cocci new file mode 100644 index 000000000..401216ad7 --- /dev/null +++ b/coccinelle/xsprintf.cocci @@ -0,0 +1,6 @@ +@@ +expression e, fmt; +expression list vaargs; +@@ +- snprintf(e, sizeof(e), fmt, vaargs); ++ xsprintf(e, fmt, vaargs); diff --git a/configure.ac b/configure.ac index ec30ff12a..5fd73c59f 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ AC_PREREQ([2.64]) AC_INIT([systemd], - [228], + [229], [http://github.com/systemd/systemd/issues], [systemd], [http://www.freedesktop.org/wiki/Software/systemd]) @@ -297,7 +297,8 @@ AC_SUBST(CAP_LIBS) AC_CHECK_FUNCS([memfd_create]) AC_CHECK_FUNCS([__secure_getenv secure_getenv]) -AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, kcmp, keyctl, key_serial_t, LO_FLAGS_PARTSCAN], +AC_CHECK_DECLS([gettid, pivot_root, name_to_handle_at, setns, getrandom, renameat2, + kcmp, keyctl, key_serial_t, char16_t, char32_t, LO_FLAGS_PARTSCAN], [], [], [[ #include #include @@ -555,7 +556,7 @@ AM_CONDITIONAL(HAVE_ZLIB, [test "$have_zlib" = "yes"]) # ------------------------------------------------------------------------------ have_bzip2=no -AC_ARG_ENABLE(bzip2, AS_HELP_STRING([--enable-bzip2], [Disable optional BZIP2 support])) +AC_ARG_ENABLE(bzip2, AS_HELP_STRING([--enable-bzip2], [Enable optional BZIP2 support])) AS_IF([test "x$enable_bzip2" != "xno"], [ AC_CHECK_HEADERS(bzlib.h, [AC_DEFINE(HAVE_BZIP2, 1, [Define if BZIP2 is available]) @@ -668,11 +669,14 @@ AC_ARG_ENABLE([smack], AS_HELP_STRING([--disable-smack],[Disable optional SMACK esac], [have_smack=auto]) -if test "x${have_smack}" = xauto; then +if test "x${have_smack}" != xno; then + AC_DEFINE(HAVE_SMACK, 1, [Define if SMACK is available]) M4_DEFINES="$M4_DEFINES -DHAVE_SMACK" have_smack=yes fi +AM_CONDITIONAL([HAVE_SMACK], [test "x$have_smack" = "xyes"]) + have_smack_run_label=no AC_ARG_WITH(smack-run-label, AS_HELP_STRING([--with-smack-run-label=STRING], @@ -690,12 +694,6 @@ AS_HELP_STRING([--with-smack-default-process-label=STRING], [AC_DEFINE_UNQUOTED(SMACK_DEFAULT_PROCESS_LABEL, ["$withval"], [Default SMACK label for executed processes])], []) -if test "x${have_smack}" = xyes ; then - AC_DEFINE(HAVE_SMACK, 1, [Define if SMACK is available]) -fi - -AM_CONDITIONAL([HAVE_SMACK], [test "x$have_smack" = "xyes"]) - # ------------------------------------------------------------------------------ AC_ARG_ENABLE([gcrypt], AS_HELP_STRING([--disable-gcrypt],[Disable optional GCRYPT support]), @@ -708,7 +706,7 @@ AC_ARG_ENABLE([gcrypt], if test "x${have_gcrypt}" != xno ; then m4_define([AM_PATH_LIBGCRYPT_FAIL], - [{ test "x$have_gcrypt" != xyes || AC_MSG_ERROR([*** GCRYPT headers not found.]); }] + [{ test "x$have_gcrypt" != xyes || AC_MSG_ERROR([*** GCRYPT/GPG-ERROR headers not found.]); }] ) m4_ifdef([AM_PATH_LIBGCRYPT], [AM_PATH_LIBGCRYPT( [1.4.5], @@ -723,12 +721,22 @@ if test "x${have_gcrypt}" != xno ; then [AM_PATH_LIBGCRYPT_FAIL] ) - if test "x$have_gcrypt" = xyes ; then - GCRYPT_LIBS="$LIBGCRYPT_LIBS" - GCRYPT_CFLAGS="$LIBGCRYPT_CFLAGS" + have_gpg_error=no + m4_ifdef([AM_PATH_GPG_ERROR], [AM_PATH_GPG_ERROR( + [1.12], + [have_gpg_error=yes], + [AM_PATH_LIBGCRYPT_FAIL] + )], + [AM_PATH_LIBGCRYPT_FAIL] + ) + + if test "x$have_gcrypt" = xyes -a "x$have_gpg_error" = xyes ; then + GCRYPT_LIBS="$LIBGCRYPT_LIBS $GPG_ERROR_LIBS" + GCRYPT_CFLAGS="$LIBGCRYPT_CFLAGS $GPG_ERROR_CFLAGS" AC_DEFINE(HAVE_GCRYPT, 1, [GCRYPT available]) else have_gcrypt=no + have_gpg_error=no fi else GCRYPT_LIBS= @@ -838,18 +846,6 @@ if test "x$enable_qrencode" != "xno"; then fi AM_CONDITIONAL(HAVE_QRENCODE, [test "$have_qrencode" = "yes"]) -# ------------------------------------------------------------------------------ -have_microhttpd=no -AC_ARG_ENABLE(microhttpd, AS_HELP_STRING([--disable-microhttpd], [disable microhttpd support])) -if test "x$enable_microhttpd" != "xno"; then - PKG_CHECK_MODULES(MICROHTTPD, [libmicrohttpd >= 0.9.33], - [AC_DEFINE(HAVE_MICROHTTPD, 1, [Define if microhttpd is available]) have_microhttpd=yes], have_microhttpd=no) - if test "x$have_microhttpd" = xno -a "x$enable_microhttpd" = xyes; then - AC_MSG_ERROR([*** microhttpd support requested but libraries not found]) - fi -fi -AM_CONDITIONAL(HAVE_MICROHTTPD, [test "$have_microhttpd" = "yes"]) - # ------------------------------------------------------------------------------ have_gnutls=no AC_ARG_ENABLE(gnutls, AS_HELP_STRING([--disable-gnutls], [disable gnutls support])) @@ -862,18 +858,39 @@ if test "x$enable_gnutls" != "xno"; then fi AM_CONDITIONAL(HAVE_GNUTLS, [test "$have_gnutls" = "yes"]) +# ------------------------------------------------------------------------------ +have_microhttpd=no +AC_ARG_ENABLE(microhttpd, AS_HELP_STRING([--disable-microhttpd], [disable microhttpd support])) +if test "x$enable_microhttpd" != "xno"; then + PKG_CHECK_MODULES(MICROHTTPD, [libmicrohttpd >= 0.9.33], + [AC_DEFINE(HAVE_MICROHTTPD, 1, [Define if microhttpd is available]) + have_microhttpd=yes + M4_DEFINES="$M4_DEFINES -DHAVE_MICROHTTPD"], + [have_microhttpd=no]) + if test "x$have_microhttpd" = xno -a "x$enable_microhttpd" = xyes; then + AC_MSG_ERROR([*** microhttpd support requested but libraries not found]) + fi +fi +AM_CONDITIONAL(HAVE_MICROHTTPD, [test "$have_microhttpd" = "yes"]) + # ------------------------------------------------------------------------------ have_libcurl=no AC_ARG_ENABLE(libcurl, AS_HELP_STRING([--disable-libcurl], [disable libcurl support])) if test "x$enable_libcurl" != "xno"; then PKG_CHECK_MODULES(LIBCURL, [libcurl], - [AC_DEFINE(HAVE_LIBCURL, 1, [Define if libcurl is available]) have_libcurl=yes], have_libcurl=no) + [AC_DEFINE(HAVE_LIBCURL, 1, [Define if libcurl is available]) + have_libcurl=yes + M4_DEFINES="$M4_DEFINES -DHAVE_LIBCURL"], + [have_libcurl=no]) if test "x$have_libcurl" = xno -a "x$enable_libcurl" = xyes; then AC_MSG_ERROR([*** libcurl support requested but libraries not found]) fi fi AM_CONDITIONAL(HAVE_LIBCURL, [test "$have_libcurl" = "yes"]) +# ------------------------------------------------------------------------------ +AM_CONDITIONAL(HAVE_REMOTE, [test "$have_microhttpd" = "yes" -o "$have_libcurl" = "yes"]) + # ------------------------------------------------------------------------------ have_libidn=no AC_ARG_ENABLE(libidn, AS_HELP_STRING([--disable-libidn], [Disable optional LIBIDN support])) @@ -1089,6 +1106,7 @@ have_coredump=no AC_ARG_ENABLE(coredump, AS_HELP_STRING([--disable-coredump], [disable coredump hook])) if test "x$enable_coredump" != "xno"; then have_coredump=yes + M4_DEFINES="$M4_DEFINES -DENABLE_COREDUMP" fi AM_CONDITIONAL(ENABLE_COREDUMP, [test "$have_coredump" = "yes"]) @@ -1159,7 +1177,7 @@ AC_SUBST([EFI_ARCH]) AC_SUBST([EFI_MACHINE_TYPE_NAME]) have_gnuefi=no -AC_ARG_ENABLE(gnuefi, AS_HELP_STRING([--enable-gnuefi], [Disable optional gnuefi support])) +AC_ARG_ENABLE(gnuefi, AS_HELP_STRING([--enable-gnuefi], [Enable optional gnuefi support])) AS_IF([test "x$enable_gnuefi" != "xno"], [ AC_CHECK_HEADERS(efi/${EFI_ARCH}/efibind.h, [AC_DEFINE(HAVE_GNUEFI, 1, [Define if gnuefi is available]) @@ -1285,9 +1303,9 @@ AM_CONDITIONAL(ENABLE_HWDB, [test x$enable_hwdb = xyes]) # ------------------------------------------------------------------------------ have_manpages=no AC_ARG_ENABLE(manpages, AS_HELP_STRING([--disable-manpages], [disable manpages])) +AC_PATH_PROG([XSLTPROC], [xsltproc]) AS_IF([test "x$enable_manpages" != xno], [ have_manpages=yes - AC_PATH_PROG([XSLTPROC], [xsltproc]) AS_IF([test -z "$XSLTPROC"], AC_MSG_ERROR([*** xsltproc is required for man pages])) ]) @@ -1421,14 +1439,6 @@ AC_ARG_ENABLE([split-usr], enable_split_usr=no ])]) -AC_ARG_WITH([dkr-index-url], - [AS_HELP_STRING([--dkr-index-url=URL], [Specify the default index URL to use for image downloads])], - [DEFAULT_DKR_INDEX_URL="\"$withval\""], - [DEFAULT_DKR_INDEX_URL="NULL"]) - -AC_DEFINE_UNQUOTED(DEFAULT_DKR_INDEX_URL, [$DEFAULT_DKR_INDEX_URL], [Default index URL to use for image downloads]) -AC_SUBST(DEFAULT_DKR_INDEX_URL) - AS_IF([test "x${enable_split_usr}" = "xyes"], [ AC_DEFINE(HAVE_SPLIT_USR, 1, [Define if /bin, /sbin aren't symlinks into /usr]) ]) @@ -1597,7 +1607,6 @@ AC_MSG_RESULT([ Maximum System UID: ${SYSTEM_UID_MAX} Maximum System GID: ${SYSTEM_GID_MAX} Certificate root: ${CERTIFICATEROOT} - Default dkr Index ${DEFAULT_DKR_INDEX_URL} CFLAGS: ${OUR_CFLAGS} ${CFLAGS} CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS} diff --git a/hwdb/20-OUI.hwdb b/hwdb/20-OUI.hwdb index 62e77714c..80f189071 100644 --- a/hwdb/20-OUI.hwdb +++ b/hwdb/20-OUI.hwdb @@ -629,9 +629,6 @@ OUI:001BC508C* OUI:001BC5090* ID_OUI_FROM_DATABASE=Seven Solutions S.L -OUI:001BC5087* - ID_OUI_FROM_DATABASE=Onnet Technologies And Innovations - OUI:001BC507D* ID_OUI_FROM_DATABASE=Greatcom AG @@ -779,6 +776,78 @@ OUI:70B3D5A6F* OUI:70B3D5929* ID_OUI_FROM_DATABASE=OutSys +OUI:70B3D5120* + ID_OUI_FROM_DATABASE=GSP Sprachtechnologie GmbH + +OUI:70B3D523E* + ID_OUI_FROM_DATABASE=Tornado Modular Systems + +OUI:70B3D5EA2* + ID_OUI_FROM_DATABASE=Transportal Solutions Ltd + +OUI:70B3D545D* + ID_OUI_FROM_DATABASE=Sensapex Oy + +OUI:70B3D58B0* + ID_OUI_FROM_DATABASE=IES S.r.l. + +OUI:70B3D5FB6* + ID_OUI_FROM_DATABASE=KRONOTECH SRL + +OUI:70B3D5EB7* + ID_OUI_FROM_DATABASE=Skreens + +OUI:70B3D538F* + ID_OUI_FROM_DATABASE=Sorynorydotcom Inc + +OUI:70B3D57E9* + ID_OUI_FROM_DATABASE=Mecsel Oy + +OUI:70B3D506C* + ID_OUI_FROM_DATABASE=AppTek + +OUI:70B3D5818* + ID_OUI_FROM_DATABASE=CRDE + +OUI:70B3D5895* + ID_OUI_FROM_DATABASE=Integrated Control Corp. + +OUI:70B3D5232* + ID_OUI_FROM_DATABASE=UCONSYS + +OUI:70B3D501A* + ID_OUI_FROM_DATABASE=Cubro Acronet GesmbH + +OUI:70B3D537B* + ID_OUI_FROM_DATABASE=Power Ltd. + +OUI:70B3D5FCC* + ID_OUI_FROM_DATABASE=DIgSILENT GmbH + +OUI:70B3D5FD8* + ID_OUI_FROM_DATABASE=MB connect line GmbH Fernwartungssysteme + +OUI:70B3D576B* + ID_OUI_FROM_DATABASE=EMPELOR GmbH + +OUI:70B3D50B8* + ID_OUI_FROM_DATABASE=Lucas-Nülle GmbH + +OUI:70B3D5FEB* + ID_OUI_FROM_DATABASE=Les distributions Multi-Secure incorporee + +OUI:70B3D5658* + ID_OUI_FROM_DATABASE=emperor brands + +OUI:70B3D53A9* + ID_OUI_FROM_DATABASE=Vivalnk + +OUI:001BC5087* + ID_OUI_FROM_DATABASE=Onnet Technologies and Innovations LLC + +OUI:70B3D5720* + ID_OUI_FROM_DATABASE=Private + OUI:70B3D5D60* ID_OUI_FROM_DATABASE=Flintab AB @@ -1130,9 +1199,6 @@ OUI:70B3D5DE7* OUI:70B3D51F4* ID_OUI_FROM_DATABASE=Hangzhou Woosiyuan Communication Co.,Ltd. -OUI:70B3D5B7E* - ID_OUI_FROM_DATABASE=Elbit Systems of America - FMF Operations - OUI:70B3D5092* ID_OUI_FROM_DATABASE=inomed Medizintechnik GmbH @@ -1472,6 +1538,102 @@ OUI:70B3D5384* OUI:70B3D5893* ID_OUI_FROM_DATABASE=Cubitech +OUI:70B3D509E* + ID_OUI_FROM_DATABASE=MobiPromo + +OUI:70B3D549E* + ID_OUI_FROM_DATABASE=CAPTEMP, Lda + +OUI:70B3D54B6* + ID_OUI_FROM_DATABASE=VEILUX INC. + +OUI:70B3D57CF* + ID_OUI_FROM_DATABASE=ORCA Technologies, LLC + +OUI:70B3D55A3* + ID_OUI_FROM_DATABASE=CT Company + +OUI:70B3D580A* + ID_OUI_FROM_DATABASE=SENSING LABS + +OUI:70B3D5E45* + ID_OUI_FROM_DATABASE=Momentum Data Systems + +OUI:70B3D5059* + ID_OUI_FROM_DATABASE=Pro-Digital Projetos Eletronicos Ltda + +OUI:70B3D5091* + ID_OUI_FROM_DATABASE=PROFITT Ltd + +OUI:70B3D5647* + ID_OUI_FROM_DATABASE=KZTA + +OUI:70B3D56DF* + ID_OUI_FROM_DATABASE=Mango DSP, Inc. + +OUI:70B3D5CBE* + ID_OUI_FROM_DATABASE=Ensura Solutions BV + +OUI:70B3D5CAC* + ID_OUI_FROM_DATABASE=CRDE + +OUI:70B3D58B9* + ID_OUI_FROM_DATABASE=Toptech Systems, Inc. + +OUI:70B3D574E* + ID_OUI_FROM_DATABASE=PushCorp, Inc. + +OUI:70B3D5FD2* + ID_OUI_FROM_DATABASE=DALIAN LEVEAR ELECTRIC CO., LTD + +OUI:70B3D5F08* + ID_OUI_FROM_DATABASE=Szabo Software & Engineering UK Ltd + +OUI:70B3D56A1* + ID_OUI_FROM_DATABASE=GLIAL TECHNOLOGY + +OUI:70B3D5955* + ID_OUI_FROM_DATABASE=Dynacard Co., Ltd. + +OUI:70B3D512B* + ID_OUI_FROM_DATABASE=RIC Electronics + +OUI:70B3D517E* + ID_OUI_FROM_DATABASE=OCULI VISION + +OUI:70B3D5046* + ID_OUI_FROM_DATABASE=Shenzhen Rihuida Electronics Co,. Ltd + +OUI:70B3D5268* + ID_OUI_FROM_DATABASE=Cardinal Scale Mfg Co + +OUI:70B3D5B7E* + ID_OUI_FROM_DATABASE=Elbit Systems of America - Fort Worth Operations + +OUI:70B3D5DB5* + ID_OUI_FROM_DATABASE=Xiamen Point Circle Technologh Co,ltd + +OUI:70B3D5429* + ID_OUI_FROM_DATABASE=Redco Audio Inc + +OUI:70B3D52E7* + ID_OUI_FROM_DATABASE=Atos spa + +OUI:70B3D5766* + ID_OUI_FROM_DATABASE=Tirasoft Nederland + +OUI:70B3D517D* + ID_OUI_FROM_DATABASE=Entech Electronics + +OUI:70B3D599A* + ID_OUI_FROM_DATABASE=KEVIC. inc, + +OUI:70B3D502A* + ID_OUI_FROM_DATABASE=BAE Systems Surface Ships Limited + +OUI:70B3D5DE2* + ID_OUI_FROM_DATABASE=ACD Elekronik GmbH + OUI:70B3D5FFF* ID_OUI_FROM_DATABASE=Private @@ -1961,9 +2123,6 @@ OUI:70B3D5AC8* OUI:70B3D5F2A* ID_OUI_FROM_DATABASE=WIBOND Informationssysteme GmbH -OUI:70B3D5C24* - ID_OUI_FROM_DATABASE=Elbit Systems of America - OUI:70B3D52A5* ID_OUI_FROM_DATABASE=Taitotekniikka @@ -2141,6 +2300,93 @@ OUI:70B3D55D1* OUI:70B3D5A2E* ID_OUI_FROM_DATABASE=Kokam Co., Ltd +OUI:70B3D58A6* + ID_OUI_FROM_DATABASE=CRDE + +OUI:70B3D5FB5* + ID_OUI_FROM_DATABASE=Orange Tree Technologies Ltd + +OUI:70B3D5E02* + ID_OUI_FROM_DATABASE=YEHL & JORDAN LLC + +OUI:70B3D5F56* + ID_OUI_FROM_DATABASE=VirtualHere Pty. Ltd. + +OUI:70B3D58BE* + ID_OUI_FROM_DATABASE=Connoiseur Electronics Private Limited + +OUI:70B3D526B* + ID_OUI_FROM_DATABASE=Sorama BV + +OUI:70B3D52FA* + ID_OUI_FROM_DATABASE=Toray Medical Co.,Ltd + +OUI:70B3D5975* + ID_OUI_FROM_DATABASE=Coester Automação Ltda + +OUI:70B3D513C* + ID_OUI_FROM_DATABASE=Detec Systems Ltd + +OUI:70B3D5455* + ID_OUI_FROM_DATABASE=Heartlandmicropayments + +OUI:70B3D5070* + ID_OUI_FROM_DATABASE=Lumiplan Duhamel + +OUI:70B3D58D8* + ID_OUI_FROM_DATABASE=VNG Corporation + +OUI:70B3D5392* + ID_OUI_FROM_DATABASE=Contec DTx + +OUI:70B3D514D* + ID_OUI_FROM_DATABASE=2-Observe + +OUI:70B3D5A9F* + ID_OUI_FROM_DATABASE=Private + +OUI:70B3D59CB* + ID_OUI_FROM_DATABASE=Alligator Communications + +OUI:70B3D5B67* + ID_OUI_FROM_DATABASE=RedWave Labs Ltd + +OUI:70B3D5B93* + ID_OUI_FROM_DATABASE=INTERNET PROTOCOLO LOGICA SL + +OUI:70B3D5B89* + ID_OUI_FROM_DATABASE=IDA + +OUI:70B3D57E2* + ID_OUI_FROM_DATABASE=Depro Électronique inc + +OUI:70B3D5772* + ID_OUI_FROM_DATABASE=enModus + +OUI:70B3D53C5* + ID_OUI_FROM_DATABASE=P4Q ELECTRONICS, S.L. + +OUI:70B3D5FE2* + ID_OUI_FROM_DATABASE=Galileo Tıp Teknolojileri San. ve Tic. A.S. + +OUI:70B3D5C24* + ID_OUI_FROM_DATABASE=Elbit Systems of America - Fort Worth Operations + +OUI:70B3D5AC6* + ID_OUI_FROM_DATABASE=SMTC Corporation + +OUI:70B3D5028* + ID_OUI_FROM_DATABASE=AT-Automation Technology GmbH + +OUI:70B3D50B9* + ID_OUI_FROM_DATABASE=Easy Digital Concept + +OUI:70B3D5CF2* + ID_OUI_FROM_DATABASE=tinnos + +OUI:70B3D59E0* + ID_OUI_FROM_DATABASE=ES Industrial Systems Co., Ltd. + OUI:70B3D566B* ID_OUI_FROM_DATABASE=Innitive B.V. @@ -2555,9 +2801,6 @@ OUI:70B3D5710* OUI:70B3D5A0B* ID_OUI_FROM_DATABASE=ambiHome GmbH -OUI:70B3D58B1* - ID_OUI_FROM_DATABASE=M-Tech Innovations Ltd - OUI:70B3D5204* ID_OUI_FROM_DATABASE=TWC @@ -2762,6 +3005,111 @@ OUI:70B3D5B05* OUI:70B3D5847* ID_OUI_FROM_DATABASE=Ai-Lynx +OUI:70B3D5148* + ID_OUI_FROM_DATABASE=Power Electronics Espana, S.L. + +OUI:70B3D5BFE* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:70B3D5261* + ID_OUI_FROM_DATABASE=Potter Electric Signal Co. LLC + +OUI:70B3D5618* + ID_OUI_FROM_DATABASE=Motec Pty Ltd + +OUI:70B3D5892* + ID_OUI_FROM_DATABASE=ABB + +OUI:70B3D59BA* + ID_OUI_FROM_DATABASE=ATIM Radiocommunication + +OUI:70B3D54C4* + ID_OUI_FROM_DATABASE=OOO Research and Production Center Computer Technologies + +OUI:70B3D59B3* + ID_OUI_FROM_DATABASE=K&J Schmittschneider AG + +OUI:70B3D5747* + ID_OUI_FROM_DATABASE=Eva Automation + +OUI:70B3D53F4* + ID_OUI_FROM_DATABASE=Wincode Technology Co., Ltd. + +OUI:70B3D56E6* + ID_OUI_FROM_DATABASE=Eleven Engineering Incorporated + +OUI:70B3D5E39* + ID_OUI_FROM_DATABASE=Thinnect, Inc, + +OUI:70B3D5216* + ID_OUI_FROM_DATABASE=FLEXTRONICS + +OUI:70B3D50FE* + ID_OUI_FROM_DATABASE=Vocality International Ltd + +OUI:70B3D54B7* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:70B3D555C* + ID_OUI_FROM_DATABASE=Saratoga Speed, Inc. + +OUI:70B3D5428* + ID_OUI_FROM_DATABASE=Presentation Switchers, Inc. + +OUI:70B3D5C32* + ID_OUI_FROM_DATABASE=INFRASAFE/ ADVANTOR SYSTEMS + +OUI:70B3D5592* + ID_OUI_FROM_DATABASE=CRDE + +OUI:70B3D5F1A* + ID_OUI_FROM_DATABASE=Sator Controls s.r.o. + +OUI:70B3D505A* + ID_OUI_FROM_DATABASE=Uni Control System Sp. z o. o. + +OUI:70B3D59EF* + ID_OUI_FROM_DATABASE=Cottonwood Creek Technologies, Inc. + +OUI:70B3D59EB* + ID_OUI_FROM_DATABASE=Preston Industries dba PolyScience + +OUI:70B3D5A3B* + ID_OUI_FROM_DATABASE=Grace Design/Lunatec LLC + +OUI:70B3D57A0* + ID_OUI_FROM_DATABASE=Reactec Ltd + +OUI:70B3D529B* + ID_OUI_FROM_DATABASE=DermaLumics S.L. + +OUI:70B3D5202* + ID_OUI_FROM_DATABASE=DEUTA-WERKE GmbH + +OUI:70B3D5259* + ID_OUI_FROM_DATABASE=Zebra Elektronik A.S. + +OUI:70B3D5FBE* + ID_OUI_FROM_DATABASE=Hanbat National University + +OUI:70B3D5FE4* + ID_OUI_FROM_DATABASE=CARE PVT LTD + +OUI:70B3D58B1* + ID_OUI_FROM_DATABASE=M-Tech Innovations Limited + +OUI:70B3D5D34* + ID_OUI_FROM_DATABASE=G-PHILOS CO.,LTD + +OUI:70B3D5528* + ID_OUI_FROM_DATABASE=Aplex Technology Inc. + +OUI:70B3D5B81* + ID_OUI_FROM_DATABASE=Instro Precision Limited + +OUI:70B3D5479* + ID_OUI_FROM_DATABASE=LINEAGE POWER PVT. LTD. + OUI:70B3D58AB* ID_OUI_FROM_DATABASE=EMAC, Inc. @@ -3239,9 +3587,6 @@ OUI:70B3D5918* OUI:70B3D5308* ID_OUI_FROM_DATABASE=DSD MICROTECHNOLOGY,INC. -OUI:70B3D5184* - ID_OUI_FROM_DATABASE=XV360 Optical Information Systems Ltd. - OUI:70B3D56D3* ID_OUI_FROM_DATABASE=DEUTA-WERKE GmbH @@ -3392,6 +3737,105 @@ OUI:70B3D5297* OUI:70B3D5942* ID_OUI_FROM_DATABASE=TruTeq Devices (Pty) Ltd +OUI:70B3D5F7B* + ID_OUI_FROM_DATABASE=KST technology + +OUI:70B3D5B99* + ID_OUI_FROM_DATABASE=DomoSafety S.A. + +OUI:70B3D5D51* + ID_OUI_FROM_DATABASE=Azcom Technology S.r.l. + +OUI:70B3D5BA1* + ID_OUI_FROM_DATABASE=Cathwell AS + +OUI:70B3D5286* + ID_OUI_FROM_DATABASE=Pedax Danmark + +OUI:70B3D51A9* + ID_OUI_FROM_DATABASE=OCEANIX INC. + +OUI:70B3D5733* + ID_OUI_FROM_DATABASE=SA Instrumentation Limited + +OUI:70B3D5652* + ID_OUI_FROM_DATABASE=Robert Bosch, LLC + +OUI:70B3D5F65* + ID_OUI_FROM_DATABASE=MARKUS LABS + +OUI:70B3D5F2E* + ID_OUI_FROM_DATABASE=Shanghai JCY Technology Company + +OUI:70B3D57F8* + ID_OUI_FROM_DATABASE=Solvera Lynx d.d. + +OUI:70B3D55BE* + ID_OUI_FROM_DATABASE=CASWA + +OUI:70B3D5F55* + ID_OUI_FROM_DATABASE=Kohler Mira Ltd + +OUI:70B3D57ED* + ID_OUI_FROM_DATABASE=The Things Network Foundation + +OUI:70B3D5A9D* + ID_OUI_FROM_DATABASE=VITEC MULTIMEDIA + +OUI:70B3D51A8* + ID_OUI_FROM_DATABASE=STC Rainbow Ltd. + +OUI:70B3D53CA* + ID_OUI_FROM_DATABASE=TTI Ltd + +OUI:70B3D5E1C* + ID_OUI_FROM_DATABASE=Xcenter AS + +OUI:70B3D5184* + ID_OUI_FROM_DATABASE=XV360 Optical Information Systems Ltd. + +OUI:70B3D5B5C* + ID_OUI_FROM_DATABASE=Prozess Technologie + +OUI:70B3D5AF4* + ID_OUI_FROM_DATABASE=TATTILE SRL + +OUI:70B3D5531* + ID_OUI_FROM_DATABASE=ATEME + +OUI:70B3D5BA7* + ID_OUI_FROM_DATABASE=Digital Yacht Ltd + +OUI:70B3D51C7* + ID_OUI_FROM_DATABASE=Hoshin Electronics Co., Ltd. + +OUI:70B3D528B* + ID_OUI_FROM_DATABASE=Arnouse Digital Devices, Corp. + +OUI:70B3D5D94* + ID_OUI_FROM_DATABASE=Dewetron GmbH + +OUI:70B3D5974* + ID_OUI_FROM_DATABASE=Jireh Industries Ltd. + +OUI:70B3D5544* + ID_OUI_FROM_DATABASE=Silicon Safe Ltd + +OUI:70B3D5EE1* + ID_OUI_FROM_DATABASE=allora Factory BVBA + +OUI:70B3D5389* + ID_OUI_FROM_DATABASE=Private + +OUI:70B3D5640* + ID_OUI_FROM_DATABASE=Electronic Equipment Company Pvt. Ltd. + +OUI:70B3D5D65* + ID_OUI_FROM_DATABASE=CRDE + +OUI:70B3D53C3* + ID_OUI_FROM_DATABASE=AIMCO + OUI:1C8776D* ID_OUI_FROM_DATABASE=Qivivo @@ -3851,6 +4295,75 @@ OUI:1C8774E* OUI:78CA834* ID_OUI_FROM_DATABASE=Pinhole (Beijing) Technology Co., Ltd. +OUI:78CA83E* + ID_OUI_FROM_DATABASE=Konecranes + +OUI:38B8EBB* + ID_OUI_FROM_DATABASE=ExaScaler Inc. + +OUI:38FDFEC* + ID_OUI_FROM_DATABASE=New Garden Co., Ltd. + +OUI:38FDFE5* + ID_OUI_FROM_DATABASE=CaptiveAire Systems Inc. + +OUI:5CF2867* + ID_OUI_FROM_DATABASE=Access IS + +OUI:5CF286C* + ID_OUI_FROM_DATABASE=Sunpet Industries Limited + +OUI:5CF2862* + ID_OUI_FROM_DATABASE=Shanghai Notion Information Technology CO.,LTD. + +OUI:5CF2866* + ID_OUI_FROM_DATABASE=VPInstruments + +OUI:5CF286A* + ID_OUI_FROM_DATABASE=Unfors Raysafe AB + +OUI:7C477C5* + ID_OUI_FROM_DATABASE=Midwest Microwave Solutions + +OUI:5CF286E* + ID_OUI_FROM_DATABASE=Daisen Electronic Industrial Co., Ltd. + +OUI:7C477C1* + ID_OUI_FROM_DATABASE=Photosynth Inc. + +OUI:986D35A* + ID_OUI_FROM_DATABASE=iWave Japan, Inc. + +OUI:986D357* + ID_OUI_FROM_DATABASE=Zhejiang Hanshow Technology Co., Ltd. + +OUI:50FF99C* + ID_OUI_FROM_DATABASE=Goetting KG + +OUI:50FF995* + ID_OUI_FROM_DATABASE=Garrison Technology + +OUI:50FF997* + ID_OUI_FROM_DATABASE=Honeywell International + +OUI:50FF99B* + ID_OUI_FROM_DATABASE=Sichuan Dowlab Electronics Technology Co. Ltd + +OUI:E0B6F55* + ID_OUI_FROM_DATABASE=Shenzhen Civicom Technology Co.,Limited + +OUI:E0B6F50* + ID_OUI_FROM_DATABASE=BeSTAR Corporation + +OUI:E0B6F57* + ID_OUI_FROM_DATABASE=Shenzhen Xrinda Technology Ltd + +OUI:E0B6F5B* + ID_OUI_FROM_DATABASE=Moog Crossbow + +OUI:E0B6F5C* + ID_OUI_FROM_DATABASE=funktel GmbH + OUI:1C8776C* ID_OUI_FROM_DATABASE=Strone Technology @@ -4301,6 +4814,84 @@ OUI:78CA839* OUI:78CA83C* ID_OUI_FROM_DATABASE=Elanview Technology Co.,Ltd +OUI:38B8EB8* + ID_OUI_FROM_DATABASE=CeeNex Inc + +OUI:38B8EBD* + ID_OUI_FROM_DATABASE=Yellowbrick Data, Inc. + +OUI:38B8EB6* + ID_OUI_FROM_DATABASE=MATRIXSTREAM TECHNOLOGIES, INC. + +OUI:38B8EB2* + ID_OUI_FROM_DATABASE=barox Kommunikation GmbH + +OUI:38B8EBC* + ID_OUI_FROM_DATABASE=Ajax Systems Inc + +OUI:38B8EBE* + ID_OUI_FROM_DATABASE=Wyres SAS + +OUI:38FDFE1* + ID_OUI_FROM_DATABASE=WAYTONE (BEIIJNG) COMMUNICATIONS CO.,LTD + +OUI:38FDFEE* + ID_OUI_FROM_DATABASE=iSmart electronic technology co.,LTD + +OUI:38FDFE8* + ID_OUI_FROM_DATABASE=Indra Navia AS + +OUI:5CF2864* + ID_OUI_FROM_DATABASE=CHIPSEN Co.,Ltd. + +OUI:5CF2868* + ID_OUI_FROM_DATABASE=SHENZHEN HIVT TECHNOLOGY CO.,LTD + +OUI:7C477C9* + ID_OUI_FROM_DATABASE=DaLian Cheering Tech Co.,Ltd + +OUI:7C477C0* + ID_OUI_FROM_DATABASE=BungBungame Inc + +OUI:7C477C4* + ID_OUI_FROM_DATABASE=RLC Electronics Systems + +OUI:7C477CE* + ID_OUI_FROM_DATABASE=I-Convergence.com + +OUI:986D35D* + ID_OUI_FROM_DATABASE=Praesideo B.V. + +OUI:986D358* + ID_OUI_FROM_DATABASE=Beijing 3CAVI Tech Co.,Ltd + +OUI:986D350* + ID_OUI_FROM_DATABASE=Shenzhen MALATA Mobile Communication Co.,LTD + +OUI:986D354* + ID_OUI_FROM_DATABASE=blossom communications corp. + +OUI:50FF998* + ID_OUI_FROM_DATABASE=Dolphin Concepts Limited + +OUI:50FF99D* + ID_OUI_FROM_DATABASE=Shenzhen Haipengxin Electronic Co., Ltd. + +OUI:50FF993* + ID_OUI_FROM_DATABASE=Yongjing Shanghai Electronic Science and Technology + +OUI:50FF992* + ID_OUI_FROM_DATABASE=SHENZHEN KINGVT ELECTRONICS CO.,LTD + +OUI:E0B6F5A* + ID_OUI_FROM_DATABASE=Folksam AB + +OUI:E0B6F54* + ID_OUI_FROM_DATABASE=Agora + +OUI:E0B6F5E* + ID_OUI_FROM_DATABASE=Advatek Lighting Pty Ltd + OUI:1C87790* ID_OUI_FROM_DATABASE=Wurm GmbH & Co. KG Elektronische Systeme @@ -4811,6 +5402,66 @@ OUI:78CA831* OUI:78CA837* ID_OUI_FROM_DATABASE=Beijing CarePulse Electronic Technology +OUI:78CA83D* + ID_OUI_FROM_DATABASE=Hubei Boyuan Zhijia Network Media Co. Ltd. + +OUI:38B8EB3* + ID_OUI_FROM_DATABASE=Aina Wireless Inc + +OUI:38FDFE3* + ID_OUI_FROM_DATABASE=Siemens AG, PG IE R&D + +OUI:38FDFED* + ID_OUI_FROM_DATABASE=FUBA Automotive Electronics GmbH + +OUI:38FDFE7* + ID_OUI_FROM_DATABASE=Rademacher Geraete-Elektronik GmbH + +OUI:38FDFE0* + ID_OUI_FROM_DATABASE=Edge I&D Co., Ltd. + +OUI:5CF286B* + ID_OUI_FROM_DATABASE=Itron UK Limited + +OUI:7C477C2* + ID_OUI_FROM_DATABASE=POWERLAND LIMITED + +OUI:5CF286D* + ID_OUI_FROM_DATABASE=BrightSky, LLC + +OUI:7C477CB* + ID_OUI_FROM_DATABASE=Hangzhou Yiyitaidi Information Technology Co., Ltd. + +OUI:7C477C3* + ID_OUI_FROM_DATABASE=EyeLock LLC + +OUI:986D351* + ID_OUI_FROM_DATABASE=Shenzhen cositea electronics technology co.,LTD + +OUI:986D35C* + ID_OUI_FROM_DATABASE=my-PV GmbH + +OUI:986D35E* + ID_OUI_FROM_DATABASE=BAYCOM OPTO-ELECTRONICS TECHNOLGY CO., LTD. + +OUI:50FF994* + ID_OUI_FROM_DATABASE=IPC Global + +OUI:50FF996* + ID_OUI_FROM_DATABASE=LEGEND WINNER LIMITED + +OUI:50FF99A* + ID_OUI_FROM_DATABASE=metraTec GmbH + +OUI:50FF99E* + ID_OUI_FROM_DATABASE=Informa LLC + +OUI:E0B6F5D* + ID_OUI_FROM_DATABASE=ITEL MOBILE LIMITED + +OUI:E0B6F53* + ID_OUI_FROM_DATABASE=Huizhou GISUN Industrial CO. LTD + OUI:1C8776B* ID_OUI_FROM_DATABASE=Hekatron Vertriebs GmbH @@ -5105,9 +5756,6 @@ OUI:28FD804* OUI:2C265FB* ID_OUI_FROM_DATABASE=Rexgen Inc. -OUI:2C265FC* - ID_OUI_FROM_DATABASE=AATON DIGITAL - OUI:2C265F6* ID_OUI_FROM_DATABASE=Appostar Technology Co. Ltd @@ -5342,6 +5990,75 @@ OUI:78CA83B* OUI:78CA835* ID_OUI_FROM_DATABASE=Huatune Technology (Shanghai) Co., Ltd. +OUI:38B8EB0* + ID_OUI_FROM_DATABASE=Bumjin C&L Co., Ltd. + +OUI:38B8EB5* + ID_OUI_FROM_DATABASE=Dojo-Labs Ltd + +OUI:38B8EB1* + ID_OUI_FROM_DATABASE=1.A Connect GmbH + +OUI:38B8EBA* + ID_OUI_FROM_DATABASE=SECAD SA + +OUI:38B8EB7* + ID_OUI_FROM_DATABASE=Private + +OUI:38FDFE6* + ID_OUI_FROM_DATABASE=Inspero Inc + +OUI:38FDFE2* + ID_OUI_FROM_DATABASE=B.U.G.SST,Inc + +OUI:5CF2869* + ID_OUI_FROM_DATABASE=Shenzhen VST Automotive Electronics Co., LTD + +OUI:7C477C7* + ID_OUI_FROM_DATABASE=BlueSmart Technology Corporation + +OUI:7C477CA* + ID_OUI_FROM_DATABASE=Dspread Technology (Beijing) Inc. + +OUI:7C477CC* + ID_OUI_FROM_DATABASE=annapurnalabs + +OUI:986D356* + ID_OUI_FROM_DATABASE=Vitronic Dr.-Ing. Stein Bildverarbeitungssysteme GmbH + +OUI:7C477C8* + ID_OUI_FROM_DATABASE=Shenzhen Eunicum Electric Co.,Ltd. + +OUI:986D35B* + ID_OUI_FROM_DATABASE=INTECH + +OUI:986D352* + ID_OUI_FROM_DATABASE=SHENZHEN FISE TECHNOLOGY HOLDING CO.,LTD. + +OUI:50FF990* + ID_OUI_FROM_DATABASE=Simicon + +OUI:50FF991* + ID_OUI_FROM_DATABASE=Coyote Sytem + +OUI:50FF999* + ID_OUI_FROM_DATABASE=Sea Eagle Optoelectronic Information Technology(Tianjin)co,Ltd + +OUI:E0B6F58* + ID_OUI_FROM_DATABASE=Yuneec International(China)Co.,Ltd + +OUI:E0B6F52* + ID_OUI_FROM_DATABASE=Shanghai- British Information Technology Co., Ltd + +OUI:E0B6F56* + ID_OUI_FROM_DATABASE=POMCube Inc. + +OUI:2C265FC* + ID_OUI_FROM_DATABASE=AATON DIGITAL + +OUI:6891D05* + ID_OUI_FROM_DATABASE=NIPK Electron Co. + OUI:1C87740* ID_OUI_FROM_DATABASE=Philips Personal Health Solutions @@ -5801,6 +6518,57 @@ OUI:1C8774A* OUI:78CA830* ID_OUI_FROM_DATABASE=DAINCUBE +OUI:38B8EB4* + ID_OUI_FROM_DATABASE=UMLOGICS + +OUI:38B8EB9* + ID_OUI_FROM_DATABASE=NHS Sistemas de Energia + +OUI:38FDFEA* + ID_OUI_FROM_DATABASE=Management Service Corporation + +OUI:38FDFEB* + ID_OUI_FROM_DATABASE=Swedish Adrenaline AB + +OUI:38FDFE4* + ID_OUI_FROM_DATABASE=New Telecom Solutions LLC + +OUI:38FDFE9* + ID_OUI_FROM_DATABASE=OOO Group of Industrial Technologies + +OUI:5CF2860* + ID_OUI_FROM_DATABASE=Hangzhou Signwei Electronics Technology Co., Ltd + +OUI:5CF2863* + ID_OUI_FROM_DATABASE=beijing your wonderful control system technology co.,ltd + +OUI:5CF2865* + ID_OUI_FROM_DATABASE=EUROIMMUN Medizinische Labordiagnostika AG + +OUI:5CF2861* + ID_OUI_FROM_DATABASE=iSon Tech + +OUI:7C477C6* + ID_OUI_FROM_DATABASE=Zerosystem LTD.Co + +OUI:7C477CD* + ID_OUI_FROM_DATABASE=Speedifi Inc + +OUI:986D353* + ID_OUI_FROM_DATABASE=DH Mechatronic AG + +OUI:986D359* + ID_OUI_FROM_DATABASE=Private + +OUI:986D355* + ID_OUI_FROM_DATABASE=PDAHL + +OUI:E0B6F59* + ID_OUI_FROM_DATABASE=Motiveprime Consumer Electronics Pvt Ltd + +OUI:E0B6F51* + ID_OUI_FROM_DATABASE=START TODAY CO.,LTD. + OUI:E043DB* ID_OUI_FROM_DATABASE=Shenzhen ViewAt Technology Co.,Ltd. @@ -7121,9 +7889,6 @@ OUI:741F4A* OUI:88CBA5* ID_OUI_FROM_DATABASE=Suzhou Torchstar Intelligent Technology Co.,Ltd -OUI:A47B2C* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:184F32* ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. @@ -7184,9 +7949,6 @@ OUI:F85B9C* OUI:7CA237* ID_OUI_FROM_DATABASE=King Slide Technology CO., LTD. -OUI:B0E2E5* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:300EE3* ID_OUI_FROM_DATABASE=Aquantia Corporation @@ -7214,9 +7976,6 @@ OUI:D4522A* OUI:B0ECE1* ID_OUI_FROM_DATABASE=Private -OUI:AC9B0A* - ID_OUI_FROM_DATABASE=Sony Corporation - OUI:407FE0* ID_OUI_FROM_DATABASE=Glory Star Technics (ShenZhen) Limited @@ -7355,9 +8114,6 @@ OUI:3077CB* OUI:88C9D0* ID_OUI_FROM_DATABASE=LG Electronics -OUI:BC6B4D* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:3428F0* ID_OUI_FROM_DATABASE=ATN International Limited @@ -7550,9 +8306,6 @@ OUI:3C46D8* OUI:6C0273* ID_OUI_FROM_DATABASE=Shenzhen Jin Yun Video Equipment Co., Ltd. -OUI:600292* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:2CFAA2* ID_OUI_FROM_DATABASE=Alcatel-Lucent @@ -7616,9 +8369,6 @@ OUI:D8E56D* OUI:3CCD5A* ID_OUI_FROM_DATABASE=Technische Alternative GmbH -OUI:B0754D* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:604826* ID_OUI_FROM_DATABASE=Newbridge Technologies Int. Ltd. @@ -7667,9 +8417,6 @@ OUI:6C2C06* OUI:54EE75* ID_OUI_FROM_DATABASE=Wistron InfoComm(Kunshan)Co.,Ltd. -OUI:202564* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:60812B* ID_OUI_FROM_DATABASE=Custom Control Concepts @@ -7679,9 +8426,6 @@ OUI:F86601* OUI:FC4AE9* ID_OUI_FROM_DATABASE=Castlenet Technology Inc. -OUI:BC8D0E* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:34E42A* ID_OUI_FROM_DATABASE=Automatic Bar Controls Inc. @@ -7865,9 +8609,6 @@ OUI:30D6C9* OUI:107BEF* ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation -OUI:84262B* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:8CCDA2* ID_OUI_FROM_DATABASE=ACTP, Inc. @@ -7889,9 +8630,6 @@ OUI:98FF6A* OUI:AC6BAC* ID_OUI_FROM_DATABASE=Jenny Science AG -OUI:0C54A5* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:707C18* ID_OUI_FROM_DATABASE=ADATA Technology Co., Ltd @@ -7919,9 +8657,6 @@ OUI:2C3731* OUI:041A04* ID_OUI_FROM_DATABASE=WaveIP -OUI:94E98C* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:50206B* ID_OUI_FROM_DATABASE=Emerson Climate Technologies Transportation Solutions @@ -7997,9 +8732,6 @@ OUI:A0E453* OUI:404A18* ID_OUI_FROM_DATABASE=Addrek Smart Solutions -OUI:E48184* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:C4C0AE* ID_OUI_FROM_DATABASE=MIDORI ELECTRONIC CO., LTD. @@ -8222,9 +8954,6 @@ OUI:ACE42E* OUI:08EF3B* ID_OUI_FROM_DATABASE=MCS Logic Inc. -OUI:98B039* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:806C8B* ID_OUI_FROM_DATABASE=KAESER KOMPRESSOREN AG @@ -8243,9 +8972,6 @@ OUI:C47F51* OUI:E8D4E0* ID_OUI_FROM_DATABASE=Beijing BenyWave Technology Co., Ltd. -OUI:54BEF7* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:3889DC* ID_OUI_FROM_DATABASE=Opticon Sensors Europe B.V. @@ -10073,9 +10799,6 @@ OUI:4491DB* OUI:14D76E* ID_OUI_FROM_DATABASE=CONCH ELECTRONIC Co.,Ltd -OUI:1078D2* - ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM CO., LTD. - OUI:CC6B98* ID_OUI_FROM_DATABASE=Minetec Wireless Technologies @@ -10367,9 +11090,6 @@ OUI:5CE286* OUI:2CCD27* ID_OUI_FROM_DATABASE=Precor Inc -OUI:AC44F2* - ID_OUI_FROM_DATABASE=Revolabs Inc - OUI:6C5E7A* ID_OUI_FROM_DATABASE=Ubiquitous Internet Telecom Co., Ltd @@ -10823,9 +11543,6 @@ OUI:002471* OUI:002473* ID_OUI_FROM_DATABASE=3COM EUROPE LTD -OUI:002465* - ID_OUI_FROM_DATABASE=Elentec - OUI:002460* ID_OUI_FROM_DATABASE=Giaval Science Development Co. Ltd. @@ -11495,9 +12212,6 @@ OUI:001F2C* OUI:001F26* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:001F1F* - ID_OUI_FROM_DATABASE=Edimax Technology Co. Ltd. - OUI:001F1A* ID_OUI_FROM_DATABASE=Prominvest @@ -11528,9 +12242,6 @@ OUI:001E95* OUI:001E96* ID_OUI_FROM_DATABASE=Sepura Plc -OUI:001E90* - ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co - OUI:001E8B* ID_OUI_FROM_DATABASE=Infra Access Korea Co., Ltd. @@ -11633,9 +12344,6 @@ OUI:001F13* OUI:001F0F* ID_OUI_FROM_DATABASE=Select Engineered Systems -OUI:001F09* - ID_OUI_FROM_DATABASE=JASTEC CO., LTD. - OUI:001EFD* ID_OUI_FROM_DATABASE=Microbit 2.0 AB @@ -11819,9 +12527,6 @@ OUI:001E39* OUI:001E34* ID_OUI_FROM_DATABASE=CryptoMetrics -OUI:001E33* - ID_OUI_FROM_DATABASE=Inventec Corporation - OUI:001E2D* ID_OUI_FROM_DATABASE=STIM @@ -11891,9 +12596,6 @@ OUI:001CE3* OUI:001CDC* ID_OUI_FROM_DATABASE=Custom Computer Services, Inc. -OUI:001CD7* - ID_OUI_FROM_DATABASE=Harman/Becker Automotive Systems GmbH - OUI:001CD0* ID_OUI_FROM_DATABASE=Circleone Co.,Ltd. @@ -12191,9 +12893,6 @@ OUI:001A2E* OUI:001A33* ID_OUI_FROM_DATABASE=ASI Communications, Inc. -OUI:001A29* - ID_OUI_FROM_DATABASE=Johnson Outdoors Marine Electronics, Inc - OUI:001A1D* ID_OUI_FROM_DATABASE=PChome Online Inc. @@ -12626,12 +13325,6 @@ OUI:001717* OUI:00170B* ID_OUI_FROM_DATABASE=Contela, Inc. -OUI:001706* - ID_OUI_FROM_DATABASE=Techfaith Wireless Communication Technology Limited. - -OUI:0016FA* - ID_OUI_FROM_DATABASE=ECI Telecom Ltd. - OUI:0016FF* ID_OUI_FROM_DATABASE=Wamin Optocomm Mfg Corp @@ -12776,9 +13469,6 @@ OUI:0016EE* OUI:0016E7* ID_OUI_FROM_DATABASE=Dynamix Promotions Limited -OUI:0016EC* - ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co., Ltd. - OUI:0016DB* ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. @@ -13262,9 +13952,6 @@ OUI:001459* OUI:001454* ID_OUI_FROM_DATABASE=Symwave -OUI:00144F* - ID_OUI_FROM_DATABASE=Oracle Corporation - OUI:001443* ID_OUI_FROM_DATABASE=Consultronics Europe Ltd @@ -13406,9 +14093,6 @@ OUI:001199* OUI:00118F* ID_OUI_FROM_DATABASE=EUTECH INSTRUMENTS PTE. LTD. -OUI:001188* - ID_OUI_FROM_DATABASE=Enterasys - OUI:001183* ID_OUI_FROM_DATABASE=Datalogic ADC, Inc. @@ -13769,9 +14453,6 @@ OUI:000D8D* OUI:000D8E* ID_OUI_FROM_DATABASE=Koden Electronics Co., Ltd. -OUI:000D87* - ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. (ECS) - OUI:000D84* ID_OUI_FROM_DATABASE=Makus Inc. @@ -14303,9 +14984,6 @@ OUI:000AEB* OUI:000AE4* ID_OUI_FROM_DATABASE=Wistron Corp. -OUI:000AE6* - ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. (ECS) - OUI:000A0E* ID_OUI_FROM_DATABASE=Invivo Research Inc. @@ -16352,9 +17030,6 @@ OUI:0090B9* OUI:00901A* ID_OUI_FROM_DATABASE=UNISPHERE SOLUTIONS -OUI:0090AE* - ID_OUI_FROM_DATABASE=ITALTEL S.p.A. - OUI:009082* ID_OUI_FROM_DATABASE=FORCE INSTITUTE @@ -16472,9 +17147,6 @@ OUI:001074* OUI:001057* ID_OUI_FROM_DATABASE=Rebel.com, Inc. -OUI:0010E0* - ID_OUI_FROM_DATABASE=Oracle Corporation - OUI:0010BC* ID_OUI_FROM_DATABASE=Aastra Telecom @@ -16784,9 +17456,6 @@ OUI:00A052* OUI:00A0EA* ID_OUI_FROM_DATABASE=ETHERCOM CORP. -OUI:00A0B8* - ID_OUI_FROM_DATABASE=SYMBIOS LOGIC INC. - OUI:00A02E* ID_OUI_FROM_DATABASE=BRAND COMMUNICATIONS, LTD. @@ -18161,9 +18830,6 @@ OUI:001577* OUI:ACE010* ID_OUI_FROM_DATABASE=Liteon Technology Corporation -OUI:000BA2* - ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd - OUI:EC086B* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. @@ -18176,12 +18842,6 @@ OUI:00192C* OUI:2421AB* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB -OUI:001FA7* - ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. - -OUI:A8E3EE* - ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. - OUI:6C23B9* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB @@ -18200,12 +18860,6 @@ OUI:303926* OUI:00EB2D* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB -OUI:709E29* - ID_OUI_FROM_DATABASE=Sony Corporation - -OUI:FC0FE6* - ID_OUI_FROM_DATABASE=Sony Corporation - OUI:B00594* ID_OUI_FROM_DATABASE=Liteon Technology Corporation @@ -18236,9 +18890,6 @@ OUI:E86D52* OUI:0015D0* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. -OUI:001315* - ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. - OUI:0013A9* ID_OUI_FROM_DATABASE=Sony Corporation @@ -18359,27 +19010,6 @@ OUI:0010E7* OUI:5C9656* ID_OUI_FROM_DATABASE=AzureWave Technology Inc. -OUI:0881F4* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:A8D0E5* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:648788* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:28C0DA* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:80711F* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:00239C* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:001DB5* - ID_OUI_FROM_DATABASE=Juniper Networks - OUI:7C4CA5* ID_OUI_FROM_DATABASE=BSkyB Ltd @@ -18548,17 +19178,11 @@ OUI:001DBC* OUI:001F32* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. -OUI:D8FB5E* - ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP - OUI:544408* ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:0017B0* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:001BEE* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S +OUI:D8FB5E* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP OUI:1886AC* ID_OUI_FROM_DATABASE=Nokia Danmark A/S @@ -18566,11 +19190,23 @@ OUI:1886AC* OUI:0021FE* ID_OUI_FROM_DATABASE=Nokia Danmark A/S +OUI:001DFD* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001EA3* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + OUI:002266* ID_OUI_FROM_DATABASE=Nokia Danmark A/S -OUI:DCB3B4* - ID_OUI_FROM_DATABASE=Honeywell Environmental & Combustion Controls (Tianjin) Co., Ltd. +OUI:0017B0* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001BEE* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002548* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S OUI:C8D10B* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -18581,8 +19217,14 @@ OUI:C8979F* OUI:F4F5A5* ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:3CC243* - ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:DCB3B4* + ID_OUI_FROM_DATABASE=Honeywell Environmental & Combustion Controls (Tianjin) Co., Ltd. + +OUI:001D98* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:00119F* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S OUI:0015A0* ID_OUI_FROM_DATABASE=Nokia Danmark A/S @@ -18593,24 +19235,363 @@ OUI:001A16* OUI:0022FC* ID_OUI_FROM_DATABASE=Nokia Danmark A/S -OUI:002548* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S +OUI:3CC243* + ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:001DFD* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S +OUI:18A6F7* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. -OUI:001EA3* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:001D98* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:00119F* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S +OUI:246968* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. OUI:8CA2FD* ID_OUI_FROM_DATABASE=Starry, Inc. +OUI:14BB6E* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:AC61EA* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:38B54D* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:90A62F* + ID_OUI_FROM_DATABASE=NAVER + +OUI:9476B7* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:8C1ABF* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B47443* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:30CBF8* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:000BA2* + ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd + +OUI:F4ED5F* + ID_OUI_FROM_DATABASE=SHENZHEN KTC TECHNOLOGY GROUP + +OUI:2C4D79* + ID_OUI_FROM_DATABASE=GoerTek Inc. + +OUI:40D357* + ID_OUI_FROM_DATABASE=Ison Technology Co., Ltd. + +OUI:A4F1E8* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:F03404* + ID_OUI_FROM_DATABASE=TCT mobile ltd + +OUI:AC9B0A* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:FC0FE6* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:709E29* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:00351A* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:9CD48B* + ID_OUI_FROM_DATABASE=Innolux Technology Europe BV + +OUI:00A0B8* + ID_OUI_FROM_DATABASE=NetApp + +OUI:DCE838* + ID_OUI_FROM_DATABASE=CK Telecom (Shenzhen) Limited + +OUI:545AA6* + ID_OUI_FROM_DATABASE=Espressif Inc. + +OUI:BC8D0E* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:E48184* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:94E98C* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:84262B* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:98B039* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:A47B2C* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:BC6B4D* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:B0754D* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:00CCFC* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:2C9662* + ID_OUI_FROM_DATABASE=Invenit BV + +OUI:DC2DCB* + ID_OUI_FROM_DATABASE=Beijing Unis HengYue Technology Co., Ltd. + +OUI:3810D5* + ID_OUI_FROM_DATABASE=AVM Audiovisuelles Marketing und Computersysteme GmbH + +OUI:44AAF5* + ID_OUI_FROM_DATABASE=Pace plc + +OUI:1C5F2B* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:D8803C* + ID_OUI_FROM_DATABASE=Anhui Huami Information Technology Company Limited + +OUI:A8E3EE* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:001FA7* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:001315* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:703C03* + ID_OUI_FROM_DATABASE=RadiAnt Co.,Ltd + +OUI:F0D2F1* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + +OUI:583277* + ID_OUI_FROM_DATABASE=Reliance Communications LLC + +OUI:CCD3E2* + ID_OUI_FROM_DATABASE=Jiangsu Yinhe Electronics Co.,Ltd. + +OUI:182195* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:A88195* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:88ADD2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:008E73* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:B805AB* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:9C52F8* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:900325* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:DC094C* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:DCEE06* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:AC44F2* + ID_OUI_FROM_DATABASE=YAMAHA CORPORATION + +OUI:508965* + ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. + +OUI:808C97* + ID_OUI_FROM_DATABASE=Kaonmedia CO., LTD. + +OUI:30B49E* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:349971* + ID_OUI_FROM_DATABASE=Quanta Storage Inc. + +OUI:24615A* + ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. + +OUI:B0E2E5* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:AC0D1B* + ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) + +OUI:5CC7D7* + ID_OUI_FROM_DATABASE=AZROAD TECHNOLOGY COMPANY LIMITED + +OUI:A0043E* + ID_OUI_FROM_DATABASE=Parker Hannifin Manufacturing Germany GmbH & Co. KG + +OUI:001706* + ID_OUI_FROM_DATABASE=Techfaithwireless Communication Technology Limited. + +OUI:30F6B9* + ID_OUI_FROM_DATABASE=Ecocentric Energy + +OUI:1C3ADE* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:004268* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00BD82* + ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd + +OUI:603ECA* + ID_OUI_FROM_DATABASE=Cambridge Medical Robotics Ltd + +OUI:E4A1E6* + ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd + +OUI:54489C* + ID_OUI_FROM_DATABASE=CDOUBLES ELECTRONICS CO. LTD. + +OUI:54BEF7* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:0C54A5* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:202564* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:600292* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:84002D* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:8019FE* + ID_OUI_FROM_DATABASE=JianLing Technology CO., LTD + +OUI:58605F* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:001188* + ID_OUI_FROM_DATABASE=Enterasys + +OUI:1078D2* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:001E90* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:002465* + ID_OUI_FROM_DATABASE=Elentec + +OUI:001CD7* + ID_OUI_FROM_DATABASE=Harman/Becker Automotive Systems GmbH + +OUI:0016EC* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:000D87* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:000AE6* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:945089* + ID_OUI_FROM_DATABASE=SimonsVoss Technologies GmbH + +OUI:001F1F* + ID_OUI_FROM_DATABASE=Edimax Technology Co. Ltd. + +OUI:0016FA* + ID_OUI_FROM_DATABASE=ECI Telecom Ltd. + +OUI:003A7D* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:844076* + ID_OUI_FROM_DATABASE=Drivenets + +OUI:E80959* + ID_OUI_FROM_DATABASE=Guoguang Electric Co.,Ltd + +OUI:00144F* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:541379* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:0010E0* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:0090AE* + ID_OUI_FROM_DATABASE=ITALTEL S.p.A/RF-UP-I + +OUI:001E33* + ID_OUI_FROM_DATABASE=INVENTEC Corporation + +OUI:001A29* + ID_OUI_FROM_DATABASE=Johnson Outdoors Marine Electronics d/b/a Minnkota + +OUI:001F09* + ID_OUI_FROM_DATABASE=Jastec + +OUI:D0A4B1* + ID_OUI_FROM_DATABASE=Sonifex Ltd. + +OUI:001DB5* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:00239C* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:80711F* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:28F366* + ID_OUI_FROM_DATABASE=Shenzhen Bilian electronic CO.,LTD + +OUI:D44165* + ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + +OUI:8828B3* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:C4F081* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:801382* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:341290* + ID_OUI_FROM_DATABASE=Treeview Co.,Ltd. + +OUI:BCAD28* + ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd. + +OUI:3CB6B7* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + +OUI:28C0DA* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:648788* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:A8D0E5* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0881F4* + ID_OUI_FROM_DATABASE=Juniper Networks + OUI:0C6F9C* ID_OUI_FROM_DATABASE=Shaw Communications Inc. @@ -19733,9 +20714,6 @@ OUI:B88687* OUI:68F956* ID_OUI_FROM_DATABASE=Objetivos y Servicio de Valor Añadido -OUI:C07CD1* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:58B633* ID_OUI_FROM_DATABASE=Ruckus Wireless @@ -19841,9 +20819,6 @@ OUI:D468BA* OUI:A47B85* ID_OUI_FROM_DATABASE=ULTIMEDIA Co Ltd, -OUI:A8D828* - ID_OUI_FROM_DATABASE=Bayer HealthCare - OUI:CC37AB* ID_OUI_FROM_DATABASE=Edgecore Networks Corportation @@ -19868,9 +20843,6 @@ OUI:E89120* OUI:546172* ID_OUI_FROM_DATABASE=ZODIAC AEROSPACE SAS -OUI:AC620D* - ID_OUI_FROM_DATABASE=Jabil Circuit (Wuxi) Co. LTD - OUI:54CD10* ID_OUI_FROM_DATABASE=Panasonic Mobile Communications Co.,Ltd. @@ -20078,9 +21050,6 @@ OUI:EC74BA* OUI:683C7D* ID_OUI_FROM_DATABASE=Magic Intelligence Technology Limited -OUI:18A3E8* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:60128B* ID_OUI_FROM_DATABASE=CANON INC. @@ -20393,9 +21362,6 @@ OUI:B0D59D* OUI:C4913A* ID_OUI_FROM_DATABASE=Shenzhen Sanland Electronic Co., ltd. -OUI:60B617* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:A46032* ID_OUI_FROM_DATABASE=MRV Communications (Networks) LTD @@ -21197,9 +22163,6 @@ OUI:A01C05* OUI:F80DEA* ID_OUI_FROM_DATABASE=ZyCast Technology Inc. -OUI:7C0507* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:1800DB* ID_OUI_FROM_DATABASE=Fitbit Inc. @@ -21302,9 +22265,6 @@ OUI:D40FB2* OUI:74FE48* ID_OUI_FROM_DATABASE=ADVANTECH CO., LTD. -OUI:7054D2* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:D0B498* ID_OUI_FROM_DATABASE=Robert Bosch LLC Automotive Electronics @@ -21563,9 +22523,6 @@ OUI:803FD6* OUI:645FFF* ID_OUI_FROM_DATABASE=Nicolet Neuro -OUI:741E93* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:2829D9* ID_OUI_FROM_DATABASE=GlobalBeiMing technology (Beijing)Co. Ltd @@ -21758,9 +22715,6 @@ OUI:5C4A26* OUI:289EDF* ID_OUI_FROM_DATABASE=Danfoss Turbocor Compressors, Inc -OUI:E840F2* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:50053D* ID_OUI_FROM_DATABASE=CyWee Group Ltd @@ -21815,9 +22769,6 @@ OUI:045C06* OUI:504A5E* ID_OUI_FROM_DATABASE=Masimo Corporation -OUI:4CC94F* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:38BF33* ID_OUI_FROM_DATABASE=NEC CASIO Mobile Communications @@ -21890,9 +22841,6 @@ OUI:BC1401* OUI:68D925* ID_OUI_FROM_DATABASE=ProSys Development Services -OUI:2C2D48* - ID_OUI_FROM_DATABASE=bct electronic GesmbH - OUI:B41DEF* ID_OUI_FROM_DATABASE=Internet Laboratories, Inc. @@ -22136,9 +23084,6 @@ OUI:7C4B78* OUI:28D1AF* ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:3482DE* - ID_OUI_FROM_DATABASE=Kayo Technology, Inc. - OUI:68BC0C* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -22211,9 +23156,6 @@ OUI:0041B4* OUI:0007AB* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd -OUI:48F7F1* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:D453AF* ID_OUI_FROM_DATABASE=VIGO System S.A. @@ -22547,9 +23489,6 @@ OUI:408BF6* OUI:447E95* ID_OUI_FROM_DATABASE=Alpha and Omega, Inc -OUI:50C971* - ID_OUI_FROM_DATABASE=GN Netcom A/S - OUI:E8B748* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -23324,9 +24263,6 @@ OUI:9CCD82* OUI:C8AACC* ID_OUI_FROM_DATABASE=Private -OUI:008CFA* - ID_OUI_FROM_DATABASE=Inventec Corporation - OUI:003D41* ID_OUI_FROM_DATABASE=Hatteland Computer AS @@ -23627,9 +24563,6 @@ OUI:0025B7* OUI:0025B0* ID_OUI_FROM_DATABASE=Schmartz Inc -OUI:002552* - ID_OUI_FROM_DATABASE=VXI CORPORATION - OUI:002546* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -23915,9 +24848,6 @@ OUI:0023A5* OUI:0022B6* ID_OUI_FROM_DATABASE=Superflow Technologies Group -OUI:0022B1* - ID_OUI_FROM_DATABASE=Elbit Systems - OUI:0022A3* ID_OUI_FROM_DATABASE=California Eastern Laboratories @@ -24446,9 +25376,6 @@ OUI:001E9E* OUI:001E99* ID_OUI_FROM_DATABASE=Vantanol Industrial Corporation -OUI:001F45* - ID_OUI_FROM_DATABASE=Enterasys - OUI:001F36* ID_OUI_FROM_DATABASE=Bellwin Information Co. Ltd., @@ -24644,9 +25571,6 @@ OUI:001D88* OUI:001D7E* ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC -OUI:001D82* - ID_OUI_FROM_DATABASE=GN A/S (GN Netcom A/S) - OUI:001D7D* ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. @@ -25565,9 +26489,6 @@ OUI:001633* OUI:00162C* ID_OUI_FROM_DATABASE=Xanboo -OUI:001625* - ID_OUI_FROM_DATABASE=Impinj, Inc. - OUI:001627* ID_OUI_FROM_DATABASE=embedded-logic DESIGN AND MORE GmbH @@ -26048,9 +26969,6 @@ OUI:00131E* OUI:001323* ID_OUI_FROM_DATABASE=Cap Co., Ltd. -OUI:001317* - ID_OUI_FROM_DATABASE=GN Netcom as - OUI:00130B* ID_OUI_FROM_DATABASE=Mextal B.V. @@ -27014,9 +27932,6 @@ OUI:000CB5* OUI:000CBC* ID_OUI_FROM_DATABASE=Iscutum -OUI:000CC1* - ID_OUI_FROM_DATABASE=Cooper Industries Inc. - OUI:000CA3* ID_OUI_FROM_DATABASE=Rancho Technology, Inc. @@ -27470,9 +28385,6 @@ OUI:0008CA* OUI:0008BF* ID_OUI_FROM_DATABASE=Aptus Elektronik AB -OUI:0008B9* - ID_OUI_FROM_DATABASE=KAON MEDIA Co., Ltd. - OUI:0008B3* ID_OUI_FROM_DATABASE=Fastwel @@ -27812,9 +28724,6 @@ OUI:000659* OUI:000658* ID_OUI_FROM_DATABASE=Helmut Fischer GmbH Institut für Elektronik und Messtechnik -OUI:00065F* - ID_OUI_FROM_DATABASE=ECI Telecom - NGTS Ltd. - OUI:000646* ID_OUI_FROM_DATABASE=ShenZhen XunBao Network Technology Co Ltd @@ -29030,9 +29939,6 @@ OUI:0050F1* OUI:00501B* ID_OUI_FROM_DATABASE=ABL CANADA, INC. -OUI:005058* - ID_OUI_FROM_DATABASE=VegaStream Group Limted - OUI:005036* ID_OUI_FROM_DATABASE=NETCAM, LTD. @@ -29072,9 +29978,6 @@ OUI:009042* OUI:009051* ID_OUI_FROM_DATABASE=ULTIMATE TECHNOLOGY CORP. -OUI:0090F9* - ID_OUI_FROM_DATABASE=LEITCH - OUI:0090FF* ID_OUI_FROM_DATABASE=TELLUS TECHNOLOGY INC. @@ -29117,9 +30020,6 @@ OUI:009013* OUI:0090CC* ID_OUI_FROM_DATABASE=Planex Communications -OUI:0090FA* - ID_OUI_FROM_DATABASE=Emulex Corporation - OUI:009004* ID_OUI_FROM_DATABASE=3COM EUROPE LTD. @@ -29393,9 +30293,6 @@ OUI:00E0C6* OUI:00E06D* ID_OUI_FROM_DATABASE=COMPUWARE CORPORATION -OUI:00E0E6* - ID_OUI_FROM_DATABASE=INCAA DATACOM B.V. - OUI:00E074* ID_OUI_FROM_DATABASE=TIERNAN COMMUNICATIONS, INC. @@ -29726,9 +30623,6 @@ OUI:00A000* OUI:00A07B* ID_OUI_FROM_DATABASE=DAWN COMPUTER INCORPORATION -OUI:00A0DE* - ID_OUI_FROM_DATABASE=YAMAHA CORPORATION - OUI:00A05C* ID_OUI_FROM_DATABASE=INVENTORY CONVERSION, INC./ @@ -29783,9 +30677,6 @@ OUI:00C019* OUI:00A062* ID_OUI_FROM_DATABASE=AES PRODATA -OUI:00A0F4* - ID_OUI_FROM_DATABASE=GE - OUI:00A008* ID_OUI_FROM_DATABASE=NETCORP @@ -30353,9 +31244,6 @@ OUI:0080F6* OUI:00001F* ID_OUI_FROM_DATABASE=Telco Systems, Inc. -OUI:0000B4* - ID_OUI_FROM_DATABASE=EDIMAX COMPUTER COMPANY - OUI:000058* ID_OUI_FROM_DATABASE=RACORE COMPUTER PRODUCTS INC. @@ -30887,12 +31775,6 @@ OUI:948815* OUI:3010B3* ID_OUI_FROM_DATABASE=Liteon Technology Corporation -OUI:00005F* - ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd - -OUI:0008F6* - ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd - OUI:001802* ID_OUI_FROM_DATABASE=Alpha Networks Inc. @@ -31094,42 +31976,9 @@ OUI:00264D* OUI:74A528* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD -OUI:3C8AB0* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:4C9614* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:88E0F3* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:2C2172* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:7819F7* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:5C5EAB* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:009069* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:B0C69A* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:88A25E* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:001BC0* - ID_OUI_FROM_DATABASE=Juniper Networks - OUI:30A220* ID_OUI_FROM_DATABASE=ARG Telecom -OUI:F4B52F* - ID_OUI_FROM_DATABASE=Juniper Networks - OUI:783E53* ID_OUI_FROM_DATABASE=BSkyB Ltd @@ -31337,6 +32186,378 @@ OUI:0025D0* OUI:001FDE* ID_OUI_FROM_DATABASE=Nokia Danmark A/S +OUI:907282* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + +OUI:006CFD* + ID_OUI_FROM_DATABASE=Sichuan Changhong Electric Ltd. + +OUI:1C234F* + ID_OUI_FROM_DATABASE=EDMI Europe Ltd + +OUI:A444D1* + ID_OUI_FROM_DATABASE=Wingtech Group (HongKong)Limited + +OUI:1C9E46* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:005058* + ID_OUI_FROM_DATABASE=Sangoma Technologies + +OUI:3482DE* + ID_OUI_FROM_DATABASE=Kiio Inc + +OUI:0008F6* + ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd + +OUI:00005F* + ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd + +OUI:A0C589* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:74BFB7* + ID_OUI_FROM_DATABASE=Nusoft Corporation + +OUI:50DA00* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited + +OUI:9C2A83* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:E45D75* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:3CBEE1* + ID_OUI_FROM_DATABASE=NIKON CORPORATION + +OUI:047E4A* + ID_OUI_FROM_DATABASE=moobox CO., Ltd. + +OUI:104FA8* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:F01B6C* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + +OUI:E0C767* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:2C09CB* + ID_OUI_FROM_DATABASE=COBS AB + +OUI:60ACC8* + ID_OUI_FROM_DATABASE=KunTeng Inc. + +OUI:0404EA* + ID_OUI_FROM_DATABASE=Valens Semiconductor Ltd. + +OUI:800DD7* + ID_OUI_FROM_DATABASE=Latticework, Inc + +OUI:402E28* + ID_OUI_FROM_DATABASE=MiXTelematics + +OUI:18C501* + ID_OUI_FROM_DATABASE=SHENZHEN GONGJIN ELECTRONICS CO.,LT + +OUI:546D52* + ID_OUI_FROM_DATABASE=TOPVIEW OPTRONICS CORP. + +OUI:CCB3AB* + ID_OUI_FROM_DATABASE=shenzhen Biocare Bio-Medical Equipment Co.,Ltd. + +OUI:4CC94F* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:48F7F1* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:E4B318* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:00C88B* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:A85EE4* + ID_OUI_FROM_DATABASE=12Sided Technology, LLC + +OUI:000CC1* + ID_OUI_FROM_DATABASE=Eaton Corporation + +OUI:0090F9* + ID_OUI_FROM_DATABASE=Imagine Communications + +OUI:04C103* + ID_OUI_FROM_DATABASE=Clover Network, Inc. + +OUI:F877B8* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:1C553A* + ID_OUI_FROM_DATABASE=QianGua Corp. + +OUI:E4A7A0* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:E4FAED* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:789682* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:F02745* + ID_OUI_FROM_DATABASE=F-Secure Corporation + +OUI:54D0B4* + ID_OUI_FROM_DATABASE=Xiamen Four-Faith Communication Technology Co.,Ltd + +OUI:D017C2* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:10DA43* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:001625* + ID_OUI_FROM_DATABASE=Impinj, Inc. + +OUI:1CEA1B* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:DC1AC5* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + +OUI:60EE5C* + ID_OUI_FROM_DATABASE=SHENZHEN FAST TECHNOLOGIES CO.,LTD + +OUI:BC60A7* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:58D67A* + ID_OUI_FROM_DATABASE=TCPlink + +OUI:00A0DE* + ID_OUI_FROM_DATABASE=YAMAHA CORPORATION + +OUI:081F71* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:2C2D48* + ID_OUI_FROM_DATABASE=bct electronic GesmbH + +OUI:E4A471* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:60B617* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:18A3E8* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:741E93* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:F0C77F* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:00A0F4* + ID_OUI_FROM_DATABASE=GE + +OUI:00CAE5* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:4883C7* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + +OUI:7050AF* + ID_OUI_FROM_DATABASE=BSkyB Ltd + +OUI:F4EF9E* + ID_OUI_FROM_DATABASE=SGSG SCIENCE & TECHNOLOGY CO. LTD + +OUI:DC9C9F* + ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd + +OUI:0CBF3F* + ID_OUI_FROM_DATABASE=Shenzhen Lencotion Technology Co.,Ltd + +OUI:84FEDC* + ID_OUI_FROM_DATABASE=Borqs Beijing Ltd. + +OUI:F03E90* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:D8D723* + ID_OUI_FROM_DATABASE=IDS, Inc + +OUI:703A0E* + ID_OUI_FROM_DATABASE=Aruba Networks + +OUI:7054D2* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:7C0507* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:C07CD1* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:94DBDA* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:384C4F* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:E4A8B6* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:244C07* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:E840F2* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:F0D1B8* + ID_OUI_FROM_DATABASE=LEDVANCE + +OUI:60B387* + ID_OUI_FROM_DATABASE=Synergics Technologies GmbH + +OUI:7085C2* + ID_OUI_FROM_DATABASE=ASRock Incorporation + +OUI:C825E1* + ID_OUI_FROM_DATABASE=Lemobile Information Technology (Beijing) Co., Ltd + +OUI:0022B1* + ID_OUI_FROM_DATABASE=Elbit Systems Ltd. + +OUI:0000B4* + ID_OUI_FROM_DATABASE=Edimax Technology Co. Ltd. + +OUI:00065F* + ID_OUI_FROM_DATABASE=ECI Telecom Ltd. + +OUI:001F45* + ID_OUI_FROM_DATABASE=Enterasys + +OUI:0090FA* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:50C971* + ID_OUI_FROM_DATABASE=GN Netcom A/S + +OUI:001D82* + ID_OUI_FROM_DATABASE=GN Netcom A/S + +OUI:001317* + ID_OUI_FROM_DATABASE=GN Netcom A/S + +OUI:749781* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:B4B15A* + ID_OUI_FROM_DATABASE=Siemens AG Energy Management Division + +OUI:A86BAD* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:D80F99* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:A8D828* + ID_OUI_FROM_DATABASE=Ascensia Diabetes Care + +OUI:FCBC9C* + ID_OUI_FROM_DATABASE=Vimar Spa + +OUI:149ECF* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:AC620D* + ID_OUI_FROM_DATABASE=Jabil Circuit(Wuxi) Co.,Ltd + +OUI:008CFA* + ID_OUI_FROM_DATABASE=INVENTEC Corporation + +OUI:0008B9* + ID_OUI_FROM_DATABASE=Kaonmedia CO., LTD. + +OUI:C83F26* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:00E0E6* + ID_OUI_FROM_DATABASE=INCAA Computers + +OUI:5C5EAB* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:7819F7* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:2C2172* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:88E0F3* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:4C9614* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:3C8AB0* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:B0C69A* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:009069* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:204E71* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:F4B52F* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:88A25E* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:001BC0* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:F49EEF* + ID_OUI_FROM_DATABASE=Taicang T&W Electronics + +OUI:F4911E* + ID_OUI_FROM_DATABASE=ZHUHAI EWPE INFORMATION TECHNOLOGY INC + +OUI:94FE22* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:F823B2* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:DCD916* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:002552* + ID_OUI_FROM_DATABASE=VXi Corporation + +OUI:341FE4* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:006CBC* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:DC3752* + ID_OUI_FROM_DATABASE=GE + +OUI:F08261* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + +OUI:D084B0* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + OUI:5846E1* ID_OUI_FROM_DATABASE=Baxter International Inc @@ -31361,6 +32582,102 @@ OUI:B4EED4* OUI:D08CB5* ID_OUI_FROM_DATABASE=Texas Instruments +OUI:0030C5* + ID_OUI_FROM_DATABASE=CADENCE DESIGN SYSTEMS, INC. + +OUI:00FEC8* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:BC5436* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:0CC731* + ID_OUI_FROM_DATABASE=Currant, Inc. + +OUI:00142F* + ID_OUI_FROM_DATABASE=Savvius + +OUI:70CA4D* + ID_OUI_FROM_DATABASE=Shenzhen lnovance Technology Co.,Ltd. + +OUI:DCC0EB* + ID_OUI_FROM_DATABASE=ASSA ABLOY CÔTE PICARDE + +OUI:047863* + ID_OUI_FROM_DATABASE=Shanghai MXCHIP Information Technology Co., Ltd. + +OUI:24BA13* + ID_OUI_FROM_DATABASE=RISO KAGAKU CORPORATION + +OUI:24DA11* + ID_OUI_FROM_DATABASE=NO NDA Inc + +OUI:BCD1D3* + ID_OUI_FROM_DATABASE=Shenzhen TINNO Mobile Technology Corp. + +OUI:BC4434* + ID_OUI_FROM_DATABASE=Shenzhen TINNO Mobile Technology Corp. + +OUI:0041D2* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:4CFB45* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:A4BA76* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:3871DE* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:2CDDA3* + ID_OUI_FROM_DATABASE=Point Grey Research Inc. + +OUI:24FD5B* + ID_OUI_FROM_DATABASE=SmartThings, Inc. + +OUI:2876CD* + ID_OUI_FROM_DATABASE=Funshion Online Technologies Co.,Ltd + +OUI:F4F5D8* + ID_OUI_FROM_DATABASE=Google, Inc. + +OUI:F4F5E8* + ID_OUI_FROM_DATABASE=Google, Inc. + +OUI:F88FCA* + ID_OUI_FROM_DATABASE=Google, Inc. + +OUI:14D64D* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:C8BE19* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:BCF685* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:CCB255* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:84C9B2* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:EC2280* + ID_OUI_FROM_DATABASE=D-Link International + +OUI:78E3B5* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:984BE1* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:68B599* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:0C47C9* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + OUI:001831* ID_OUI_FROM_DATABASE=Texas Instruments @@ -31382,105 +32699,6 @@ OUI:505663* OUI:B0B448* ID_OUI_FROM_DATABASE=Texas Instruments -OUI:F08261* - ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS - -OUI:D084B0* - ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS - -OUI:00FEC8* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:0030C5* - ID_OUI_FROM_DATABASE=CADENCE DESIGN SYSTEMS, INC. - -OUI:EC2280* - ID_OUI_FROM_DATABASE=D-Link International - -OUI:047863* - ID_OUI_FROM_DATABASE=Shanghai MXCHIP Information Technology Co., Ltd. - -OUI:24BA13* - ID_OUI_FROM_DATABASE=RISO KAGAKU CORPORATION - -OUI:24DA11* - ID_OUI_FROM_DATABASE=NO NDA Inc - -OUI:70CA4D* - ID_OUI_FROM_DATABASE=Shenzhen lnovance Technology Co.,Ltd. - -OUI:DCC0EB* - ID_OUI_FROM_DATABASE=ASSA ABLOY CÔTE PICARDE - -OUI:001735* - ID_OUI_FROM_DATABASE=Intel Wireless Network Group - -OUI:9CDFB1* - ID_OUI_FROM_DATABASE=Shenzhen Crave Communication Co., LTD - -OUI:5CF938* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:3871DE* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:BC5436* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:0CC731* - ID_OUI_FROM_DATABASE=Currant, Inc. - -OUI:00142F* - ID_OUI_FROM_DATABASE=Savvius - -OUI:2CDDA3* - ID_OUI_FROM_DATABASE=Point Grey Research Inc. - -OUI:24FD5B* - ID_OUI_FROM_DATABASE=SmartThings, Inc. - -OUI:2876CD* - ID_OUI_FROM_DATABASE=Funshion Online Technologies Co.,Ltd - -OUI:F4F5D8* - ID_OUI_FROM_DATABASE=Google, Inc. - -OUI:F4F5E8* - ID_OUI_FROM_DATABASE=Google, Inc. - -OUI:F88FCA* - ID_OUI_FROM_DATABASE=Google, Inc. - -OUI:BCD1D3* - ID_OUI_FROM_DATABASE=Shenzhen TINNO Mobile Technology Corp. - -OUI:BC4434* - ID_OUI_FROM_DATABASE=Shenzhen TINNO Mobile Technology Corp. - -OUI:0041D2* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:4CFB45* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD - -OUI:A4BA76* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD - -OUI:003676* - ID_OUI_FROM_DATABASE=Pace plc - -OUI:78E3B5* - ID_OUI_FROM_DATABASE=Hewlett Packard - -OUI:984BE1* - ID_OUI_FROM_DATABASE=Hewlett Packard - -OUI:68B599* - ID_OUI_FROM_DATABASE=Hewlett Packard - -OUI:0C47C9* - ID_OUI_FROM_DATABASE=Amazon Technologies Inc. - OUI:0017E6* ID_OUI_FROM_DATABASE=Texas Instruments @@ -31493,35 +32711,8 @@ OUI:9059AF* OUI:E0C79D* ID_OUI_FROM_DATABASE=Texas Instruments -OUI:14D64D* - ID_OUI_FROM_DATABASE=D-Link International - -OUI:C8BE19* - ID_OUI_FROM_DATABASE=D-Link International - -OUI:BCF685* - ID_OUI_FROM_DATABASE=D-Link International - -OUI:CCB255* - ID_OUI_FROM_DATABASE=D-Link International - -OUI:84C9B2* - ID_OUI_FROM_DATABASE=D-Link International - -OUI:DCD321* - ID_OUI_FROM_DATABASE=HUMAX Co., Ltd. - -OUI:CC4EEC* - ID_OUI_FROM_DATABASE=HUMAX Co., Ltd. - -OUI:88C255* - ID_OUI_FROM_DATABASE=Texas Instruments - -OUI:DC330D* - ID_OUI_FROM_DATABASE=Qingdao Haier Telecom Co.,Ltd - -OUI:0080E1* - ID_OUI_FROM_DATABASE=STMicroelectronics SRL +OUI:003676* + ID_OUI_FROM_DATABASE=Pace plc OUI:58DC6D* ID_OUI_FROM_DATABASE=Exceptional Innovation, Inc. @@ -31565,18 +32756,6 @@ OUI:08EA44* OUI:78F882* ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) -OUI:8851FB* - ID_OUI_FROM_DATABASE=Hewlett Packard - -OUI:AC162D* - ID_OUI_FROM_DATABASE=Hewlett Packard - -OUI:A0B3CC* - ID_OUI_FROM_DATABASE=Hewlett Packard - -OUI:E4115B* - ID_OUI_FROM_DATABASE=Hewlett Packard - OUI:C8CBB8* ID_OUI_FROM_DATABASE=Hewlett Packard @@ -31598,8 +32777,29 @@ OUI:D48564* OUI:3C4A92* ID_OUI_FROM_DATABASE=Hewlett Packard -OUI:780AC7* - ID_OUI_FROM_DATABASE=Baofeng TV Co., Ltd. +OUI:0080E1* + ID_OUI_FROM_DATABASE=STMicroelectronics SRL + +OUI:2C6E85* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:00D0B7* + ID_OUI_FROM_DATABASE=Intel Corporation + +OUI:0015D1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001DD3* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:001735* + ID_OUI_FROM_DATABASE=Intel Wireless Network Group + +OUI:9CDFB1* + ID_OUI_FROM_DATABASE=Shenzhen Crave Communication Co., LTD + +OUI:5CF938* + ID_OUI_FROM_DATABASE=Apple, Inc. OUI:001D73* ID_OUI_FROM_DATABASE=BUFFALO.INC @@ -31625,21 +32825,6 @@ OUI:001B78* OUI:001E0B* ID_OUI_FROM_DATABASE=Hewlett Packard -OUI:2C6E85* - ID_OUI_FROM_DATABASE=Intel Corporate - -OUI:00D0B7* - ID_OUI_FROM_DATABASE=Intel Corporation - -OUI:0015D1* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - -OUI:C005C2* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - -OUI:6455B1* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - OUI:0002B3* ID_OUI_FROM_DATABASE=Intel Corporation @@ -31658,6 +32843,9 @@ OUI:9049FA* OUI:C8348E* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:780AC7* + ID_OUI_FROM_DATABASE=Baofeng TV Co., Ltd. + OUI:00508B* ID_OUI_FROM_DATABASE=Hewlett Packard @@ -31676,8 +32864,17 @@ OUI:A0481C* OUI:A01D48* ID_OUI_FROM_DATABASE=Hewlett Packard -OUI:001DD3* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:8851FB* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:AC162D* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:A0B3CC* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:E4115B* + ID_OUI_FROM_DATABASE=Hewlett Packard OUI:E8892C* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -31694,42 +32891,30 @@ OUI:8C09F4* OUI:3CDFA9* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:C005C2* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:6455B1* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:DCD321* + ID_OUI_FROM_DATABASE=HUMAX Co., Ltd. + +OUI:CC4EEC* + ID_OUI_FROM_DATABASE=HUMAX Co., Ltd. + +OUI:88C255* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:DC330D* + ID_OUI_FROM_DATABASE=Qingdao Haier Telecom Co.,Ltd + OUI:94B2CC* ID_OUI_FROM_DATABASE=PIONEER CORPORATION OUI:887F03* ID_OUI_FROM_DATABASE=Comper Technology Investment Limited -OUI:E06066* - ID_OUI_FROM_DATABASE=Sercomm Corporation - -OUI:0019E0* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:0023CD* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:002719* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:40169F* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:940C6D* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:74EA3A* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:90F652* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:10FEED* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:C46E1F* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - OUI:50FA84* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. @@ -31757,26 +32942,11 @@ OUI:1C994C* OUI:F02765* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. -OUI:507224* - ID_OUI_FROM_DATABASE=Texas Instruments +OUI:88308A* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. -OUI:D4970B* - ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd - -OUI:F48B32* - ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd - -OUI:20A783* - ID_OUI_FROM_DATABASE=miControl GmbH - -OUI:005053* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00500F* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:048A15* - ID_OUI_FROM_DATABASE=Avaya Inc +OUI:44A7CF* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. OUI:44322A* ID_OUI_FROM_DATABASE=Avaya Inc @@ -31808,11 +32978,77 @@ OUI:200BC7* OUI:104780* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD -OUI:88308A* - ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. +OUI:30D17E* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD -OUI:44A7CF* - ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. +OUI:9C28EF* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:E06066* + ID_OUI_FROM_DATABASE=Sercomm Corporation + +OUI:0019E0* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:0023CD* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:002719* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:40169F* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:940C6D* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:74EA3A* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:90F652* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:10FEED* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:C46E1F* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:68A0F6* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:5CF96A* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:B43052* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:88CEFA* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:582AF7* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:F48E92* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:40CBA8* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:087A4C* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:D46E5C* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:2469A5* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:C8D15E* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:F83DFF* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:0013E0* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. @@ -31874,41 +33110,29 @@ OUI:88E3AB* OUI:00664B* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD -OUI:68A0F6* +OUI:7C6097* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD -OUI:5CF96A* +OUI:60DE44* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD -OUI:B43052* +OUI:3400A3* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD -OUI:88CEFA* +OUI:643E8C* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD -OUI:582AF7* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:0012D1* + ID_OUI_FROM_DATABASE=Texas Instruments -OUI:F48E92* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:70FF76* + ID_OUI_FROM_DATABASE=Texas Instruments -OUI:40CBA8* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:B4994C* + ID_OUI_FROM_DATABASE=Texas Instruments -OUI:087A4C* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD - -OUI:D46E5C* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD - -OUI:2469A5* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD - -OUI:C8D15E* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD - -OUI:F83DFF* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:507224* + ID_OUI_FROM_DATABASE=Texas Instruments OUI:308730* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -31934,32 +33158,215 @@ OUI:A4251B* OUI:6CA849* ID_OUI_FROM_DATABASE=Avaya Inc -OUI:30D17E* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:048A15* + ID_OUI_FROM_DATABASE=Avaya Inc -OUI:9C28EF* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:D4970B* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd -OUI:7C6097* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:F48B32* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd -OUI:60DE44* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:20A783* + ID_OUI_FROM_DATABASE=miControl GmbH -OUI:3400A3* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:005053* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:643E8C* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:00500F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:0012D1* - ID_OUI_FROM_DATABASE=Texas Instruments +OUI:0050A2* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:70FF76* - ID_OUI_FROM_DATABASE=Texas Instruments +OUI:0498F3* + ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. -OUI:B4994C* - ID_OUI_FROM_DATABASE=Texas Instruments +OUI:38C096* + ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. + +OUI:E0750A* + ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. + +OUI:B05947* + ID_OUI_FROM_DATABASE=Shenzhen Qihu Intelligent Technology Company Limited + +OUI:00E04F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:001011* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:0010F6* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:80E01D* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:80E86F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:E4AA5D* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:203A07* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:34A84E* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:E4D3F1* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:1CE6C7* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:E02F6D* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:8478AC* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:4403A7* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:6886A7* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:B4E9B0* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:000832* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:B0FAEB* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:500604* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:70105C* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:C067AF* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:64E950* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:B0AA77* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:78BAF9* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:0016B6* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:0018F8* + ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC + +OUI:00252E* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:A4A24A* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:602AD0* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:001BFB* + ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. + +OUI:0016FE* + ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. + +OUI:3C08F6* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:D072DC* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:28C7CE* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:6CFA89* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:58F39C* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:346288* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:881DFC* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:000389* + ID_OUI_FROM_DATABASE=PLANTRONICS, INC. + +OUI:0CE0E4* + ID_OUI_FROM_DATABASE=PLANTRONICS, INC. + +OUI:7CFADF* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:101C0C* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:001124* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:001D4F* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:001E52* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:001F5B* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:001FF3* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:0021E9* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:00236C* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:002500* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:60FB42* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:F81EDF* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:90840D* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:D8A25E* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:C8BCC8* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:28E7CF* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:D89E3F* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:040CCE* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:A4D1D2* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:406C8F* + ID_OUI_FROM_DATABASE=Apple, Inc. OUI:00C610* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -31967,6 +33374,45 @@ OUI:00C610* OUI:70DEE2* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:0050F0* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00905F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00902B* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00100B* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00100D* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:001014* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00E08F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:189C5D* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:000EA6* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:0013D4* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:002618* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:00248C* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:14DAE9* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + OUI:182032* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -32012,238 +33458,16 @@ OUI:189EFC* OUI:6C3E6D* ID_OUI_FROM_DATABASE=Apple, Inc. -OUI:0016FE* - ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. - -OUI:0498F3* - ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. - -OUI:38C096* - ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. - -OUI:E0750A* - ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. - -OUI:B05947* - ID_OUI_FROM_DATABASE=Shenzhen Qihu Intelligent Technology Company Limited - -OUI:00E04F* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:001011* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:0010F6* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:80E01D* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:80E86F* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:E4AA5D* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:000389* - ID_OUI_FROM_DATABASE=PLANTRONICS, INC. - -OUI:0CE0E4* - ID_OUI_FROM_DATABASE=PLANTRONICS, INC. - -OUI:B0AA77* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:78BAF9* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:0016B6* - ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC - -OUI:0018F8* - ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC - -OUI:00252E* - ID_OUI_FROM_DATABASE=Cisco SPVTG - -OUI:A4A24A* - ID_OUI_FROM_DATABASE=Cisco SPVTG - -OUI:602AD0* - ID_OUI_FROM_DATABASE=Cisco SPVTG - -OUI:001BFB* - ID_OUI_FROM_DATABASE=ALPS ELECTRIC CO.,LTD. - -OUI:00E08F* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:203A07* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:34A84E* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:E4D3F1* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:1CE6C7* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:E02F6D* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:8478AC* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:4403A7* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:6886A7* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:B4E9B0* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:000832* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:B0FAEB* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:500604* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:70105C* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:7CFADF* +OUI:8C2DAA* ID_OUI_FROM_DATABASE=Apple, Inc. -OUI:101C0C* +OUI:444C0C* ID_OUI_FROM_DATABASE=Apple, Inc. -OUI:001124* +OUI:84FCFE* ID_OUI_FROM_DATABASE=Apple, Inc. -OUI:001D4F* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:001E52* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:001F5B* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:001FF3* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:0021E9* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:00236C* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:002500* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:60FB42* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:14DAE9* - ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. - -OUI:3C08F6* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:D072DC* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:28C7CE* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:6CFA89* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:58F39C* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:346288* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:881DFC* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:F81EDF* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:90840D* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:D8A25E* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:C8BCC8* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:28E7CF* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:D89E3F* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:040CCE* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:A4D1D2* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:406C8F* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:C067AF* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:64E950* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:189C5D* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:000EA6* - ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. - -OUI:0013D4* - ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. - -OUI:002618* - ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. - -OUI:00248C* - ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. - -OUI:0050A2* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:0050F0* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00905F* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00902B* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00100B* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00100D* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:001014* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:649ABE* +OUI:E48B7F* ID_OUI_FROM_DATABASE=Apple, Inc. OUI:94E96A* @@ -32270,6 +33494,36 @@ OUI:CC29F5* OUI:802994* ID_OUI_FROM_DATABASE=Technicolor CH USA +OUI:D4B8FF* + ID_OUI_FROM_DATABASE=Home Control Singapore Pte Ltd + +OUI:C8E0EB* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:A88808* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:907240* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:0C4DE9* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:D89695* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:0C3021* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:F0F61C* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:B03495* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:848E0C* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:6C709F* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -32312,52 +33566,7 @@ OUI:20A2E4* OUI:5CF5DA* ID_OUI_FROM_DATABASE=Apple, Inc. -OUI:D4B8FF* - ID_OUI_FROM_DATABASE=Home Control Singapore Pte Ltd - -OUI:28E14C* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:54E43A* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:C8E0EB* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:A88808* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:907240* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:0C4DE9* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:D89695* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:0C3021* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:F0F61C* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:B03495* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:848E0C* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:8C2DAA* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:444C0C* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:84FCFE* - ID_OUI_FROM_DATABASE=Apple, Inc. - -OUI:E48B7F* +OUI:649ABE* ID_OUI_FROM_DATABASE=Apple, Inc. OUI:5C969D* @@ -32372,38 +33581,11 @@ OUI:949426* OUI:E0F5C6* ID_OUI_FROM_DATABASE=Apple, Inc. -OUI:AC6462* - ID_OUI_FROM_DATABASE=zte corporation +OUI:28E14C* + ID_OUI_FROM_DATABASE=Apple, Inc. -OUI:C08488* - ID_OUI_FROM_DATABASE=Finis Inc - -OUI:68E8EB* - ID_OUI_FROM_DATABASE=Linktel Technologies Co.,Ltd - -OUI:20C3A4* - ID_OUI_FROM_DATABASE=RetailNext - -OUI:780541* - ID_OUI_FROM_DATABASE=Queclink Wireless Solutions Co., Ltd - -OUI:C02DEE* - ID_OUI_FROM_DATABASE=Cuff - -OUI:54A3FA* - ID_OUI_FROM_DATABASE=BQT Solutions (Australia)Pty Ltd - -OUI:30F772* - ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. - -OUI:9023EC* - ID_OUI_FROM_DATABASE=Availink, Inc. - -OUI:7467F7* - ID_OUI_FROM_DATABASE=Zebra Technologoes - -OUI:3891D5* - ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited +OUI:54E43A* + ID_OUI_FROM_DATABASE=Apple, Inc. OUI:90DFFB* ID_OUI_FROM_DATABASE=HOMERIDER SYSTEMS @@ -32414,8 +33596,11 @@ OUI:3C831E* OUI:381C23* ID_OUI_FROM_DATABASE=Hilan Technology CO.,LTD -OUI:E03676* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:AC6462* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:C08488* + ID_OUI_FROM_DATABASE=Finis Inc OUI:8C99E6* ID_OUI_FROM_DATABASE=TCT Mobile Limited @@ -32429,29 +33614,17 @@ OUI:243184* OUI:24DA9B* ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company -OUI:3052CB* - ID_OUI_FROM_DATABASE=Liteon Technology Corporation +OUI:7467F7* + ID_OUI_FROM_DATABASE=Zebra Technologoes -OUI:DCFE07* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION +OUI:3891D5* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited -OUI:B8B2EB* - ID_OUI_FROM_DATABASE=Googol Technology (HK) Limited +OUI:68E8EB* + ID_OUI_FROM_DATABASE=Linktel Technologies Co.,Ltd -OUI:C40049* - ID_OUI_FROM_DATABASE=Kamama - -OUI:50A9DE* - ID_OUI_FROM_DATABASE=Smartcom - Bulgaria AD - -OUI:54AB3A* - ID_OUI_FROM_DATABASE=QUANTA COMPUTER INC. - -OUI:8809AF* - ID_OUI_FROM_DATABASE=Masimo Corp. - -OUI:E8DED6* - ID_OUI_FROM_DATABASE=Intrising Networks, Inc. +OUI:20C3A4* + ID_OUI_FROM_DATABASE=RetailNext OUI:B844D9* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -32462,6 +33635,27 @@ OUI:DC2B2A* OUI:8C10D4* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS +OUI:B8B2EB* + ID_OUI_FROM_DATABASE=Googol Technology (HK) Limited + +OUI:C40049* + ID_OUI_FROM_DATABASE=Kamama + +OUI:50A9DE* + ID_OUI_FROM_DATABASE=Smartcom - Bulgaria AD + +OUI:C02DEE* + ID_OUI_FROM_DATABASE=Cuff + +OUI:54A3FA* + ID_OUI_FROM_DATABASE=BQT Solutions (Australia)Pty Ltd + +OUI:30F772* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:9023EC* + ID_OUI_FROM_DATABASE=Availink, Inc. + OUI:203D66* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -32471,11 +33665,26 @@ OUI:B83A9D* OUI:089B4B* ID_OUI_FROM_DATABASE=iKuai Networks +OUI:780541* + ID_OUI_FROM_DATABASE=Queclink Wireless Solutions Co., Ltd + OUI:3C7873* ID_OUI_FROM_DATABASE=Airsonics -OUI:BC5FF6* - ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. +OUI:3052CB* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:54AB3A* + ID_OUI_FROM_DATABASE=QUANTA COMPUTER INC. + +OUI:8809AF* + ID_OUI_FROM_DATABASE=Masimo Corp. + +OUI:E8DED6* + ID_OUI_FROM_DATABASE=Intrising Networks, Inc. + +OUI:E03676* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:C8F9C8* ID_OUI_FROM_DATABASE=NewSharp Technology(SuZhou)Co,Ltd @@ -32489,6 +33698,21 @@ OUI:A8741D* OUI:F4C613* ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd +OUI:D404CD* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:EC0133* + ID_OUI_FROM_DATABASE=TRINUS SYSTEMS INC. + +OUI:90D8F3* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:D84710* + ID_OUI_FROM_DATABASE=Sichuan Changhong Electric Ltd. + +OUI:444CA8* + ID_OUI_FROM_DATABASE=Arista Networks + OUI:A4C138* ID_OUI_FROM_DATABASE=Telink Semiconductor (Taipei) Co. Ltd. @@ -32501,11 +33725,8 @@ OUI:48E244* OUI:D8EFCD* ID_OUI_FROM_DATABASE=Nokia -OUI:D404CD* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - -OUI:EC0133* - ID_OUI_FROM_DATABASE=TRINUS SYSTEMS INC. +OUI:BC5FF6* + ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. OUI:1C56FE* ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company @@ -32534,39 +33755,9 @@ OUI:94F278* OUI:E8BDD1* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD -OUI:3481F4* - ID_OUI_FROM_DATABASE=SST Taiwan Ltd. - -OUI:F4B8A7* - ID_OUI_FROM_DATABASE=zte corporation - -OUI:58F102* - ID_OUI_FROM_DATABASE=BLU Products Inc. - -OUI:B869C2* - ID_OUI_FROM_DATABASE=Sunitec Enterprise Co., Ltd. - -OUI:2CC548* - ID_OUI_FROM_DATABASE=IAdea Corporation - -OUI:84DBFC* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:307CB2* ID_OUI_FROM_DATABASE=ANOV FRANCE -OUI:90D8F3* - ID_OUI_FROM_DATABASE=zte corporation - -OUI:D84710* - ID_OUI_FROM_DATABASE=Sichuan Changhong Electric Ltd. - -OUI:444CA8* - ID_OUI_FROM_DATABASE=Arista Networks - -OUI:FCE33C* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD - OUI:BC6A2F* ID_OUI_FROM_DATABASE=Henge Docks LLC @@ -32579,11 +33770,47 @@ OUI:48066A* OUI:1CF03E* ID_OUI_FROM_DATABASE=Wearhaus Inc. -OUI:DCDB70* - ID_OUI_FROM_DATABASE=Tonfunk Systementwicklung und Service GmbH +OUI:BCF811* + ID_OUI_FROM_DATABASE=Xiamen DNAKE Technology Co.,Ltd -OUI:C47D46* - ID_OUI_FROM_DATABASE=FUJITSU LIMITED +OUI:A8827F* + ID_OUI_FROM_DATABASE=CIBN Oriental Network(Beijing) CO.,Ltd + +OUI:609C9F* + ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. + +OUI:249EAB* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:DC56E6* + ID_OUI_FROM_DATABASE=Shenzhen Bococom Technology Co.,LTD + +OUI:5CA178* + ID_OUI_FROM_DATABASE=TableTop Media (dba Ziosk) + +OUI:A0B437* + ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSEMS + +OUI:B89ACD* + ID_OUI_FROM_DATABASE=ELITE OPTOELECTRONIC(ASIA)CO.,LTD + +OUI:800184* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:38FACA* + ID_OUI_FROM_DATABASE=Skyworth Digital Technology(Shenzhen) Co.,Ltd + +OUI:44C69B* + ID_OUI_FROM_DATABASE=Wuhan Feng Tian Information Network CO.,LTD + +OUI:C02567* + ID_OUI_FROM_DATABASE=Nexxt Solutions + +OUI:B46D35* + ID_OUI_FROM_DATABASE=Dalian Seasky Automation Co;Ltd + +OUI:FCE33C* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:68EDA4* ID_OUI_FROM_DATABASE=Shenzhen Seavo Technology Co.,Ltd @@ -32606,62 +33833,29 @@ OUI:10DF8B* OUI:00A784* ID_OUI_FROM_DATABASE=ITX security -OUI:800184* - ID_OUI_FROM_DATABASE=HTC Corporation +OUI:3481F4* + ID_OUI_FROM_DATABASE=SST Taiwan Ltd. -OUI:38FACA* - ID_OUI_FROM_DATABASE=Skyworth Digital Technology(Shenzhen) Co.,Ltd +OUI:F4B8A7* + ID_OUI_FROM_DATABASE=zte corporation -OUI:44C69B* - ID_OUI_FROM_DATABASE=Wuhan Feng Tian Information Network CO.,LTD +OUI:58F102* + ID_OUI_FROM_DATABASE=BLU Products Inc. -OUI:C02567* - ID_OUI_FROM_DATABASE=Nexxt Solutions +OUI:B869C2* + ID_OUI_FROM_DATABASE=Sunitec Enterprise Co., Ltd. -OUI:B46D35* - ID_OUI_FROM_DATABASE=Dalian Seasky Automation Co;Ltd +OUI:2CC548* + ID_OUI_FROM_DATABASE=IAdea Corporation -OUI:B89ACD* - ID_OUI_FROM_DATABASE=ELITE OPTOELECTRONIC(ASIA)CO.,LTD +OUI:84DBFC* + ID_OUI_FROM_DATABASE=Alcatel-Lucent -OUI:241C04* - ID_OUI_FROM_DATABASE=SHENZHEN JEHE TECHNOLOGY DEVELOPMENT CO., LTD. +OUI:DCDB70* + ID_OUI_FROM_DATABASE=Tonfunk Systementwicklung und Service GmbH -OUI:F8CFC5* - ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company - -OUI:BCF811* - ID_OUI_FROM_DATABASE=Xiamen DNAKE Technology Co.,Ltd - -OUI:A8827F* - ID_OUI_FROM_DATABASE=CIBN Oriental Network(Beijing) CO.,Ltd - -OUI:609C9F* - ID_OUI_FROM_DATABASE=Brocade Communications Systems, Inc. - -OUI:900A39* - ID_OUI_FROM_DATABASE=Wiio, Inc. - -OUI:C4693E* - ID_OUI_FROM_DATABASE=Turbulence Design Inc. - -OUI:1C8341* - ID_OUI_FROM_DATABASE=Hefei Bitland Information Technology Co.Ltd - -OUI:4011DC* - ID_OUI_FROM_DATABASE=Sonance - -OUI:249EAB* - ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD - -OUI:DC56E6* - ID_OUI_FROM_DATABASE=Shenzhen Bococom Technology Co.,LTD - -OUI:5CA178* - ID_OUI_FROM_DATABASE=TableTop Media (dba Ziosk) - -OUI:A0B437* - ID_OUI_FROM_DATABASE=GENERAL DYNAMICS C4 SYSEMS +OUI:C47D46* + ID_OUI_FROM_DATABASE=FUJITSU LIMITED OUI:702A7D* ID_OUI_FROM_DATABASE=EpSpot AB @@ -32672,12 +33866,30 @@ OUI:B8B3DC* OUI:347A60* ID_OUI_FROM_DATABASE=Pace plc +OUI:C4EA1D* + ID_OUI_FROM_DATABASE=Technicolor + +OUI:900A39* + ID_OUI_FROM_DATABASE=Wiio, Inc. + +OUI:C4693E* + ID_OUI_FROM_DATABASE=Turbulence Design Inc. + +OUI:1C8341* + ID_OUI_FROM_DATABASE=Hefei Bitland Information Technology Co.Ltd + OUI:6C1E70* ID_OUI_FROM_DATABASE=Guangzhou YBDS IT Co.,Ltd OUI:C8E130* ID_OUI_FROM_DATABASE=Milkyway Group Ltd +OUI:20E407* + ID_OUI_FROM_DATABASE=Spark srl + +OUI:887384* + ID_OUI_FROM_DATABASE=Toshiba + OUI:8833BE* ID_OUI_FROM_DATABASE=Ivenix, Inc. @@ -32690,23 +33902,8 @@ OUI:144146* OUI:F41563* ID_OUI_FROM_DATABASE=F5 Networks, Inc. -OUI:C4EA1D* - ID_OUI_FROM_DATABASE=Technicolor - -OUI:20E407* - ID_OUI_FROM_DATABASE=Spark srl - -OUI:887384* - ID_OUI_FROM_DATABASE=Toshiba - -OUI:584704* - ID_OUI_FROM_DATABASE=Shenzhen Webridge Technology Co.,Ltd - -OUI:1C14B3* - ID_OUI_FROM_DATABASE=Pinyon Technologies - -OUI:A0E4CB* - ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation +OUI:4011DC* + ID_OUI_FROM_DATABASE=Sonance OUI:749CE3* ID_OUI_FROM_DATABASE=Art2Wave Canada Inc. @@ -32723,9 +33920,6 @@ OUI:7CC709* OUI:3C8C40* ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited -OUI:0071C2* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:D45556* ID_OUI_FROM_DATABASE=Fiber Mountain Inc. @@ -32747,6 +33941,9 @@ OUI:08D34B* OUI:C808E9* ID_OUI_FROM_DATABASE=LG Electronics +OUI:589B0B* + ID_OUI_FROM_DATABASE=Shineway Technologies, Inc. + OUI:78ACBF* ID_OUI_FROM_DATABASE=Igneous Systems @@ -32762,6 +33959,12 @@ OUI:844BB7* OUI:148F21* ID_OUI_FROM_DATABASE=Garmin International +OUI:1C7D22* + ID_OUI_FROM_DATABASE=Fuji Xerox Co., Ltd. + +OUI:ACD1B8* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + OUI:3C6A9D* ID_OUI_FROM_DATABASE=Dexatek Technology LTD. @@ -32771,20 +33974,17 @@ OUI:14893E* OUI:60F189* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. -OUI:74A34A* - ID_OUI_FROM_DATABASE=ZIMI CORPORATION +OUI:241C04* + ID_OUI_FROM_DATABASE=SHENZHEN JEHE TECHNOLOGY DEVELOPMENT CO., LTD. -OUI:98F5A9* - ID_OUI_FROM_DATABASE=OHSUNG ELECTRONICS CO.,LTD. +OUI:F8CFC5* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company -OUI:D89341* - ID_OUI_FROM_DATABASE=General Electric Global Research +OUI:7C11CD* + ID_OUI_FROM_DATABASE=QianTang Technology -OUI:F4645D* - ID_OUI_FROM_DATABASE=Toshiba - -OUI:30D587* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:0492EE* + ID_OUI_FROM_DATABASE=iway AG OUI:B04519* ID_OUI_FROM_DATABASE=TCT mobile ltd @@ -32801,8 +34001,23 @@ OUI:2C337A* OUI:844464* ID_OUI_FROM_DATABASE=ServerU Inc -OUI:589B0B* - ID_OUI_FROM_DATABASE=Shineway Technologies, Inc. +OUI:78312B* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:74A34A* + ID_OUI_FROM_DATABASE=ZIMI CORPORATION + +OUI:98F5A9* + ID_OUI_FROM_DATABASE=OHSUNG ELECTRONICS CO.,LTD. + +OUI:D89341* + ID_OUI_FROM_DATABASE=General Electric Global Research + +OUI:F4645D* + ID_OUI_FROM_DATABASE=Toshiba + +OUI:30D587* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd OUI:A48CDB* ID_OUI_FROM_DATABASE=Lenovo @@ -32813,35 +34028,20 @@ OUI:4062B6* OUI:3C2C94* ID_OUI_FROM_DATABASE=杭州德澜科技有限公司(HangZhou Delan Technology Co.,Ltd) -OUI:78312B* - ID_OUI_FROM_DATABASE=zte corporation - -OUI:C035C5* - ID_OUI_FROM_DATABASE=Prosoft Systems LTD - -OUI:F8B2F3* - ID_OUI_FROM_DATABASE=GUANGZHOU BOSMA TECHNOLOGY CO.,LTD - -OUI:1C7D22* - ID_OUI_FROM_DATABASE=Fuji Xerox Co., Ltd. - -OUI:ACD1B8* - ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. - -OUI:7C11CD* - ID_OUI_FROM_DATABASE=QianTang Technology - -OUI:0492EE* - ID_OUI_FROM_DATABASE=iway AG - OUI:48A9D2* ID_OUI_FROM_DATABASE=Wistron Neweb Corp. OUI:F02A23* ID_OUI_FROM_DATABASE=Creative Next Design -OUI:8C9109* - ID_OUI_FROM_DATABASE=Toyoshima Electric Technoeogy(Suzhou) Co.,Ltd. +OUI:584704* + ID_OUI_FROM_DATABASE=Shenzhen Webridge Technology Co.,Ltd + +OUI:1C14B3* + ID_OUI_FROM_DATABASE=Pinyon Technologies + +OUI:A0E4CB* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation OUI:307350* ID_OUI_FROM_DATABASE=Inpeco SA @@ -32861,26 +34061,8 @@ OUI:3C1E13* OUI:B4A828* ID_OUI_FROM_DATABASE=Shenzhen Concox Information Technology Co., Ltd -OUI:A41242* - ID_OUI_FROM_DATABASE=NEC Platforms, Ltd. - -OUI:404EEB* - ID_OUI_FROM_DATABASE=Higher Way Electronic Co., Ltd. - -OUI:50BD5F* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:147590* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:ECB907* - ID_OUI_FROM_DATABASE=CloudGenix Inc - -OUI:5CF9F0* - ID_OUI_FROM_DATABASE=Atomos Engineering P/L - -OUI:F409D8* - ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co., LTD. +OUI:50F43C* + ID_OUI_FROM_DATABASE=Leeo Inc OUI:FCDBB3* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. @@ -32906,8 +34088,8 @@ OUI:C0EEFB* OUI:E00DB9* ID_OUI_FROM_DATABASE=Private -OUI:108A1B* - ID_OUI_FROM_DATABASE=RAONIX Inc. +OUI:A41242* + ID_OUI_FROM_DATABASE=NEC Platforms, Ltd. OUI:8CF813* ID_OUI_FROM_DATABASE=ORANGE POLSKA @@ -32927,29 +34109,8 @@ OUI:C401CE* OUI:D01242* ID_OUI_FROM_DATABASE=BIOS Corporation -OUI:50F43C* - ID_OUI_FROM_DATABASE=Leeo Inc - -OUI:B43934* - ID_OUI_FROM_DATABASE=Pen Generations, Inc. - -OUI:C03896* - ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. - -OUI:DCC622* - ID_OUI_FROM_DATABASE=BUHEUNG SYSTEM - -OUI:5C2BF5* - ID_OUI_FROM_DATABASE=Vivint - -OUI:6C0B84* - ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co.,Ltd. - -OUI:D062A0* - ID_OUI_FROM_DATABASE=China Essence Technology (Zhumadian) Co., Ltd. - -OUI:CC10A3* - ID_OUI_FROM_DATABASE=Beijing Nan Bao Technology Co., Ltd. +OUI:6CBFB5* + ID_OUI_FROM_DATABASE=Noon Technology Co., Ltd OUI:2CA30E* ID_OUI_FROM_DATABASE=POWER DRAGON DEVELOPMENT LIMITED @@ -32975,26 +34136,8 @@ OUI:CC3080* OUI:F82441* ID_OUI_FROM_DATABASE=Yeelink -OUI:6CBFB5* - ID_OUI_FROM_DATABASE=Noon Technology Co., Ltd - -OUI:489D18* - ID_OUI_FROM_DATABASE=Flashbay Limited - -OUI:8CB094* - ID_OUI_FROM_DATABASE=Airtech I&C Co., Ltd - -OUI:70F196* - ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc - -OUI:6C6EFE* - ID_OUI_FROM_DATABASE=Core Logic Inc. - -OUI:E4C62B* - ID_OUI_FROM_DATABASE=Airware - -OUI:80F8EB* - ID_OUI_FROM_DATABASE=RayTight +OUI:108A1B* + ID_OUI_FROM_DATABASE=RAONIX Inc. OUI:94B40F* ID_OUI_FROM_DATABASE=Aruba Networks @@ -33014,9 +34157,60 @@ OUI:CC3F1D* OUI:902181* ID_OUI_FROM_DATABASE=Shanghai Huaqin Telecom Technology Co.,Ltd +OUI:D062A0* + ID_OUI_FROM_DATABASE=China Essence Technology (Zhumadian) Co., Ltd. + +OUI:CC10A3* + ID_OUI_FROM_DATABASE=Beijing Nan Bao Technology Co., Ltd. + +OUI:B43934* + ID_OUI_FROM_DATABASE=Pen Generations, Inc. + +OUI:C03896* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:DCC622* + ID_OUI_FROM_DATABASE=BUHEUNG SYSTEM + +OUI:5C2BF5* + ID_OUI_FROM_DATABASE=Vivint + +OUI:6C0B84* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co.,Ltd. + OUI:600417* ID_OUI_FROM_DATABASE=POSBANK CO.,LTD +OUI:489D18* + ID_OUI_FROM_DATABASE=Flashbay Limited + +OUI:8CB094* + ID_OUI_FROM_DATABASE=Airtech I&C Co., Ltd + +OUI:70F196* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:6C6EFE* + ID_OUI_FROM_DATABASE=Core Logic Inc. + +OUI:E4C62B* + ID_OUI_FROM_DATABASE=Airware + +OUI:80F8EB* + ID_OUI_FROM_DATABASE=RayTight + +OUI:F409D8* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co., LTD. + +OUI:C035C5* + ID_OUI_FROM_DATABASE=Prosoft Systems LTD + +OUI:F8B2F3* + ID_OUI_FROM_DATABASE=GUANGZHOU BOSMA TECHNOLOGY CO.,LTD + +OUI:8C9109* + ID_OUI_FROM_DATABASE=Toyoshima Electric Technoeogy(Suzhou) Co.,Ltd. + OUI:A44AD3* ID_OUI_FROM_DATABASE=ST Electronics(Shanghai) Co.,Ltd @@ -33044,23 +34238,11 @@ OUI:907EBA* OUI:488244* ID_OUI_FROM_DATABASE=Life Fitness / Div. of Brunswick -OUI:A8F7E0* - ID_OUI_FROM_DATABASE=PLANET Technology Corporation +OUI:D85DFB* + ID_OUI_FROM_DATABASE=Private -OUI:2C5BE1* - ID_OUI_FROM_DATABASE=Centripetal Networks, Inc - -OUI:D87EB1* - ID_OUI_FROM_DATABASE=x.o.ware, inc. - -OUI:4045DA* - ID_OUI_FROM_DATABASE=Spreadtrum Communications (Shanghai) Co., Ltd. - -OUI:98BE94* - ID_OUI_FROM_DATABASE=IBM - -OUI:D4B43E* - ID_OUI_FROM_DATABASE=Messcomp Datentechnik GmbH +OUI:7CC4EF* + ID_OUI_FROM_DATABASE=Devialet OUI:A8E539* ID_OUI_FROM_DATABASE=Moimstone Co.,Ltd @@ -33071,21 +34253,27 @@ OUI:98F170* OUI:04C991* ID_OUI_FROM_DATABASE=Phistek INC. +OUI:404EEB* + ID_OUI_FROM_DATABASE=Higher Way Electronic Co., Ltd. + +OUI:50BD5F* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:147590* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:ECB907* + ID_OUI_FROM_DATABASE=CloudGenix Inc + +OUI:5CF9F0* + ID_OUI_FROM_DATABASE=Atomos Engineering P/L + OUI:581F67* ID_OUI_FROM_DATABASE=Open-m technology limited OUI:BC25F0* ID_OUI_FROM_DATABASE=3D Display Technologies Co., Ltd. -OUI:7CE524* - ID_OUI_FROM_DATABASE=Quirky, Inc. - -OUI:D85DFB* - ID_OUI_FROM_DATABASE=Private - -OUI:7CC4EF* - ID_OUI_FROM_DATABASE=Devialet - OUI:94AEE3* ID_OUI_FROM_DATABASE=Belden Hirschmann Industries (Suzhou) Ltd. @@ -33098,15 +34286,6 @@ OUI:705B2E* OUI:0C8C8F* ID_OUI_FROM_DATABASE=Kamo Technology Limited -OUI:F4FD2B* - ID_OUI_FROM_DATABASE=ZOYI Company - -OUI:FCAA14* - ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. - -OUI:50FEF2* - ID_OUI_FROM_DATABASE=Sify Technologies Ltd - OUI:3CD9CE* ID_OUI_FROM_DATABASE=Eclipse WiFi @@ -33128,6 +34307,27 @@ OUI:ECD9D1* OUI:748F4D* ID_OUI_FROM_DATABASE=MEN Mikro Elektronik GmbH +OUI:F4FD2B* + ID_OUI_FROM_DATABASE=ZOYI Company + +OUI:FCAA14* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:50FEF2* + ID_OUI_FROM_DATABASE=Sify Technologies Ltd + +OUI:7CE524* + ID_OUI_FROM_DATABASE=Quirky, Inc. + +OUI:7CD30A* + ID_OUI_FROM_DATABASE=INVENTEC Corporation + +OUI:3481C4* + ID_OUI_FROM_DATABASE=AVM GmbH + +OUI:885BDD* + ID_OUI_FROM_DATABASE=Aerohive Networks Inc. + OUI:A47E39* ID_OUI_FROM_DATABASE=zte corporation @@ -33140,17 +34340,23 @@ OUI:ACA9A0* OUI:A8A668* ID_OUI_FROM_DATABASE=zte corporation -OUI:60E327* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:A8F7E0* + ID_OUI_FROM_DATABASE=PLANET Technology Corporation -OUI:E4D332* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:2C5BE1* + ID_OUI_FROM_DATABASE=Centripetal Networks, Inc -OUI:A0DA92* - ID_OUI_FROM_DATABASE=Nanjing Glarun Atten Technology Co. Ltd. +OUI:D87EB1* + ID_OUI_FROM_DATABASE=x.o.ware, inc. -OUI:6828BA* - ID_OUI_FROM_DATABASE=Dejai +OUI:4045DA* + ID_OUI_FROM_DATABASE=Spreadtrum Communications (Shanghai) Co., Ltd. + +OUI:98BE94* + ID_OUI_FROM_DATABASE=IBM + +OUI:D4B43E* + ID_OUI_FROM_DATABASE=Messcomp Datentechnik GmbH OUI:48D18E* ID_OUI_FROM_DATABASE=Metis Communication Co.,Ltd @@ -33158,18 +34364,6 @@ OUI:48D18E* OUI:A49F85* ID_OUI_FROM_DATABASE=Lyve Minds, Inc -OUI:7CD30A* - ID_OUI_FROM_DATABASE=INVENTEC Corporation - -OUI:3481C4* - ID_OUI_FROM_DATABASE=AVM GmbH - -OUI:885BDD* - ID_OUI_FROM_DATABASE=Aerohive Networks Inc. - -OUI:085700* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - OUI:888914* ID_OUI_FROM_DATABASE=All Components Incorporated @@ -33182,8 +34376,8 @@ OUI:A06518* OUI:748F1B* ID_OUI_FROM_DATABASE=MasterImage 3D -OUI:F03A4B* - ID_OUI_FROM_DATABASE=Bloombase, Inc. +OUI:684898* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd OUI:E4121D* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -33248,17 +34442,20 @@ OUI:50B695* OUI:B48547* ID_OUI_FROM_DATABASE=Amptown System Company GmbH -OUI:3C25D7* - ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:085700* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. -OUI:1889DF* - ID_OUI_FROM_DATABASE=CerebrEX Inc. +OUI:60E327* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. -OUI:30A8DB* - ID_OUI_FROM_DATABASE=Sony Mobile Communications AB +OUI:E4D332* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. -OUI:CC9F35* - ID_OUI_FROM_DATABASE=Transbit Sp. z o.o. +OUI:A0DA92* + ID_OUI_FROM_DATABASE=Nanjing Glarun Atten Technology Co. Ltd. + +OUI:6828BA* + ID_OUI_FROM_DATABASE=Dejai OUI:407875* ID_OUI_FROM_DATABASE=IMBEL - Industria de Material Belico do Brasil @@ -33290,23 +34487,29 @@ OUI:88E8F8* OUI:2C073C* ID_OUI_FROM_DATABASE=DEVLINE LIMITED -OUI:7CE4AA* - ID_OUI_FROM_DATABASE=Private +OUI:F015A0* + ID_OUI_FROM_DATABASE=KyungDong One Co., Ltd. -OUI:1820A6* - ID_OUI_FROM_DATABASE=Sage Co., Ltd. +OUI:ECF72B* + ID_OUI_FROM_DATABASE=HD DIGITAL TECH CO., LTD. -OUI:BCF61C* - ID_OUI_FROM_DATABASE=Geomodeling Wuxi Technology Co. Ltd. +OUI:D8B6D6* + ID_OUI_FROM_DATABASE=Blu Tether Limited -OUI:083F3E* - ID_OUI_FROM_DATABASE=WSH GmbH +OUI:847207* + ID_OUI_FROM_DATABASE=I&C Technology -OUI:6C09D6* - ID_OUI_FROM_DATABASE=Digiquest Electronics LTD +OUI:3C25D7* + ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:684898* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:1889DF* + ID_OUI_FROM_DATABASE=CerebrEX Inc. + +OUI:30A8DB* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:CC9F35* + ID_OUI_FROM_DATABASE=Transbit Sp. z o.o. OUI:8C569D* ID_OUI_FROM_DATABASE=Imaging Solutions Group @@ -33329,11 +34532,26 @@ OUI:4CE1BB* OUI:8CDE99* ID_OUI_FROM_DATABASE=Comlab Inc. -OUI:1088CE* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. +OUI:085AE0* + ID_OUI_FROM_DATABASE=Recovision Technology Co., Ltd. -OUI:FCF647* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. +OUI:7CE4AA* + ID_OUI_FROM_DATABASE=Private + +OUI:1820A6* + ID_OUI_FROM_DATABASE=Sage Co., Ltd. + +OUI:BCF61C* + ID_OUI_FROM_DATABASE=Geomodeling Wuxi Technology Co. Ltd. + +OUI:083F3E* + ID_OUI_FROM_DATABASE=WSH GmbH + +OUI:6C09D6* + ID_OUI_FROM_DATABASE=Digiquest Electronics LTD + +OUI:F03A4B* + ID_OUI_FROM_DATABASE=Bloombase, Inc. OUI:2C9AA4* ID_OUI_FROM_DATABASE=NGI SpA @@ -33347,35 +34565,47 @@ OUI:283B96* OUI:80D433* ID_OUI_FROM_DATABASE=LzLabs GmbH -OUI:085AE0* - ID_OUI_FROM_DATABASE=Recovision Technology Co., Ltd. - -OUI:BCEE7B* - ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. - -OUI:8C3AE3* - ID_OUI_FROM_DATABASE=LG Electronics - -OUI:FC09D8* - ID_OUI_FROM_DATABASE=ACTEON Group - -OUI:0C1262* - ID_OUI_FROM_DATABASE=zte corporation - OUI:687CC8* ID_OUI_FROM_DATABASE=Measurement Systems S. de R.L. -OUI:F015A0* - ID_OUI_FROM_DATABASE=KyungDong One Co., Ltd. +OUI:38BF2F* + ID_OUI_FROM_DATABASE=Espec Corp. -OUI:ECF72B* - ID_OUI_FROM_DATABASE=HD DIGITAL TECH CO., LTD. +OUI:182012* + ID_OUI_FROM_DATABASE=Aztech Associates Inc. -OUI:D8B6D6* - ID_OUI_FROM_DATABASE=Blu Tether Limited +OUI:34BE00* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd -OUI:847207* - ID_OUI_FROM_DATABASE=I&C Technology +OUI:343111* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:0CBD51* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + +OUI:C0F991* + ID_OUI_FROM_DATABASE=GME Standard Communications P/L + +OUI:14EDA5* + ID_OUI_FROM_DATABASE=Wächter GmbH Sicherheitssysteme + +OUI:E056F4* + ID_OUI_FROM_DATABASE=AxesNetwork Solutions inc. + +OUI:B8C1A2* + ID_OUI_FROM_DATABASE=Dragon Path Technologies Co., Limited + +OUI:50ED78* + ID_OUI_FROM_DATABASE=Changzhou Yongse Infotech Co.,Ltd + +OUI:8CB7F7* + ID_OUI_FROM_DATABASE=Shenzhen UniStrong Science & Technology Co., Ltd + +OUI:085240* + ID_OUI_FROM_DATABASE=EbV Elektronikbau- und Vertriebs GmbH + +OUI:80F25E* + ID_OUI_FROM_DATABASE=Kyynel OUI:94DF4E* ID_OUI_FROM_DATABASE=Wistron InfoComm(Kunshan)Co.,Ltd. @@ -33383,9 +34613,6 @@ OUI:94DF4E* OUI:E0AEB2* ID_OUI_FROM_DATABASE=Bender GmbH & Co.KG -OUI:BC9889* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:2C553C* ID_OUI_FROM_DATABASE=Gainspeed, Inc. @@ -33404,21 +34631,6 @@ OUI:2464EF* OUI:50B888* ID_OUI_FROM_DATABASE=wi2be Tecnologia S/A -OUI:B8C1A2* - ID_OUI_FROM_DATABASE=Dragon Path Technologies Co., Limited - -OUI:50ED78* - ID_OUI_FROM_DATABASE=Changzhou Yongse Infotech Co.,Ltd - -OUI:8CB7F7* - ID_OUI_FROM_DATABASE=Shenzhen UniStrong Science & Technology Co., Ltd - -OUI:085240* - ID_OUI_FROM_DATABASE=EbV Elektronikbau- und Vertriebs GmbH - -OUI:80F25E* - ID_OUI_FROM_DATABASE=Kyynel - OUI:844F03* ID_OUI_FROM_DATABASE=Ablelink Electronics Ltd @@ -33452,62 +34664,11 @@ OUI:D46867* OUI:68692E* ID_OUI_FROM_DATABASE=Zycoo Co.,Ltd -OUI:A875E2* - ID_OUI_FROM_DATABASE=Aventura Technologies, Inc. +OUI:1C63B7* + ID_OUI_FROM_DATABASE=OpenProducts 237 AB -OUI:38BF2F* - ID_OUI_FROM_DATABASE=Espec Corp. - -OUI:182012* - ID_OUI_FROM_DATABASE=Aztech Associates Inc. - -OUI:34BE00* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:343111* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:0CBD51* - ID_OUI_FROM_DATABASE=TCT Mobile Limited - -OUI:C0F991* - ID_OUI_FROM_DATABASE=GME Standard Communications P/L - -OUI:14EDA5* - ID_OUI_FROM_DATABASE=Wächter GmbH Sicherheitssysteme - -OUI:E056F4* - ID_OUI_FROM_DATABASE=AxesNetwork Solutions inc. - -OUI:385AA8* - ID_OUI_FROM_DATABASE=Beijing Zhongdun Security Technology Development Co. - -OUI:FC3FAB* - ID_OUI_FROM_DATABASE=Henan Lanxin Technology Co., Ltd - -OUI:F8FF5F* - ID_OUI_FROM_DATABASE=Shenzhen Communication Technology Co.,Ltd - -OUI:DCC422* - ID_OUI_FROM_DATABASE=Systembase Limited - -OUI:F4BD7C* - ID_OUI_FROM_DATABASE=Chengdu jinshi communication Co., LTD - -OUI:C8F36B* - ID_OUI_FROM_DATABASE=Yamato Scale Co.,Ltd. - -OUI:6C90B1* - ID_OUI_FROM_DATABASE=SanLogic Inc - -OUI:845C93* - ID_OUI_FROM_DATABASE=Chabrier Services - -OUI:D44C9C* - ID_OUI_FROM_DATABASE=Shenzhen YOOBAO Technology Co.Ltd - -OUI:A88D7B* - ID_OUI_FROM_DATABASE=SunDroid Global limited. +OUI:A0A23C* + ID_OUI_FROM_DATABASE=GPMS OUI:A03B1B* ID_OUI_FROM_DATABASE=Inspire Tech @@ -33530,6 +34691,30 @@ OUI:6C4B7F* OUI:0CCB8D* ID_OUI_FROM_DATABASE=ASCO Numatics GmbH +OUI:FC019E* + ID_OUI_FROM_DATABASE=VIEVU + +OUI:34AA8B* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:F45F69* + ID_OUI_FROM_DATABASE=Matsufu Electronics distribution Company + +OUI:F4A294* + ID_OUI_FROM_DATABASE=EAGLE WORLD DEVELOPMENT CO., LIMITED + +OUI:2CCD69* + ID_OUI_FROM_DATABASE=Aqavi.com + +OUI:947C3E* + ID_OUI_FROM_DATABASE=Polewall Norge AS + +OUI:385AA8* + ID_OUI_FROM_DATABASE=Beijing Zhongdun Security Technology Development Co. + +OUI:FC3FAB* + ID_OUI_FROM_DATABASE=Henan Lanxin Technology Co., Ltd + OUI:2847AA* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -33539,11 +34724,14 @@ OUI:682DDC* OUI:FCB0C4* ID_OUI_FROM_DATABASE=Shanghai DareGlobal Technologies Co., Ltd -OUI:1C63B7* - ID_OUI_FROM_DATABASE=OpenProducts 237 AB +OUI:9CBB98* + ID_OUI_FROM_DATABASE=Shen Zhen RND Electronic Co.,LTD -OUI:A0A23C* - ID_OUI_FROM_DATABASE=GPMS +OUI:345C40* + ID_OUI_FROM_DATABASE=Cargt Holdings LLC + +OUI:34885D* + ID_OUI_FROM_DATABASE=Logitech Far East OUI:708D09* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -33557,17 +34745,8 @@ OUI:38B74D* OUI:A0E5E9* ID_OUI_FROM_DATABASE=enimai Inc -OUI:9CBB98* - ID_OUI_FROM_DATABASE=Shen Zhen RND Electronic Co.,LTD - -OUI:345C40* - ID_OUI_FROM_DATABASE=Cargt Holdings LLC - -OUI:34885D* - ID_OUI_FROM_DATABASE=Logitech Far East - -OUI:B462AD* - ID_OUI_FROM_DATABASE=raytest GmbH +OUI:A88D7B* + ID_OUI_FROM_DATABASE=SunDroid Global limited. OUI:6064A1* ID_OUI_FROM_DATABASE=RADiflow Ltd. @@ -33587,23 +34766,20 @@ OUI:FC1BFF* OUI:AC5036* ID_OUI_FROM_DATABASE=Pi-Coral Inc -OUI:FC019E* - ID_OUI_FROM_DATABASE=VIEVU +OUI:BCEE7B* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. -OUI:34AA8B* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:8C3AE3* + ID_OUI_FROM_DATABASE=LG Electronics -OUI:F45F69* - ID_OUI_FROM_DATABASE=Matsufu Electronics distribution Company +OUI:FC09D8* + ID_OUI_FROM_DATABASE=ACTEON Group -OUI:F4A294* - ID_OUI_FROM_DATABASE=EAGLE WORLD DEVELOPMENT CO., LIMITED +OUI:0C1262* + ID_OUI_FROM_DATABASE=zte corporation -OUI:2CCD69* - ID_OUI_FROM_DATABASE=Aqavi.com - -OUI:947C3E* - ID_OUI_FROM_DATABASE=Polewall Norge AS +OUI:A875E2* + ID_OUI_FROM_DATABASE=Aventura Technologies, Inc. OUI:E0D1E6* ID_OUI_FROM_DATABASE=Aliph dba Jawbone @@ -33629,17 +34805,35 @@ OUI:306112* OUI:A0C6EC* ID_OUI_FROM_DATABASE=ShenZhen ANYK Technology Co.,LTD -OUI:C80258* - ID_OUI_FROM_DATABASE=ITW GSE ApS +OUI:6405BE* + ID_OUI_FROM_DATABASE=NEW LIGHT LED -OUI:1001CA* - ID_OUI_FROM_DATABASE=Ashley Butterworth +OUI:F8FF5F* + ID_OUI_FROM_DATABASE=Shenzhen Communication Technology Co.,Ltd -OUI:246AAB* - ID_OUI_FROM_DATABASE=IT-IS International +OUI:DCC422* + ID_OUI_FROM_DATABASE=Systembase Limited -OUI:28F532* - ID_OUI_FROM_DATABASE=ADD-Engineering BV +OUI:F4BD7C* + ID_OUI_FROM_DATABASE=Chengdu jinshi communication Co., LTD + +OUI:C8F36B* + ID_OUI_FROM_DATABASE=Yamato Scale Co.,Ltd. + +OUI:6C90B1* + ID_OUI_FROM_DATABASE=SanLogic Inc + +OUI:845C93* + ID_OUI_FROM_DATABASE=Chabrier Services + +OUI:D44C9C* + ID_OUI_FROM_DATABASE=Shenzhen YOOBAO Technology Co.Ltd + +OUI:68E166* + ID_OUI_FROM_DATABASE=Private + +OUI:60FEF9* + ID_OUI_FROM_DATABASE=Thomas & Betts OUI:FC4BBC* ID_OUI_FROM_DATABASE=Sunplus Technology Co., Ltd. @@ -33677,54 +34871,6 @@ OUI:E8519D* OUI:00B78D* ID_OUI_FROM_DATABASE=Nanjing Shining Electric Automation Co., Ltd -OUI:68E166* - ID_OUI_FROM_DATABASE=Private - -OUI:60FEF9* - ID_OUI_FROM_DATABASE=Thomas & Betts - -OUI:78FE41* - ID_OUI_FROM_DATABASE=Socus networks - -OUI:083571* - ID_OUI_FROM_DATABASE=CASwell INC. - -OUI:DCF755* - ID_OUI_FROM_DATABASE=SITRONIK - -OUI:E42D02* - ID_OUI_FROM_DATABASE=TCT Mobile Limited - -OUI:ACCA8E* - ID_OUI_FROM_DATABASE=ODA Technologies - -OUI:6405BE* - ID_OUI_FROM_DATABASE=NEW LIGHT LED - -OUI:E03E4A* - ID_OUI_FROM_DATABASE=Cavanagh Group International - -OUI:D890E8* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:24C696* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:30766F* - ID_OUI_FROM_DATABASE=LG Electronics - -OUI:6CB350* - ID_OUI_FROM_DATABASE=Anhui comhigher tech co.,ltd - -OUI:A42305* - ID_OUI_FROM_DATABASE=Open Networking Laboratory - -OUI:1C86AD* - ID_OUI_FROM_DATABASE=MCT CO., LTD. - -OUI:28D93E* - ID_OUI_FROM_DATABASE=Telecor Inc. - OUI:882364* ID_OUI_FROM_DATABASE=Watchnet DVR Inc @@ -33755,6 +34901,57 @@ OUI:201D03* OUI:C06C6D* ID_OUI_FROM_DATABASE=MagneMotion, Inc. +OUI:E03E4A* + ID_OUI_FROM_DATABASE=Cavanagh Group International + +OUI:D890E8* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:24C696* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:30766F* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:6CB350* + ID_OUI_FROM_DATABASE=Anhui comhigher tech co.,ltd + +OUI:A42305* + ID_OUI_FROM_DATABASE=Open Networking Laboratory + +OUI:1C86AD* + ID_OUI_FROM_DATABASE=MCT CO., LTD. + +OUI:28D93E* + ID_OUI_FROM_DATABASE=Telecor Inc. + +OUI:C80258* + ID_OUI_FROM_DATABASE=ITW GSE ApS + +OUI:1001CA* + ID_OUI_FROM_DATABASE=Ashley Butterworth + +OUI:246AAB* + ID_OUI_FROM_DATABASE=IT-IS International + +OUI:28F532* + ID_OUI_FROM_DATABASE=ADD-Engineering BV + +OUI:78FE41* + ID_OUI_FROM_DATABASE=Socus networks + +OUI:083571* + ID_OUI_FROM_DATABASE=CASwell INC. + +OUI:DCF755* + ID_OUI_FROM_DATABASE=SITRONIK + +OUI:E42D02* + ID_OUI_FROM_DATABASE=TCT Mobile Limited + +OUI:ACCA8E* + ID_OUI_FROM_DATABASE=ODA Technologies + OUI:74CA25* ID_OUI_FROM_DATABASE=Calxeda, Inc. @@ -33764,42 +34961,6 @@ OUI:181EB0* OUI:CCBD35* ID_OUI_FROM_DATABASE=Steinel GmbH -OUI:788DF7* - ID_OUI_FROM_DATABASE=Hitron Technologies. Inc - -OUI:6CECA1* - ID_OUI_FROM_DATABASE=SHENZHEN CLOU ELECTRONICS CO. LTD. - -OUI:D862DB* - ID_OUI_FROM_DATABASE=Eno Inc. - -OUI:68DB67* - ID_OUI_FROM_DATABASE=Nantong Coship Electronics Co., Ltd - -OUI:BC261D* - ID_OUI_FROM_DATABASE=HONG KONG TECON TECHNOLOGY - -OUI:888964* - ID_OUI_FROM_DATABASE=GSI Electronics Inc. - -OUI:4C82CF* - ID_OUI_FROM_DATABASE=Echostar Technologies - -OUI:9CA577* - ID_OUI_FROM_DATABASE=Osorno Enterprises Inc. - -OUI:C0C3B6* - ID_OUI_FROM_DATABASE=Automatic Systems - -OUI:A8294C* - ID_OUI_FROM_DATABASE=Precision Optical Transceivers, Inc. - -OUI:D0EB03* - ID_OUI_FROM_DATABASE=Zhehua technology limited - -OUI:A0861D* - ID_OUI_FROM_DATABASE=Chengdu Fuhuaxin Technology co.,Ltd - OUI:9498A2* ID_OUI_FROM_DATABASE=Shanghai LISTEN TECH.LTD @@ -33818,68 +34979,14 @@ OUI:D82916* OUI:6472D8* ID_OUI_FROM_DATABASE=GooWi Technology Co.,Limited -OUI:84ACA4* - ID_OUI_FROM_DATABASE=Beijing Novel Super Digital TV Technology Co., Ltd +OUI:3C081E* + ID_OUI_FROM_DATABASE=Beijing Yupont Electric Power Technology Co.,Ltd -OUI:3C6FF7* - ID_OUI_FROM_DATABASE=EnTek Systems, Inc. +OUI:7CA15D* + ID_OUI_FROM_DATABASE=GN ReSound A/S -OUI:B838CA* - ID_OUI_FROM_DATABASE=Kyokko Tsushin System CO.,LTD - -OUI:380FE4* - ID_OUI_FROM_DATABASE=Dedicated Network Partners Oy - -OUI:847A88* - ID_OUI_FROM_DATABASE=HTC Corporation - -OUI:0808C2* - ID_OUI_FROM_DATABASE=Samsung Electronics - -OUI:5461EA* - ID_OUI_FROM_DATABASE=Zaplox AB - -OUI:78324F* - ID_OUI_FROM_DATABASE=Millennium Group, Inc. - -OUI:F05DC8* - ID_OUI_FROM_DATABASE=Duracell Powermat - -OUI:48F925* - ID_OUI_FROM_DATABASE=Maestronic - -OUI:C0885B* - ID_OUI_FROM_DATABASE=SnD Tech Co., Ltd. - -OUI:64C667* - ID_OUI_FROM_DATABASE=Barnes&Noble - -OUI:C47DCC* - ID_OUI_FROM_DATABASE=Zebra Technologies Inc - -OUI:64535D* - ID_OUI_FROM_DATABASE=Frauscher Sensortechnik - -OUI:105F06* - ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc - -OUI:841715* - ID_OUI_FROM_DATABASE=GP Electronics (HK) Ltd. - -OUI:087999* - ID_OUI_FROM_DATABASE=AIM GmbH - -OUI:84C2E4* - ID_OUI_FROM_DATABASE=Jiangsu Qinheng Co., Ltd. - -OUI:C0B8B1* - ID_OUI_FROM_DATABASE=BitBox Ltd - -OUI:0C722C* - ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. - -OUI:B01408* - ID_OUI_FROM_DATABASE=LIGHTSPEED INTERNATIONAL CO. +OUI:B4DD15* + ID_OUI_FROM_DATABASE=ControlThings Oy Ab OUI:F8FEA8* ID_OUI_FROM_DATABASE=Technico Japan Corporation @@ -33902,6 +35009,60 @@ OUI:282CB2* OUI:D43A65* ID_OUI_FROM_DATABASE=IGRS Engineering Lab Ltd. +OUI:D0EB03* + ID_OUI_FROM_DATABASE=Zhehua technology limited + +OUI:A0861D* + ID_OUI_FROM_DATABASE=Chengdu Fuhuaxin Technology co.,Ltd + +OUI:888964* + ID_OUI_FROM_DATABASE=GSI Electronics Inc. + +OUI:4C82CF* + ID_OUI_FROM_DATABASE=Echostar Technologies + +OUI:9CA577* + ID_OUI_FROM_DATABASE=Osorno Enterprises Inc. + +OUI:C0C3B6* + ID_OUI_FROM_DATABASE=Automatic Systems + +OUI:A8294C* + ID_OUI_FROM_DATABASE=Precision Optical Transceivers, Inc. + +OUI:3C86A8* + ID_OUI_FROM_DATABASE=Sangshin elecom .co,, LTD + +OUI:FCDD55* + ID_OUI_FROM_DATABASE=Shenzhen WeWins wireless Co.,Ltd + +OUI:CC0DEC* + ID_OUI_FROM_DATABASE=Cisco SPVTG + +OUI:68B094* + ID_OUI_FROM_DATABASE=INESA ELECTRON CO.,LTD + +OUI:40E730* + ID_OUI_FROM_DATABASE=DEY Storage Systems, Inc. + +OUI:F05DC8* + ID_OUI_FROM_DATABASE=Duracell Powermat + +OUI:6C8686* + ID_OUI_FROM_DATABASE=Technonia + +OUI:4432C8* + ID_OUI_FROM_DATABASE=Technicolor USA Inc. + +OUI:78521A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:68DB67* + ID_OUI_FROM_DATABASE=Nantong Coship Electronics Co., Ltd + +OUI:BC261D* + ID_OUI_FROM_DATABASE=HONG KONG TECON TECHNOLOGY + OUI:10B9FE* ID_OUI_FROM_DATABASE=Lika srl @@ -33923,41 +35084,47 @@ OUI:30CDA7* OUI:104D77* ID_OUI_FROM_DATABASE=Innovative Computer Engineering -OUI:3C081E* - ID_OUI_FROM_DATABASE=Beijing Yupont Electric Power Technology Co.,Ltd +OUI:788DF7* + ID_OUI_FROM_DATABASE=Hitron Technologies. Inc -OUI:7CA15D* - ID_OUI_FROM_DATABASE=GN ReSound A/S +OUI:6CECA1* + ID_OUI_FROM_DATABASE=SHENZHEN CLOU ELECTRONICS CO. LTD. -OUI:B4DD15* - ID_OUI_FROM_DATABASE=ControlThings Oy Ab - -OUI:3C86A8* - ID_OUI_FROM_DATABASE=Sangshin elecom .co,, LTD - -OUI:FCDD55* - ID_OUI_FROM_DATABASE=Shenzhen WeWins wireless Co.,Ltd - -OUI:CC0DEC* - ID_OUI_FROM_DATABASE=Cisco SPVTG - -OUI:68B094* - ID_OUI_FROM_DATABASE=INESA ELECTRON CO.,LTD - -OUI:40E730* - ID_OUI_FROM_DATABASE=DEY Storage Systems, Inc. +OUI:D862DB* + ID_OUI_FROM_DATABASE=Eno Inc. OUI:A8D236* ID_OUI_FROM_DATABASE=Lightware Visual Engineering -OUI:6C8686* - ID_OUI_FROM_DATABASE=Technonia +OUI:48F925* + ID_OUI_FROM_DATABASE=Maestronic -OUI:4432C8* - ID_OUI_FROM_DATABASE=Technicolor USA Inc. +OUI:C0885B* + ID_OUI_FROM_DATABASE=SnD Tech Co., Ltd. -OUI:78521A* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:64C667* + ID_OUI_FROM_DATABASE=Barnes&Noble + +OUI:C47DCC* + ID_OUI_FROM_DATABASE=Zebra Technologies Inc + +OUI:64535D* + ID_OUI_FROM_DATABASE=Frauscher Sensortechnik + +OUI:105F06* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:00B56D* + ID_OUI_FROM_DATABASE=David Electronics Co., LTD. + +OUI:B461FF* + ID_OUI_FROM_DATABASE=Lumigon A/S + +OUI:9038DF* + ID_OUI_FROM_DATABASE=Changzhou Tiannengbo System Co. Ltd. + +OUI:CC593E* + ID_OUI_FROM_DATABASE=TOUMAZ LTD OUI:84E714* ID_OUI_FROM_DATABASE=Liang Herng Enterprise,Co.Ltd. @@ -33965,15 +35132,6 @@ OUI:84E714* OUI:303D08* ID_OUI_FROM_DATABASE=GLINTT TES S.A. -OUI:9C541C* - ID_OUI_FROM_DATABASE=Shenzhen My-power Technology Co.,Ltd - -OUI:90187C* - ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co., LTD. - -OUI:FC1F19* - ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS CO., LTD. - OUI:E496AE* ID_OUI_FROM_DATABASE=ALTOGRAPHICS Inc. @@ -34004,6 +35162,111 @@ OUI:ECB541* OUI:D40057* ID_OUI_FROM_DATABASE=MC Technologies GmbH +OUI:B85AF7* + ID_OUI_FROM_DATABASE=Ouya, Inc + +OUI:E0D9A2* + ID_OUI_FROM_DATABASE=Hippih aps + +OUI:B0C4E7* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:F0F669* + ID_OUI_FROM_DATABASE=Motion Analysis Corporation + +OUI:F0219D* + ID_OUI_FROM_DATABASE=Cal-Comp Electronics & Communications Company Ltd. + +OUI:F8D7BF* + ID_OUI_FROM_DATABASE=REV Ritter GmbH + +OUI:AC5D10* + ID_OUI_FROM_DATABASE=Pace Americas + +OUI:88F490* + ID_OUI_FROM_DATABASE=Jetmobile Pte Ltd + +OUI:AC8D14* + ID_OUI_FROM_DATABASE=Smartrove Inc + +OUI:18673F* + ID_OUI_FROM_DATABASE=Hanover Displays Limited + +OUI:A00ABF* + ID_OUI_FROM_DATABASE=Wieson Technologies Co., Ltd. + +OUI:2091D9* + ID_OUI_FROM_DATABASE=I'M SPA + +OUI:744D79* + ID_OUI_FROM_DATABASE=Arrive Systems Inc. + +OUI:C83D97* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:38192F* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:141BF0* + ID_OUI_FROM_DATABASE=Intellimedia Systems Ltd + +OUI:101D51* + ID_OUI_FROM_DATABASE=ON-Q LLC dba ON-Q Mesh Networks + +OUI:34C99D* + ID_OUI_FROM_DATABASE=EIDOLON COMMUNICATIONS TECHNOLOGY CO. LTD. + +OUI:8C4AEE* + ID_OUI_FROM_DATABASE=GIGA TMS INC + +OUI:F46DE2* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:B838CA* + ID_OUI_FROM_DATABASE=Kyokko Tsushin System CO.,LTD + +OUI:380FE4* + ID_OUI_FROM_DATABASE=Dedicated Network Partners Oy + +OUI:847A88* + ID_OUI_FROM_DATABASE=HTC Corporation + +OUI:0808C2* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:5461EA* + ID_OUI_FROM_DATABASE=Zaplox AB + +OUI:78324F* + ID_OUI_FROM_DATABASE=Millennium Group, Inc. + +OUI:38B5BD* + ID_OUI_FROM_DATABASE=E.G.O. Elektro-Ger + +OUI:841715* + ID_OUI_FROM_DATABASE=GP Electronics (HK) Ltd. + +OUI:087999* + ID_OUI_FROM_DATABASE=AIM GmbH + +OUI:84C2E4* + ID_OUI_FROM_DATABASE=Jiangsu Qinheng Co., Ltd. + +OUI:C0B8B1* + ID_OUI_FROM_DATABASE=BitBox Ltd + +OUI:0C722C* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:B01408* + ID_OUI_FROM_DATABASE=LIGHTSPEED INTERNATIONAL CO. + +OUI:84ACA4* + ID_OUI_FROM_DATABASE=Beijing Novel Super Digital TV Technology Co., Ltd + +OUI:3C6FF7* + ID_OUI_FROM_DATABASE=EnTek Systems, Inc. + OUI:48B8DE* ID_OUI_FROM_DATABASE=HOMEWINS TECHNOLOGY CO.,LTD. @@ -34031,147 +35294,93 @@ OUI:547FA8* OUI:5474E6* ID_OUI_FROM_DATABASE=Webtech Wireless -OUI:AC5D10* - ID_OUI_FROM_DATABASE=Pace Americas - -OUI:88F490* - ID_OUI_FROM_DATABASE=Jetmobile Pte Ltd - OUI:E8A364* ID_OUI_FROM_DATABASE=Signal Path International / Peachtree Audio OUI:D0D6CC* ID_OUI_FROM_DATABASE=Wintop -OUI:101D51* - ID_OUI_FROM_DATABASE=ON-Q LLC dba ON-Q Mesh Networks +OUI:FC1F19* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS CO., LTD. -OUI:34C99D* - ID_OUI_FROM_DATABASE=EIDOLON COMMUNICATIONS TECHNOLOGY CO. LTD. +OUI:9C541C* + ID_OUI_FROM_DATABASE=Shenzhen My-power Technology Co.,Ltd -OUI:8C4AEE* - ID_OUI_FROM_DATABASE=GIGA TMS INC +OUI:90187C* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics co., LTD. -OUI:F46DE2* - ID_OUI_FROM_DATABASE=zte corporation +OUI:10F3DB* + ID_OUI_FROM_DATABASE=Gridco Systems, Inc. -OUI:04F8C2* - ID_OUI_FROM_DATABASE=Flaircomm Microelectronics, Inc. +OUI:B01203* + ID_OUI_FROM_DATABASE=Dynamics Hong Kong Limited -OUI:0C93FB* - ID_OUI_FROM_DATABASE=BNS Solutions +OUI:7093F8* + ID_OUI_FROM_DATABASE=Space Monkey, Inc. -OUI:38B5BD* - ID_OUI_FROM_DATABASE=E.G.O. Elektro-Ger +OUI:305D38* + ID_OUI_FROM_DATABASE=Beissbarth -OUI:B85AF7* - ID_OUI_FROM_DATABASE=Ouya, Inc +OUI:FCD6BD* + ID_OUI_FROM_DATABASE=Robert Bosch GmbH -OUI:E0D9A2* - ID_OUI_FROM_DATABASE=Hippih aps +OUI:044A50* + ID_OUI_FROM_DATABASE=Ramaxel Technology (Shenzhen) limited company -OUI:B0C4E7* +OUI:A4466B* + ID_OUI_FROM_DATABASE=EOC Technology + +OUI:7C386C* + ID_OUI_FROM_DATABASE=Real Time Logic + +OUI:D8AF3B* + ID_OUI_FROM_DATABASE=Hangzhou Bigbright Integrated communications system Co.,Ltd + +OUI:78D34F* + ID_OUI_FROM_DATABASE=Pace-O-Matic, Inc. + +OUI:D857EF* ID_OUI_FROM_DATABASE=Samsung Electronics -OUI:F0F669* - ID_OUI_FROM_DATABASE=Motion Analysis Corporation +OUI:647657* + ID_OUI_FROM_DATABASE=Innovative Security Designs -OUI:F0219D* - ID_OUI_FROM_DATABASE=Cal-Comp Electronics & Communications Company Ltd. +OUI:60455E* + ID_OUI_FROM_DATABASE=Liptel s.r.o. -OUI:F8D7BF* - ID_OUI_FROM_DATABASE=REV Ritter GmbH +OUI:944A09* + ID_OUI_FROM_DATABASE=BitWise Controls -OUI:00B56D* - ID_OUI_FROM_DATABASE=David Electronics Co., LTD. +OUI:E8102E* + ID_OUI_FROM_DATABASE=Really Simple Software, Inc -OUI:B461FF* - ID_OUI_FROM_DATABASE=Lumigon A/S - -OUI:9038DF* - ID_OUI_FROM_DATABASE=Changzhou Tiannengbo System Co. Ltd. - -OUI:CC593E* - ID_OUI_FROM_DATABASE=TOUMAZ LTD - -OUI:AC8D14* - ID_OUI_FROM_DATABASE=Smartrove Inc - -OUI:18673F* - ID_OUI_FROM_DATABASE=Hanover Displays Limited - -OUI:A00ABF* - ID_OUI_FROM_DATABASE=Wieson Technologies Co., Ltd. - -OUI:2091D9* - ID_OUI_FROM_DATABASE=I'M SPA - -OUI:744D79* - ID_OUI_FROM_DATABASE=Arrive Systems Inc. - -OUI:C83D97* - ID_OUI_FROM_DATABASE=Nokia Corporation - -OUI:38192F* - ID_OUI_FROM_DATABASE=Nokia Corporation - -OUI:141BF0* - ID_OUI_FROM_DATABASE=Intellimedia Systems Ltd - -OUI:E45614* - ID_OUI_FROM_DATABASE=Suttle Apparatus - -OUI:842BBC* - ID_OUI_FROM_DATABASE=Modelleisenbahn GmbH - -OUI:E856D6* - ID_OUI_FROM_DATABASE=NCTech Ltd - -OUI:4088E0* - ID_OUI_FROM_DATABASE=Beijing Ereneben Information Technology Limited Shenzhen Branch - -OUI:1CF4CA* - ID_OUI_FROM_DATABASE=Private - -OUI:F490EA* - ID_OUI_FROM_DATABASE=Deciso B.V. - -OUI:942197* - ID_OUI_FROM_DATABASE=Stalmart Technology Limited - -OUI:AC9403* - ID_OUI_FROM_DATABASE=Envision Peripherals Inc - -OUI:A865B2* - ID_OUI_FROM_DATABASE=DONGGUAN YISHANG ELECTRONIC TECHNOLOGY CO., LIMITED - -OUI:60B982* - ID_OUI_FROM_DATABASE=RO.VE.R. Laboratories S.p.A. - -OUI:B46238* - ID_OUI_FROM_DATABASE=Exablox - -OUI:40704A* - ID_OUI_FROM_DATABASE=Power Idea Technology Limited - -OUI:A40BED* - ID_OUI_FROM_DATABASE=Carry Technology Co.,Ltd - -OUI:0CD996* +OUI:D48CB5* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:D82DE1* - ID_OUI_FROM_DATABASE=Tricascade Inc. +OUI:24A43C* + ID_OUI_FROM_DATABASE=Ubiquiti Networks, INC -OUI:C438D3* - ID_OUI_FROM_DATABASE=TAGATEC CO.,LTD +OUI:D41E35* + ID_OUI_FROM_DATABASE=TOHO Electronics INC. + +OUI:700BC0* + ID_OUI_FROM_DATABASE=Dewav Technology Company + +OUI:3CF392* + ID_OUI_FROM_DATABASE=Virtualtek. Co. Ltd + +OUI:889676* + ID_OUI_FROM_DATABASE=TTC MARCONI s.r.o. + +OUI:149FE8* + ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. + +OUI:70B599* + ID_OUI_FROM_DATABASE=Embedded Technologies s.r.o. OUI:547398* ID_OUI_FROM_DATABASE=Toyo Electronics Corporation -OUI:4C72B9* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:E0AAB0* ID_OUI_FROM_DATABASE=GENERAL VISION ELECTRONICS CO. LTD. @@ -34187,14 +35396,11 @@ OUI:C041F6* OUI:985E1B* ID_OUI_FROM_DATABASE=ConversDigital Co., Ltd. -OUI:B8B7D7* - ID_OUI_FROM_DATABASE=2GIG Technologies +OUI:9C0DAC* + ID_OUI_FROM_DATABASE=Tymphany HK Limited -OUI:1048B1* - ID_OUI_FROM_DATABASE=Beijing Duokan Technology Limited - -OUI:005D03* - ID_OUI_FROM_DATABASE=Xilinx, Inc +OUI:8CD3A2* + ID_OUI_FROM_DATABASE=VisSim AS OUI:24EE3A* ID_OUI_FROM_DATABASE=Chengdu Yingji Electronic Hi-tech Co Ltd @@ -34232,96 +35438,6 @@ OUI:ACBD0B* OUI:D8D27C* ID_OUI_FROM_DATABASE=JEMA ENERGY, SA -OUI:10F3DB* - ID_OUI_FROM_DATABASE=Gridco Systems, Inc. - -OUI:B01203* - ID_OUI_FROM_DATABASE=Dynamics Hong Kong Limited - -OUI:7093F8* - ID_OUI_FROM_DATABASE=Space Monkey, Inc. - -OUI:305D38* - ID_OUI_FROM_DATABASE=Beissbarth - -OUI:FCD6BD* - ID_OUI_FROM_DATABASE=Robert Bosch GmbH - -OUI:044A50* - ID_OUI_FROM_DATABASE=Ramaxel Technology (Shenzhen) limited company - -OUI:E42F26* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - -OUI:A4466B* - ID_OUI_FROM_DATABASE=EOC Technology - -OUI:3CF392* - ID_OUI_FROM_DATABASE=Virtualtek. Co. Ltd - -OUI:889676* - ID_OUI_FROM_DATABASE=TTC MARCONI s.r.o. - -OUI:149FE8* - ID_OUI_FROM_DATABASE=Lenovo Mobile Communication Technology Ltd. - -OUI:70B599* - ID_OUI_FROM_DATABASE=Embedded Technologies s.r.o. - -OUI:EC4C4D* - ID_OUI_FROM_DATABASE=ZAO NPK RoTeK - -OUI:E8D483* - ID_OUI_FROM_DATABASE=ULTIMATE Europe Transportation Equipment GmbH - -OUI:089E01* - ID_OUI_FROM_DATABASE=QUANTA COMPUTER INC. - -OUI:ACD9D6* - ID_OUI_FROM_DATABASE=tci GmbH - -OUI:7493A4* - ID_OUI_FROM_DATABASE=Zebra Technologies Corp. - -OUI:9C0DAC* - ID_OUI_FROM_DATABASE=Tymphany HK Limited - -OUI:8CD3A2* - ID_OUI_FROM_DATABASE=VisSim AS - -OUI:647657* - ID_OUI_FROM_DATABASE=Innovative Security Designs - -OUI:60455E* - ID_OUI_FROM_DATABASE=Liptel s.r.o. - -OUI:944A09* - ID_OUI_FROM_DATABASE=BitWise Controls - -OUI:E8102E* - ID_OUI_FROM_DATABASE=Really Simple Software, Inc - -OUI:D48CB5* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:24A43C* - ID_OUI_FROM_DATABASE=Ubiquiti Networks, INC - -OUI:D41E35* - ID_OUI_FROM_DATABASE=TOHO Electronics INC. - -OUI:700BC0* - ID_OUI_FROM_DATABASE=Dewav Technology Company - -OUI:58C38B* - ID_OUI_FROM_DATABASE=Samsung Electronics - -OUI:2CD444* - ID_OUI_FROM_DATABASE=FUJITSU LIMITED - -OUI:EC1A59* - ID_OUI_FROM_DATABASE=Belkin International Inc. - OUI:60CBFB* ID_OUI_FROM_DATABASE=AirScape Inc. @@ -34340,18 +35456,48 @@ OUI:407074* OUI:58BFEA* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:7C386C* - ID_OUI_FROM_DATABASE=Real Time Logic +OUI:E856D6* + ID_OUI_FROM_DATABASE=NCTech Ltd -OUI:D8AF3B* - ID_OUI_FROM_DATABASE=Hangzhou Bigbright Integrated communications system Co.,Ltd +OUI:4088E0* + ID_OUI_FROM_DATABASE=Beijing Ereneben Information Technology Limited Shenzhen Branch -OUI:78D34F* - ID_OUI_FROM_DATABASE=Pace-O-Matic, Inc. +OUI:1CF4CA* + ID_OUI_FROM_DATABASE=Private -OUI:D857EF* +OUI:EC4C4D* + ID_OUI_FROM_DATABASE=ZAO NPK RoTeK + +OUI:E8D483* + ID_OUI_FROM_DATABASE=ULTIMATE Europe Transportation Equipment GmbH + +OUI:089E01* + ID_OUI_FROM_DATABASE=QUANTA COMPUTER INC. + +OUI:ACD9D6* + ID_OUI_FROM_DATABASE=tci GmbH + +OUI:7493A4* + ID_OUI_FROM_DATABASE=Zebra Technologies Corp. + +OUI:58C38B* ID_OUI_FROM_DATABASE=Samsung Electronics +OUI:2CD444* + ID_OUI_FROM_DATABASE=FUJITSU LIMITED + +OUI:EC1A59* + ID_OUI_FROM_DATABASE=Belkin International Inc. + +OUI:04F8C2* + ID_OUI_FROM_DATABASE=Flaircomm Microelectronics, Inc. + +OUI:0C93FB* + ID_OUI_FROM_DATABASE=BNS Solutions + +OUI:E45614* + ID_OUI_FROM_DATABASE=Suttle Apparatus + OUI:784405* ID_OUI_FROM_DATABASE=FUJITU(HONG KONG) ELECTRONIC Co.,LTD. @@ -34361,15 +35507,54 @@ OUI:C03F2A* OUI:5001BB* ID_OUI_FROM_DATABASE=Samsung Electronics -OUI:F0FDA0* - ID_OUI_FROM_DATABASE=Acurix Networks LP +OUI:A40BED* + ID_OUI_FROM_DATABASE=Carry Technology Co.,Ltd + +OUI:0CD996* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:D82DE1* + ID_OUI_FROM_DATABASE=Tricascade Inc. + +OUI:C438D3* + ID_OUI_FROM_DATABASE=TAGATEC CO.,LTD + +OUI:842BBC* + ID_OUI_FROM_DATABASE=Modelleisenbahn GmbH + +OUI:B8B7D7* + ID_OUI_FROM_DATABASE=2GIG Technologies + +OUI:1048B1* + ID_OUI_FROM_DATABASE=Beijing Duokan Technology Limited + +OUI:005D03* + ID_OUI_FROM_DATABASE=Xilinx, Inc + +OUI:20FABB* + ID_OUI_FROM_DATABASE=Cambridge Executive Limited + +OUI:1C0B52* + ID_OUI_FROM_DATABASE=EPICOM S.A + +OUI:747E2D* + ID_OUI_FROM_DATABASE=Beijing Thomson CITIC Digital Technology Co. LTD. + +OUI:E80C75* + ID_OUI_FROM_DATABASE=Syncbak, Inc. + +OUI:BC8B55* + ID_OUI_FROM_DATABASE=NPP ELIKS America Inc. DBA T&M Atlantic + +OUI:D8EB97* + ID_OUI_FROM_DATABASE=TRENDnet, Inc. + +OUI:202598* + ID_OUI_FROM_DATABASE=Teleview OUI:44B382* ID_OUI_FROM_DATABASE=Kuang-chi Institute of Advanced Technology -OUI:344B3D* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:D80DE3* ID_OUI_FROM_DATABASE=FXI TECHNOLOGIES AS @@ -34382,66 +35567,6 @@ OUI:0CC0C0* OUI:AC40EA* ID_OUI_FROM_DATABASE=C&T Solution Inc. -OUI:BC8B55* - ID_OUI_FROM_DATABASE=NPP ELIKS America Inc. DBA T&M Atlantic - -OUI:D8EB97* - ID_OUI_FROM_DATABASE=TRENDnet, Inc. - -OUI:202598* - ID_OUI_FROM_DATABASE=Teleview - -OUI:844915* - ID_OUI_FROM_DATABASE=vArmour Networks, Inc. - -OUI:A04CC1* - ID_OUI_FROM_DATABASE=Helixtech Corp. - -OUI:1CB243* - ID_OUI_FROM_DATABASE=TDC A/S - -OUI:1C51B5* - ID_OUI_FROM_DATABASE=Techaya LTD - -OUI:80DB31* - ID_OUI_FROM_DATABASE=Power Quotient International Co., Ltd. - -OUI:AC0142* - ID_OUI_FROM_DATABASE=Uriel Technologies SIA - -OUI:A007B6* - ID_OUI_FROM_DATABASE=Advanced Technical Support, Inc. - -OUI:542A9C* - ID_OUI_FROM_DATABASE=LSY Defense, LLC. - -OUI:D487D8* - ID_OUI_FROM_DATABASE=Samsung Electronics - -OUI:F89955* - ID_OUI_FROM_DATABASE=Fortress Technology Inc - -OUI:B827EB* - ID_OUI_FROM_DATABASE=Raspberry Pi Foundation - -OUI:E88DF5* - ID_OUI_FROM_DATABASE=ZNYX Networks, Inc. - -OUI:48EA63* - ID_OUI_FROM_DATABASE=Zhejiang Uniview Technologies Co., Ltd. - -OUI:0CE5D3* - ID_OUI_FROM_DATABASE=DH electronics GmbH - -OUI:C47130* - ID_OUI_FROM_DATABASE=Fon Technology S.L. - -OUI:90CF7D* - ID_OUI_FROM_DATABASE=Qingdao Hisense Electric Co.,Ltd. - -OUI:48D7FF* - ID_OUI_FROM_DATABASE=BLANKOM Antennentechnik GmbH - OUI:F47F35* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -34466,35 +35591,20 @@ OUI:5C0A5B* OUI:6CA96F* ID_OUI_FROM_DATABASE=TransPacket AS -OUI:48ED80* - ID_OUI_FROM_DATABASE=daesung eltec +OUI:AC0142* + ID_OUI_FROM_DATABASE=Uriel Technologies SIA -OUI:A086EC* - ID_OUI_FROM_DATABASE=SAEHAN HITEC Co., Ltd +OUI:A007B6* + ID_OUI_FROM_DATABASE=Advanced Technical Support, Inc. -OUI:BC4B79* - ID_OUI_FROM_DATABASE=SensingTek +OUI:542A9C* + ID_OUI_FROM_DATABASE=LSY Defense, LLC. -OUI:2818FD* - ID_OUI_FROM_DATABASE=Aditya Infotech Ltd. +OUI:D487D8* + ID_OUI_FROM_DATABASE=Samsung Electronics -OUI:9003B7* - ID_OUI_FROM_DATABASE=PARROT - -OUI:E42C56* - ID_OUI_FROM_DATABASE=Lilee Systems, Ltd. - -OUI:50008C* - ID_OUI_FROM_DATABASE=Hong Kong Telecommunications (HKT) Limited - -OUI:DCA8CF* - ID_OUI_FROM_DATABASE=New Spin Golf, LLC. - -OUI:34BA9A* - ID_OUI_FROM_DATABASE=Asiatelco Technologies Co. - -OUI:642DB7* - ID_OUI_FROM_DATABASE=SEUNGIL ELECTRONICS +OUI:F89955* + ID_OUI_FROM_DATABASE=Fortress Technology Inc OUI:008DDA* ID_OUI_FROM_DATABASE=Link One Co., Ltd. @@ -34520,53 +35630,29 @@ OUI:F48E09* OUI:882012* ID_OUI_FROM_DATABASE=LMI Technologies -OUI:D443A8* - ID_OUI_FROM_DATABASE=Changzhou Haojie Electric Co., Ltd. - -OUI:BCB852* - ID_OUI_FROM_DATABASE=Cybera, Inc. - -OUI:70D6B6* - ID_OUI_FROM_DATABASE=Metrum Technologies - -OUI:28D576* - ID_OUI_FROM_DATABASE=Premier Wireless, Inc. - -OUI:6CE907* - ID_OUI_FROM_DATABASE=Nokia Corporation - -OUI:94DF58* - ID_OUI_FROM_DATABASE=IJ Electron CO.,Ltd. - -OUI:8C0CA3* - ID_OUI_FROM_DATABASE=Amper - -OUI:28940F* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:5CEB4E* - ID_OUI_FROM_DATABASE=R. STAHL HMI Systems GmbH - -OUI:B8DAF7* - ID_OUI_FROM_DATABASE=Advanced Photonics, Inc. - -OUI:2C36A0* - ID_OUI_FROM_DATABASE=Capisco Limited - OUI:800A06* ID_OUI_FROM_DATABASE=COMTEC co.,ltd -OUI:20FABB* - ID_OUI_FROM_DATABASE=Cambridge Executive Limited +OUI:B827EB* + ID_OUI_FROM_DATABASE=Raspberry Pi Foundation -OUI:1C0B52* - ID_OUI_FROM_DATABASE=EPICOM S.A +OUI:E88DF5* + ID_OUI_FROM_DATABASE=ZNYX Networks, Inc. -OUI:747E2D* - ID_OUI_FROM_DATABASE=Beijing Thomson CITIC Digital Technology Co. LTD. +OUI:48EA63* + ID_OUI_FROM_DATABASE=Zhejiang Uniview Technologies Co., Ltd. -OUI:E80C75* - ID_OUI_FROM_DATABASE=Syncbak, Inc. +OUI:0CE5D3* + ID_OUI_FROM_DATABASE=DH electronics GmbH + +OUI:C47130* + ID_OUI_FROM_DATABASE=Fon Technology S.L. + +OUI:90CF7D* + ID_OUI_FROM_DATABASE=Qingdao Hisense Electric Co.,Ltd. + +OUI:48D7FF* + ID_OUI_FROM_DATABASE=BLANKOM Antennentechnik GmbH OUI:18D66A* ID_OUI_FROM_DATABASE=Inmarsat @@ -34574,6 +35660,78 @@ OUI:18D66A* OUI:C85645* ID_OUI_FROM_DATABASE=Intermas France +OUI:F490EA* + ID_OUI_FROM_DATABASE=Deciso B.V. + +OUI:942197* + ID_OUI_FROM_DATABASE=Stalmart Technology Limited + +OUI:AC9403* + ID_OUI_FROM_DATABASE=Envision Peripherals Inc + +OUI:A865B2* + ID_OUI_FROM_DATABASE=DONGGUAN YISHANG ELECTRONIC TECHNOLOGY CO., LIMITED + +OUI:60B982* + ID_OUI_FROM_DATABASE=RO.VE.R. Laboratories S.p.A. + +OUI:B46238* + ID_OUI_FROM_DATABASE=Exablox + +OUI:40704A* + ID_OUI_FROM_DATABASE=Power Idea Technology Limited + +OUI:F0FDA0* + ID_OUI_FROM_DATABASE=Acurix Networks LP + +OUI:D8BF4C* + ID_OUI_FROM_DATABASE=Victory Concept Electronics Limited + +OUI:C0DF77* + ID_OUI_FROM_DATABASE=Conrad Electronic SE + +OUI:C86000* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:645299* + ID_OUI_FROM_DATABASE=The Chamberlain Group, Inc + +OUI:BC125E* + ID_OUI_FROM_DATABASE=Beijing WisVideo INC. + +OUI:C80718* + ID_OUI_FROM_DATABASE=TDSi + +OUI:48ED80* + ID_OUI_FROM_DATABASE=daesung eltec + +OUI:A086EC* + ID_OUI_FROM_DATABASE=SAEHAN HITEC Co., Ltd + +OUI:BC4B79* + ID_OUI_FROM_DATABASE=SensingTek + +OUI:2818FD* + ID_OUI_FROM_DATABASE=Aditya Infotech Ltd. + +OUI:9003B7* + ID_OUI_FROM_DATABASE=PARROT + +OUI:844915* + ID_OUI_FROM_DATABASE=vArmour Networks, Inc. + +OUI:A04CC1* + ID_OUI_FROM_DATABASE=Helixtech Corp. + +OUI:1CB243* + ID_OUI_FROM_DATABASE=TDC A/S + +OUI:1C51B5* + ID_OUI_FROM_DATABASE=Techaya LTD + +OUI:80DB31* + ID_OUI_FROM_DATABASE=Power Quotient International Co., Ltd. + OUI:8C604F* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -34595,23 +35753,26 @@ OUI:34FC6F* OUI:C0B357* ID_OUI_FROM_DATABASE=Yoshiki Electronics Industry Ltd. -OUI:D8BF4C* - ID_OUI_FROM_DATABASE=Victory Concept Electronics Limited +OUI:642DB7* + ID_OUI_FROM_DATABASE=SEUNGIL ELECTRONICS -OUI:C0DF77* - ID_OUI_FROM_DATABASE=Conrad Electronic SE +OUI:A898C6* + ID_OUI_FROM_DATABASE=Shinbo Co., Ltd. -OUI:C86000* - ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. +OUI:006BA0* + ID_OUI_FROM_DATABASE=SHENZHEN UNIVERSAL INTELLISYS PTE LTD -OUI:645299* - ID_OUI_FROM_DATABASE=The Chamberlain Group, Inc +OUI:502690* + ID_OUI_FROM_DATABASE=FUJITSU LIMITED -OUI:BC125E* - ID_OUI_FROM_DATABASE=Beijing WisVideo INC. +OUI:B4211D* + ID_OUI_FROM_DATABASE=Beijing GuangXin Technology Co., Ltd -OUI:C80718* - ID_OUI_FROM_DATABASE=TDSi +OUI:E039D7* + ID_OUI_FROM_DATABASE=Plexxi, Inc. + +OUI:FC946C* + ID_OUI_FROM_DATABASE=UBIVELOX OUI:B4944E* ID_OUI_FROM_DATABASE=WeTelecom Co., Ltd. @@ -34625,41 +35786,71 @@ OUI:988BAD* OUI:4050E0* ID_OUI_FROM_DATABASE=Milton Security Group LLC +OUI:E42C56* + ID_OUI_FROM_DATABASE=Lilee Systems, Ltd. + +OUI:50008C* + ID_OUI_FROM_DATABASE=Hong Kong Telecommunications (HKT) Limited + +OUI:DCA8CF* + ID_OUI_FROM_DATABASE=New Spin Golf, LLC. + +OUI:34BA9A* + ID_OUI_FROM_DATABASE=Asiatelco Technologies Co. + +OUI:D443A8* + ID_OUI_FROM_DATABASE=Changzhou Haojie Electric Co., Ltd. + +OUI:BCB852* + ID_OUI_FROM_DATABASE=Cybera, Inc. + +OUI:70D6B6* + ID_OUI_FROM_DATABASE=Metrum Technologies + +OUI:28D576* + ID_OUI_FROM_DATABASE=Premier Wireless, Inc. + OUI:C87CBC* ID_OUI_FROM_DATABASE=Valink Co., Ltd. OUI:409FC7* ID_OUI_FROM_DATABASE=BAEKCHUN I&C Co., Ltd. -OUI:D4E33F* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:C87D77* ID_OUI_FROM_DATABASE=Shenzhen Kingtech Communication Equipment Co.,Ltd OUI:A078BA* ID_OUI_FROM_DATABASE=Pantech Co., Ltd. -OUI:D4507A* - ID_OUI_FROM_DATABASE=CEIVA Logic, Inc +OUI:20BBC6* + ID_OUI_FROM_DATABASE=Jabil Circuit Hungary Ltd. -OUI:184617* - ID_OUI_FROM_DATABASE=Samsung Electronics +OUI:2C9717* + ID_OUI_FROM_DATABASE=I.C.Y. B.V. -OUI:9CC7D1* - ID_OUI_FROM_DATABASE=SHARP Corporation +OUI:64E84F* + ID_OUI_FROM_DATABASE=Serialway Communication Technology Co. Ltd -OUI:AC9CE4* - ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd +OUI:6CE907* + ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:00B9F6* - ID_OUI_FROM_DATABASE=Shenzhen Super Rich Electronics Co.,Ltd +OUI:94DF58* + ID_OUI_FROM_DATABASE=IJ Electron CO.,Ltd. -OUI:9C5C8D* - ID_OUI_FROM_DATABASE=FIREMAX INDÚSTRIA E COMÉRCIO DE PRODUTOS ELETRÔNICOS LTDA +OUI:8C0CA3* + ID_OUI_FROM_DATABASE=Amper -OUI:E01E07* - ID_OUI_FROM_DATABASE=Anite Telecoms US. Inc +OUI:28940F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:5CEB4E* + ID_OUI_FROM_DATABASE=R. STAHL HMI Systems GmbH + +OUI:B8DAF7* + ID_OUI_FROM_DATABASE=Advanced Photonics, Inc. + +OUI:2C36A0* + ID_OUI_FROM_DATABASE=Capisco Limited OUI:B06CBF* ID_OUI_FROM_DATABASE=3ality Digital Systems GmbH @@ -34688,6 +35879,42 @@ OUI:70704C* OUI:F47ACC* ID_OUI_FROM_DATABASE=SolidFire, Inc. +OUI:F8D3A9* + ID_OUI_FROM_DATABASE=AXAN Networks + +OUI:5CD4AB* + ID_OUI_FROM_DATABASE=Zektor + +OUI:F8462D* + ID_OUI_FROM_DATABASE=SYNTEC Incorporation + +OUI:58677F* + ID_OUI_FROM_DATABASE=Clare Controls Inc. + +OUI:CCA374* + ID_OUI_FROM_DATABASE=Guangdong Guanglian Electronic Technology Co.Ltd + +OUI:50F61A* + ID_OUI_FROM_DATABASE=Kunshan JADE Technologies co., Ltd. + +OUI:941D1C* + ID_OUI_FROM_DATABASE=TLab West Systems AB + +OUI:40667A* + ID_OUI_FROM_DATABASE=mediola - connected living AG + +OUI:64808B* + ID_OUI_FROM_DATABASE=VG Controls, Inc. + +OUI:7C6B52* + ID_OUI_FROM_DATABASE=Tigaro Wireless + +OUI:48C1AC* + ID_OUI_FROM_DATABASE=PLANTRONICS, INC. + +OUI:D826B9* + ID_OUI_FROM_DATABASE=Guangdong Coagent Electronics S &T Co., Ltd. + OUI:24BC82* ID_OUI_FROM_DATABASE=Dali Wireless, Inc. @@ -34706,6 +35933,21 @@ OUI:C4237A* OUI:8430E5* ID_OUI_FROM_DATABASE=SkyHawke Technologies, LLC +OUI:046D42* + ID_OUI_FROM_DATABASE=Bryston Ltd. + +OUI:50CCF8* + ID_OUI_FROM_DATABASE=Samsung Electro Mechanics + +OUI:D0CF5E* + ID_OUI_FROM_DATABASE=Energy Micro AS + +OUI:644D70* + ID_OUI_FROM_DATABASE=dSPACE GmbH + +OUI:807693* + ID_OUI_FROM_DATABASE=Newag SA + OUI:2C002C* ID_OUI_FROM_DATABASE=UNOWHY @@ -34715,23 +35957,50 @@ OUI:0481AE* OUI:C09132* ID_OUI_FROM_DATABASE=Patriot Memory -OUI:A898C6* - ID_OUI_FROM_DATABASE=Shinbo Co., Ltd. +OUI:AC81F3* + ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:006BA0* - ID_OUI_FROM_DATABASE=SHENZHEN UNIVERSAL INTELLISYS PTE LTD +OUI:94C6EB* + ID_OUI_FROM_DATABASE=NOVA electronics, Inc. -OUI:502690* - ID_OUI_FROM_DATABASE=FUJITSU LIMITED +OUI:10F9EE* + ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:B4211D* - ID_OUI_FROM_DATABASE=Beijing GuangXin Technology Co., Ltd +OUI:80971B* + ID_OUI_FROM_DATABASE=Altenergy Power System,Inc. -OUI:E039D7* - ID_OUI_FROM_DATABASE=Plexxi, Inc. +OUI:1071F9* + ID_OUI_FROM_DATABASE=Cloud Telecomputers, LLC -OUI:FC946C* - ID_OUI_FROM_DATABASE=UBIVELOX +OUI:B8B42E* + ID_OUI_FROM_DATABASE=Gionee Communication Equipment Co,Ltd.ShenZhen + +OUI:A84041* + ID_OUI_FROM_DATABASE=Dragino Technology Co., Limited + +OUI:DCF05D* + ID_OUI_FROM_DATABASE=Letta Teknoloji + +OUI:D05A0F* + ID_OUI_FROM_DATABASE=I-BT DIGITAL CO.,LTD + +OUI:FC2E2D* + ID_OUI_FROM_DATABASE=Lorom Industrial Co.LTD. + +OUI:E84E06* + ID_OUI_FROM_DATABASE=EDUP INTERNATIONAL (HK) CO., LTD + +OUI:B4C799* + ID_OUI_FROM_DATABASE=Zebra Technologies Inc + +OUI:70B921* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:C47B2F* + ID_OUI_FROM_DATABASE=Beijing JoinHope Image Technology Ltd. + +OUI:18F650* + ID_OUI_FROM_DATABASE=Multimedia Pacific Limited OUI:38DE60* ID_OUI_FROM_DATABASE=Mohlenhoff GmbH @@ -34754,65 +36023,56 @@ OUI:18C451* OUI:582EFE* ID_OUI_FROM_DATABASE=Lighting Science Group -OUI:D826B9* - ID_OUI_FROM_DATABASE=Guangdong Coagent Electronics S &T Co., Ltd. +OUI:D4507A* + ID_OUI_FROM_DATABASE=CEIVA Logic, Inc -OUI:F8D3A9* - ID_OUI_FROM_DATABASE=AXAN Networks +OUI:184617* + ID_OUI_FROM_DATABASE=Samsung Electronics -OUI:5CD4AB* - ID_OUI_FROM_DATABASE=Zektor +OUI:9CC7D1* + ID_OUI_FROM_DATABASE=SHARP Corporation -OUI:F8462D* - ID_OUI_FROM_DATABASE=SYNTEC Incorporation +OUI:AC9CE4* + ID_OUI_FROM_DATABASE=Alcatel-Lucent Shanghai Bell Co., Ltd -OUI:58677F* - ID_OUI_FROM_DATABASE=Clare Controls Inc. +OUI:00B9F6* + ID_OUI_FROM_DATABASE=Shenzhen Super Rich Electronics Co.,Ltd -OUI:CCA374* - ID_OUI_FROM_DATABASE=Guangdong Guanglian Electronic Technology Co.Ltd +OUI:9C5C8D* + ID_OUI_FROM_DATABASE=FIREMAX INDÚSTRIA E COMÉRCIO DE PRODUTOS ELETRÔNICOS LTDA -OUI:50F61A* - ID_OUI_FROM_DATABASE=Kunshan JADE Technologies co., Ltd. +OUI:E01E07* + ID_OUI_FROM_DATABASE=Anite Telecoms US. Inc -OUI:20BBC6* - ID_OUI_FROM_DATABASE=Jabil Circuit Hungary Ltd. +OUI:64D989* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:2C9717* - ID_OUI_FROM_DATABASE=I.C.Y. B.V. +OUI:44D3CA* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:64E84F* - ID_OUI_FROM_DATABASE=Serialway Communication Technology Co. Ltd +OUI:24DAB6* + ID_OUI_FROM_DATABASE=Sistemas de Gestión Energética S.A. de C.V -OUI:941D1C* - ID_OUI_FROM_DATABASE=TLab West Systems AB +OUI:B8F5E7* + ID_OUI_FROM_DATABASE=WayTools, LLC -OUI:40667A* - ID_OUI_FROM_DATABASE=mediola - connected living AG - -OUI:64808B* - ID_OUI_FROM_DATABASE=VG Controls, Inc. - -OUI:7C6B52* - ID_OUI_FROM_DATABASE=Tigaro Wireless - -OUI:48C1AC* - ID_OUI_FROM_DATABASE=PLANTRONICS, INC. - -OUI:046D42* - ID_OUI_FROM_DATABASE=Bryston Ltd. - -OUI:50CCF8* +OUI:980C82* ID_OUI_FROM_DATABASE=Samsung Electro Mechanics -OUI:D0CF5E* - ID_OUI_FROM_DATABASE=Energy Micro AS +OUI:148A70* + ID_OUI_FROM_DATABASE=ADS GmbH -OUI:644D70* - ID_OUI_FROM_DATABASE=dSPACE GmbH +OUI:FC0012* + ID_OUI_FROM_DATABASE=Toshiba Samsung Storage Technolgoy Korea Corporation -OUI:807693* - ID_OUI_FROM_DATABASE=Newag SA +OUI:F44450* + ID_OUI_FROM_DATABASE=BND Co., Ltd. + +OUI:644346* + ID_OUI_FROM_DATABASE=GuangDong Quick Network Computer CO.,LTD + +OUI:FCE892* + ID_OUI_FROM_DATABASE=Hangzhou Lancable Technology Co.,Ltd OUI:FC1794* ID_OUI_FROM_DATABASE=InterCreative Co., Ltd @@ -34823,26 +36083,11 @@ OUI:181420* OUI:D03110* ID_OUI_FROM_DATABASE=Ingenic Semiconductor Co.,Ltd -OUI:AC81F3* - ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:48C862* + ID_OUI_FROM_DATABASE=Simo Wireless,Inc. -OUI:94C6EB* - ID_OUI_FROM_DATABASE=NOVA electronics, Inc. - -OUI:10F9EE* - ID_OUI_FROM_DATABASE=Nokia Corporation - -OUI:80971B* - ID_OUI_FROM_DATABASE=Altenergy Power System,Inc. - -OUI:1071F9* - ID_OUI_FROM_DATABASE=Cloud Telecomputers, LLC - -OUI:C47B2F* - ID_OUI_FROM_DATABASE=Beijing JoinHope Image Technology Ltd. - -OUI:18F650* - ID_OUI_FROM_DATABASE=Multimedia Pacific Limited +OUI:3C26D5* + ID_OUI_FROM_DATABASE=Sotera Wireless OUI:704AAE* ID_OUI_FROM_DATABASE=Xstream Flow (Pty) Ltd @@ -34850,47 +36095,98 @@ OUI:704AAE* OUI:9C934E* ID_OUI_FROM_DATABASE=Xerox Corporation -OUI:3C26D5* - ID_OUI_FROM_DATABASE=Sotera Wireless +OUI:9439E5* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. -OUI:FC2E2D* - ID_OUI_FROM_DATABASE=Lorom Industrial Co.LTD. +OUI:7CDD20* + ID_OUI_FROM_DATABASE=IOXOS Technologies S.A. -OUI:E84E06* - ID_OUI_FROM_DATABASE=EDUP INTERNATIONAL (HK) CO., LTD +OUI:A0E9DB* + ID_OUI_FROM_DATABASE=Ningbo FreeWings Technologies Co.,Ltd -OUI:B4C799* - ID_OUI_FROM_DATABASE=Zebra Technologies Inc +OUI:9C7BD2* + ID_OUI_FROM_DATABASE=NEOLAB Convergence -OUI:70B921* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD +OUI:900D66* + ID_OUI_FROM_DATABASE=Digimore Electronics Co., Ltd -OUI:948FEE* - ID_OUI_FROM_DATABASE=Hughes Telematics, Inc. +OUI:BC35E5* + ID_OUI_FROM_DATABASE=Hydro Systems Company -OUI:E8C320* - ID_OUI_FROM_DATABASE=Austco Communication Systems Pty Ltd +OUI:283410* + ID_OUI_FROM_DATABASE=Enigma Diagnostics Limited -OUI:D8973B* - ID_OUI_FROM_DATABASE=Artesyn Embedded Technologies +OUI:28CCFF* + ID_OUI_FROM_DATABASE=Corporacion Empresarial Altra SL -OUI:008D4E* - ID_OUI_FROM_DATABASE=CJSC NII STT +OUI:14B73D* + ID_OUI_FROM_DATABASE=ARCHEAN Technologies -OUI:10C586* - ID_OUI_FROM_DATABASE=BIO SOUND LAB CO., LTD. +OUI:A433D1* + ID_OUI_FROM_DATABASE=Fibrlink Communications Co.,Ltd. -OUI:E8BA70* +OUI:84DE3D* + ID_OUI_FROM_DATABASE=Crystal Vision Ltd + +OUI:F87B8C* + ID_OUI_FROM_DATABASE=Amped Wireless + +OUI:44D2CA* + ID_OUI_FROM_DATABASE=Anvia TV Oy + +OUI:4C1A3A* + ID_OUI_FROM_DATABASE=PRIMA Research And Production Enterprise Ltd. + +OUI:AC0613* + ID_OUI_FROM_DATABASE=Senselogix Ltd + +OUI:B4AA4D* + ID_OUI_FROM_DATABASE=Ensequence, Inc. + +OUI:040A83* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:B42A39* + ID_OUI_FROM_DATABASE=ORBIT MERRET, spol. s r. o. + +OUI:B80B9D* + ID_OUI_FROM_DATABASE=ROPEX Industrie-Elektronik GmbH + +OUI:18AEBB* + ID_OUI_FROM_DATABASE=Siemens Convergence Creators GmbH&Co.KG + +OUI:3891FB* + ID_OUI_FROM_DATABASE=Xenox Holding BV + +OUI:50FAAB* + ID_OUI_FROM_DATABASE=L-tek d.o.o. + +OUI:A8E018* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:44AAE8* + ID_OUI_FROM_DATABASE=Nanotec Electronic GmbH & Co. KG + +OUI:D8DF0D* + ID_OUI_FROM_DATABASE=beroNet GmbH + +OUI:D8C068* + ID_OUI_FROM_DATABASE=Netgenetech.co.,ltd. + +OUI:3C9157* + ID_OUI_FROM_DATABASE=Hangzhou Yulong Conmunication Co.,Ltd + +OUI:50E549* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:A8FCB7* + ID_OUI_FROM_DATABASE=Consolidated Resource Imaging + +OUI:6400F1* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:6473E2* - ID_OUI_FROM_DATABASE=Arbiter Systems, Inc. - -OUI:00A1DE* - ID_OUI_FROM_DATABASE=ShenZhen ShiHua Technology CO.,LTD - -OUI:04E1C8* - ID_OUI_FROM_DATABASE=IMS Soluções em Energia Ltda. +OUI:04C5A4* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc OUI:E4DD79* ID_OUI_FROM_DATABASE=En-Vision America, Inc. @@ -34916,185 +36212,14 @@ OUI:CCB55A* OUI:587521* ID_OUI_FROM_DATABASE=CJSC RTSoft -OUI:64D989* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:948FEE* + ID_OUI_FROM_DATABASE=Hughes Telematics, Inc. -OUI:44D3CA* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:E8C320* + ID_OUI_FROM_DATABASE=Austco Communication Systems Pty Ltd -OUI:24DAB6* - ID_OUI_FROM_DATABASE=Sistemas de Gestión Energética S.A. de C.V - -OUI:B8F5E7* - ID_OUI_FROM_DATABASE=WayTools, LLC - -OUI:148A70* - ID_OUI_FROM_DATABASE=ADS GmbH - -OUI:FC0012* - ID_OUI_FROM_DATABASE=Toshiba Samsung Storage Technolgoy Korea Corporation - -OUI:F44450* - ID_OUI_FROM_DATABASE=BND Co., Ltd. - -OUI:644346* - ID_OUI_FROM_DATABASE=GuangDong Quick Network Computer CO.,LTD - -OUI:FCE892* - ID_OUI_FROM_DATABASE=Hangzhou Lancable Technology Co.,Ltd - -OUI:B8B42E* - ID_OUI_FROM_DATABASE=Gionee Communication Equipment Co,Ltd.ShenZhen - -OUI:A84041* - ID_OUI_FROM_DATABASE=Dragino Technology Co., Limited - -OUI:686E23* - ID_OUI_FROM_DATABASE=Wi3 Inc. - -OUI:DCF05D* - ID_OUI_FROM_DATABASE=Letta Teknoloji - -OUI:D05A0F* - ID_OUI_FROM_DATABASE=I-BT DIGITAL CO.,LTD - -OUI:9439E5* - ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. - -OUI:7CDD20* - ID_OUI_FROM_DATABASE=IOXOS Technologies S.A. - -OUI:A0E9DB* - ID_OUI_FROM_DATABASE=Ningbo FreeWings Technologies Co.,Ltd - -OUI:9C7BD2* - ID_OUI_FROM_DATABASE=NEOLAB Convergence - -OUI:900D66* - ID_OUI_FROM_DATABASE=Digimore Electronics Co., Ltd - -OUI:980C82* - ID_OUI_FROM_DATABASE=Samsung Electro Mechanics - -OUI:48C862* - ID_OUI_FROM_DATABASE=Simo Wireless,Inc. - -OUI:0CF3EE* - ID_OUI_FROM_DATABASE=EM Microelectronic - -OUI:F0C27C* - ID_OUI_FROM_DATABASE=Mianyang Netop Telecom Equipment Co.,Ltd. - -OUI:BC35E5* - ID_OUI_FROM_DATABASE=Hydro Systems Company - -OUI:283410* - ID_OUI_FROM_DATABASE=Enigma Diagnostics Limited - -OUI:28CCFF* - ID_OUI_FROM_DATABASE=Corporacion Empresarial Altra SL - -OUI:14B73D* - ID_OUI_FROM_DATABASE=ARCHEAN Technologies - -OUI:A433D1* - ID_OUI_FROM_DATABASE=Fibrlink Communications Co.,Ltd. - -OUI:84DE3D* - ID_OUI_FROM_DATABASE=Crystal Vision Ltd - -OUI:B4AA4D* - ID_OUI_FROM_DATABASE=Ensequence, Inc. - -OUI:040A83* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - -OUI:B42A39* - ID_OUI_FROM_DATABASE=ORBIT MERRET, spol. s r. o. - -OUI:B80B9D* - ID_OUI_FROM_DATABASE=ROPEX Industrie-Elektronik GmbH - -OUI:18AEBB* - ID_OUI_FROM_DATABASE=Siemens Convergence Creators GmbH&Co.KG - -OUI:3891FB* - ID_OUI_FROM_DATABASE=Xenox Holding BV - -OUI:50FAAB* - ID_OUI_FROM_DATABASE=L-tek d.o.o. - -OUI:547F54* - ID_OUI_FROM_DATABASE=INGENICO - -OUI:A8E018* - ID_OUI_FROM_DATABASE=Nokia Corporation - -OUI:44AAE8* - ID_OUI_FROM_DATABASE=Nanotec Electronic GmbH & Co. KG - -OUI:D8DF0D* - ID_OUI_FROM_DATABASE=beroNet GmbH - -OUI:D8C068* - ID_OUI_FROM_DATABASE=Netgenetech.co.,ltd. - -OUI:3C9157* - ID_OUI_FROM_DATABASE=Hangzhou Yulong Conmunication Co.,Ltd - -OUI:50E549* - ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. - -OUI:A8FCB7* - ID_OUI_FROM_DATABASE=Consolidated Resource Imaging - -OUI:F87B8C* - ID_OUI_FROM_DATABASE=Amped Wireless - -OUI:44D2CA* - ID_OUI_FROM_DATABASE=Anvia TV Oy - -OUI:4C1A3A* - ID_OUI_FROM_DATABASE=PRIMA Research And Production Enterprise Ltd. - -OUI:AC0613* - ID_OUI_FROM_DATABASE=Senselogix Ltd - -OUI:CCF67A* - ID_OUI_FROM_DATABASE=Ayecka Communication Systems LTD - -OUI:200A5E* - ID_OUI_FROM_DATABASE=Xiangshan Giant Eagle Technology Developing co.,LTD - -OUI:747818* - ID_OUI_FROM_DATABASE=ServiceAssure - -OUI:00BB8E* - ID_OUI_FROM_DATABASE=HME Co., Ltd. - -OUI:C0A26D* - ID_OUI_FROM_DATABASE=Abbott Point of Care - -OUI:205B2A* - ID_OUI_FROM_DATABASE=Private - -OUI:18B430* - ID_OUI_FROM_DATABASE=Nest Labs Inc. - -OUI:F8769B* - ID_OUI_FROM_DATABASE=Neopis Co., Ltd. - -OUI:08E672* - ID_OUI_FROM_DATABASE=JEBSEE ELECTRONICS CO.,LTD. - -OUI:C89CDC* - ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM CO., LTD. - -OUI:58E476* - ID_OUI_FROM_DATABASE=CENTRON COMMUNICATIONS TECHNOLOGIES FUJIAN CO.,LTD - -OUI:B435F7* - ID_OUI_FROM_DATABASE=Zhejiang Pearmain Electronics Co.ltd. +OUI:D8973B* + ID_OUI_FROM_DATABASE=Artesyn Embedded Technologies OUI:0C6E4F* ID_OUI_FROM_DATABASE=PrimeVOLT Co., Ltd. @@ -35114,6 +36239,33 @@ OUI:CC5D4E* OUI:D0EB9E* ID_OUI_FROM_DATABASE=Seowoo Inc. +OUI:BC99BC* + ID_OUI_FROM_DATABASE=FonSee Technology Inc. + +OUI:986022* + ID_OUI_FROM_DATABASE=EMW Co., Ltd. + +OUI:80B32A* + ID_OUI_FROM_DATABASE=Alstom Grid + +OUI:803457* + ID_OUI_FROM_DATABASE=OT Systems Limited + +OUI:B83D4E* + ID_OUI_FROM_DATABASE=Shenzhen Cultraview Digital Technology Co.,Ltd Shanghai Branch + +OUI:3CA72B* + ID_OUI_FROM_DATABASE=MRV Communications (Networks) LTD + +OUI:EC55F9* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:F4D9FB* + ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD + +OUI:584C19* + ID_OUI_FROM_DATABASE=Chongqing Guohong Technology Development Company Limited + OUI:8C5FDF* ID_OUI_FROM_DATABASE=Beijing Railway Signal Factory @@ -35150,6 +36302,30 @@ OUI:7C6C39* OUI:9C5D95* ID_OUI_FROM_DATABASE=VTC Electronics Corp. +OUI:0CF3EE* + ID_OUI_FROM_DATABASE=EM Microelectronic + +OUI:F0C27C* + ID_OUI_FROM_DATABASE=Mianyang Netop Telecom Equipment Co.,Ltd. + +OUI:008D4E* + ID_OUI_FROM_DATABASE=CJSC NII STT + +OUI:10C586* + ID_OUI_FROM_DATABASE=BIO SOUND LAB CO., LTD. + +OUI:E8BA70* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:6473E2* + ID_OUI_FROM_DATABASE=Arbiter Systems, Inc. + +OUI:00A1DE* + ID_OUI_FROM_DATABASE=ShenZhen ShiHua Technology CO.,LTD + +OUI:04E1C8* + ID_OUI_FROM_DATABASE=IMS Soluções em Energia Ltda. + OUI:DC05ED* ID_OUI_FROM_DATABASE=Nabtesco Corporation @@ -35162,71 +36338,71 @@ OUI:94E848* OUI:AC5E8C* ID_OUI_FROM_DATABASE=Utillink +OUI:CCF3A5* + ID_OUI_FROM_DATABASE=Chi Mei Communication Systems, Inc + +OUI:C4242E* + ID_OUI_FROM_DATABASE=Galvanic Applied Sciences Inc + OUI:549B12* ID_OUI_FROM_DATABASE=Samsung Electronics OUI:CC7EE7* ID_OUI_FROM_DATABASE=Panasonic AVC Networks Company -OUI:BC99BC* - ID_OUI_FROM_DATABASE=FonSee Technology Inc. +OUI:58E476* + ID_OUI_FROM_DATABASE=CENTRON COMMUNICATIONS TECHNOLOGIES FUJIAN CO.,LTD -OUI:986022* - ID_OUI_FROM_DATABASE=EMW Co., Ltd. +OUI:B435F7* + ID_OUI_FROM_DATABASE=Zhejiang Pearmain Electronics Co.ltd. -OUI:80B32A* - ID_OUI_FROM_DATABASE=Alstom Grid +OUI:346F92* + ID_OUI_FROM_DATABASE=White Rodgers Division -OUI:803457* - ID_OUI_FROM_DATABASE=OT Systems Limited +OUI:8CDB25* + ID_OUI_FROM_DATABASE=ESG Solutions -OUI:B83D4E* - ID_OUI_FROM_DATABASE=Shenzhen Cultraview Digital Technology Co.,Ltd Shanghai Branch +OUI:641A22* + ID_OUI_FROM_DATABASE=Heliospectra AB -OUI:CCF3A5* - ID_OUI_FROM_DATABASE=Chi Mei Communication Systems, Inc +OUI:BC20BA* + ID_OUI_FROM_DATABASE=Inspur (Shandong) Electronic Information Co., Ltd -OUI:143E60* - ID_OUI_FROM_DATABASE=Alcatel-Lucent +OUI:249442* + ID_OUI_FROM_DATABASE=OPEN ROAD SOLUTIONS , INC. -OUI:C4242E* - ID_OUI_FROM_DATABASE=Galvanic Applied Sciences Inc +OUI:E0F379* + ID_OUI_FROM_DATABASE=Vaddio -OUI:6400F1* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:B09AE2* + ID_OUI_FROM_DATABASE=STEMMER IMAGING GmbH -OUI:04C5A4* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:E441E6* + ID_OUI_FROM_DATABASE=Ottec Technology GmbH -OUI:3CA72B* - ID_OUI_FROM_DATABASE=MRV Communications (Networks) LTD +OUI:10E2D5* + ID_OUI_FROM_DATABASE=Qi Hardware Inc. -OUI:EC55F9* - ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. +OUI:7CDA84* + ID_OUI_FROM_DATABASE=Dongnian Networks Inc. -OUI:F4D9FB* - ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD +OUI:A036FA* + ID_OUI_FROM_DATABASE=Ettus Research LLC -OUI:584C19* - ID_OUI_FROM_DATABASE=Chongqing Guohong Technology Development Company Limited +OUI:EC836C* + ID_OUI_FROM_DATABASE=RM Tech Co., Ltd. -OUI:D0A311* - ID_OUI_FROM_DATABASE=Neuberger Gebäudeautomation GmbH +OUI:BC71C1* + ID_OUI_FROM_DATABASE=XTrillion, Inc. -OUI:3C5A37* - ID_OUI_FROM_DATABASE=Samsung Electronics +OUI:0C469D* + ID_OUI_FROM_DATABASE=MS Sedco -OUI:10A13B* - ID_OUI_FROM_DATABASE=FUJIKURA RUBBER LTD. +OUI:E0E8E8* + ID_OUI_FROM_DATABASE=Olive Telecommunication Pvt. Ltd -OUI:F4E142* - ID_OUI_FROM_DATABASE=Delta Elektronika BV - -OUI:F00248* - ID_OUI_FROM_DATABASE=SmarteBuilding - -OUI:2CDD0C* - ID_OUI_FROM_DATABASE=Discovergy GmbH +OUI:0C3C65* + ID_OUI_FROM_DATABASE=Dome Imaging Inc OUI:40B2C8* ID_OUI_FROM_DATABASE=Nortel Networks @@ -35252,68 +36428,26 @@ OUI:088DC8* OUI:D491AF* ID_OUI_FROM_DATABASE=Electroacustica General Iberica, S.A. -OUI:1CDF0F* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:CCF67A* + ID_OUI_FROM_DATABASE=Ayecka Communication Systems LTD -OUI:34DF2A* - ID_OUI_FROM_DATABASE=Fujikon Industrial Co.,Limited +OUI:00BB8E* + ID_OUI_FROM_DATABASE=HME Co., Ltd. -OUI:C88447* - ID_OUI_FROM_DATABASE=Beautiful Enterprise Co., Ltd +OUI:C0A26D* + ID_OUI_FROM_DATABASE=Abbott Point of Care -OUI:C88B47* - ID_OUI_FROM_DATABASE=Nolangroup S.P.A con Socio Unico +OUI:205B2A* + ID_OUI_FROM_DATABASE=Private -OUI:24BA30* - ID_OUI_FROM_DATABASE=Technical Consumer Products, Inc. +OUI:18B430* + ID_OUI_FROM_DATABASE=Nest Labs Inc. -OUI:74D675* - ID_OUI_FROM_DATABASE=WYMA Tecnologia +OUI:F8769B* + ID_OUI_FROM_DATABASE=Neopis Co., Ltd. -OUI:D01CBB* - ID_OUI_FROM_DATABASE=Beijing Ctimes Digital Technology Co., Ltd. - -OUI:9481A4* - ID_OUI_FROM_DATABASE=Azuray Technologies - -OUI:BCE09D* - ID_OUI_FROM_DATABASE=Eoslink - -OUI:346F92* - ID_OUI_FROM_DATABASE=White Rodgers Division - -OUI:8CDB25* - ID_OUI_FROM_DATABASE=ESG Solutions - -OUI:641A22* - ID_OUI_FROM_DATABASE=Heliospectra AB - -OUI:30142D* - ID_OUI_FROM_DATABASE=Piciorgros GmbH - -OUI:E441E6* - ID_OUI_FROM_DATABASE=Ottec Technology GmbH - -OUI:10E2D5* - ID_OUI_FROM_DATABASE=Qi Hardware Inc. - -OUI:7CDA84* - ID_OUI_FROM_DATABASE=Dongnian Networks Inc. - -OUI:A036FA* - ID_OUI_FROM_DATABASE=Ettus Research LLC - -OUI:EC836C* - ID_OUI_FROM_DATABASE=RM Tech Co., Ltd. - -OUI:C0C520* - ID_OUI_FROM_DATABASE=Ruckus Wireless - -OUI:6083B2* - ID_OUI_FROM_DATABASE=GkWare e.K. - -OUI:80D019* - ID_OUI_FROM_DATABASE=Embed, Inc +OUI:08E672* + ID_OUI_FROM_DATABASE=JEBSEE ELECTRONICS CO.,LTD. OUI:D41296* ID_OUI_FROM_DATABASE=Anobit Technologies Ltd. @@ -35333,17 +36467,17 @@ OUI:649B24* OUI:0475F5* ID_OUI_FROM_DATABASE=CSST -OUI:BC20BA* - ID_OUI_FROM_DATABASE=Inspur (Shandong) Electronic Information Co., Ltd +OUI:10A13B* + ID_OUI_FROM_DATABASE=FUJIKURA RUBBER LTD. -OUI:249442* - ID_OUI_FROM_DATABASE=OPEN ROAD SOLUTIONS , INC. +OUI:F4E142* + ID_OUI_FROM_DATABASE=Delta Elektronika BV -OUI:E0F379* - ID_OUI_FROM_DATABASE=Vaddio +OUI:F00248* + ID_OUI_FROM_DATABASE=SmarteBuilding -OUI:B09AE2* - ID_OUI_FROM_DATABASE=STEMMER IMAGING GmbH +OUI:2CDD0C* + ID_OUI_FROM_DATABASE=Discovergy GmbH OUI:CCD811* ID_OUI_FROM_DATABASE=Aiconn Technology Corporation @@ -35363,8 +36497,14 @@ OUI:44599F* OUI:3C2F3A* ID_OUI_FROM_DATABASE=SFORZATO Corp. -OUI:EC9233* - ID_OUI_FROM_DATABASE=Eddyfi NDT Inc +OUI:C0C520* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:6083B2* + ID_OUI_FROM_DATABASE=GkWare e.K. + +OUI:80D019* + ID_OUI_FROM_DATABASE=Embed, Inc OUI:ECE90B* ID_OUI_FROM_DATABASE=SISTEMA SOLUCOES ELETRONICAS LTDA - EASYTECH @@ -35393,17 +36533,8 @@ OUI:6C33A9* OUI:08B7EC* ID_OUI_FROM_DATABASE=Wireless Seismic -OUI:BC71C1* - ID_OUI_FROM_DATABASE=XTrillion, Inc. - -OUI:0C469D* - ID_OUI_FROM_DATABASE=MS Sedco - -OUI:E0E8E8* - ID_OUI_FROM_DATABASE=Olive Telecommunication Pvt. Ltd - -OUI:0C3C65* - ID_OUI_FROM_DATABASE=Dome Imaging Inc +OUI:30142D* + ID_OUI_FROM_DATABASE=Piciorgros GmbH OUI:942053* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -35420,17 +36551,47 @@ OUI:2CB0DF* OUI:5CF3FC* ID_OUI_FROM_DATABASE=IBM Corp -OUI:D43D67* - ID_OUI_FROM_DATABASE=Carma Industries Inc. +OUI:D01CBB* + ID_OUI_FROM_DATABASE=Beijing Ctimes Digital Technology Co., Ltd. -OUI:00BD27* - ID_OUI_FROM_DATABASE=Exar Corp. +OUI:9481A4* + ID_OUI_FROM_DATABASE=Azuray Technologies -OUI:C8A729* - ID_OUI_FROM_DATABASE=SYStronics Co., Ltd. +OUI:BCE09D* + ID_OUI_FROM_DATABASE=Eoslink -OUI:6C9CE9* - ID_OUI_FROM_DATABASE=Nimble Storage +OUI:D0A311* + ID_OUI_FROM_DATABASE=Neuberger Gebäudeautomation GmbH + +OUI:3C5A37* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:EC9233* + ID_OUI_FROM_DATABASE=Eddyfi NDT Inc + +OUI:0C8D98* + ID_OUI_FROM_DATABASE=TOP EIGHT IND CORP + +OUI:30493B* + ID_OUI_FROM_DATABASE=Nanjing Z-Com Wireless Co.,Ltd + +OUI:785712* + ID_OUI_FROM_DATABASE=Mobile Integration Workgroup + +OUI:380A0A* + ID_OUI_FROM_DATABASE=Sky-City Communication and Electronics Limited Company + +OUI:38521A* + ID_OUI_FROM_DATABASE=Alcatel-Lucent 7705 + +OUI:C8A1B6* + ID_OUI_FROM_DATABASE=Shenzhen Longway Technologies Co., Ltd + +OUI:641E81* + ID_OUI_FROM_DATABASE=Dowslake Microsystems + +OUI:88ACC1* + ID_OUI_FROM_DATABASE=Generiton Co., Ltd. OUI:700258* ID_OUI_FROM_DATABASE=01DB-METRAVIB @@ -35447,42 +36608,6 @@ OUI:389592* OUI:705EAA* ID_OUI_FROM_DATABASE=Action Target, Inc. -OUI:0C8D98* - ID_OUI_FROM_DATABASE=TOP EIGHT IND CORP - -OUI:30493B* - ID_OUI_FROM_DATABASE=Nanjing Z-Com Wireless Co.,Ltd - -OUI:68DB96* - ID_OUI_FROM_DATABASE=OPWILL Technologies CO .,LTD - -OUI:00F860* - ID_OUI_FROM_DATABASE=PT. Panggung Electric Citrabuana - -OUI:FCEDB9* - ID_OUI_FROM_DATABASE=Arrayent - -OUI:44ED57* - ID_OUI_FROM_DATABASE=Longicorn, inc. - -OUI:38521A* - ID_OUI_FROM_DATABASE=Alcatel-Lucent 7705 - -OUI:C8A1B6* - ID_OUI_FROM_DATABASE=Shenzhen Longway Technologies Co., Ltd - -OUI:641E81* - ID_OUI_FROM_DATABASE=Dowslake Microsystems - -OUI:88ACC1* - ID_OUI_FROM_DATABASE=Generiton Co., Ltd. - -OUI:785712* - ID_OUI_FROM_DATABASE=Mobile Integration Workgroup - -OUI:380A0A* - ID_OUI_FROM_DATABASE=Sky-City Communication and Electronics Limited Company - OUI:141BBD* ID_OUI_FROM_DATABASE=Volex Inc. @@ -35513,87 +36638,6 @@ OUI:988EDD* OUI:98FC11* ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC -OUI:180C77* - ID_OUI_FROM_DATABASE=Westinghouse Electric Company, LLC - -OUI:ACA016* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:78E400* - ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. - -OUI:E4AD7D* - ID_OUI_FROM_DATABASE=SCL Elements - -OUI:40D40E* - ID_OUI_FROM_DATABASE=Biodata Ltd - -OUI:7C051E* - ID_OUI_FROM_DATABASE=RAFAEL LTD. - -OUI:58570D* - ID_OUI_FROM_DATABASE=Danfoss Solar Inverters - -OUI:E47CF9* - ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD - -OUI:0C826A* - ID_OUI_FROM_DATABASE=Wuhan Huagong Genuine Optics Technology Co., Ltd - -OUI:5C0E8B* - ID_OUI_FROM_DATABASE=Zebra Technologies Inc - -OUI:38C7BA* - ID_OUI_FROM_DATABASE=CS Services Co.,Ltd. - -OUI:70D57E* - ID_OUI_FROM_DATABASE=Scalar Corporation - -OUI:7866AE* - ID_OUI_FROM_DATABASE=ZTEC Instruments, Inc. - -OUI:24AF4A* - ID_OUI_FROM_DATABASE=Alcatel-Lucent-IPD - -OUI:78818F* - ID_OUI_FROM_DATABASE=Server Racks Australia Pty Ltd - -OUI:E0589E* - ID_OUI_FROM_DATABASE=Laerdal Medical - -OUI:44D63D* - ID_OUI_FROM_DATABASE=Talari Networks - -OUI:58FD20* - ID_OUI_FROM_DATABASE=Bravida Sakerhet AB - -OUI:9835B8* - ID_OUI_FROM_DATABASE=Assembled Products Corporation - -OUI:240B2A* - ID_OUI_FROM_DATABASE=Viettel Group - -OUI:68E41F* - ID_OUI_FROM_DATABASE=Unglaube Identech GmbH - -OUI:84F64C* - ID_OUI_FROM_DATABASE=Cross Point BV - -OUI:206A8A* - ID_OUI_FROM_DATABASE=Wistron InfoComm Manufacturing(Kunshan)Co.,Ltd. - -OUI:F80F41* - ID_OUI_FROM_DATABASE=Wistron InfoComm(ZhongShan) Corporation - -OUI:90513F* - ID_OUI_FROM_DATABASE=Elettronica Santerno SpA - -OUI:7CA29B* - ID_OUI_FROM_DATABASE=D.SignT GmbH & Co. KG - -OUI:34AAEE* - ID_OUI_FROM_DATABASE=Mikrovisatos Servisas UAB - OUI:A40CC3* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -35627,26 +36671,65 @@ OUI:609AA4* OUI:F0ED1E* ID_OUI_FROM_DATABASE=Bilkon Bilgisayar Kontrollu Cih. Im.Ltd. -OUI:24A937* - ID_OUI_FROM_DATABASE=PURE Storage +OUI:206A8A* + ID_OUI_FROM_DATABASE=Wistron InfoComm Manufacturing(Kunshan)Co.,Ltd. -OUI:348302* - ID_OUI_FROM_DATABASE=iFORCOM Co., Ltd +OUI:F80F41* + ID_OUI_FROM_DATABASE=Wistron InfoComm(ZhongShan) Corporation -OUI:949C55* - ID_OUI_FROM_DATABASE=Alta Data Technologies +OUI:1CDF0F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:389F83* - ID_OUI_FROM_DATABASE=OTN Systems N.V. +OUI:34DF2A* + ID_OUI_FROM_DATABASE=Fujikon Industrial Co.,Limited -OUI:8C541D* - ID_OUI_FROM_DATABASE=LGE +OUI:C88447* + ID_OUI_FROM_DATABASE=Beautiful Enterprise Co., Ltd -OUI:601283* - ID_OUI_FROM_DATABASE=Soluciones Tecnologicas para la Salud y el Bienestar SA +OUI:C88B47* + ID_OUI_FROM_DATABASE=Nolangroup S.P.A con Socio Unico -OUI:003A9D* - ID_OUI_FROM_DATABASE=NEC Platforms, Ltd. +OUI:24BA30* + ID_OUI_FROM_DATABASE=Technical Consumer Products, Inc. + +OUI:74D675* + ID_OUI_FROM_DATABASE=WYMA Tecnologia + +OUI:D43D67* + ID_OUI_FROM_DATABASE=Carma Industries Inc. + +OUI:78818F* + ID_OUI_FROM_DATABASE=Server Racks Australia Pty Ltd + +OUI:E0589E* + ID_OUI_FROM_DATABASE=Laerdal Medical + +OUI:44D63D* + ID_OUI_FROM_DATABASE=Talari Networks + +OUI:58FD20* + ID_OUI_FROM_DATABASE=Bravida Sakerhet AB + +OUI:9835B8* + ID_OUI_FROM_DATABASE=Assembled Products Corporation + +OUI:240B2A* + ID_OUI_FROM_DATABASE=Viettel Group + +OUI:68E41F* + ID_OUI_FROM_DATABASE=Unglaube Identech GmbH + +OUI:84F64C* + ID_OUI_FROM_DATABASE=Cross Point BV + +OUI:180C77* + ID_OUI_FROM_DATABASE=Westinghouse Electric Company, LLC + +OUI:ACA016* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:78E400* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. OUI:905446* ID_OUI_FROM_DATABASE=TES ELECTRONIC SOLUTIONS @@ -35666,11 +36749,41 @@ OUI:A4BE61* OUI:E06290* ID_OUI_FROM_DATABASE=Jinan Jovision Science & Technology Co., Ltd. -OUI:A01859* - ID_OUI_FROM_DATABASE=Shenzhen Yidashi Electronics Co Ltd +OUI:68DB96* + ID_OUI_FROM_DATABASE=OPWILL Technologies CO .,LTD -OUI:042234* - ID_OUI_FROM_DATABASE=Wireless Standard Extensions +OUI:00F860* + ID_OUI_FROM_DATABASE=PT. Panggung Electric Citrabuana + +OUI:FCEDB9* + ID_OUI_FROM_DATABASE=Arrayent + +OUI:44ED57* + ID_OUI_FROM_DATABASE=Longicorn, inc. + +OUI:90513F* + ID_OUI_FROM_DATABASE=Elettronica Santerno SpA + +OUI:7CA29B* + ID_OUI_FROM_DATABASE=D.SignT GmbH & Co. KG + +OUI:34AAEE* + ID_OUI_FROM_DATABASE=Mikrovisatos Servisas UAB + +OUI:7866AE* + ID_OUI_FROM_DATABASE=ZTEC Instruments, Inc. + +OUI:24AF4A* + ID_OUI_FROM_DATABASE=Alcatel-Lucent-IPD + +OUI:00BD27* + ID_OUI_FROM_DATABASE=Exar Corp. + +OUI:C8A729* + ID_OUI_FROM_DATABASE=SYStronics Co., Ltd. + +OUI:6C9CE9* + ID_OUI_FROM_DATABASE=Nimble Storage OUI:7812B8* ID_OUI_FROM_DATABASE=ORANTEK LIMITED @@ -35702,6 +36815,72 @@ OUI:CC69B0* OUI:2872C5* ID_OUI_FROM_DATABASE=Smartmatic Corp +OUI:E4AD7D* + ID_OUI_FROM_DATABASE=SCL Elements + +OUI:40D40E* + ID_OUI_FROM_DATABASE=Biodata Ltd + +OUI:7C051E* + ID_OUI_FROM_DATABASE=RAFAEL LTD. + +OUI:58570D* + ID_OUI_FROM_DATABASE=Danfoss Solar Inverters + +OUI:E47CF9* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., LTD + +OUI:0C826A* + ID_OUI_FROM_DATABASE=Wuhan Huagong Genuine Optics Technology Co., Ltd + +OUI:5C0E8B* + ID_OUI_FROM_DATABASE=Zebra Technologies Inc + +OUI:38C7BA* + ID_OUI_FROM_DATABASE=CS Services Co.,Ltd. + +OUI:70D57E* + ID_OUI_FROM_DATABASE=Scalar Corporation + +OUI:24A937* + ID_OUI_FROM_DATABASE=PURE Storage + +OUI:348302* + ID_OUI_FROM_DATABASE=iFORCOM Co., Ltd + +OUI:949C55* + ID_OUI_FROM_DATABASE=Alta Data Technologies + +OUI:70D5E7* + ID_OUI_FROM_DATABASE=Wellcore Corporation + +OUI:3CF72A* + ID_OUI_FROM_DATABASE=Nokia Corporation + +OUI:FCE192* + ID_OUI_FROM_DATABASE=Sichuan Jinwangtong Electronic Science&Technology Co,.Ltd + +OUI:F8912A* + ID_OUI_FROM_DATABASE=GLP German Light Products GmbH + +OUI:E02630* + ID_OUI_FROM_DATABASE=Intrigue Technologies, Inc. + +OUI:8C9236* + ID_OUI_FROM_DATABASE=Aus.Linx Technology Co., Ltd. + +OUI:F445ED* + ID_OUI_FROM_DATABASE=Portable Innovation Technology Ltd. + +OUI:6C32DE* + ID_OUI_FROM_DATABASE=Indieon Technologies Pvt. Ltd. + +OUI:FCCF62* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:D8E72B* + ID_OUI_FROM_DATABASE=NetScout Systems, Inc. + OUI:B8A3E0* ID_OUI_FROM_DATABASE=BenRui Technology Co.,Ltd @@ -35729,17 +36908,23 @@ OUI:506313* OUI:A8995C* ID_OUI_FROM_DATABASE=aizo ag -OUI:F445ED* - ID_OUI_FROM_DATABASE=Portable Innovation Technology Ltd. +OUI:4012E4* + ID_OUI_FROM_DATABASE=Compass-EOS -OUI:6C32DE* - ID_OUI_FROM_DATABASE=Indieon Technologies Pvt. Ltd. +OUI:F8DC7A* + ID_OUI_FROM_DATABASE=Variscite LTD -OUI:FCCF62* - ID_OUI_FROM_DATABASE=IBM Corp +OUI:EC4476* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:D8E72B* - ID_OUI_FROM_DATABASE=NetScout Systems, Inc. +OUI:9CEBE8* + ID_OUI_FROM_DATABASE=BizLink (Kunshan) Co.,Ltd + +OUI:A01859* + ID_OUI_FROM_DATABASE=Shenzhen Yidashi Electronics Co Ltd + +OUI:042234* + ID_OUI_FROM_DATABASE=Wireless Standard Extensions OUI:B09074* ID_OUI_FROM_DATABASE=Fulan Electronics Limited @@ -35759,35 +36944,29 @@ OUI:8C736E* OUI:30EFD1* ID_OUI_FROM_DATABASE=Alstom Strongwish (Shenzhen) Co., Ltd. -OUI:C835B8* - ID_OUI_FROM_DATABASE=Ericsson, EAB/RWI/K +OUI:7C2CF3* + ID_OUI_FROM_DATABASE=Secure Electrans Ltd -OUI:243C20* - ID_OUI_FROM_DATABASE=Dynamode Group +OUI:304174* + ID_OUI_FROM_DATABASE=ALTEC LANSING LLC -OUI:70D5E7* - ID_OUI_FROM_DATABASE=Wellcore Corporation +OUI:7830E1* + ID_OUI_FROM_DATABASE=UltraClenz, LLC -OUI:3CF72A* - ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:FCFBFB* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:FCE192* - ID_OUI_FROM_DATABASE=Sichuan Jinwangtong Electronic Science&Technology Co,.Ltd +OUI:1C129D* + ID_OUI_FROM_DATABASE=IEEE PES PSRC/SUB -OUI:F8912A* - ID_OUI_FROM_DATABASE=GLP German Light Products GmbH +OUI:B40832* + ID_OUI_FROM_DATABASE=TC Communications -OUI:E02630* - ID_OUI_FROM_DATABASE=Intrigue Technologies, Inc. +OUI:B42CBE* + ID_OUI_FROM_DATABASE=Direct Payment Solutions Limited -OUI:8C9236* - ID_OUI_FROM_DATABASE=Aus.Linx Technology Co., Ltd. - -OUI:4012E4* - ID_OUI_FROM_DATABASE=Compass-EOS - -OUI:F8DC7A* - ID_OUI_FROM_DATABASE=Variscite LTD +OUI:F47626* + ID_OUI_FROM_DATABASE=Viltechmeda UAB OUI:003A9C* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -35807,17 +36986,50 @@ OUI:0494A1* OUI:2C3427* ID_OUI_FROM_DATABASE=ERCO & GENER -OUI:B42CBE* - ID_OUI_FROM_DATABASE=Direct Payment Solutions Limited +OUI:389F83* + ID_OUI_FROM_DATABASE=OTN Systems N.V. -OUI:F47626* - ID_OUI_FROM_DATABASE=Viltechmeda UAB +OUI:8C541D* + ID_OUI_FROM_DATABASE=LGE -OUI:EC4476* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:601283* + ID_OUI_FROM_DATABASE=Soluciones Tecnologicas para la Salud y el Bienestar SA -OUI:9CEBE8* - ID_OUI_FROM_DATABASE=BizLink (Kunshan) Co.,Ltd +OUI:003A9D* + ID_OUI_FROM_DATABASE=NEC Platforms, Ltd. + +OUI:C835B8* + ID_OUI_FROM_DATABASE=Ericsson, EAB/RWI/K + +OUI:243C20* + ID_OUI_FROM_DATABASE=Dynamode Group + +OUI:E09153* + ID_OUI_FROM_DATABASE=XAVi Technologies Corp. + +OUI:CC0080* + ID_OUI_FROM_DATABASE=BETTINI SRL + +OUI:644BC3* + ID_OUI_FROM_DATABASE=Shanghai WOASiS Telecommunications Ltd., Co. + +OUI:0CE709* + ID_OUI_FROM_DATABASE=Fox Crypto B.V. + +OUI:002720* + ID_OUI_FROM_DATABASE=NEW-SOL COM + +OUI:00271C* + ID_OUI_FROM_DATABASE=MERCURY CORPORATION + +OUI:002712* + ID_OUI_FROM_DATABASE=MaxVision LLC + +OUI:00270F* + ID_OUI_FROM_DATABASE=Envisionnovation Inc + +OUI:002703* + ID_OUI_FROM_DATABASE=Testech Electronics Pte Ltd OUI:88ED1C* ID_OUI_FROM_DATABASE=Cudo Communication Co., Ltd. @@ -35846,41 +37058,26 @@ OUI:C87E75* OUI:889821* ID_OUI_FROM_DATABASE=TERAON -OUI:CC5076* - ID_OUI_FROM_DATABASE=Ocom Communications, Inc. +OUI:0026FD* + ID_OUI_FROM_DATABASE=Interactive Intelligence -OUI:705812* - ID_OUI_FROM_DATABASE=Panasonic AVC Networks Company +OUI:0026F6* + ID_OUI_FROM_DATABASE=Military Communication Institute -OUI:7C2CF3* - ID_OUI_FROM_DATABASE=Secure Electrans Ltd +OUI:0026F0* + ID_OUI_FROM_DATABASE=cTrixs International GmbH. -OUI:304174* - ID_OUI_FROM_DATABASE=ALTEC LANSING LLC +OUI:0026EA* + ID_OUI_FROM_DATABASE=Cheerchip Electronic Technology (ShangHai) Co., Ltd. -OUI:7830E1* - ID_OUI_FROM_DATABASE=UltraClenz, LLC +OUI:0026E3* + ID_OUI_FROM_DATABASE=DTI -OUI:FCFBFB* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:0026DD* + ID_OUI_FROM_DATABASE=Fival Science & Technology Co.,Ltd. -OUI:1C129D* - ID_OUI_FROM_DATABASE=IEEE PES PSRC/SUB - -OUI:B40832* - ID_OUI_FROM_DATABASE=TC Communications - -OUI:002720* - ID_OUI_FROM_DATABASE=NEW-SOL COM - -OUI:00271C* - ID_OUI_FROM_DATABASE=MERCURY CORPORATION - -OUI:002712* - ID_OUI_FROM_DATABASE=MaxVision LLC - -OUI:00270F* - ID_OUI_FROM_DATABASE=Envisionnovation Inc +OUI:0026DE* + ID_OUI_FROM_DATABASE=FDI MATELEC OUI:0026D7* ID_OUI_FROM_DATABASE=KM Electornic Technology Co., Ltd. @@ -35888,6 +37085,42 @@ OUI:0026D7* OUI:0026D1* ID_OUI_FROM_DATABASE=S Squared Innovations Inc. +OUI:54B620* + ID_OUI_FROM_DATABASE=SUHDOL E&C Co.Ltd. + +OUI:C4AAA1* + ID_OUI_FROM_DATABASE=SUMMIT DEVELOPMENT, spol.s r.o. + +OUI:78C40E* + ID_OUI_FROM_DATABASE=H&D Wireless + +OUI:9C5B96* + ID_OUI_FROM_DATABASE=NMR Corporation + +OUI:E4FFDD* + ID_OUI_FROM_DATABASE=ELECTRON INDIA + +OUI:6C8CDB* + ID_OUI_FROM_DATABASE=Otus Technologies Ltd + +OUI:B4417A* + ID_OUI_FROM_DATABASE=ShenZhen Gongjin Electronics Co.,Ltd + +OUI:401597* + ID_OUI_FROM_DATABASE=Protect America, Inc. + +OUI:F852DF* + ID_OUI_FROM_DATABASE=VNL Europe AB + +OUI:1CF061* + ID_OUI_FROM_DATABASE=SCAPS GmbH + +OUI:A893E6* + ID_OUI_FROM_DATABASE=JIANGXI JINGGANGSHAN CKING COMMUNICATION TECHNOLOGY CO.,LTD + +OUI:7825AD* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRONICS CO., LTD. + OUI:0026CB* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -35912,30 +37145,6 @@ OUI:0026A8* OUI:0026A7* ID_OUI_FROM_DATABASE=CONNECT SRL -OUI:0026A1* - ID_OUI_FROM_DATABASE=Megger - -OUI:0026A2* - ID_OUI_FROM_DATABASE=Instrumentation Technology Systems - -OUI:00269B* - ID_OUI_FROM_DATABASE=SOKRAT Ltd. - -OUI:002695* - ID_OUI_FROM_DATABASE=ZT Group Int'l Inc - -OUI:00268F* - ID_OUI_FROM_DATABASE=MTA SpA - -OUI:6C8CDB* - ID_OUI_FROM_DATABASE=Otus Technologies Ltd - -OUI:B4417A* - ID_OUI_FROM_DATABASE=ShenZhen Gongjin Electronics Co.,Ltd - -OUI:401597* - ID_OUI_FROM_DATABASE=Protect America, Inc. - OUI:60391F* ID_OUI_FROM_DATABASE=ABB Ltd @@ -35960,173 +37169,11 @@ OUI:10BAA5* OUI:586ED6* ID_OUI_FROM_DATABASE=Private -OUI:E09153* - ID_OUI_FROM_DATABASE=XAVi Technologies Corp. +OUI:CC5076* + ID_OUI_FROM_DATABASE=Ocom Communications, Inc. -OUI:CC0080* - ID_OUI_FROM_DATABASE=BETTINI SRL - -OUI:644BC3* - ID_OUI_FROM_DATABASE=Shanghai WOASiS Telecommunications Ltd., Co. - -OUI:0CE709* - ID_OUI_FROM_DATABASE=Fox Crypto B.V. - -OUI:002703* - ID_OUI_FROM_DATABASE=Testech Electronics Pte Ltd - -OUI:0026FD* - ID_OUI_FROM_DATABASE=Interactive Intelligence - -OUI:0026F6* - ID_OUI_FROM_DATABASE=Military Communication Institute - -OUI:0026F0* - ID_OUI_FROM_DATABASE=cTrixs International GmbH. - -OUI:0026EA* - ID_OUI_FROM_DATABASE=Cheerchip Electronic Technology (ShangHai) Co., Ltd. - -OUI:0026E3* - ID_OUI_FROM_DATABASE=DTI - -OUI:0026DD* - ID_OUI_FROM_DATABASE=Fival Science & Technology Co.,Ltd. - -OUI:0026DE* - ID_OUI_FROM_DATABASE=FDI MATELEC - -OUI:7825AD* - ID_OUI_FROM_DATABASE=SAMSUNG ELECTRONICS CO., LTD. - -OUI:54B620* - ID_OUI_FROM_DATABASE=SUHDOL E&C Co.Ltd. - -OUI:C4AAA1* - ID_OUI_FROM_DATABASE=SUMMIT DEVELOPMENT, spol.s r.o. - -OUI:78C40E* - ID_OUI_FROM_DATABASE=H&D Wireless - -OUI:9C5B96* - ID_OUI_FROM_DATABASE=NMR Corporation - -OUI:E4FFDD* - ID_OUI_FROM_DATABASE=ELECTRON INDIA - -OUI:F852DF* - ID_OUI_FROM_DATABASE=VNL Europe AB - -OUI:1CF061* - ID_OUI_FROM_DATABASE=SCAPS GmbH - -OUI:A893E6* - ID_OUI_FROM_DATABASE=JIANGXI JINGGANGSHAN CKING COMMUNICATION TECHNOLOGY CO.,LTD - -OUI:00267C* - ID_OUI_FROM_DATABASE=Metz-Werke GmbH & Co KG - -OUI:002676* - ID_OUI_FROM_DATABASE=COMMidt AS - -OUI:00266F* - ID_OUI_FROM_DATABASE=Coordiwise Technology Corp. - -OUI:002670* - ID_OUI_FROM_DATABASE=Cinch Connectors - -OUI:002663* - ID_OUI_FROM_DATABASE=Shenzhen Huitaiwei Tech. Ltd, co. - -OUI:00265D* - ID_OUI_FROM_DATABASE=Samsung Electronics - -OUI:0025CD* - ID_OUI_FROM_DATABASE=Skylane Optics - -OUI:0025C8* - ID_OUI_FROM_DATABASE=S-Access GmbH - -OUI:0025C7* - ID_OUI_FROM_DATABASE=altek Corporation - -OUI:0025C1* - ID_OUI_FROM_DATABASE=Nawoo Korea Corp. - -OUI:0025BA* - ID_OUI_FROM_DATABASE=Alcatel-Lucent IPD - -OUI:0025B5* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:0025AE* - ID_OUI_FROM_DATABASE=Microsoft Corporation - -OUI:0025A8* - ID_OUI_FROM_DATABASE=Kontron (BeiJing) Technology Co.,Ltd - -OUI:0025A7* - ID_OUI_FROM_DATABASE=Comverge, Inc. - -OUI:00262B* - ID_OUI_FROM_DATABASE=Wongs Electronics Co. Ltd. - -OUI:002625* - ID_OUI_FROM_DATABASE=MediaSputnik - -OUI:00261E* - ID_OUI_FROM_DATABASE=QINGBANG ELEC(SZ) CO., LTD - -OUI:002619* - ID_OUI_FROM_DATABASE=FRC - -OUI:002612* - ID_OUI_FROM_DATABASE=Space Exploration Technologies - -OUI:00260B* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00260C* - ID_OUI_FROM_DATABASE=Dataram - -OUI:0025FF* - ID_OUI_FROM_DATABASE=CreNova Multimedia Co., Ltd - -OUI:002606* - ID_OUI_FROM_DATABASE=RAUMFELD GmbH - -OUI:0025F9* - ID_OUI_FROM_DATABASE=GMK electronic design GmbH - -OUI:0025A2* - ID_OUI_FROM_DATABASE=Alta Definicion LINCEO S.L. - -OUI:002596* - ID_OUI_FROM_DATABASE=GIGAVISION srl - -OUI:00259B* - ID_OUI_FROM_DATABASE=Beijing PKUNITY Microsystems Technology Co., Ltd - -OUI:002595* - ID_OUI_FROM_DATABASE=Northwest Signal Supply, Inc - -OUI:00258F* - ID_OUI_FROM_DATABASE=Trident Microsystems, Inc. - -OUI:00258B* - ID_OUI_FROM_DATABASE=Mellanox Technologies Ltd - -OUI:002585* - ID_OUI_FROM_DATABASE=KOKUYO S&T Co., Ltd. - -OUI:00257B* - ID_OUI_FROM_DATABASE=STJ ELECTRONICS PVT LTD - -OUI:002574* - ID_OUI_FROM_DATABASE=KUNIMI MEDIA DEVICE Co., Ltd. - -OUI:00264F* - ID_OUI_FROM_DATABASE=Krüger &Gothe GmbH +OUI:705812* + ID_OUI_FROM_DATABASE=Panasonic AVC Networks Company OUI:002648* ID_OUI_FROM_DATABASE=Emitech Corp. @@ -36146,71 +37193,44 @@ OUI:00263D* OUI:002631* ID_OUI_FROM_DATABASE=COMMTACT LTD -OUI:00256F* - ID_OUI_FROM_DATABASE=Dantherm Power +OUI:00262B* + ID_OUI_FROM_DATABASE=Wongs Electronics Co. Ltd. -OUI:002562* - ID_OUI_FROM_DATABASE=interbro Co. Ltd. +OUI:002625* + ID_OUI_FROM_DATABASE=MediaSputnik -OUI:002561* - ID_OUI_FROM_DATABASE=ProCurve Networking by HP +OUI:00261E* + ID_OUI_FROM_DATABASE=QINGBANG ELEC(SZ) CO., LTD -OUI:00255C* - ID_OUI_FROM_DATABASE=NEC Corporation +OUI:002619* + ID_OUI_FROM_DATABASE=FRC -OUI:002550* - ID_OUI_FROM_DATABASE=Riverbed Technology +OUI:0025BA* + ID_OUI_FROM_DATABASE=Alcatel-Lucent IPD -OUI:002555* - ID_OUI_FROM_DATABASE=Visonic Technologies 1993 Ltd - -OUI:00254F* - ID_OUI_FROM_DATABASE=ELETTROLAB Srl - -OUI:002518* - ID_OUI_FROM_DATABASE=Power PLUS Communications AG - -OUI:002511* - ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM CO., LTD. - -OUI:002513* - ID_OUI_FROM_DATABASE=CXP DIGITAL BV - -OUI:00250C* - ID_OUI_FROM_DATABASE=Enertrac - -OUI:002505* - ID_OUI_FROM_DATABASE=eks Engel GmbH & Co. KG - -OUI:0024F9* +OUI:0025B5* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:0024F2* - ID_OUI_FROM_DATABASE=Uniphone Telecommunication Co., Ltd. +OUI:0025AE* + ID_OUI_FROM_DATABASE=Microsoft Corporation -OUI:0024F4* - ID_OUI_FROM_DATABASE=Kaminario Technologies Ltd. +OUI:0025A8* + ID_OUI_FROM_DATABASE=Kontron (BeiJing) Technology Co.,Ltd -OUI:0024ED* - ID_OUI_FROM_DATABASE=YT Elec. Co,.Ltd. +OUI:0025A7* + ID_OUI_FROM_DATABASE=Comverge, Inc. -OUI:0024E6* - ID_OUI_FROM_DATABASE=In Motion Technology Inc. +OUI:0025A2* + ID_OUI_FROM_DATABASE=Alta Definicion LINCEO S.L. -OUI:0024E1* - ID_OUI_FROM_DATABASE=Convey Computer Corp. +OUI:002596* + ID_OUI_FROM_DATABASE=GIGAVISION srl -OUI:0024DF* - ID_OUI_FROM_DATABASE=Digitalbox Europe GmbH +OUI:00259B* + ID_OUI_FROM_DATABASE=Beijing PKUNITY Microsystems Technology Co., Ltd -OUI:0024DA* - ID_OUI_FROM_DATABASE=Innovar Systems Limited - -OUI:002549* - ID_OUI_FROM_DATABASE=Jeorich Tech. Co.,Ltd. - -OUI:002538* - ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd., Memory Division +OUI:002595* + ID_OUI_FROM_DATABASE=Northwest Signal Supply, Inc OUI:002542* ID_OUI_FROM_DATABASE=Pittasoft @@ -36227,17 +37247,65 @@ OUI:002522* OUI:00251D* ID_OUI_FROM_DATABASE=DSA Encore, LLC -OUI:0025F5* - ID_OUI_FROM_DATABASE=DVS Korea, Co., Ltd +OUI:002518* + ID_OUI_FROM_DATABASE=Power PLUS Communications AG -OUI:0025F0* - ID_OUI_FROM_DATABASE=Suga Electronics Limited +OUI:002513* + ID_OUI_FROM_DATABASE=CXP DIGITAL BV -OUI:0025EA* - ID_OUI_FROM_DATABASE=Iphion BV +OUI:0026A1* + ID_OUI_FROM_DATABASE=Megger -OUI:0025E4* - ID_OUI_FROM_DATABASE=OMNI-WiFi, LLC +OUI:0026A2* + ID_OUI_FROM_DATABASE=Instrumentation Technology Systems + +OUI:00269B* + ID_OUI_FROM_DATABASE=SOKRAT Ltd. + +OUI:002695* + ID_OUI_FROM_DATABASE=ZT Group Int'l Inc + +OUI:00268F* + ID_OUI_FROM_DATABASE=MTA SpA + +OUI:00267C* + ID_OUI_FROM_DATABASE=Metz-Werke GmbH & Co KG + +OUI:00255C* + ID_OUI_FROM_DATABASE=NEC Corporation + +OUI:002550* + ID_OUI_FROM_DATABASE=Riverbed Technology + +OUI:002555* + ID_OUI_FROM_DATABASE=Visonic Technologies 1993 Ltd + +OUI:00254F* + ID_OUI_FROM_DATABASE=ELETTROLAB Srl + +OUI:002549* + ID_OUI_FROM_DATABASE=Jeorich Tech. Co.,Ltd. + +OUI:002538* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd., Memory Division + +OUI:002676* + ID_OUI_FROM_DATABASE=COMMidt AS + +OUI:00266F* + ID_OUI_FROM_DATABASE=Coordiwise Technology Corp. + +OUI:002670* + ID_OUI_FROM_DATABASE=Cinch Connectors + +OUI:002663* + ID_OUI_FROM_DATABASE=Shenzhen Huitaiwei Tech. Ltd, co. + +OUI:00265D* + ID_OUI_FROM_DATABASE=Samsung Electronics + +OUI:00264F* + ID_OUI_FROM_DATABASE=Krüger &Gothe GmbH OUI:0025E0* ID_OUI_FROM_DATABASE=CeedTec Sdn Bhd @@ -36251,11 +37319,71 @@ OUI:0025D9* OUI:0025D4* ID_OUI_FROM_DATABASE=Fortress Technologies -OUI:002410* - ID_OUI_FROM_DATABASE=NUETEQ Technology,Inc. +OUI:0025CD* + ID_OUI_FROM_DATABASE=Skylane Optics -OUI:002409* - ID_OUI_FROM_DATABASE=The Toro Company +OUI:0025C8* + ID_OUI_FROM_DATABASE=S-Access GmbH + +OUI:0025C7* + ID_OUI_FROM_DATABASE=altek Corporation + +OUI:0025C1* + ID_OUI_FROM_DATABASE=Nawoo Korea Corp. + +OUI:002612* + ID_OUI_FROM_DATABASE=Space Exploration Technologies + +OUI:00260B* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00260C* + ID_OUI_FROM_DATABASE=Dataram + +OUI:0025FF* + ID_OUI_FROM_DATABASE=CreNova Multimedia Co., Ltd + +OUI:002606* + ID_OUI_FROM_DATABASE=RAUMFELD GmbH + +OUI:0025F9* + ID_OUI_FROM_DATABASE=GMK electronic design GmbH + +OUI:0025F5* + ID_OUI_FROM_DATABASE=DVS Korea, Co., Ltd + +OUI:0025F0* + ID_OUI_FROM_DATABASE=Suga Electronics Limited + +OUI:0025EA* + ID_OUI_FROM_DATABASE=Iphion BV + +OUI:0025E4* + ID_OUI_FROM_DATABASE=OMNI-WiFi, LLC + +OUI:00258F* + ID_OUI_FROM_DATABASE=Trident Microsystems, Inc. + +OUI:00258B* + ID_OUI_FROM_DATABASE=Mellanox Technologies Ltd + +OUI:002585* + ID_OUI_FROM_DATABASE=KOKUYO S&T Co., Ltd. + +OUI:00257B* + ID_OUI_FROM_DATABASE=STJ ELECTRONICS PVT LTD + +OUI:002574* + ID_OUI_FROM_DATABASE=KUNIMI MEDIA DEVICE Co., Ltd. + +OUI:00256F* + ID_OUI_FROM_DATABASE=Dantherm Power + +OUI:002562* + ID_OUI_FROM_DATABASE=interbro Co. Ltd. + +OUI:002561* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP OUI:0023F7* ID_OUI_FROM_DATABASE=Private @@ -36272,29 +37400,8 @@ OUI:0023EC* OUI:0023E7* ID_OUI_FROM_DATABASE=Hinke A/S -OUI:002387* - ID_OUI_FROM_DATABASE=ThinkFlood, Inc. - -OUI:002381* - ID_OUI_FROM_DATABASE=Lengda Technology(Xiamen) Co.,Ltd. - -OUI:002382* - ID_OUI_FROM_DATABASE=Lih Rong Electronic Enterprise Co., Ltd. - -OUI:00237B* - ID_OUI_FROM_DATABASE=WHDI LLC - -OUI:002372* - ID_OUI_FROM_DATABASE=MORE STAR INDUSTRIAL GROUP LIMITED - -OUI:0024CE* - ID_OUI_FROM_DATABASE=Exeltech Inc - -OUI:0024D3* - ID_OUI_FROM_DATABASE=QUALICA Inc. - -OUI:0024C7* - ID_OUI_FROM_DATABASE=Mobilarm Ltd +OUI:0023E0* + ID_OUI_FROM_DATABASE=INO Therapeutics LLC OUI:0024C2* ID_OUI_FROM_DATABASE=Asumo Co.,Ltd. @@ -36317,39 +37424,6 @@ OUI:00249A* OUI:00249F* ID_OUI_FROM_DATABASE=RIM Testing Services -OUI:002487* - ID_OUI_FROM_DATABASE=Blackboard Inc. - -OUI:002498* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:002485* - ID_OUI_FROM_DATABASE=ConteXtream Ltd - -OUI:002480* - ID_OUI_FROM_DATABASE=Meteocontrol GmbH - -OUI:002454* - ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD - -OUI:002448* - ID_OUI_FROM_DATABASE=SpiderCloud Wireless, Inc - -OUI:00244A* - ID_OUI_FROM_DATABASE=Voyant International - -OUI:002449* - ID_OUI_FROM_DATABASE=Shen Zhen Lite Star Electronics Technology Co., Ltd - -OUI:002443* - ID_OUI_FROM_DATABASE=Nortel Networks - -OUI:002439* - ID_OUI_FROM_DATABASE=Digital Barriers Advanced Technologies - -OUI:002479* - ID_OUI_FROM_DATABASE=Optec Displays, Inc. - OUI:00246D* ID_OUI_FROM_DATABASE=Weinzierl Engineering GmbH @@ -36371,32 +37445,53 @@ OUI:00245C* OUI:00244F* ID_OUI_FROM_DATABASE=Asantron Technologies Ltd. -OUI:0023BB* - ID_OUI_FROM_DATABASE=Schmitt Industries +OUI:002454* + ID_OUI_FROM_DATABASE=Samsung Electronics CO., LTD -OUI:0023BA* - ID_OUI_FROM_DATABASE=Chroma +OUI:002448* + ID_OUI_FROM_DATABASE=SpiderCloud Wireless, Inc -OUI:0023B5* - ID_OUI_FROM_DATABASE=ORTANA LTD +OUI:00244A* + ID_OUI_FROM_DATABASE=Voyant International -OUI:0023A8* - ID_OUI_FROM_DATABASE=Marshall Electronics +OUI:002449* + ID_OUI_FROM_DATABASE=Shen Zhen Lite Star Electronics Technology Co., Ltd -OUI:00239B* - ID_OUI_FROM_DATABASE=Elster Solutions, LLC +OUI:00250C* + ID_OUI_FROM_DATABASE=Enertrac -OUI:002396* - ID_OUI_FROM_DATABASE=ANDES TECHNOLOGY CORPORATION +OUI:002505* + ID_OUI_FROM_DATABASE=eks Engel GmbH & Co. KG -OUI:002391* - ID_OUI_FROM_DATABASE=Maxian +OUI:0024F9* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:00238C* - ID_OUI_FROM_DATABASE=Private +OUI:0024F2* + ID_OUI_FROM_DATABASE=Uniphone Telecommunication Co., Ltd. -OUI:002432* - ID_OUI_FROM_DATABASE=Neostar Technology Co.,LTD +OUI:0024ED* + ID_OUI_FROM_DATABASE=YT Elec. Co,.Ltd. + +OUI:0024E6* + ID_OUI_FROM_DATABASE=In Motion Technology Inc. + +OUI:0024E1* + ID_OUI_FROM_DATABASE=Convey Computer Corp. + +OUI:0024DF* + ID_OUI_FROM_DATABASE=Digitalbox Europe GmbH + +OUI:0024DA* + ID_OUI_FROM_DATABASE=Innovar Systems Limited + +OUI:0024CE* + ID_OUI_FROM_DATABASE=Exeltech Inc + +OUI:0024D3* + ID_OUI_FROM_DATABASE=QUALICA Inc. + +OUI:0024C7* + ID_OUI_FROM_DATABASE=Mobilarm Ltd OUI:002429* ID_OUI_FROM_DATABASE=MK MASTER INC. @@ -36410,8 +37505,35 @@ OUI:002428* OUI:002416* ID_OUI_FROM_DATABASE=Any Use -OUI:0023E0* - ID_OUI_FROM_DATABASE=INO Therapeutics LLC +OUI:002410* + ID_OUI_FROM_DATABASE=NUETEQ Technology,Inc. + +OUI:002409* + ID_OUI_FROM_DATABASE=The Toro Company + +OUI:002487* + ID_OUI_FROM_DATABASE=Blackboard Inc. + +OUI:002498* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:002485* + ID_OUI_FROM_DATABASE=ConteXtream Ltd + +OUI:002480* + ID_OUI_FROM_DATABASE=Meteocontrol GmbH + +OUI:002479* + ID_OUI_FROM_DATABASE=Optec Displays, Inc. + +OUI:002443* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:002439* + ID_OUI_FROM_DATABASE=Digital Barriers Advanced Technologies + +OUI:002432* + ID_OUI_FROM_DATABASE=Neostar Technology Co.,LTD OUI:0023DA* ID_OUI_FROM_DATABASE=Industrial Computer Source (Deutschland)GmbH @@ -36425,26 +37547,53 @@ OUI:0023C7* OUI:0023C1* ID_OUI_FROM_DATABASE=Securitas Direct AB -OUI:0021DC* - ID_OUI_FROM_DATABASE=TECNOALARM S.r.l. +OUI:0023BB* + ID_OUI_FROM_DATABASE=Schmitt Industries -OUI:0021E2* - ID_OUI_FROM_DATABASE=Creative Electronic GmbH +OUI:0023BA* + ID_OUI_FROM_DATABASE=Chroma -OUI:0021D6* - ID_OUI_FROM_DATABASE=LXI Consortium +OUI:0023B5* + ID_OUI_FROM_DATABASE=ORTANA LTD -OUI:0021CF* - ID_OUI_FROM_DATABASE=The Crypto Group +OUI:002381* + ID_OUI_FROM_DATABASE=Lengda Technology(Xiamen) Co.,Ltd. -OUI:0021C9* - ID_OUI_FROM_DATABASE=Wavecom Asia Pacific Limited +OUI:002382* + ID_OUI_FROM_DATABASE=Lih Rong Electronic Enterprise Co., Ltd. -OUI:0021CA* - ID_OUI_FROM_DATABASE=ART System Co., Ltd. +OUI:00237B* + ID_OUI_FROM_DATABASE=WHDI LLC -OUI:0021C3* - ID_OUI_FROM_DATABASE=CORNELL Communications, Inc. +OUI:002372* + ID_OUI_FROM_DATABASE=MORE STAR INDUSTRIAL GROUP LIMITED + +OUI:002366* + ID_OUI_FROM_DATABASE=Beijing Siasun Electronic System Co.,Ltd. + +OUI:00236B* + ID_OUI_FROM_DATABASE=Xembedded, Inc. + +OUI:002359* + ID_OUI_FROM_DATABASE=Benchmark Electronics ( Thailand ) Public Company Limited + +OUI:00235F* + ID_OUI_FROM_DATABASE=Silicon Micro Sensors GmbH + +OUI:002353* + ID_OUI_FROM_DATABASE=F E T Elettronica snc + +OUI:002347* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP + +OUI:00234C* + ID_OUI_FROM_DATABASE=KTC AB + +OUI:00233A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:002339* + ID_OUI_FROM_DATABASE=Samsung Electronics OUI:002334* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -36473,120 +37622,9 @@ OUI:002317* OUI:002310* ID_OUI_FROM_DATABASE=LNC Technology Co., Ltd. -OUI:002273* - ID_OUI_FROM_DATABASE=Techway - -OUI:002274* - ID_OUI_FROM_DATABASE=FamilyPhone AB - -OUI:00226F* - ID_OUI_FROM_DATABASE=3onedata Technology Co. Ltd. - -OUI:00226A* - ID_OUI_FROM_DATABASE=Honeywell - -OUI:002260* - ID_OUI_FROM_DATABASE=AFREEY Inc. - -OUI:00225B* - ID_OUI_FROM_DATABASE=Teradici Corporation - -OUI:002256* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:002255* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00224D* - ID_OUI_FROM_DATABASE=MITAC INTERNATIONAL CORP. - -OUI:002252* - ID_OUI_FROM_DATABASE=ZOLL Lifecor Corporation - -OUI:002246* - ID_OUI_FROM_DATABASE=Evoc Intelligent Technology Co.,Ltd. - -OUI:002366* - ID_OUI_FROM_DATABASE=Beijing Siasun Electronic System Co.,Ltd. - -OUI:00236B* - ID_OUI_FROM_DATABASE=Xembedded, Inc. - -OUI:002359* - ID_OUI_FROM_DATABASE=Benchmark Electronics ( Thailand ) Public Company Limited - -OUI:00235F* - ID_OUI_FROM_DATABASE=Silicon Micro Sensors GmbH - -OUI:002353* - ID_OUI_FROM_DATABASE=F E T Elettronica snc - -OUI:002347* - ID_OUI_FROM_DATABASE=ProCurve Networking by HP - -OUI:00234C* - ID_OUI_FROM_DATABASE=KTC AB - -OUI:002340* - ID_OUI_FROM_DATABASE=MiX Telematics - -OUI:00233A* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:002339* - ID_OUI_FROM_DATABASE=Samsung Electronics - OUI:002304* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:0022F3* - ID_OUI_FROM_DATABASE=SHARP Corporation - -OUI:0022EE* - ID_OUI_FROM_DATABASE=Algo Communication Products Ltd - -OUI:0022E7* - ID_OUI_FROM_DATABASE=WPS Parking Systems - -OUI:0022E1* - ID_OUI_FROM_DATABASE=ZORT Labs, LLC. - -OUI:0022E2* - ID_OUI_FROM_DATABASE=WABTEC Transit Division - -OUI:0022DB* - ID_OUI_FROM_DATABASE=Translogic Corporation - -OUI:0022A1* - ID_OUI_FROM_DATABASE=Huawei Symantec Technologies Co.,Ltd. - -OUI:00229B* - ID_OUI_FROM_DATABASE=AverLogic Technologies, Inc. - -OUI:00229C* - ID_OUI_FROM_DATABASE=Verismo Networks Inc - -OUI:002295* - ID_OUI_FROM_DATABASE=SGM Technology for lighting spa - -OUI:00228E* - ID_OUI_FROM_DATABASE=TV-NUMERIC - -OUI:002289* - ID_OUI_FROM_DATABASE=Optosecurity Inc. - -OUI:002282* - ID_OUI_FROM_DATABASE=8086 Consultancy - -OUI:00227C* - ID_OUI_FROM_DATABASE=Woori SMT Co.,ltd - -OUI:002279* - ID_OUI_FROM_DATABASE=Nippon Conlux Co., Ltd. - -OUI:00223C* - ID_OUI_FROM_DATABASE=RATIO Entwicklungen GmbH - OUI:002236* ID_OUI_FROM_DATABASE=VECTOR SP. Z O.O. @@ -36617,23 +37655,53 @@ OUI:002211* OUI:00220A* ID_OUI_FROM_DATABASE=OnLive, Inc -OUI:002204* - ID_OUI_FROM_DATABASE=KORATEK +OUI:002295* + ID_OUI_FROM_DATABASE=SGM Technology for lighting spa -OUI:0021FF* - ID_OUI_FROM_DATABASE=Cyfrowy Polsat SA +OUI:00228E* + ID_OUI_FROM_DATABASE=TV-NUMERIC -OUI:0021FB* - ID_OUI_FROM_DATABASE=LG Electronics +OUI:002289* + ID_OUI_FROM_DATABASE=Optosecurity Inc. -OUI:0021F5* - ID_OUI_FROM_DATABASE=Western Engravers Supply, Inc. +OUI:002282* + ID_OUI_FROM_DATABASE=8086 Consultancy -OUI:0021EF* - ID_OUI_FROM_DATABASE=Kapsys +OUI:00227C* + ID_OUI_FROM_DATABASE=Woori SMT Co.,ltd -OUI:0021EE* - ID_OUI_FROM_DATABASE=Full Spectrum Inc. +OUI:002279* + ID_OUI_FROM_DATABASE=Nippon Conlux Co., Ltd. + +OUI:002273* + ID_OUI_FROM_DATABASE=Techway + +OUI:002274* + ID_OUI_FROM_DATABASE=FamilyPhone AB + +OUI:00226F* + ID_OUI_FROM_DATABASE=3onedata Technology Co. Ltd. + +OUI:00226A* + ID_OUI_FROM_DATABASE=Honeywell + +OUI:0022F3* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:0022EE* + ID_OUI_FROM_DATABASE=Algo Communication Products Ltd + +OUI:0022E7* + ID_OUI_FROM_DATABASE=WPS Parking Systems + +OUI:0022E1* + ID_OUI_FROM_DATABASE=ZORT Labs, LLC. + +OUI:0022E2* + ID_OUI_FROM_DATABASE=WABTEC Transit Division + +OUI:0022DB* + ID_OUI_FROM_DATABASE=Translogic Corporation OUI:0022CF* ID_OUI_FROM_DATABASE=PLANEX Communications INC @@ -36647,6 +37715,30 @@ OUI:0022CA* OUI:0022C5* ID_OUI_FROM_DATABASE=INFORSON Co,Ltd. +OUI:002260* + ID_OUI_FROM_DATABASE=AFREEY Inc. + +OUI:00225B* + ID_OUI_FROM_DATABASE=Teradici Corporation + +OUI:002256* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:002255* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00224D* + ID_OUI_FROM_DATABASE=MITAC INTERNATIONAL CORP. + +OUI:002252* + ID_OUI_FROM_DATABASE=ZOLL Lifecor Corporation + +OUI:002246* + ID_OUI_FROM_DATABASE=Evoc Intelligent Technology Co.,Ltd. + +OUI:00223C* + ID_OUI_FROM_DATABASE=RATIO Entwicklungen GmbH + OUI:0022C0* ID_OUI_FROM_DATABASE=Shenzhen Forcelink Electronic Co, Ltd @@ -36662,59 +37754,53 @@ OUI:0022AD* OUI:0022A8* ID_OUI_FROM_DATABASE=Ouman Oy -OUI:002132* - ID_OUI_FROM_DATABASE=Masterclock, Inc. +OUI:0022A1* + ID_OUI_FROM_DATABASE=Huawei Symantec Technologies Co.,Ltd. -OUI:00212C* - ID_OUI_FROM_DATABASE=SemIndia System Private Limited +OUI:00229B* + ID_OUI_FROM_DATABASE=AverLogic Technologies, Inc. -OUI:002131* - ID_OUI_FROM_DATABASE=Blynke Inc. +OUI:00229C* + ID_OUI_FROM_DATABASE=Verismo Networks Inc -OUI:00211F* - ID_OUI_FROM_DATABASE=SHINSUNG DELTATECH CO.,LTD. +OUI:0023A8* + ID_OUI_FROM_DATABASE=Marshall Electronics -OUI:002120* - ID_OUI_FROM_DATABASE=Sequel Technologies +OUI:00239B* + ID_OUI_FROM_DATABASE=Elster Solutions, LLC -OUI:002125* - ID_OUI_FROM_DATABASE=KUK JE TONG SHIN Co.,LTD +OUI:002396* + ID_OUI_FROM_DATABASE=ANDES TECHNOLOGY CORPORATION -OUI:002119* - ID_OUI_FROM_DATABASE=Samsung Electro-Mechanics +OUI:002391* + ID_OUI_FROM_DATABASE=Maxian -OUI:002112* - ID_OUI_FROM_DATABASE=WISCOM SYSTEM CO.,LTD +OUI:00238C* + ID_OUI_FROM_DATABASE=Private -OUI:001FB9* - ID_OUI_FROM_DATABASE=Paltronics +OUI:002387* + ID_OUI_FROM_DATABASE=ThinkFlood, Inc. -OUI:001FB7* - ID_OUI_FROM_DATABASE=WiMate Technologies Corp. +OUI:0021D6* + ID_OUI_FROM_DATABASE=LXI Consortium -OUI:001FB8* - ID_OUI_FROM_DATABASE=Universal Remote Control, Inc. +OUI:0021CF* + ID_OUI_FROM_DATABASE=The Crypto Group -OUI:001FB2* - ID_OUI_FROM_DATABASE=Sontheim Industrie Elektronik GmbH +OUI:0021C9* + ID_OUI_FROM_DATABASE=Wavecom Asia Pacific Limited -OUI:001FAB* - ID_OUI_FROM_DATABASE=I.S HIGH TECH.INC +OUI:0021CA* + ID_OUI_FROM_DATABASE=ART System Co., Ltd. -OUI:001FA6* - ID_OUI_FROM_DATABASE=Stilo srl +OUI:0021C3* + ID_OUI_FROM_DATABASE=CORNELL Communications, Inc. -OUI:001FA1* - ID_OUI_FROM_DATABASE=Gtran Inc +OUI:0021BC* + ID_OUI_FROM_DATABASE=ZALA COMPUTER -OUI:001F9C* - ID_OUI_FROM_DATABASE=LEDCO - -OUI:00215E* - ID_OUI_FROM_DATABASE=IBM Corp - -OUI:002151* - ID_OUI_FROM_DATABASE=Millinet Co., Ltd. +OUI:0021B7* + ID_OUI_FROM_DATABASE=Lexmark International Inc. OUI:002152* ID_OUI_FROM_DATABASE=General Satellite Research & Development Limited @@ -36737,6 +37823,66 @@ OUI:00213C* OUI:00213B* ID_OUI_FROM_DATABASE=Berkshire Products, Inc +OUI:002132* + ID_OUI_FROM_DATABASE=Masterclock, Inc. + +OUI:00212C* + ID_OUI_FROM_DATABASE=SemIndia System Private Limited + +OUI:002131* + ID_OUI_FROM_DATABASE=Blynke Inc. + +OUI:001FD1* + ID_OUI_FROM_DATABASE=OPTEX CO.,LTD. + +OUI:001FCA* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:001FBE* + ID_OUI_FROM_DATABASE=Shenzhen Mopnet Industrial Co.,Ltd + +OUI:001FB9* + ID_OUI_FROM_DATABASE=Paltronics + +OUI:001FB7* + ID_OUI_FROM_DATABASE=WiMate Technologies Corp. + +OUI:001FB8* + ID_OUI_FROM_DATABASE=Universal Remote Control, Inc. + +OUI:001FB2* + ID_OUI_FROM_DATABASE=Sontheim Industrie Elektronik GmbH + +OUI:00211F* + ID_OUI_FROM_DATABASE=SHINSUNG DELTATECH CO.,LTD. + +OUI:002120* + ID_OUI_FROM_DATABASE=Sequel Technologies + +OUI:002125* + ID_OUI_FROM_DATABASE=KUK JE TONG SHIN Co.,LTD + +OUI:002119* + ID_OUI_FROM_DATABASE=Samsung Electro-Mechanics + +OUI:002112* + ID_OUI_FROM_DATABASE=WISCOM SYSTEM CO.,LTD + +OUI:002103* + ID_OUI_FROM_DATABASE=GHI Electronics, LLC + +OUI:0021B0* + ID_OUI_FROM_DATABASE=Tyco Telecommunications + +OUI:0021A4* + ID_OUI_FROM_DATABASE=Dbii Networks + +OUI:00219A* + ID_OUI_FROM_DATABASE=Cambridge Visual Networks Ltd + +OUI:002196* + ID_OUI_FROM_DATABASE=Telsey S.p.A. + OUI:002190* ID_OUI_FROM_DATABASE=Goliath Solutions @@ -36749,24 +37895,6 @@ OUI:002184* OUI:002183* ID_OUI_FROM_DATABASE=VATECH HYDRO -OUI:00217D* - ID_OUI_FROM_DATABASE=PYXIS S.R.L. - -OUI:002177* - ID_OUI_FROM_DATABASE=W. L. Gore & Associates - -OUI:002176* - ID_OUI_FROM_DATABASE=YMax Telecom Ltd. - -OUI:002171* - ID_OUI_FROM_DATABASE=Wesung TNC Co., Ltd. - -OUI:002164* - ID_OUI_FROM_DATABASE=Special Design Bureau for Seismic Instrumentation - -OUI:002103* - ID_OUI_FROM_DATABASE=GHI Electronics, LLC - OUI:001FFA* ID_OUI_FROM_DATABASE=Coretree, Co, Ltd @@ -36785,81 +37913,66 @@ OUI:001FE7* OUI:001FDB* ID_OUI_FROM_DATABASE=Network Supply Corp., -OUI:001FD1* - ID_OUI_FROM_DATABASE=OPTEX CO.,LTD. +OUI:00217D* + ID_OUI_FROM_DATABASE=PYXIS S.R.L. -OUI:001FCA* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:002177* + ID_OUI_FROM_DATABASE=W. L. Gore & Associates -OUI:001FBE* - ID_OUI_FROM_DATABASE=Shenzhen Mopnet Industrial Co.,Ltd +OUI:002176* + ID_OUI_FROM_DATABASE=YMax Telecom Ltd. -OUI:001F62* - ID_OUI_FROM_DATABASE=JSC Stilsoft +OUI:002171* + ID_OUI_FROM_DATABASE=Wesung TNC Co., Ltd. -OUI:001F67* - ID_OUI_FROM_DATABASE=Hitachi,Ltd. +OUI:002164* + ID_OUI_FROM_DATABASE=Special Design Bureau for Seismic Instrumentation -OUI:001F55* - ID_OUI_FROM_DATABASE=Honeywell Security (China) Co., Ltd. +OUI:00215E* + ID_OUI_FROM_DATABASE=IBM Corp -OUI:001F56* - ID_OUI_FROM_DATABASE=DIGITAL FORECAST +OUI:002151* + ID_OUI_FROM_DATABASE=Millinet Co., Ltd. -OUI:001F4F* - ID_OUI_FROM_DATABASE=Thinkware Co. Ltd. +OUI:002204* + ID_OUI_FROM_DATABASE=KORATEK -OUI:001F48* - ID_OUI_FROM_DATABASE=Mojix Inc. +OUI:0021FF* + ID_OUI_FROM_DATABASE=Cyfrowy Polsat SA -OUI:001F43* - ID_OUI_FROM_DATABASE=ENTES ELEKTRONIK +OUI:0021FB* + ID_OUI_FROM_DATABASE=LG Electronics + +OUI:0021F5* + ID_OUI_FROM_DATABASE=Western Engravers Supply, Inc. + +OUI:0021EF* + ID_OUI_FROM_DATABASE=Kapsys + +OUI:0021EE* + ID_OUI_FROM_DATABASE=Full Spectrum Inc. + +OUI:0021DC* + ID_OUI_FROM_DATABASE=TECNOALARM S.r.l. + +OUI:0021E2* + ID_OUI_FROM_DATABASE=Creative Electronic GmbH + +OUI:001FAB* + ID_OUI_FROM_DATABASE=I.S HIGH TECH.INC + +OUI:001FA6* + ID_OUI_FROM_DATABASE=Stilo srl + +OUI:001FA1* + ID_OUI_FROM_DATABASE=Gtran Inc + +OUI:001F9C* + ID_OUI_FROM_DATABASE=LEDCO OUI:001F8E* ID_OUI_FROM_DATABASE=Metris USA Inc. -OUI:001F88* - ID_OUI_FROM_DATABASE=FMS Force Measuring Systems AG - -OUI:001F81* - ID_OUI_FROM_DATABASE=Accel Semiconductor Corp - -OUI:001B58* - ID_OUI_FROM_DATABASE=ACE CAD Enterprise Co., Ltd. - -OUI:001F78* - ID_OUI_FROM_DATABASE=Blue Fox Porini Textile - -OUI:001F6E* - ID_OUI_FROM_DATABASE=Vtech Engineering Corporation - -OUI:001F68* - ID_OUI_FROM_DATABASE=Martinsson Elektronik AB - -OUI:0021BC* - ID_OUI_FROM_DATABASE=ZALA COMPUTER - -OUI:0021B7* - ID_OUI_FROM_DATABASE=Lexmark International Inc. - -OUI:0021B0* - ID_OUI_FROM_DATABASE=Tyco Telecommunications - -OUI:0021A4* - ID_OUI_FROM_DATABASE=Dbii Networks - -OUI:00219A* - ID_OUI_FROM_DATABASE=Cambridge Visual Networks Ltd - -OUI:002196* - ID_OUI_FROM_DATABASE=Telsey S.p.A. - -OUI:001E4B* - ID_OUI_FROM_DATABASE=City Theatrical - -OUI:001E47* - ID_OUI_FROM_DATABASE=PT. Hariff Daya Tunggal Engineering - OUI:001E41* ID_OUI_FROM_DATABASE=Microwave Communication & Component, Inc. @@ -36872,84 +37985,6 @@ OUI:001E27* OUI:001E28* ID_OUI_FROM_DATABASE=Lumexis Corporation -OUI:001DF2* - ID_OUI_FROM_DATABASE=Netflix, Inc. - -OUI:001DEB* - ID_OUI_FROM_DATABASE=DINEC International - -OUI:001DEC* - ID_OUI_FROM_DATABASE=Marusys - -OUI:001DE6* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:001DDA* - ID_OUI_FROM_DATABASE=Mikroelektronika spol. s r. o. - -OUI:001DDF* - ID_OUI_FROM_DATABASE=Sunitec Enterprise Co., Ltd. - -OUI:001DCC* - ID_OUI_FROM_DATABASE=Hetra Secure Solutions - -OUI:001DC7* - ID_OUI_FROM_DATABASE=L-3 Communications Geneva Aerospace - -OUI:001DC0* - ID_OUI_FROM_DATABASE=Enphase Energy - -OUI:001ED8* - ID_OUI_FROM_DATABASE=Digital United Inc. - -OUI:001ED2* - ID_OUI_FROM_DATABASE=Ray Shine Video Technology Inc - -OUI:001ED1* - ID_OUI_FROM_DATABASE=Keyprocessor B.V. - -OUI:001ECC* - ID_OUI_FROM_DATABASE=CDVI - -OUI:001EC5* - ID_OUI_FROM_DATABASE=Middle Atlantic Products Inc - -OUI:001EC0* - ID_OUI_FROM_DATABASE=Microchip Technology Inc. - -OUI:001EBF* - ID_OUI_FROM_DATABASE=Haas Automation Inc. - -OUI:001EB9* - ID_OUI_FROM_DATABASE=Sing Fai Technology Limited - -OUI:001EB2* - ID_OUI_FROM_DATABASE=LG innotek - -OUI:001F2E* - ID_OUI_FROM_DATABASE=Triangle Research Int'l Pte Ltd - -OUI:001F2D* - ID_OUI_FROM_DATABASE=Electro-Optical Imaging, Inc. - -OUI:001F27* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:001F20* - ID_OUI_FROM_DATABASE=Logitech Europe SA - -OUI:001F14* - ID_OUI_FROM_DATABASE=NexG - -OUI:001F1B* - ID_OUI_FROM_DATABASE=RoyalTek Company Ltd. - -OUI:001F0D* - ID_OUI_FROM_DATABASE=L3 Communications - Telemetry West - -OUI:001F0E* - ID_OUI_FROM_DATABASE=Japan Kyastem Co., Ltd - OUI:001E22* ID_OUI_FROM_DATABASE=ARVOO Imaging Products BV @@ -36977,17 +38012,41 @@ OUI:001DFE* OUI:001DF9* ID_OUI_FROM_DATABASE=Cybiotronics (Far East) Limited -OUI:001EAD* - ID_OUI_FROM_DATABASE=Wingtech Group Limited +OUI:001DF2* + ID_OUI_FROM_DATABASE=Netflix, Inc. -OUI:001EA2* - ID_OUI_FROM_DATABASE=Symx Systems, Inc. +OUI:001DEB* + ID_OUI_FROM_DATABASE=DINEC International -OUI:001EA7* - ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc +OUI:001DEC* + ID_OUI_FROM_DATABASE=Marusys -OUI:001EA1* - ID_OUI_FROM_DATABASE=Brunata a/s +OUI:001F88* + ID_OUI_FROM_DATABASE=FMS Force Measuring Systems AG + +OUI:001F81* + ID_OUI_FROM_DATABASE=Accel Semiconductor Corp + +OUI:001B58* + ID_OUI_FROM_DATABASE=ACE CAD Enterprise Co., Ltd. + +OUI:001F78* + ID_OUI_FROM_DATABASE=Blue Fox Porini Textile + +OUI:001F6E* + ID_OUI_FROM_DATABASE=Vtech Engineering Corporation + +OUI:001F68* + ID_OUI_FROM_DATABASE=Martinsson Elektronik AB + +OUI:001F62* + ID_OUI_FROM_DATABASE=JSC Stilsoft + +OUI:001F67* + ID_OUI_FROM_DATABASE=Hitachi,Ltd. + +OUI:001F55* + ID_OUI_FROM_DATABASE=Honeywell Security (China) Co., Ltd. OUI:001E9B* ID_OUI_FROM_DATABASE=San-Eisha, Ltd. @@ -37004,11 +38063,35 @@ OUI:001E87* OUI:001E80* ID_OUI_FROM_DATABASE=Last Mile Ltd. -OUI:001EFC* - ID_OUI_FROM_DATABASE=JSC MASSA-K +OUI:001E7B* + ID_OUI_FROM_DATABASE=R.I.CO. S.r.l. -OUI:001F08* - ID_OUI_FROM_DATABASE=RISCO LTD +OUI:001E76* + ID_OUI_FROM_DATABASE=Thermo Fisher Scientific + +OUI:001E6A* + ID_OUI_FROM_DATABASE=Beijing Bluexon Technology Co.,Ltd + +OUI:001F56* + ID_OUI_FROM_DATABASE=DIGITAL FORECAST + +OUI:001F4F* + ID_OUI_FROM_DATABASE=Thinkware Co. Ltd. + +OUI:001F48* + ID_OUI_FROM_DATABASE=Mojix Inc. + +OUI:001F43* + ID_OUI_FROM_DATABASE=ENTES ELEKTRONIK + +OUI:001F2E* + ID_OUI_FROM_DATABASE=Triangle Research Int'l Pte Ltd + +OUI:001F2D* + ID_OUI_FROM_DATABASE=Electro-Optical Imaging, Inc. + +OUI:001F27* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc OUI:001EF5* ID_OUI_FROM_DATABASE=Hitek Automated Inc. @@ -37025,14 +38108,65 @@ OUI:001EEE* OUI:001EE2* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd -OUI:001E7B* - ID_OUI_FROM_DATABASE=R.I.CO. S.r.l. +OUI:001ED8* + ID_OUI_FROM_DATABASE=Digital United Inc. -OUI:001E76* - ID_OUI_FROM_DATABASE=Thermo Fisher Scientific +OUI:001ED2* + ID_OUI_FROM_DATABASE=Ray Shine Video Technology Inc -OUI:001E6A* - ID_OUI_FROM_DATABASE=Beijing Bluexon Technology Co.,Ltd +OUI:001ED1* + ID_OUI_FROM_DATABASE=Keyprocessor B.V. + +OUI:001ECC* + ID_OUI_FROM_DATABASE=CDVI + +OUI:001EC5* + ID_OUI_FROM_DATABASE=Middle Atlantic Products Inc + +OUI:001EC0* + ID_OUI_FROM_DATABASE=Microchip Technology Inc. + +OUI:001EBF* + ID_OUI_FROM_DATABASE=Haas Automation Inc. + +OUI:001EB9* + ID_OUI_FROM_DATABASE=Sing Fai Technology Limited + +OUI:001EB2* + ID_OUI_FROM_DATABASE=LG innotek + +OUI:001EAD* + ID_OUI_FROM_DATABASE=Wingtech Group Limited + +OUI:001EA2* + ID_OUI_FROM_DATABASE=Symx Systems, Inc. + +OUI:001EA7* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:001EA1* + ID_OUI_FROM_DATABASE=Brunata a/s + +OUI:001F20* + ID_OUI_FROM_DATABASE=Logitech Europe SA + +OUI:001F14* + ID_OUI_FROM_DATABASE=NexG + +OUI:001F1B* + ID_OUI_FROM_DATABASE=RoyalTek Company Ltd. + +OUI:001F0D* + ID_OUI_FROM_DATABASE=L3 Communications - Telemetry West + +OUI:001F0E* + ID_OUI_FROM_DATABASE=Japan Kyastem Co., Ltd + +OUI:001EFC* + ID_OUI_FROM_DATABASE=JSC MASSA-K + +OUI:001F08* + ID_OUI_FROM_DATABASE=RISCO LTD OUI:001E71* ID_OUI_FROM_DATABASE=MIrcom Group of Companies @@ -37049,29 +38183,11 @@ OUI:001E57* OUI:001E51* ID_OUI_FROM_DATABASE=Converter Industry Srl -OUI:001DB9* - ID_OUI_FROM_DATABASE=Wellspring Wireless +OUI:001E4B* + ID_OUI_FROM_DATABASE=City Theatrical -OUI:001DB4* - ID_OUI_FROM_DATABASE=KUMHO ENG CO.,LTD - -OUI:001DAF* - ID_OUI_FROM_DATABASE=Nortel - -OUI:001D9E* - ID_OUI_FROM_DATABASE=AXION TECHNOLOGIES - -OUI:001DA3* - ID_OUI_FROM_DATABASE=SabiOso - -OUI:001D9D* - ID_OUI_FROM_DATABASE=ARTJOY INTERNATIONAL LIMITED - -OUI:001D45* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:001D3E* - ID_OUI_FROM_DATABASE=SAKA TECHNO SCIENCE CO.,LTD +OUI:001E47* + ID_OUI_FROM_DATABASE=PT. Hariff Daya Tunggal Engineering OUI:001D37* ID_OUI_FROM_DATABASE=Thales-Panda Transportation System @@ -37097,32 +38213,8 @@ OUI:001D25* OUI:001D1A* ID_OUI_FROM_DATABASE=OvisLink S.A. -OUI:001D7A* - ID_OUI_FROM_DATABASE=Wideband Semiconductor, Inc. - -OUI:001D74* - ID_OUI_FROM_DATABASE=Tianjin China-Silicon Microelectronics Co., Ltd. - -OUI:001D62* - ID_OUI_FROM_DATABASE=InPhase Technologies - -OUI:001D61* - ID_OUI_FROM_DATABASE=BIJ Corporation - -OUI:001D5B* - ID_OUI_FROM_DATABASE=Tecvan Informática Ltda - -OUI:001D54* - ID_OUI_FROM_DATABASE=Sunnic Technology & Merchandise INC. - -OUI:001D4A* - ID_OUI_FROM_DATABASE=Carestream Health, Inc. - -OUI:001CE8* - ID_OUI_FROM_DATABASE=Cummins Inc - -OUI:001CE4* - ID_OUI_FROM_DATABASE=EleSy JSC +OUI:001D14* + ID_OUI_FROM_DATABASE=SPERADTONE INFORMATION TECHNOLOGY LIMITED OUI:001CDD* ID_OUI_FROM_DATABASE=COWBELL ENGINEERING CO., LTD. @@ -37142,30 +38234,6 @@ OUI:001CCB* OUI:001CC5* ID_OUI_FROM_DATABASE=3Com Ltd -OUI:001D0D* - ID_OUI_FROM_DATABASE=Sony Computer Entertainment inc. - -OUI:001D14* - ID_OUI_FROM_DATABASE=SPERADTONE INFORMATION TECHNOLOGY LIMITED - -OUI:001D08* - ID_OUI_FROM_DATABASE=JIANGSU YINHE ELECTRONICS CO., LTD - -OUI:001D07* - ID_OUI_FROM_DATABASE=Shenzhen Sang Fei Consumer Communications Co.,Ltd - -OUI:001D01* - ID_OUI_FROM_DATABASE=Neptune Digital - -OUI:001CFA* - ID_OUI_FROM_DATABASE=Alarm.com - -OUI:001CEE* - ID_OUI_FROM_DATABASE=SHARP Corporation - -OUI:001CF5* - ID_OUI_FROM_DATABASE=Wiseblue Technology Limited - OUI:001CB9* ID_OUI_FROM_DATABASE=KWANG SUNG ELECTRONICS CO., LTD. @@ -37175,60 +38243,6 @@ OUI:001CAF* OUI:001CB4* ID_OUI_FROM_DATABASE=Iridium Satellite LLC -OUI:001C9F* - ID_OUI_FROM_DATABASE=Razorstream, LLC - -OUI:001C99* - ID_OUI_FROM_DATABASE=Shunra Software Ltd. - -OUI:001C8C* - ID_OUI_FROM_DATABASE=DIAL TECHNOLOGY LTD. - -OUI:001C93* - ID_OUI_FROM_DATABASE=ExaDigm Inc - -OUI:001C87* - ID_OUI_FROM_DATABASE=Uriver Inc. - -OUI:001C82* - ID_OUI_FROM_DATABASE=Genew Technologies - -OUI:001C1A* - ID_OUI_FROM_DATABASE=Thomas Instrumentation, Inc - -OUI:001C0E* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:001C13* - ID_OUI_FROM_DATABASE=OPTSYS TECHNOLOGY CO., LTD. - -OUI:001C07* - ID_OUI_FROM_DATABASE=Cwlinux Limited - -OUI:001C00* - ID_OUI_FROM_DATABASE=Entry Point, LLC - -OUI:001BF4* - ID_OUI_FROM_DATABASE=KENWIN INDUSTRIAL(HK) LTD. - -OUI:001BEF* - ID_OUI_FROM_DATABASE=Blossoms Digital Technology Co.,Ltd. - -OUI:001BE2* - ID_OUI_FROM_DATABASE=AhnLab,Inc. - -OUI:001C7D* - ID_OUI_FROM_DATABASE=Excelpoint Manufacturing Pte Ltd - -OUI:001C73* - ID_OUI_FROM_DATABASE=Arista Networks, Inc. - -OUI:001C78* - ID_OUI_FROM_DATABASE=WYPLAY SAS - -OUI:001C6C* - ID_OUI_FROM_DATABASE=Jabil Circuit (Guangzhou) Limited - OUI:001C65* ID_OUI_FROM_DATABASE=JoeScan, Inc. @@ -37259,26 +38273,95 @@ OUI:001C37* OUI:001C3C* ID_OUI_FROM_DATABASE=Seon Design Inc. -OUI:001C30* - ID_OUI_FROM_DATABASE=Mode Lighting (UK ) Ltd. +OUI:001DE6* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:001C2B* - ID_OUI_FROM_DATABASE=Alertme.com Limited +OUI:001DDA* + ID_OUI_FROM_DATABASE=Mikroelektronika spol. s r. o. -OUI:001C2A* - ID_OUI_FROM_DATABASE=Envisacor Technologies Inc. +OUI:001DDF* + ID_OUI_FROM_DATABASE=Sunitec Enterprise Co., Ltd. -OUI:001C29* - ID_OUI_FROM_DATABASE=CORE DIGITAL ELECTRONICS CO., LTD +OUI:001DCC* + ID_OUI_FROM_DATABASE=Hetra Secure Solutions -OUI:001C24* - ID_OUI_FROM_DATABASE=Formosa Wireless Systems Corp. +OUI:001DC7* + ID_OUI_FROM_DATABASE=L-3 Communications Geneva Aerospace -OUI:001C1F* - ID_OUI_FROM_DATABASE=Quest Retail Technology Pty Ltd +OUI:001DC0* + ID_OUI_FROM_DATABASE=Enphase Energy -OUI:001D97* - ID_OUI_FROM_DATABASE=Alertus Technologies LLC +OUI:001DB9* + ID_OUI_FROM_DATABASE=Wellspring Wireless + +OUI:001D07* + ID_OUI_FROM_DATABASE=Shenzhen Sang Fei Consumer Communications Co.,Ltd + +OUI:001D01* + ID_OUI_FROM_DATABASE=Neptune Digital + +OUI:001CFA* + ID_OUI_FROM_DATABASE=Alarm.com + +OUI:001CEE* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:001CF5* + ID_OUI_FROM_DATABASE=Wiseblue Technology Limited + +OUI:001CE8* + ID_OUI_FROM_DATABASE=Cummins Inc + +OUI:001CE4* + ID_OUI_FROM_DATABASE=EleSy JSC + +OUI:001C9F* + ID_OUI_FROM_DATABASE=Razorstream, LLC + +OUI:001C99* + ID_OUI_FROM_DATABASE=Shunra Software Ltd. + +OUI:001C8C* + ID_OUI_FROM_DATABASE=DIAL TECHNOLOGY LTD. + +OUI:001C93* + ID_OUI_FROM_DATABASE=ExaDigm Inc + +OUI:001C87* + ID_OUI_FROM_DATABASE=Uriver Inc. + +OUI:001C82* + ID_OUI_FROM_DATABASE=Genew Technologies + +OUI:001C7D* + ID_OUI_FROM_DATABASE=Excelpoint Manufacturing Pte Ltd + +OUI:001C73* + ID_OUI_FROM_DATABASE=Arista Networks, Inc. + +OUI:001C78* + ID_OUI_FROM_DATABASE=WYPLAY SAS + +OUI:001D62* + ID_OUI_FROM_DATABASE=InPhase Technologies + +OUI:001D61* + ID_OUI_FROM_DATABASE=BIJ Corporation + +OUI:001D5B* + ID_OUI_FROM_DATABASE=Tecvan Informática Ltda + +OUI:001D54* + ID_OUI_FROM_DATABASE=Sunnic Technology & Merchandise INC. + +OUI:001D4A* + ID_OUI_FROM_DATABASE=Carestream Health, Inc. + +OUI:001D45* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:001D3E* + ID_OUI_FROM_DATABASE=SAKA TECHNO SCIENCE CO.,LTD OUI:001D90* ID_OUI_FROM_DATABASE=EMCO Flow Systems @@ -37289,65 +38372,29 @@ OUI:001D84* OUI:001D67* ID_OUI_FROM_DATABASE=AMEC -OUI:001A93* - ID_OUI_FROM_DATABASE=ERCO Leuchten GmbH +OUI:001D7A* + ID_OUI_FROM_DATABASE=Wideband Semiconductor, Inc. -OUI:001A98* - ID_OUI_FROM_DATABASE=Asotel Communication Limited Taiwan Branch +OUI:001D74* + ID_OUI_FROM_DATABASE=Tianjin China-Silicon Microelectronics Co., Ltd. -OUI:001A8E* - ID_OUI_FROM_DATABASE=3Way Networks Ltd +OUI:001DB4* + ID_OUI_FROM_DATABASE=KUMHO ENG CO.,LTD -OUI:001A7D* - ID_OUI_FROM_DATABASE=cyber-blue(HK)Ltd +OUI:001DAF* + ID_OUI_FROM_DATABASE=Nortel -OUI:001A82* - ID_OUI_FROM_DATABASE=PROBA Building Automation Co.,LTD +OUI:001D9E* + ID_OUI_FROM_DATABASE=AXION TECHNOLOGIES -OUI:001A7C* - ID_OUI_FROM_DATABASE=Hirschmann Multimedia B.V. +OUI:001DA3* + ID_OUI_FROM_DATABASE=SabiOso -OUI:001A78* - ID_OUI_FROM_DATABASE=ubtos +OUI:001D9D* + ID_OUI_FROM_DATABASE=ARTJOY INTERNATIONAL LIMITED -OUI:001A7B* - ID_OUI_FROM_DATABASE=Teleco, Inc. - -OUI:001A71* - ID_OUI_FROM_DATABASE=Diostech Co., Ltd. - -OUI:001A6C* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:001A65* - ID_OUI_FROM_DATABASE=Seluxit - -OUI:001B7D* - ID_OUI_FROM_DATABASE=CXR Anderson Jacobson - -OUI:001B71* - ID_OUI_FROM_DATABASE=Telular Corp. - -OUI:001B6A* - ID_OUI_FROM_DATABASE=Powerwave Technologies Sweden AB - -OUI:001B65* - ID_OUI_FROM_DATABASE=China Gridcom Co., Ltd - -OUI:001B5E* - ID_OUI_FROM_DATABASE=BPL Limited - -OUI:001B57* - ID_OUI_FROM_DATABASE=SEMINDIA SYSTEMS PRIVATE LIMITED - -OUI:001B46* - ID_OUI_FROM_DATABASE=Blueone Technology Co.,Ltd - -OUI:001B4B* - ID_OUI_FROM_DATABASE=SANION Co., Ltd. - -OUI:001BAD* - ID_OUI_FROM_DATABASE=iControl Incorporated +OUI:001D97* + ID_OUI_FROM_DATABASE=Alertus Technologies LLC OUI:001BA6* ID_OUI_FROM_DATABASE=intotech inc. @@ -37379,11 +38426,32 @@ OUI:001B8A* OUI:001B84* ID_OUI_FROM_DATABASE=Scan Engineering Telecom -OUI:001BD1* - ID_OUI_FROM_DATABASE=SOGESTMATIC +OUI:001B7D* + ID_OUI_FROM_DATABASE=CXR Anderson Jacobson -OUI:001BD6* - ID_OUI_FROM_DATABASE=Kelvin Hughes Ltd +OUI:001B71* + ID_OUI_FROM_DATABASE=Telular Corp. + +OUI:001B6A* + ID_OUI_FROM_DATABASE=Powerwave Technologies Sweden AB + +OUI:001B65* + ID_OUI_FROM_DATABASE=China Gridcom Co., Ltd + +OUI:001B5E* + ID_OUI_FROM_DATABASE=BPL Limited + +OUI:001B57* + ID_OUI_FROM_DATABASE=SEMINDIA SYSTEMS PRIVATE LIMITED + +OUI:001B46* + ID_OUI_FROM_DATABASE=Blueone Technology Co.,Ltd + +OUI:001B4B* + ID_OUI_FROM_DATABASE=SANION Co., Ltd. + +OUI:001B3F* + ID_OUI_FROM_DATABASE=ProCurve Networking by HP OUI:001BCF* ID_OUI_FROM_DATABASE=Dataupia Corporation @@ -37403,8 +38471,101 @@ OUI:001BBE* OUI:001BB4* ID_OUI_FROM_DATABASE=Airvod Limited -OUI:001BB9* - ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. +OUI:001BAD* + ID_OUI_FROM_DATABASE=iControl Incorporated + +OUI:001AD1* + ID_OUI_FROM_DATABASE=FARGO CO., LTD. + +OUI:001AD8* + ID_OUI_FROM_DATABASE=AlsterAero GmbH + +OUI:001ACA* + ID_OUI_FROM_DATABASE=Tilera Corporation + +OUI:001ACC* + ID_OUI_FROM_DATABASE=Celestial Semiconductor, Ltd + +OUI:001AC5* + ID_OUI_FROM_DATABASE=BreakingPoint Systems, Inc. + +OUI:001ABB* + ID_OUI_FROM_DATABASE=Fontal Technology Incorporation + +OUI:001AC0* + ID_OUI_FROM_DATABASE=JOYBIEN TECHNOLOGIES CO., LTD. + +OUI:001AB4* + ID_OUI_FROM_DATABASE=FFEI Ltd. + +OUI:001AAF* + ID_OUI_FROM_DATABASE=BLUSENS TECHNOLOGY + +OUI:001C07* + ID_OUI_FROM_DATABASE=Cwlinux Limited + +OUI:001C00* + ID_OUI_FROM_DATABASE=Entry Point, LLC + +OUI:001BF4* + ID_OUI_FROM_DATABASE=KENWIN INDUSTRIAL(HK) LTD. + +OUI:001BEF* + ID_OUI_FROM_DATABASE=Blossoms Digital Technology Co.,Ltd. + +OUI:001BE2* + ID_OUI_FROM_DATABASE=AhnLab,Inc. + +OUI:001BD1* + ID_OUI_FROM_DATABASE=SOGESTMATIC + +OUI:001BD6* + ID_OUI_FROM_DATABASE=Kelvin Hughes Ltd + +OUI:001C30* + ID_OUI_FROM_DATABASE=Mode Lighting (UK ) Ltd. + +OUI:001C2B* + ID_OUI_FROM_DATABASE=Alertme.com Limited + +OUI:001C2A* + ID_OUI_FROM_DATABASE=Envisacor Technologies Inc. + +OUI:001C29* + ID_OUI_FROM_DATABASE=CORE DIGITAL ELECTRONICS CO., LTD + +OUI:001C24* + ID_OUI_FROM_DATABASE=Formosa Wireless Systems Corp. + +OUI:001C1F* + ID_OUI_FROM_DATABASE=Quest Retail Technology Pty Ltd + +OUI:001C1A* + ID_OUI_FROM_DATABASE=Thomas Instrumentation, Inc + +OUI:001C0E* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:001C13* + ID_OUI_FROM_DATABASE=OPTSYS TECHNOLOGY CO., LTD. + +OUI:001B3A* + ID_OUI_FROM_DATABASE=SIMS Corp. + +OUI:001B2C* + ID_OUI_FROM_DATABASE=ATRON electronic GmbH + +OUI:001B27* + ID_OUI_FROM_DATABASE=Merlin CSI + +OUI:001B25* + ID_OUI_FROM_DATABASE=Nortel + +OUI:001B20* + ID_OUI_FROM_DATABASE=TPine Technology + +OUI:001B19* + ID_OUI_FROM_DATABASE=IEEE I&M Society TC9 OUI:001B14* ID_OUI_FROM_DATABASE=Carex Lighting Equipment Factory @@ -37412,6 +38573,24 @@ OUI:001B14* OUI:001B0D* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:001AA8* + ID_OUI_FROM_DATABASE=Mamiya Digital Imaging Co., Ltd. + +OUI:001A9F* + ID_OUI_FROM_DATABASE=A-Link Ltd + +OUI:001AA6* + ID_OUI_FROM_DATABASE=Telefunken Radio Communication Systems GmbH &CO.KG + +OUI:001A93* + ID_OUI_FROM_DATABASE=ERCO Leuchten GmbH + +OUI:001A98* + ID_OUI_FROM_DATABASE=Asotel Communication Limited Taiwan Branch + +OUI:001A8E* + ID_OUI_FROM_DATABASE=3Way Networks Ltd + OUI:001B06* ID_OUI_FROM_DATABASE=Ateliers R. LAUMONIER @@ -37436,90 +38615,6 @@ OUI:001AE4* OUI:001ADD* ID_OUI_FROM_DATABASE=PePWave Ltd -OUI:001AD1* - ID_OUI_FROM_DATABASE=FARGO CO., LTD. - -OUI:001AD8* - ID_OUI_FROM_DATABASE=AlsterAero GmbH - -OUI:001ACA* - ID_OUI_FROM_DATABASE=Tilera Corporation - -OUI:001ACC* - ID_OUI_FROM_DATABASE=Celestial Semiconductor, Ltd - -OUI:001AC5* - ID_OUI_FROM_DATABASE=BreakingPoint Systems, Inc. - -OUI:001ABB* - ID_OUI_FROM_DATABASE=Fontal Technology Incorporation - -OUI:001AC0* - ID_OUI_FROM_DATABASE=JOYBIEN TECHNOLOGIES CO., LTD. - -OUI:001A60* - ID_OUI_FROM_DATABASE=Wave Electronics Co.,Ltd. - -OUI:001A55* - ID_OUI_FROM_DATABASE=ACA-Digital Corporation - -OUI:001A5A* - ID_OUI_FROM_DATABASE=Korea Electric Power Data Network (KDN) Co., Ltd - -OUI:001A4E* - ID_OUI_FROM_DATABASE=NTI AG / LinMot - -OUI:001A53* - ID_OUI_FROM_DATABASE=Zylaya - -OUI:001A42* - ID_OUI_FROM_DATABASE=Techcity Technology co., Ltd. - -OUI:001A47* - ID_OUI_FROM_DATABASE=Agami Systems, Inc. - -OUI:001A3B* - ID_OUI_FROM_DATABASE=Doah Elecom Inc. - -OUI:001B3F* - ID_OUI_FROM_DATABASE=ProCurve Networking by HP - -OUI:001B3A* - ID_OUI_FROM_DATABASE=SIMS Corp. - -OUI:001B2C* - ID_OUI_FROM_DATABASE=ATRON electronic GmbH - -OUI:001B27* - ID_OUI_FROM_DATABASE=Merlin CSI - -OUI:001B25* - ID_OUI_FROM_DATABASE=Nortel - -OUI:001B20* - ID_OUI_FROM_DATABASE=TPine Technology - -OUI:001B19* - ID_OUI_FROM_DATABASE=IEEE I&M Society TC9 - -OUI:001AB4* - ID_OUI_FROM_DATABASE=FFEI Ltd. - -OUI:001AAF* - ID_OUI_FROM_DATABASE=BLUSENS TECHNOLOGY - -OUI:001AA8* - ID_OUI_FROM_DATABASE=Mamiya Digital Imaging Co., Ltd. - -OUI:001A9F* - ID_OUI_FROM_DATABASE=A-Link Ltd - -OUI:001AA6* - ID_OUI_FROM_DATABASE=Telefunken Radio Communication Systems GmbH &CO.KG - -OUI:00193F* - ID_OUI_FROM_DATABASE=RDI technology(Shenzhen) Co.,LTD - OUI:001933* ID_OUI_FROM_DATABASE=Strix Systems, Inc. @@ -37529,9 +38624,6 @@ OUI:001938* OUI:00192D* ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:001921* - ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. - OUI:001926* ID_OUI_FROM_DATABASE=BitsGen Co., Ltd. @@ -37550,12 +38642,6 @@ OUI:001915* OUI:00191A* ID_OUI_FROM_DATABASE=IRLINK -OUI:001993* - ID_OUI_FROM_DATABASE=Changshu Switchgear MFG. Co.,Ltd. (Former Changshu Switchgea - -OUI:001998* - ID_OUI_FROM_DATABASE=SATO CORPORATION - OUI:00199D* ID_OUI_FROM_DATABASE=VIZIO, Inc. @@ -37592,11 +38678,59 @@ OUI:001946* OUI:001944* ID_OUI_FROM_DATABASE=Fossil Partners, L.P. -OUI:001A2F* +OUI:00193F* + ID_OUI_FROM_DATABASE=RDI technology(Shenzhen) Co.,LTD + +OUI:001A7D* + ID_OUI_FROM_DATABASE=cyber-blue(HK)Ltd + +OUI:001A82* + ID_OUI_FROM_DATABASE=PROBA Building Automation Co.,LTD + +OUI:001A7C* + ID_OUI_FROM_DATABASE=Hirschmann Multimedia B.V. + +OUI:001A78* + ID_OUI_FROM_DATABASE=ubtos + +OUI:001A7B* + ID_OUI_FROM_DATABASE=Teleco, Inc. + +OUI:001A71* + ID_OUI_FROM_DATABASE=Diostech Co., Ltd. + +OUI:001A6C* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:001A34* - ID_OUI_FROM_DATABASE=Konka Group Co., Ltd. +OUI:001A65* + ID_OUI_FROM_DATABASE=Seluxit + +OUI:001A60* + ID_OUI_FROM_DATABASE=Wave Electronics Co.,Ltd. + +OUI:001A55* + ID_OUI_FROM_DATABASE=ACA-Digital Corporation + +OUI:001A5A* + ID_OUI_FROM_DATABASE=Korea Electric Power Data Network (KDN) Co., Ltd + +OUI:001A4E* + ID_OUI_FROM_DATABASE=NTI AG / LinMot + +OUI:001A53* + ID_OUI_FROM_DATABASE=Zylaya + +OUI:001A42* + ID_OUI_FROM_DATABASE=Techcity Technology co., Ltd. + +OUI:001A47* + ID_OUI_FROM_DATABASE=Agami Systems, Inc. + +OUI:001A3B* + ID_OUI_FROM_DATABASE=Doah Elecom Inc. + +OUI:001A2F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc OUI:001A36* ID_OUI_FROM_DATABASE=Aipermon GmbH & Co. KG @@ -37604,99 +38738,6 @@ OUI:001A36* OUI:001A25* ID_OUI_FROM_DATABASE=DELTA DORE -OUI:001A17* - ID_OUI_FROM_DATABASE=Teak Technologies, Inc. - -OUI:001A19* - ID_OUI_FROM_DATABASE=Computer Engineering Limited - -OUI:001A12* - ID_OUI_FROM_DATABASE=Essilor - -OUI:001A0B* - ID_OUI_FROM_DATABASE=BONA TECHNOLOGY INC. - -OUI:001A06* - ID_OUI_FROM_DATABASE=OpVista, Inc. - -OUI:0018CD* - ID_OUI_FROM_DATABASE=Erae Electronics Industry Co., Ltd - -OUI:0018D2* - ID_OUI_FROM_DATABASE=High-Gain Antennas LLC - -OUI:0018D7* - ID_OUI_FROM_DATABASE=Javad Navigation Systems Inc. - -OUI:0018D9* - ID_OUI_FROM_DATABASE=Santosha Internatonal, Inc - -OUI:0018C1* - ID_OUI_FROM_DATABASE=Almitec Informática e Comércio - -OUI:0018C8* - ID_OUI_FROM_DATABASE=ISONAS Inc. - -OUI:0018BC* - ID_OUI_FROM_DATABASE=ZAO NVP Bolid - -OUI:0018B5* - ID_OUI_FROM_DATABASE=Magna Carta - -OUI:0018B0* - ID_OUI_FROM_DATABASE=Nortel - -OUI:0018AE* - ID_OUI_FROM_DATABASE=TVT CO.,LTD - -OUI:001902* - ID_OUI_FROM_DATABASE=Cambridge Consultants Ltd - -OUI:001907* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:0018FD* - ID_OUI_FROM_DATABASE=Optimal Technologies International Inc. - -OUI:0018F1* - ID_OUI_FROM_DATABASE=Chunichi Denshi Co.,LTD. - -OUI:0018EA* - ID_OUI_FROM_DATABASE=Alltec GmbH - -OUI:0018EC* - ID_OUI_FROM_DATABASE=Welding Technology Corporation - -OUI:0018E5* - ID_OUI_FROM_DATABASE=Adhoco AG - -OUI:0018A2* - ID_OUI_FROM_DATABASE=XIP Technology AB - -OUI:0018A9* - ID_OUI_FROM_DATABASE=Ethernet Direct Corporation - -OUI:00189D* - ID_OUI_FROM_DATABASE=Navcast Inc. - -OUI:001893* - ID_OUI_FROM_DATABASE=SHENZHEN PHOTON BROADBAND TECHNOLOGY CO.,LTD - -OUI:001898* - ID_OUI_FROM_DATABASE=KINGSTATE ELECTRONICS CORPORATION - -OUI:001891* - ID_OUI_FROM_DATABASE=Zhongshan General K-mate Electronics Co., Ltd - -OUI:001885* - ID_OUI_FROM_DATABASE=Avigilon Corporation - -OUI:00188C* - ID_OUI_FROM_DATABASE=Mobile Action Technology Inc. - -OUI:0019C8* - ID_OUI_FROM_DATABASE=AnyDATA Corporation - OUI:0019C3* ID_OUI_FROM_DATABASE=Qualitrol @@ -37718,12 +38759,60 @@ OUI:0019AB* OUI:0019B0* ID_OUI_FROM_DATABASE=HanYang System +OUI:001993* + ID_OUI_FROM_DATABASE=Changshu Switchgear MFG. Co.,Ltd. (Former Changshu Switchgea + +OUI:001998* + ID_OUI_FROM_DATABASE=SATO CORPORATION + +OUI:001A17* + ID_OUI_FROM_DATABASE=Teak Technologies, Inc. + +OUI:001A19* + ID_OUI_FROM_DATABASE=Computer Engineering Limited + +OUI:001A12* + ID_OUI_FROM_DATABASE=Essilor + +OUI:001A0B* + ID_OUI_FROM_DATABASE=BONA TECHNOLOGY INC. + +OUI:001A06* + ID_OUI_FROM_DATABASE=OpVista, Inc. + OUI:0019FA* ID_OUI_FROM_DATABASE=Cable Vision Electronics CO., LTD. OUI:0019FF* ID_OUI_FROM_DATABASE=Finnzymes +OUI:001902* + ID_OUI_FROM_DATABASE=Cambridge Consultants Ltd + +OUI:001907* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:0018FD* + ID_OUI_FROM_DATABASE=Optimal Technologies International Inc. + +OUI:0018F1* + ID_OUI_FROM_DATABASE=Chunichi Denshi Co.,LTD. + +OUI:0018EA* + ID_OUI_FROM_DATABASE=Alltec GmbH + +OUI:0018EC* + ID_OUI_FROM_DATABASE=Welding Technology Corporation + +OUI:0018E5* + ID_OUI_FROM_DATABASE=Adhoco AG + +OUI:0018CD* + ID_OUI_FROM_DATABASE=Erae Electronics Industry Co., Ltd + +OUI:0018D2* + ID_OUI_FROM_DATABASE=High-Gain Antennas LLC + OUI:0019EC* ID_OUI_FROM_DATABASE=Sagamore Systems, Inc. @@ -37748,8 +38837,8 @@ OUI:0019D4* OUI:0019D9* ID_OUI_FROM_DATABASE=Zeutschel GmbH -OUI:001823* - ID_OUI_FROM_DATABASE=Delta Electronics, Inc. +OUI:0019C8* + ID_OUI_FROM_DATABASE=AnyDATA Corporation OUI:001817* ID_OUI_FROM_DATABASE=D. E. Shaw Research, LLC @@ -37769,11 +38858,14 @@ OUI:00180B* OUI:001805* ID_OUI_FROM_DATABASE=Beijing InHand Networking Technology Co.,Ltd. -OUI:0017B8* - ID_OUI_FROM_DATABASE=NOVATRON CO., LTD. +OUI:0017F4* + ID_OUI_FROM_DATABASE=ZERON ALLIANCE -OUI:0017BD* - ID_OUI_FROM_DATABASE=Tibetsystem +OUI:0017F9* + ID_OUI_FROM_DATABASE=Forcom Sp. z o.o. + +OUI:001800* + ID_OUI_FROM_DATABASE=UNIGRAND LTD OUI:0017B1* ID_OUI_FROM_DATABASE=ACIST Medical Systems, Inc. @@ -37793,27 +38885,6 @@ OUI:0017A0* OUI:00179B* ID_OUI_FROM_DATABASE=Chant Sincere CO., LTD. -OUI:00170F* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:001705* - ID_OUI_FROM_DATABASE=Methode Electronics - -OUI:00170A* - ID_OUI_FROM_DATABASE=INEW DIGITAL COMPANY - -OUI:0016F9* - ID_OUI_FROM_DATABASE=CETRTA POT, d.o.o., Kranj - -OUI:0016F2* - ID_OUI_FROM_DATABASE=Dmobile System Co., Ltd. - -OUI:0016F7* - ID_OUI_FROM_DATABASE=L-3 Communications, Aviation Recorders - -OUI:0016E6* - ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. - OUI:00178F* ID_OUI_FROM_DATABASE=NINGBO YIDONG ELECTRONIC CO.,LTD. @@ -37823,6 +38894,33 @@ OUI:001794* OUI:00178D* ID_OUI_FROM_DATABASE=Checkpoint Systems, Inc. +OUI:0018D9* + ID_OUI_FROM_DATABASE=Santosha Internatonal, Inc + +OUI:0018C1* + ID_OUI_FROM_DATABASE=Almitec Informática e Comércio + +OUI:0018C8* + ID_OUI_FROM_DATABASE=ISONAS Inc. + +OUI:0018BC* + ID_OUI_FROM_DATABASE=ZAO NVP Bolid + +OUI:0018B5* + ID_OUI_FROM_DATABASE=Magna Carta + +OUI:0018B0* + ID_OUI_FROM_DATABASE=Nortel + +OUI:0018AE* + ID_OUI_FROM_DATABASE=TVT CO.,LTD + +OUI:0018A2* + ID_OUI_FROM_DATABASE=XIP Technology AB + +OUI:0018A9* + ID_OUI_FROM_DATABASE=Ethernet Direct Corporation + OUI:00177C* ID_OUI_FROM_DATABASE=Smartlink Network Systems Limited @@ -37850,6 +38948,24 @@ OUI:001765* OUI:001767* ID_OUI_FROM_DATABASE=Earforce AS +OUI:001759* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:001880* + ID_OUI_FROM_DATABASE=Maxim Integrated Products + +OUI:00186D* + ID_OUI_FROM_DATABASE=Zhenjiang Sapphire Electronic Industry CO. + +OUI:001872* + ID_OUI_FROM_DATABASE=Expertise Engineering + +OUI:001874* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:001879* + ID_OUI_FROM_DATABASE=dSys + OUI:00185A* ID_OUI_FROM_DATABASE=uControl, Inc. @@ -37889,8 +39005,8 @@ OUI:00182A* OUI:001836* ID_OUI_FROM_DATABASE=Reliance Electric Limited -OUI:001759* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:001823* + ID_OUI_FROM_DATABASE=Delta Electronics, Inc. OUI:001754* ID_OUI_FROM_DATABASE=Arkino HiTOP Corporation Limited @@ -37916,30 +39032,6 @@ OUI:00173A* OUI:00172E* ID_OUI_FROM_DATABASE=FXC Inc. -OUI:001727* - ID_OUI_FROM_DATABASE=Thermo Ramsey Italia s.r.l. - -OUI:001722* - ID_OUI_FROM_DATABASE=Hanazeder Electronic GmbH - -OUI:00171B* - ID_OUI_FROM_DATABASE=Innovation Lab Corp. - -OUI:001714* - ID_OUI_FROM_DATABASE=BR Controls Nederland bv - -OUI:001716* - ID_OUI_FROM_DATABASE=Qno Technology Inc. - -OUI:0017F4* - ID_OUI_FROM_DATABASE=ZERON ALLIANCE - -OUI:0017F9* - ID_OUI_FROM_DATABASE=Forcom Sp. z o.o. - -OUI:001800* - ID_OUI_FROM_DATABASE=UNIGRAND LTD - OUI:0017ED* ID_OUI_FROM_DATABASE=WooJooIT Ltd. @@ -37961,23 +39053,29 @@ OUI:0017D0* OUI:0017C4* ID_OUI_FROM_DATABASE=Quanta Microsystems, INC. -OUI:001880* - ID_OUI_FROM_DATABASE=Maxim Integrated Products +OUI:0017B8* + ID_OUI_FROM_DATABASE=NOVATRON CO., LTD. -OUI:00186D* - ID_OUI_FROM_DATABASE=Zhenjiang Sapphire Electronic Industry CO. +OUI:0017BD* + ID_OUI_FROM_DATABASE=Tibetsystem -OUI:001872* - ID_OUI_FROM_DATABASE=Expertise Engineering +OUI:00189D* + ID_OUI_FROM_DATABASE=Navcast Inc. -OUI:001874* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:001893* + ID_OUI_FROM_DATABASE=SHENZHEN PHOTON BROADBAND TECHNOLOGY CO.,LTD -OUI:001879* - ID_OUI_FROM_DATABASE=dSys +OUI:001898* + ID_OUI_FROM_DATABASE=KINGSTATE ELECTRONICS CORPORATION -OUI:001686* - ID_OUI_FROM_DATABASE=Karl Storz Imaging +OUI:001891* + ID_OUI_FROM_DATABASE=Zhongshan General K-mate Electronics Co., Ltd + +OUI:001885* + ID_OUI_FROM_DATABASE=Avigilon Corporation + +OUI:00188C* + ID_OUI_FROM_DATABASE=Mobile Action Technology Inc. OUI:00167F* ID_OUI_FROM_DATABASE=Bluebird Soft Inc. @@ -38009,120 +39107,12 @@ OUI:001666* OUI:00165F* ID_OUI_FROM_DATABASE=Fairmount Automation -OUI:0016AA* - ID_OUI_FROM_DATABASE=Kei Communication Technology Inc. - -OUI:0016AF* - ID_OUI_FROM_DATABASE=Shenzhen Union Networks Equipment Co.,Ltd. - -OUI:0016A5* - ID_OUI_FROM_DATABASE=Tandberg Storage ASA - -OUI:001699* - ID_OUI_FROM_DATABASE=Tonic DVB Marketing Ltd - -OUI:0016A0* - ID_OUI_FROM_DATABASE=Auto-Maskin - -OUI:001692* - ID_OUI_FROM_DATABASE=Scientific-Atlanta, Inc. - -OUI:001694* - ID_OUI_FROM_DATABASE=Sennheiser Communications A/S - -OUI:00168D* - ID_OUI_FROM_DATABASE=KORWIN CO., Ltd. - OUI:00165A* ID_OUI_FROM_DATABASE=Harman Specialty Group OUI:001653* ID_OUI_FROM_DATABASE=LEGO System A/S IE Electronics Division -OUI:00164C* - ID_OUI_FROM_DATABASE=PLANET INT Co., Ltd - -OUI:001647* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:001642* - ID_OUI_FROM_DATABASE=Pangolin - -OUI:00163D* - ID_OUI_FROM_DATABASE=Tsinghua Tongfang Legend Silicon Tech. Co., Ltd. - -OUI:001636* - ID_OUI_FROM_DATABASE=Quanta Computer Inc. - -OUI:001631* - ID_OUI_FROM_DATABASE=Xteam - -OUI:00162F* - ID_OUI_FROM_DATABASE=Geutebrück GmbH - -OUI:001630* - ID_OUI_FROM_DATABASE=Vativ Technologies - -OUI:0015F5* - ID_OUI_FROM_DATABASE=Sustainable Energy Systems - -OUI:0015F4* - ID_OUI_FROM_DATABASE=Eventide - -OUI:0015EE* - ID_OUI_FROM_DATABASE=Omnex Control Systems - -OUI:0015F3* - ID_OUI_FROM_DATABASE=PELTOR AB - -OUI:0015E7* - ID_OUI_FROM_DATABASE=Quantec Tontechnik - -OUI:0015E2* - ID_OUI_FROM_DATABASE=Dr.Ing. Herbert Knauer GmbH - -OUI:0015DD* - ID_OUI_FROM_DATABASE=IP Control Systems Ltd. - -OUI:0015D8* - ID_OUI_FROM_DATABASE=Interlink Electronics - -OUI:0015CA* - ID_OUI_FROM_DATABASE=TeraRecon, Inc. - -OUI:001598* - ID_OUI_FROM_DATABASE=Kolektor group - -OUI:001593* - ID_OUI_FROM_DATABASE=U4EA Technologies Inc. - -OUI:00158C* - ID_OUI_FROM_DATABASE=Liab ApS - -OUI:001586* - ID_OUI_FROM_DATABASE=Xiamen Overseas Chinese Electronic Co., Ltd. - -OUI:001585* - ID_OUI_FROM_DATABASE=Aonvision Technolopy Corp. - -OUI:001587* - ID_OUI_FROM_DATABASE=Takenaka Seisakusho Co.,Ltd - -OUI:001580* - ID_OUI_FROM_DATABASE=U-WAY CORPORATION - -OUI:00157B* - ID_OUI_FROM_DATABASE=Leuze electronic GmbH + Co. KG - -OUI:001576* - ID_OUI_FROM_DATABASE=LABiTec - Labor Biomedical Technologies GmbH - -OUI:00156A* - ID_OUI_FROM_DATABASE=DG2L Technologies Pvt. Ltd. - -OUI:00156F* - ID_OUI_FROM_DATABASE=Xiranet Communications GmbH - OUI:0016DF* ID_OUI_FROM_DATABASE=Lundinova AB @@ -38147,6 +39137,12 @@ OUI:0016C2* OUI:0016BB* ID_OUI_FROM_DATABASE=Law-Chain Computer Technology Co Ltd +OUI:0016AA* + ID_OUI_FROM_DATABASE=Kei Communication Technology Inc. + +OUI:0016AF* + ID_OUI_FROM_DATABASE=Shenzhen Union Networks Equipment Co.,Ltd. + OUI:00162A* ID_OUI_FROM_DATABASE=Antik computers & communications s.r.o. @@ -38168,26 +39164,95 @@ OUI:001606* OUI:0015FA* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:001563* +OUI:0015F5* + ID_OUI_FROM_DATABASE=Sustainable Energy Systems + +OUI:0015F4* + ID_OUI_FROM_DATABASE=Eventide + +OUI:001705* + ID_OUI_FROM_DATABASE=Methode Electronics + +OUI:00170A* + ID_OUI_FROM_DATABASE=INEW DIGITAL COMPANY + +OUI:0016F9* + ID_OUI_FROM_DATABASE=CETRTA POT, d.o.o., Kranj + +OUI:0016F2* + ID_OUI_FROM_DATABASE=Dmobile System Co., Ltd. + +OUI:0016F7* + ID_OUI_FROM_DATABASE=L-3 Communications, Aviation Recorders + +OUI:0016E6* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:00164C* + ID_OUI_FROM_DATABASE=PLANET INT Co., Ltd + +OUI:001647* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:001557* - ID_OUI_FROM_DATABASE=Olivetti +OUI:001642* + ID_OUI_FROM_DATABASE=Pangolin -OUI:00155C* - ID_OUI_FROM_DATABASE=Dresser Wayne +OUI:00163D* + ID_OUI_FROM_DATABASE=Tsinghua Tongfang Legend Silicon Tech. Co., Ltd. -OUI:00154B* - ID_OUI_FROM_DATABASE=Wonde Proud Technology Co., Ltd +OUI:001636* + ID_OUI_FROM_DATABASE=Quanta Computer Inc. -OUI:001550* - ID_OUI_FROM_DATABASE=Nits Technology Inc +OUI:001631* + ID_OUI_FROM_DATABASE=Xteam -OUI:001545* - ID_OUI_FROM_DATABASE=SEECODE Co., Ltd. +OUI:00162F* + ID_OUI_FROM_DATABASE=Geutebrück GmbH -OUI:00153E* - ID_OUI_FROM_DATABASE=Q-Matic Sweden AB +OUI:001630* + ID_OUI_FROM_DATABASE=Vativ Technologies + +OUI:0016A5* + ID_OUI_FROM_DATABASE=Tandberg Storage ASA + +OUI:001699* + ID_OUI_FROM_DATABASE=Tonic DVB Marketing Ltd + +OUI:0016A0* + ID_OUI_FROM_DATABASE=Auto-Maskin + +OUI:001692* + ID_OUI_FROM_DATABASE=Scientific-Atlanta, Inc. + +OUI:001694* + ID_OUI_FROM_DATABASE=Sennheiser Communications A/S + +OUI:00168D* + ID_OUI_FROM_DATABASE=KORWIN CO., Ltd. + +OUI:001686* + ID_OUI_FROM_DATABASE=Karl Storz Imaging + +OUI:0015EE* + ID_OUI_FROM_DATABASE=Omnex Control Systems + +OUI:0015F3* + ID_OUI_FROM_DATABASE=PELTOR AB + +OUI:0015E7* + ID_OUI_FROM_DATABASE=Quantec Tontechnik + +OUI:0015E2* + ID_OUI_FROM_DATABASE=Dr.Ing. Herbert Knauer GmbH + +OUI:0015DD* + ID_OUI_FROM_DATABASE=IP Control Systems Ltd. + +OUI:0015D8* + ID_OUI_FROM_DATABASE=Interlink Electronics + +OUI:0015CA* + ID_OUI_FROM_DATABASE=TeraRecon, Inc. OUI:0015BC* ID_OUI_FROM_DATABASE=Develco @@ -38207,6 +39272,51 @@ OUI:0015A6* OUI:00159F* ID_OUI_FROM_DATABASE=Terascala, Inc. +OUI:001598* + ID_OUI_FROM_DATABASE=Kolektor group + +OUI:001727* + ID_OUI_FROM_DATABASE=Thermo Ramsey Italia s.r.l. + +OUI:001722* + ID_OUI_FROM_DATABASE=Hanazeder Electronic GmbH + +OUI:00171B* + ID_OUI_FROM_DATABASE=Innovation Lab Corp. + +OUI:001714* + ID_OUI_FROM_DATABASE=BR Controls Nederland bv + +OUI:001716* + ID_OUI_FROM_DATABASE=Qno Technology Inc. + +OUI:00170F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:0014AA* + ID_OUI_FROM_DATABASE=Ashly Audio, Inc. + +OUI:00149D* + ID_OUI_FROM_DATABASE=Sound ID Inc. + +OUI:001498* + ID_OUI_FROM_DATABASE=Viking Design Technology + +OUI:00148A* + ID_OUI_FROM_DATABASE=Elin Ebg Traction Gmbh + +OUI:001491* + ID_OUI_FROM_DATABASE=Daniels Electronics Ltd. dbo Codan Rado Communications + +OUI:001485* + ID_OUI_FROM_DATABASE=Giga-Byte + +OUI:00147E* + ID_OUI_FROM_DATABASE=InnerWireless + +OUI:001478* + ID_OUI_FROM_DATABASE=ShenZhen TP-LINK Technologies Co., Ltd. + OUI:001532* ID_OUI_FROM_DATABASE=Consumer Technologies Group, LLC @@ -38237,8 +39347,11 @@ OUI:001515* OUI:001510* ID_OUI_FROM_DATABASE=Techsphere Co., Ltd -OUI:001453* - ID_OUI_FROM_DATABASE=ADVANTECH TECHNOLOGIES CO.,LTD +OUI:001502* + ID_OUI_FROM_DATABASE=BETA tech + +OUI:001509* + ID_OUI_FROM_DATABASE=Plus Technology Co., Ltd OUI:00144E* ID_OUI_FROM_DATABASE=SRISA @@ -38261,65 +39374,59 @@ OUI:00143B* OUI:001436* ID_OUI_FROM_DATABASE=Qwerty Elektronik AB -OUI:00142A* - ID_OUI_FROM_DATABASE=Elitegroup Computer System Co., Ltd +OUI:001423* + ID_OUI_FROM_DATABASE=J-S Co. NEUROCOM -OUI:0014AB* - ID_OUI_FROM_DATABASE=Senhai Electronic Technology Co., Ltd. +OUI:001593* + ID_OUI_FROM_DATABASE=U4EA Technologies Inc. -OUI:0014B0* - ID_OUI_FROM_DATABASE=Naeil Community +OUI:00158C* + ID_OUI_FROM_DATABASE=Liab ApS -OUI:0014B4* - ID_OUI_FROM_DATABASE=General Dynamics United Kingdom Ltd +OUI:001586* + ID_OUI_FROM_DATABASE=Xiamen Overseas Chinese Electronic Co., Ltd. -OUI:0014A9* +OUI:001585* + ID_OUI_FROM_DATABASE=Aonvision Technolopy Corp. + +OUI:001587* + ID_OUI_FROM_DATABASE=Takenaka Seisakusho Co.,Ltd + +OUI:001580* + ID_OUI_FROM_DATABASE=U-WAY CORPORATION + +OUI:00157B* + ID_OUI_FROM_DATABASE=Leuze electronic GmbH + Co. KG + +OUI:001576* + ID_OUI_FROM_DATABASE=LABiTec - Labor Biomedical Technologies GmbH + +OUI:00156A* + ID_OUI_FROM_DATABASE=DG2L Technologies Pvt. Ltd. + +OUI:00156F* + ID_OUI_FROM_DATABASE=Xiranet Communications GmbH + +OUI:001563* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:0014AA* - ID_OUI_FROM_DATABASE=Ashly Audio, Inc. +OUI:0014FD* + ID_OUI_FROM_DATABASE=Thecus Technology Corp. -OUI:00149D* - ID_OUI_FROM_DATABASE=Sound ID Inc. +OUI:0014EF* + ID_OUI_FROM_DATABASE=TZero Technologies, Inc. -OUI:001498* - ID_OUI_FROM_DATABASE=Viking Design Technology +OUI:0014F1* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:00148A* - ID_OUI_FROM_DATABASE=Elin Ebg Traction Gmbh +OUI:0014F0* + ID_OUI_FROM_DATABASE=Business Security OL AB -OUI:001491* - ID_OUI_FROM_DATABASE=Daniels Electronics Ltd. dbo Codan Rado Communications +OUI:0014EA* + ID_OUI_FROM_DATABASE=S Digm Inc. (Safe Paradigm Inc.) -OUI:001485* - ID_OUI_FROM_DATABASE=Giga-Byte - -OUI:001479* - ID_OUI_FROM_DATABASE=NEC Magnus Communications,Ltd. - -OUI:00147E* - ID_OUI_FROM_DATABASE=InnerWireless - -OUI:001478* - ID_OUI_FROM_DATABASE=ShenZhen TP-LINK Technologies Co., Ltd. - -OUI:001477* - ID_OUI_FROM_DATABASE=Nertec Inc. - -OUI:001472* - ID_OUI_FROM_DATABASE=China Broadband Wireless IP Standard Group - -OUI:001466* - ID_OUI_FROM_DATABASE=Kleinhenz Elektronik GmbH - -OUI:00146B* - ID_OUI_FROM_DATABASE=Anagran, Inc. - -OUI:00145F* - ID_OUI_FROM_DATABASE=ADITEC CO. LTD - -OUI:001458* - ID_OUI_FROM_DATABASE=HS Automatic ApS +OUI:0014E5* + ID_OUI_FROM_DATABASE=Alticast OUI:0014E6* ID_OUI_FROM_DATABASE=AIM Infrarotmodule GmbH @@ -38348,56 +39455,56 @@ OUI:0014BA* OUI:0014B5* ID_OUI_FROM_DATABASE=PHYSIOMETRIX,INC -OUI:0013C7* - ID_OUI_FROM_DATABASE=IONOS Co.,Ltd. +OUI:0014AB* + ID_OUI_FROM_DATABASE=Senhai Electronic Technology Co., Ltd. -OUI:0013C0* - ID_OUI_FROM_DATABASE=Trix Tecnologia Ltda. +OUI:0014B0* + ID_OUI_FROM_DATABASE=Naeil Community -OUI:0013B6* - ID_OUI_FROM_DATABASE=Sling Media, Inc. +OUI:0014B4* + ID_OUI_FROM_DATABASE=General Dynamics United Kingdom Ltd -OUI:0013AF* - ID_OUI_FROM_DATABASE=NUMA Technology,Inc. - -OUI:0013B0* - ID_OUI_FROM_DATABASE=Jablotron - -OUI:0013AA* - ID_OUI_FROM_DATABASE=ALS & TEC Ltd. - -OUI:0013A3* - ID_OUI_FROM_DATABASE=Siemens Com CPE Devices - -OUI:00139E* - ID_OUI_FROM_DATABASE=Ciara Technologies Inc. - -OUI:001502* - ID_OUI_FROM_DATABASE=BETA tech - -OUI:001509* - ID_OUI_FROM_DATABASE=Plus Technology Co., Ltd - -OUI:0014FD* - ID_OUI_FROM_DATABASE=Thecus Technology Corp. - -OUI:0014EF* - ID_OUI_FROM_DATABASE=TZero Technologies, Inc. - -OUI:0014F1* +OUI:0014A9* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:0014F0* - ID_OUI_FROM_DATABASE=Business Security OL AB +OUI:001557* + ID_OUI_FROM_DATABASE=Olivetti -OUI:0014EA* - ID_OUI_FROM_DATABASE=S Digm Inc. (Safe Paradigm Inc.) +OUI:00155C* + ID_OUI_FROM_DATABASE=Dresser Wayne -OUI:0014E5* - ID_OUI_FROM_DATABASE=Alticast +OUI:00154B* + ID_OUI_FROM_DATABASE=Wonde Proud Technology Co., Ltd -OUI:001423* - ID_OUI_FROM_DATABASE=J-S Co. NEUROCOM +OUI:001550* + ID_OUI_FROM_DATABASE=Nits Technology Inc + +OUI:001545* + ID_OUI_FROM_DATABASE=SEECODE Co., Ltd. + +OUI:00153E* + ID_OUI_FROM_DATABASE=Q-Matic Sweden AB + +OUI:001477* + ID_OUI_FROM_DATABASE=Nertec Inc. + +OUI:001472* + ID_OUI_FROM_DATABASE=China Broadband Wireless IP Standard Group + +OUI:001466* + ID_OUI_FROM_DATABASE=Kleinhenz Elektronik GmbH + +OUI:00146B* + ID_OUI_FROM_DATABASE=Anagran, Inc. + +OUI:00145F* + ID_OUI_FROM_DATABASE=ADITEC CO. LTD + +OUI:001458* + ID_OUI_FROM_DATABASE=HS Automatic ApS + +OUI:001453* + ID_OUI_FROM_DATABASE=ADVANTECH TECHNOLOGIES CO.,LTD OUI:001419* ID_OUI_FROM_DATABASE=SIDSA @@ -38423,20 +39530,38 @@ OUI:0013F8* OUI:0013F1* ID_OUI_FROM_DATABASE=AMOD Technology Co., Ltd. -OUI:0013F7* - ID_OUI_FROM_DATABASE=SMC Networks, Inc. +OUI:00135C* + ID_OUI_FROM_DATABASE=OnSite Systems, Inc. -OUI:0013E7* - ID_OUI_FROM_DATABASE=Halcro +OUI:001355* + ID_OUI_FROM_DATABASE=TOMEN Cyber-business Solutions, Inc. -OUI:0013DB* - ID_OUI_FROM_DATABASE=SHOEI Electric Co.,Ltd +OUI:001356* + ID_OUI_FROM_DATABASE=FLIR Radiation Inc -OUI:0013CC* - ID_OUI_FROM_DATABASE=Tall Maple Systems +OUI:001350* + ID_OUI_FROM_DATABASE=Silver Spring Networks, Inc -OUI:001283* - ID_OUI_FROM_DATABASE=Nortel Networks +OUI:001344* + ID_OUI_FROM_DATABASE=Fargo Electronics Inc. + +OUI:001349* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:001343* + ID_OUI_FROM_DATABASE=Matsushita Electronic Components (Europe) GmbH + +OUI:00133D* + ID_OUI_FROM_DATABASE=Micro Memory Curtiss Wright Co + +OUI:00132A* + ID_OUI_FROM_DATABASE=Sitronics Telecom Solutions + +OUI:001331* + ID_OUI_FROM_DATABASE=CellPoint Connect + +OUI:001336* + ID_OUI_FROM_DATABASE=Tianjin 712 Communication Broadcasting co., ltd. OUI:001284* ID_OUI_FROM_DATABASE=Lab33 Srl @@ -38462,63 +39587,75 @@ OUI:001264* OUI:00125A* ID_OUI_FROM_DATABASE=Microsoft Corporation -OUI:00125F* - ID_OUI_FROM_DATABASE=AWIND Inc. +OUI:0012FA* + ID_OUI_FROM_DATABASE=THX LTD -OUI:001255* - ID_OUI_FROM_DATABASE=NetEffect Incorporated +OUI:001301* + ID_OUI_FROM_DATABASE=IronGate S.L. -OUI:00124E* - ID_OUI_FROM_DATABASE=XAC AUTOMATION CORP. +OUI:001307* + ID_OUI_FROM_DATABASE=Paravirtual Corporation -OUI:001247* - ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. +OUI:0012F5* + ID_OUI_FROM_DATABASE=Imarda New Zealand Limited -OUI:001248* - ID_OUI_FROM_DATABASE=EMC Corporation (Kashya) +OUI:0012EB* + ID_OUI_FROM_DATABASE=PDH Solutions, LLC -OUI:001242* - ID_OUI_FROM_DATABASE=Millennial Net +OUI:0012DE* + ID_OUI_FROM_DATABASE=Radio Components Sweden AB -OUI:001236* - ID_OUI_FROM_DATABASE=ConSentry Networks +OUI:0012DD* + ID_OUI_FROM_DATABASE=Shengqu Information Technology (Shanghai) Co., Ltd. -OUI:00123B* - ID_OUI_FROM_DATABASE=KeRo Systems ApS +OUI:0012E4* + ID_OUI_FROM_DATABASE=ZIEHL industrie-electronik GmbH + Co KG -OUI:001368* - ID_OUI_FROM_DATABASE=Saab Danmark A/S +OUI:0012D8* + ID_OUI_FROM_DATABASE=International Games System Co., Ltd. -OUI:00135C* - ID_OUI_FROM_DATABASE=OnSite Systems, Inc. +OUI:0013B6* + ID_OUI_FROM_DATABASE=Sling Media, Inc. -OUI:001355* - ID_OUI_FROM_DATABASE=TOMEN Cyber-business Solutions, Inc. +OUI:0013AF* + ID_OUI_FROM_DATABASE=NUMA Technology,Inc. -OUI:001356* - ID_OUI_FROM_DATABASE=FLIR Radiation Inc +OUI:0013B0* + ID_OUI_FROM_DATABASE=Jablotron -OUI:001350* - ID_OUI_FROM_DATABASE=Silver Spring Networks, Inc +OUI:0013AA* + ID_OUI_FROM_DATABASE=ALS & TEC Ltd. -OUI:001344* - ID_OUI_FROM_DATABASE=Fargo Electronics Inc. +OUI:0013A3* + ID_OUI_FROM_DATABASE=Siemens Com CPE Devices -OUI:001349* - ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation - -OUI:001343* - ID_OUI_FROM_DATABASE=Matsushita Electronic Components (Europe) GmbH - -OUI:00133D* - ID_OUI_FROM_DATABASE=Micro Memory Curtiss Wright Co - -OUI:001397* - ID_OUI_FROM_DATABASE=Oracle Corporation +OUI:00139E* + ID_OUI_FROM_DATABASE=Ciara Technologies Inc. OUI:00139D* ID_OUI_FROM_DATABASE=Marvell Hispana S.L. +OUI:0012A8* + ID_OUI_FROM_DATABASE=intec GmbH + +OUI:0012A2* + ID_OUI_FROM_DATABASE=VITA + +OUI:0012A1* + ID_OUI_FROM_DATABASE=BluePacket Communications Co., Ltd. + +OUI:00129C* + ID_OUI_FROM_DATABASE=Yulinet + +OUI:001290* + ID_OUI_FROM_DATABASE=KYOWA Electric & Machinery Corp. + +OUI:001295* + ID_OUI_FROM_DATABASE=Aiware Inc. + +OUI:001283* + ID_OUI_FROM_DATABASE=Nortel Networks + OUI:00138B* ID_OUI_FROM_DATABASE=Phantom Technologies LLC @@ -38546,60 +39683,45 @@ OUI:001375* OUI:001363* ID_OUI_FROM_DATABASE=Verascape, Inc. -OUI:0012FA* - ID_OUI_FROM_DATABASE=THX LTD +OUI:001368* + ID_OUI_FROM_DATABASE=Saab Danmark A/S -OUI:001301* - ID_OUI_FROM_DATABASE=IronGate S.L. +OUI:0013F7* + ID_OUI_FROM_DATABASE=SMC Networks, Inc. -OUI:001307* - ID_OUI_FROM_DATABASE=Paravirtual Corporation +OUI:0013E7* + ID_OUI_FROM_DATABASE=Halcro -OUI:0012F5* - ID_OUI_FROM_DATABASE=Imarda New Zealand Limited +OUI:0013DB* + ID_OUI_FROM_DATABASE=SHOEI Electric Co.,Ltd -OUI:0012EB* - ID_OUI_FROM_DATABASE=PDH Solutions, LLC +OUI:0013CC* + ID_OUI_FROM_DATABASE=Tall Maple Systems -OUI:0012DE* - ID_OUI_FROM_DATABASE=Radio Components Sweden AB +OUI:0013C7* + ID_OUI_FROM_DATABASE=IONOS Co.,Ltd. -OUI:0012DD* - ID_OUI_FROM_DATABASE=Shengqu Information Technology (Shanghai) Co., Ltd. +OUI:0013C0* + ID_OUI_FROM_DATABASE=Trix Tecnologia Ltda. -OUI:0012E4* - ID_OUI_FROM_DATABASE=ZIEHL industrie-electronik GmbH + Co KG +OUI:0012CB* + ID_OUI_FROM_DATABASE=CSS Inc. + +OUI:0012C5* + ID_OUI_FROM_DATABASE=V-Show Technology (China) Co.,Ltd + +OUI:0012CC* + ID_OUI_FROM_DATABASE=Bitatek CO., LTD + +OUI:0012B4* + ID_OUI_FROM_DATABASE=Work Microwave GmbH + +OUI:0012BB* + ID_OUI_FROM_DATABASE=Telecommunications Industry Association TR-41 Committee OUI:0012AF* ID_OUI_FROM_DATABASE=ELPRO Technologies -OUI:0012A8* - ID_OUI_FROM_DATABASE=intec GmbH - -OUI:0012A2* - ID_OUI_FROM_DATABASE=VITA - -OUI:0012A1* - ID_OUI_FROM_DATABASE=BluePacket Communications Co., Ltd. - -OUI:00129C* - ID_OUI_FROM_DATABASE=Yulinet - -OUI:001290* - ID_OUI_FROM_DATABASE=KYOWA Electric & Machinery Corp. - -OUI:001295* - ID_OUI_FROM_DATABASE=Aiware Inc. - -OUI:00132A* - ID_OUI_FROM_DATABASE=Sitronics Telecom Solutions - -OUI:001331* - ID_OUI_FROM_DATABASE=CellPoint Connect - -OUI:001336* - ID_OUI_FROM_DATABASE=Tianjin 712 Communication Broadcasting co., ltd. - OUI:001324* ID_OUI_FROM_DATABASE=Schneider Electric Ultra Terminal @@ -38618,47 +39740,53 @@ OUI:00130D* OUI:001308* ID_OUI_FROM_DATABASE=Nuvera Fuel Cells -OUI:00122F* - ID_OUI_FROM_DATABASE=Sanei Electric Inc. +OUI:001181* + ID_OUI_FROM_DATABASE=InterEnergy Co.Ltd, -OUI:001235* - ID_OUI_FROM_DATABASE=Andrew Corporation +OUI:00117B* + ID_OUI_FROM_DATABASE=Büchi Labortechnik AG -OUI:00122B* - ID_OUI_FROM_DATABASE=Virbiage Pty Ltd +OUI:00116F* + ID_OUI_FROM_DATABASE=Netforyou Co., LTD. -OUI:001212* - ID_OUI_FROM_DATABASE=PLUS Corporation +OUI:001168* + ID_OUI_FROM_DATABASE=HomeLogic LLC -OUI:001219* - ID_OUI_FROM_DATABASE=Ahead Communication Systems Inc +OUI:00115E* + ID_OUI_FROM_DATABASE=ProMinent Dosiertechnik GmbH -OUI:0012D8* - ID_OUI_FROM_DATABASE=International Games System Co., Ltd. +OUI:001157* + ID_OUI_FROM_DATABASE=Oki Electric Industry Co., Ltd. -OUI:0012CB* - ID_OUI_FROM_DATABASE=CSS Inc. +OUI:001158* + ID_OUI_FROM_DATABASE=Nortel Networks -OUI:0012C5* - ID_OUI_FROM_DATABASE=V-Show Technology (China) Co.,Ltd +OUI:001152* + ID_OUI_FROM_DATABASE=Eidsvoll Electronics AS -OUI:0012CC* - ID_OUI_FROM_DATABASE=Bitatek CO., LTD +OUI:0011A4* + ID_OUI_FROM_DATABASE=JStream Technologies Inc. -OUI:0012B4* - ID_OUI_FROM_DATABASE=Work Microwave GmbH +OUI:001198* + ID_OUI_FROM_DATABASE=Prism Media Products Limited -OUI:0012BB* - ID_OUI_FROM_DATABASE=Telecommunications Industry Association TR-41 Committee +OUI:00119D* + ID_OUI_FROM_DATABASE=Diginfo Technology Corporation -OUI:001206* - ID_OUI_FROM_DATABASE=iQuest (NZ) Ltd +OUI:00119E* + ID_OUI_FROM_DATABASE=Solectron Brazil -OUI:00120B* - ID_OUI_FROM_DATABASE=Chinasys Technologies Limited +OUI:00118E* + ID_OUI_FROM_DATABASE=Halytech Mace -OUI:00120C* - ID_OUI_FROM_DATABASE=CE-Infosys Pte Ltd +OUI:001193* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:001187* + ID_OUI_FROM_DATABASE=Category Solutions, Inc + +OUI:001182* + ID_OUI_FROM_DATABASE=IMI Norgren Ltd OUI:0011FF* ID_OUI_FROM_DATABASE=Digitro Tecnologia Ltda @@ -38678,93 +39806,78 @@ OUI:0011EF* OUI:0011E9* ID_OUI_FROM_DATABASE=STARNEX CO., LTD. -OUI:001187* - ID_OUI_FROM_DATABASE=Category Solutions, Inc - -OUI:001182* - ID_OUI_FROM_DATABASE=IMI Norgren Ltd - -OUI:001181* - ID_OUI_FROM_DATABASE=InterEnergy Co.Ltd, - -OUI:00117B* - ID_OUI_FROM_DATABASE=Büchi Labortechnik AG - -OUI:001174* - ID_OUI_FROM_DATABASE=Wibhu Technologies, Inc. - -OUI:00116F* - ID_OUI_FROM_DATABASE=Netforyou Co., LTD. - -OUI:001168* - ID_OUI_FROM_DATABASE=HomeLogic LLC - -OUI:00115E* - ID_OUI_FROM_DATABASE=ProMinent Dosiertechnik GmbH - -OUI:001157* - ID_OUI_FROM_DATABASE=Oki Electric Industry Co., Ltd. - -OUI:001158* - ID_OUI_FROM_DATABASE=Nortel Networks - -OUI:000FB2* - ID_OUI_FROM_DATABASE=Broadband Pacenet (India) Pvt. Ltd. - -OUI:000FA5* - ID_OUI_FROM_DATABASE=BWA Technology GmbH - -OUI:000FB1* - ID_OUI_FROM_DATABASE=Cognio Inc. - -OUI:000FAC* - ID_OUI_FROM_DATABASE=IEEE 802.11 - -OUI:000F9C* - ID_OUI_FROM_DATABASE=Panduit Corp - -OUI:000FA0* - ID_OUI_FROM_DATABASE=CANON KOREA BUSINESS SOLUTIONS INC. - -OUI:000F97* - ID_OUI_FROM_DATABASE=Avanex Corporation - -OUI:000F8A* - ID_OUI_FROM_DATABASE=WideView - -OUI:000F89* - ID_OUI_FROM_DATABASE=Winnertec System Co., Ltd. - -OUI:000F90* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:000FD7* - ID_OUI_FROM_DATABASE=Harman Music Group - -OUI:000FD1* - ID_OUI_FROM_DATABASE=Applied Wireless Identifications Group, Inc. - -OUI:000FD2* - ID_OUI_FROM_DATABASE=EWA Technologies, Inc. - -OUI:000FC4* - ID_OUI_FROM_DATABASE=NST co.,LTD. - -OUI:000FCB* - ID_OUI_FROM_DATABASE=3Com Ltd - -OUI:000FBF* - ID_OUI_FROM_DATABASE=DGT Sp. z o.o. - -OUI:000FB8* - ID_OUI_FROM_DATABASE=CallURL Inc. - OUI:0011DD* ID_OUI_FROM_DATABASE=FROMUS TEC. Co., Ltd. OUI:0011E2* ID_OUI_FROM_DATABASE=Hua Jung Components Co., Ltd. +OUI:000FFA* + ID_OUI_FROM_DATABASE=Optinel Systems, Inc. + +OUI:000FFF* + ID_OUI_FROM_DATABASE=Control4 + +OUI:000FF1* + ID_OUI_FROM_DATABASE=nex-G Systems Pte.Ltd + +OUI:000FE4* + ID_OUI_FROM_DATABASE=Pantech Co.,Ltd + +OUI:000FEA* + ID_OUI_FROM_DATABASE=Giga-Byte Technology Co.,LTD. + +OUI:000FE3* + ID_OUI_FROM_DATABASE=Damm Cellular Systems A/S + +OUI:000FD7* + ID_OUI_FROM_DATABASE=Harman Music Group + +OUI:001235* + ID_OUI_FROM_DATABASE=Andrew Corporation + +OUI:00122B* + ID_OUI_FROM_DATABASE=Virbiage Pty Ltd + +OUI:001212* + ID_OUI_FROM_DATABASE=PLUS Corporation + +OUI:001219* + ID_OUI_FROM_DATABASE=Ahead Communication Systems Inc + +OUI:001206* + ID_OUI_FROM_DATABASE=iQuest (NZ) Ltd + +OUI:00120B* + ID_OUI_FROM_DATABASE=Chinasys Technologies Limited + +OUI:00120C* + ID_OUI_FROM_DATABASE=CE-Infosys Pte Ltd + +OUI:001130* + ID_OUI_FROM_DATABASE=Allied Telesis (Hong Kong) Ltd. + +OUI:00111E* + ID_OUI_FROM_DATABASE=EPSG (Ethernet Powerlink Standardization Group) + +OUI:00111F* + ID_OUI_FROM_DATABASE=Doremi Labs, Inc. + +OUI:001112* + ID_OUI_FROM_DATABASE=Honeywell CMSS + +OUI:001118* + ID_OUI_FROM_DATABASE=BLX IC Design Corp., Ltd. + +OUI:001105* + ID_OUI_FROM_DATABASE=Sunplus Technology Co., Ltd. + +OUI:00110C* + ID_OUI_FROM_DATABASE=Atmark Techno, Inc. + +OUI:000FF9* + ID_OUI_FROM_DATABASE=Valcretec, Inc. + OUI:0011CF* ID_OUI_FROM_DATABASE=Thrane & Thrane A/S @@ -38789,59 +39902,38 @@ OUI:0011BE* OUI:0011BD* ID_OUI_FROM_DATABASE=Bombardier Transportation -OUI:001105* - ID_OUI_FROM_DATABASE=Sunplus Technology Co., Ltd. - -OUI:00110C* - ID_OUI_FROM_DATABASE=Atmark Techno, Inc. - -OUI:000FF9* - ID_OUI_FROM_DATABASE=Valcretec, Inc. - -OUI:000FFA* - ID_OUI_FROM_DATABASE=Optinel Systems, Inc. - -OUI:000FFF* - ID_OUI_FROM_DATABASE=Control4 - -OUI:000FF1* - ID_OUI_FROM_DATABASE=nex-G Systems Pte.Ltd - -OUI:000FE4* - ID_OUI_FROM_DATABASE=Pantech Co.,Ltd - -OUI:000FEA* - ID_OUI_FROM_DATABASE=Giga-Byte Technology Co.,LTD. - -OUI:000FE3* - ID_OUI_FROM_DATABASE=Damm Cellular Systems A/S - OUI:0011AB* ID_OUI_FROM_DATABASE=TRUSTABLE TECHNOLOGY CO.,LTD. OUI:0011B0* ID_OUI_FROM_DATABASE=Fortelink Inc. -OUI:0011A4* - ID_OUI_FROM_DATABASE=JStream Technologies Inc. +OUI:00125F* + ID_OUI_FROM_DATABASE=AWIND Inc. -OUI:001198* - ID_OUI_FROM_DATABASE=Prism Media Products Limited +OUI:001255* + ID_OUI_FROM_DATABASE=NetEffect Incorporated -OUI:00119D* - ID_OUI_FROM_DATABASE=Diginfo Technology Corporation +OUI:00124E* + ID_OUI_FROM_DATABASE=XAC AUTOMATION CORP. -OUI:00119E* - ID_OUI_FROM_DATABASE=Solectron Brazil +OUI:001247* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd. -OUI:00118E* - ID_OUI_FROM_DATABASE=Halytech Mace +OUI:001248* + ID_OUI_FROM_DATABASE=EMC Corporation (Kashya) -OUI:001193* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:001242* + ID_OUI_FROM_DATABASE=Millennial Net -OUI:001152* - ID_OUI_FROM_DATABASE=Eidsvoll Electronics AS +OUI:001236* + ID_OUI_FROM_DATABASE=ConSentry Networks + +OUI:00123B* + ID_OUI_FROM_DATABASE=KeRo Systems ApS + +OUI:00122F* + ID_OUI_FROM_DATABASE=Sanei Electric Inc. OUI:00114F* ID_OUI_FROM_DATABASE=US Digital Television, Inc @@ -38864,20 +39956,23 @@ OUI:001136* OUI:00112C* ID_OUI_FROM_DATABASE=IZT GmbH -OUI:001130* - ID_OUI_FROM_DATABASE=Allied Telesis (Hong Kong) Ltd. +OUI:000F77* + ID_OUI_FROM_DATABASE=DENTUM CO.,LTD -OUI:00111E* - ID_OUI_FROM_DATABASE=EPSG (Ethernet Powerlink Standardization Group) +OUI:000F71* + ID_OUI_FROM_DATABASE=Sanmei Electronics Co.,Ltd -OUI:00111F* - ID_OUI_FROM_DATABASE=Doremi Labs, Inc. +OUI:000F78* + ID_OUI_FROM_DATABASE=Datacap Systems Inc -OUI:001112* - ID_OUI_FROM_DATABASE=Honeywell CMSS +OUI:000F6A* + ID_OUI_FROM_DATABASE=Nortel Networks -OUI:001118* - ID_OUI_FROM_DATABASE=BLX IC Design Corp., Ltd. +OUI:000F65* + ID_OUI_FROM_DATABASE=icube Corp. + +OUI:000F5E* + ID_OUI_FROM_DATABASE=Veo OUI:000F58* ID_OUI_FROM_DATABASE=Adder Technology Limited @@ -38915,9 +40010,6 @@ OUI:000F32* OUI:000F2B* ID_OUI_FROM_DATABASE=GREENBELL SYSTEMS -OUI:000E98* - ID_OUI_FROM_DATABASE=HME Clear-Com LTD. - OUI:000E93* ID_OUI_FROM_DATABASE=Milénio 3 Sistemas Electrónicos, Lda. @@ -38939,6 +40031,36 @@ OUI:000E74* OUI:000E79* ID_OUI_FROM_DATABASE=Ample Communications Inc. +OUI:000E71* + ID_OUI_FROM_DATABASE=Gemstar Technology Development Ltd. + +OUI:000E6C* + ID_OUI_FROM_DATABASE=Device Drivers Limited + +OUI:000EB8* + ID_OUI_FROM_DATABASE=Iiga co.,Ltd + +OUI:000EB7* + ID_OUI_FROM_DATABASE=Knovative, Inc. + +OUI:000EBE* + ID_OUI_FROM_DATABASE=B&B Electronics Manufacturing Co. + +OUI:000EB2* + ID_OUI_FROM_DATABASE=Micro-Research Finland Oy + +OUI:000EAB* + ID_OUI_FROM_DATABASE=Cray Inc + +OUI:000EA5* + ID_OUI_FROM_DATABASE=BLIP Systems + +OUI:000E9F* + ID_OUI_FROM_DATABASE=TEMIC SDS GmbH + +OUI:000E98* + ID_OUI_FROM_DATABASE=HME Clear-Com LTD. + OUI:000F24* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -38963,35 +40085,62 @@ OUI:000F00* OUI:000F05* ID_OUI_FROM_DATABASE=3B SYSTEM INC. +OUI:000EF9* + ID_OUI_FROM_DATABASE=REA Elektronik GmbH + +OUI:000FAC* + ID_OUI_FROM_DATABASE=IEEE 802.11 + +OUI:000F9C* + ID_OUI_FROM_DATABASE=Panduit Corp + +OUI:000FA0* + ID_OUI_FROM_DATABASE=CANON KOREA BUSINESS SOLUTIONS INC. + +OUI:000F97* + ID_OUI_FROM_DATABASE=Avanex Corporation + +OUI:000F8A* + ID_OUI_FROM_DATABASE=WideView + +OUI:000F89* + ID_OUI_FROM_DATABASE=Winnertec System Co., Ltd. + +OUI:000F90* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:000F7D* ID_OUI_FROM_DATABASE=Xirrus OUI:000F84* ID_OUI_FROM_DATABASE=Astute Networks, Inc. -OUI:000F77* - ID_OUI_FROM_DATABASE=DENTUM CO.,LTD +OUI:000FD1* + ID_OUI_FROM_DATABASE=Applied Wireless Identifications Group, Inc. -OUI:000F71* - ID_OUI_FROM_DATABASE=Sanmei Electronics Co.,Ltd +OUI:000FD2* + ID_OUI_FROM_DATABASE=EWA Technologies, Inc. -OUI:000F78* - ID_OUI_FROM_DATABASE=Datacap Systems Inc +OUI:000FC4* + ID_OUI_FROM_DATABASE=NST co.,LTD. -OUI:000F6A* - ID_OUI_FROM_DATABASE=Nortel Networks +OUI:000FCB* + ID_OUI_FROM_DATABASE=3Com Ltd -OUI:000F65* - ID_OUI_FROM_DATABASE=icube Corp. +OUI:000FBF* + ID_OUI_FROM_DATABASE=DGT Sp. z o.o. -OUI:000F5E* - ID_OUI_FROM_DATABASE=Veo +OUI:000FB8* + ID_OUI_FROM_DATABASE=CallURL Inc. -OUI:000E71* - ID_OUI_FROM_DATABASE=Gemstar Technology Development Ltd. +OUI:000FB2* + ID_OUI_FROM_DATABASE=Broadband Pacenet (India) Pvt. Ltd. -OUI:000E6C* - ID_OUI_FROM_DATABASE=Device Drivers Limited +OUI:000FA5* + ID_OUI_FROM_DATABASE=BWA Technology GmbH + +OUI:000FB1* + ID_OUI_FROM_DATABASE=Cognio Inc. OUI:000E65* ID_OUI_FROM_DATABASE=TransCore @@ -39017,63 +40166,6 @@ OUI:000E40* OUI:000E3F* ID_OUI_FROM_DATABASE=Soronti, Inc. -OUI:000EC5* - ID_OUI_FROM_DATABASE=Digital Multitools Inc - -OUI:000EB8* - ID_OUI_FROM_DATABASE=Iiga co.,Ltd - -OUI:000EB7* - ID_OUI_FROM_DATABASE=Knovative, Inc. - -OUI:000EBE* - ID_OUI_FROM_DATABASE=B&B Electronics Manufacturing Co. - -OUI:000EB2* - ID_OUI_FROM_DATABASE=Micro-Research Finland Oy - -OUI:000EAB* - ID_OUI_FROM_DATABASE=Cray Inc - -OUI:000EA5* - ID_OUI_FROM_DATABASE=BLIP Systems - -OUI:000E9F* - ID_OUI_FROM_DATABASE=TEMIC SDS GmbH - -OUI:000E0A* - ID_OUI_FROM_DATABASE=SAKUMA DESIGN OFFICE - -OUI:000E12* - ID_OUI_FROM_DATABASE=Adaptive Micro Systems Inc. - -OUI:000E04* - ID_OUI_FROM_DATABASE=CMA/Microdialysis AB - -OUI:000DF7* - ID_OUI_FROM_DATABASE=Space Dynamics Lab - -OUI:000DFE* - ID_OUI_FROM_DATABASE=Hauppauge Computer Works, Inc. - -OUI:000E03* - ID_OUI_FROM_DATABASE=Emulex Corporation - -OUI:000DF1* - ID_OUI_FROM_DATABASE=IONIX INC. - -OUI:000DEB* - ID_OUI_FROM_DATABASE=CompXs Limited - -OUI:000DF2* - ID_OUI_FROM_DATABASE=Private - -OUI:000DE4* - ID_OUI_FROM_DATABASE=DIGINICS, Inc. - -OUI:000EF9* - ID_OUI_FROM_DATABASE=REA Elektronik GmbH - OUI:000EF2* ID_OUI_FROM_DATABASE=Infinico Corporation @@ -39098,6 +40190,150 @@ OUI:000EDA* OUI:000ED6* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:000EC5* + ID_OUI_FROM_DATABASE=Digital Multitools Inc + +OUI:000DB2* + ID_OUI_FROM_DATABASE=Ammasso, Inc. + +OUI:000DAD* + ID_OUI_FROM_DATABASE=Dataprobe, Inc. + +OUI:000D9E* + ID_OUI_FROM_DATABASE=TOKUDEN OHIZUMI SEISAKUSYO Co.,Ltd. + +OUI:000DA5* + ID_OUI_FROM_DATABASE=Fabric7 Systems, Inc + +OUI:000D99* + ID_OUI_FROM_DATABASE=Orbital Sciences Corp.; Launch Systems Group + +OUI:000D8C* + ID_OUI_FROM_DATABASE=Shanghai Wedone Digital Ltd. CO. + +OUI:000D8B* + ID_OUI_FROM_DATABASE=T&D Corporation + +OUI:000D85* + ID_OUI_FROM_DATABASE=Tapwave, Inc. + +OUI:000D86* + ID_OUI_FROM_DATABASE=Huber + Suhner AG + +OUI:000DD8* + ID_OUI_FROM_DATABASE=BBN + +OUI:000DCC* + ID_OUI_FROM_DATABASE=NEOSMART Corp. + +OUI:000DBF* + ID_OUI_FROM_DATABASE=TekTone Sound & Signal Mfg., Inc. + +OUI:000DC0* + ID_OUI_FROM_DATABASE=Spagat AS + +OUI:000DC5* + ID_OUI_FROM_DATABASE=EchoStar Global B.V. + +OUI:000DB9* + ID_OUI_FROM_DATABASE=PC Engines GmbH + +OUI:000D4C* + ID_OUI_FROM_DATABASE=Outline Electronics Ltd. + +OUI:000D53* + ID_OUI_FROM_DATABASE=Beijing 5w Communication Corp. + +OUI:000D3F* + ID_OUI_FROM_DATABASE=VTI Instruments Corporation + +OUI:000D44* + ID_OUI_FROM_DATABASE=Audio BU - Logitech + +OUI:000D38* + ID_OUI_FROM_DATABASE=NISSIN INC. + +OUI:000D32* + ID_OUI_FROM_DATABASE=DispenseSource, Inc. + +OUI:000D31* + ID_OUI_FROM_DATABASE=Compellent Technologies, Inc. + +OUI:000E04* + ID_OUI_FROM_DATABASE=CMA/Microdialysis AB + +OUI:000DF7* + ID_OUI_FROM_DATABASE=Space Dynamics Lab + +OUI:000DFE* + ID_OUI_FROM_DATABASE=Hauppauge Computer Works, Inc. + +OUI:000DF1* + ID_OUI_FROM_DATABASE=IONIX INC. + +OUI:000DEB* + ID_OUI_FROM_DATABASE=CompXs Limited + +OUI:000DF2* + ID_OUI_FROM_DATABASE=Private + +OUI:000DE4* + ID_OUI_FROM_DATABASE=DIGINICS, Inc. + +OUI:000DDF* + ID_OUI_FROM_DATABASE=Japan Image & Network Inc. + +OUI:000DD2* + ID_OUI_FROM_DATABASE=Simrad Optronics ASA + +OUI:000DD1* + ID_OUI_FROM_DATABASE=Stryker Corporation + +OUI:000D2C* + ID_OUI_FROM_DATABASE=Patapsco Designs Ltd + +OUI:000D25* + ID_OUI_FROM_DATABASE=SANDEN CORPORATION + +OUI:000D1F* + ID_OUI_FROM_DATABASE=AV Digital + +OUI:000D19* + ID_OUI_FROM_DATABASE=ROBE Show lighting + +OUI:000D20* + ID_OUI_FROM_DATABASE=ASAHIKASEI TECHNOSYSTEM CO.,LTD. + +OUI:000D0D* + ID_OUI_FROM_DATABASE=ITSupported, LLC + +OUI:000D12* + ID_OUI_FROM_DATABASE=AXELL Corporation + +OUI:000D00* + ID_OUI_FROM_DATABASE=Seaway Networks Inc. + +OUI:000D06* + ID_OUI_FROM_DATABASE=Compulogic Limited + +OUI:000CD1* + ID_OUI_FROM_DATABASE=SFOM Technology Corp. + +OUI:000CD6* + ID_OUI_FROM_DATABASE=PARTNER TECH + +OUI:000CDD* + ID_OUI_FROM_DATABASE=AOS technologies AG + +OUI:000CCA* + ID_OUI_FROM_DATABASE=HGST a Western Digital Company + +OUI:000CC4* + ID_OUI_FROM_DATABASE=Tiptel AG + +OUI:000CB1* + ID_OUI_FROM_DATABASE=Salland Engineering (Europe) BV + OUI:000E37* ID_OUI_FROM_DATABASE=Harms & Wende GmbH & Co.KG @@ -39125,6 +40361,87 @@ OUI:000E17* OUI:000E0E* ID_OUI_FROM_DATABASE=ESA elettronica S.P.A. +OUI:000E0A* + ID_OUI_FROM_DATABASE=SAKUMA DESIGN OFFICE + +OUI:000E12* + ID_OUI_FROM_DATABASE=Adaptive Micro Systems Inc. + +OUI:000D7E* + ID_OUI_FROM_DATABASE=Axiowave Networks, Inc. + +OUI:000D78* + ID_OUI_FROM_DATABASE=Engineering & Security + +OUI:000D77* + ID_OUI_FROM_DATABASE=FalconStor Software + +OUI:000D6B* + ID_OUI_FROM_DATABASE=Mita-Teknik A/S + +OUI:000D65* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:000D5F* + ID_OUI_FROM_DATABASE=Minds Inc + +OUI:000D66* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:000D58* + ID_OUI_FROM_DATABASE=Private + +OUI:000CFA* + ID_OUI_FROM_DATABASE=Digital Systems Corp + +OUI:000CFF* + ID_OUI_FROM_DATABASE=MRO-TEK LIMITED + +OUI:000CED* + ID_OUI_FROM_DATABASE=Real Digital Media + +OUI:000CEE* + ID_OUI_FROM_DATABASE=jp-embedded + +OUI:000CF3* + ID_OUI_FROM_DATABASE=CALL IMAGE SA + +OUI:000CE7* + ID_OUI_FROM_DATABASE=MediaTek Inc. + +OUI:000CE3* + ID_OUI_FROM_DATABASE=Option International N.V. + +OUI:000B8F* + ID_OUI_FROM_DATABASE=AKITA ELECTRONICS SYSTEMS CO.,LTD. + +OUI:000B89* + ID_OUI_FROM_DATABASE=Top Global Technology, Ltd. + +OUI:000B8E* + ID_OUI_FROM_DATABASE=Ascent Corporation + +OUI:000B90* + ID_OUI_FROM_DATABASE=ADVA Optical Networking Ltd. + +OUI:000B7D* + ID_OUI_FROM_DATABASE=SOLOMON EXTREME INTERNATIONAL LTD. + +OUI:000B82* + ID_OUI_FROM_DATABASE=Grandstream Networks, Inc. + +OUI:000B6F* + ID_OUI_FROM_DATABASE=Media Streaming Networks Inc + +OUI:000B76* + ID_OUI_FROM_DATABASE=ET&T Technology Co. Ltd. + +OUI:000B5E* + ID_OUI_FROM_DATABASE=Audio Engineering Society Inc. + +OUI:000B63* + ID_OUI_FROM_DATABASE=Kaleidescape + OUI:000C7E* ID_OUI_FROM_DATABASE=Tellium Incorporated @@ -39149,68 +40466,152 @@ OUI:000C6B* OUI:000C6D* ID_OUI_FROM_DATABASE=Edwards Ltd. -OUI:000DDF* - ID_OUI_FROM_DATABASE=Japan Image & Network Inc. +OUI:000C4E* + ID_OUI_FROM_DATABASE=Winbest Technology CO,LT -OUI:000DD2* - ID_OUI_FROM_DATABASE=Simrad Optronics ASA +OUI:000C53* + ID_OUI_FROM_DATABASE=Private -OUI:000DD1* - ID_OUI_FROM_DATABASE=Stryker Corporation +OUI:000C5A* + ID_OUI_FROM_DATABASE=IBSmm Embedded Electronics Consulting -OUI:000DD8* - ID_OUI_FROM_DATABASE=BBN +OUI:000C5F* + ID_OUI_FROM_DATABASE=Avtec, Inc. -OUI:000DCC* - ID_OUI_FROM_DATABASE=NEOSMART Corp. +OUI:000C47* + ID_OUI_FROM_DATABASE=SK Teletech(R&D Planning Team) -OUI:000DBF* - ID_OUI_FROM_DATABASE=TekTone Sound & Signal Mfg., Inc. +OUI:000C4C* + ID_OUI_FROM_DATABASE=Arcor AG&Co. -OUI:000DC0* - ID_OUI_FROM_DATABASE=Spagat AS +OUI:000C3E* + ID_OUI_FROM_DATABASE=Crest Audio -OUI:000DC5* - ID_OUI_FROM_DATABASE=EchoStar Global B.V. +OUI:000C37* + ID_OUI_FROM_DATABASE=Geomation, Inc. -OUI:000DB9* - ID_OUI_FROM_DATABASE=PC Engines GmbH +OUI:000C2D* + ID_OUI_FROM_DATABASE=FullWave Technology Co., Ltd. -OUI:000D8C* - ID_OUI_FROM_DATABASE=Shanghai Wedone Digital Ltd. CO. +OUI:000C1A* + ID_OUI_FROM_DATABASE=Quest Technical Solutions Inc. -OUI:000D8B* - ID_OUI_FROM_DATABASE=T&D Corporation +OUI:000B2E* + ID_OUI_FROM_DATABASE=Cal-Comp Electronics (Thailand) Public Company Limited Taipe -OUI:000D85* - ID_OUI_FROM_DATABASE=Tapwave, Inc. +OUI:000B1B* + ID_OUI_FROM_DATABASE=Systronix, Inc. -OUI:000D86* - ID_OUI_FROM_DATABASE=Huber + Suhner AG +OUI:000B20* + ID_OUI_FROM_DATABASE=Hirata corporation -OUI:000D7E* - ID_OUI_FROM_DATABASE=Axiowave Networks, Inc. +OUI:000B22* + ID_OUI_FROM_DATABASE=Environmental Systems and Services -OUI:000D78* - ID_OUI_FROM_DATABASE=Engineering & Security +OUI:000B14* + ID_OUI_FROM_DATABASE=ViewSonic Corporation -OUI:000D77* - ID_OUI_FROM_DATABASE=FalconStor Software +OUI:000B0D* + ID_OUI_FROM_DATABASE=Air2U, Inc. -OUI:000D6B* - ID_OUI_FROM_DATABASE=Mita-Teknik A/S +OUI:000B0F* + ID_OUI_FROM_DATABASE=Bosch Rexroth -OUI:000D65* +OUI:000B08* + ID_OUI_FROM_DATABASE=Pillar Data Systems + +OUI:000AFC* + ID_OUI_FROM_DATABASE=Core Tec Communications, LLC + +OUI:000B01* + ID_OUI_FROM_DATABASE=DAIICHI ELECTRONICS CO., LTD. + +OUI:000B55* + ID_OUI_FROM_DATABASE=ADInstruments + +OUI:000B5A* + ID_OUI_FROM_DATABASE=HyperEdge + +OUI:000B52* + ID_OUI_FROM_DATABASE=JOYMAX ELECTRONICS CO. LTD. + +OUI:000B4D* + ID_OUI_FROM_DATABASE=Emuzed + +OUI:000B41* + ID_OUI_FROM_DATABASE=Ing. Büro Dr. Beutlhauser + +OUI:000B46* ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:000D5F* - ID_OUI_FROM_DATABASE=Minds Inc +OUI:000B33* + ID_OUI_FROM_DATABASE=Vivato Technologies -OUI:000D66* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:000B3A* + ID_OUI_FROM_DATABASE=QuStream Corporation -OUI:000CB1* - ID_OUI_FROM_DATABASE=Salland Engineering (Europe) BV +OUI:000B3F* + ID_OUI_FROM_DATABASE=Anthology Solutions Inc. + +OUI:000B27* + ID_OUI_FROM_DATABASE=Scion Corporation + +OUI:000C1E* + ID_OUI_FROM_DATABASE=Global Cache + +OUI:000C23* + ID_OUI_FROM_DATABASE=Beijing Lanchuan Tech. Co., Ltd. + +OUI:000C0E* + ID_OUI_FROM_DATABASE=XtremeSpectrum, Inc. + +OUI:000C15* + ID_OUI_FROM_DATABASE=CyberPower Systems, Inc. + +OUI:000C09* + ID_OUI_FROM_DATABASE=Hitachi IE Systems Co., Ltd + +OUI:000BF6* + ID_OUI_FROM_DATABASE=Nitgen Co., Ltd + +OUI:000BFB* + ID_OUI_FROM_DATABASE=D-NET International Corporation + +OUI:000C02* + ID_OUI_FROM_DATABASE=ABB Oy + +OUI:000BC7* + ID_OUI_FROM_DATABASE=ICET S.p.A. + +OUI:000BCE* + ID_OUI_FROM_DATABASE=Free2move AB + +OUI:000BC2* + ID_OUI_FROM_DATABASE=Corinex Communication Corp. + +OUI:000BBB* + ID_OUI_FROM_DATABASE=Etin Systems Co., Ltd + +OUI:000BC0* + ID_OUI_FROM_DATABASE=China IWNComm Co., Ltd. + +OUI:000BAF* + ID_OUI_FROM_DATABASE=WOOJU COMMUNICATIONS Co,.Ltd + +OUI:000BB4* + ID_OUI_FROM_DATABASE=RDC Semiconductor Inc., + +OUI:000BA5* + ID_OUI_FROM_DATABASE=Quasar Cipta Mandiri, PT + +OUI:000BAA* + ID_OUI_FROM_DATABASE=Aiphone co.,Ltd + +OUI:000B9E* + ID_OUI_FROM_DATABASE=Yasing Technology Corp. + +OUI:000B95* + ID_OUI_FROM_DATABASE=eBet Gaming Systems Pty Ltd OUI:000CB7* ID_OUI_FROM_DATABASE=Nanjing Huazhuo Electronics Co., Ltd. @@ -39245,110 +40646,29 @@ OUI:000C8D* OUI:000C92* ID_OUI_FROM_DATABASE=WolfVision Gmbh -OUI:000D32* - ID_OUI_FROM_DATABASE=DispenseSource, Inc. +OUI:000BEA* + ID_OUI_FROM_DATABASE=Zultys Technologies -OUI:000D31* - ID_OUI_FROM_DATABASE=Compellent Technologies, Inc. +OUI:000BEF* + ID_OUI_FROM_DATABASE=Code Corporation -OUI:000D2C* - ID_OUI_FROM_DATABASE=Patapsco Designs Ltd +OUI:000BE3* + ID_OUI_FROM_DATABASE=Key Stream Co., Ltd. -OUI:000D25* - ID_OUI_FROM_DATABASE=SANDEN CORPORATION +OUI:000BE8* + ID_OUI_FROM_DATABASE=AOIP -OUI:000D1F* - ID_OUI_FROM_DATABASE=AV Digital +OUI:000BE9* + ID_OUI_FROM_DATABASE=Actel Corporation -OUI:000D19* - ID_OUI_FROM_DATABASE=ROBE Show lighting +OUI:000BD7* + ID_OUI_FROM_DATABASE=DORMA Time + Access GmbH -OUI:000D20* - ID_OUI_FROM_DATABASE=ASAHIKASEI TECHNOSYSTEM CO.,LTD. +OUI:000BDC* + ID_OUI_FROM_DATABASE=AKCP -OUI:000D0D* - ID_OUI_FROM_DATABASE=ITSupported, LLC - -OUI:000D12* - ID_OUI_FROM_DATABASE=AXELL Corporation - -OUI:000DB2* - ID_OUI_FROM_DATABASE=Ammasso, Inc. - -OUI:000DAD* - ID_OUI_FROM_DATABASE=Dataprobe, Inc. - -OUI:000D9E* - ID_OUI_FROM_DATABASE=TOKUDEN OHIZUMI SEISAKUSYO Co.,Ltd. - -OUI:000DA5* - ID_OUI_FROM_DATABASE=Fabric7 Systems, Inc - -OUI:000D99* - ID_OUI_FROM_DATABASE=Orbital Sciences Corp.; Launch Systems Group - -OUI:000D58* - ID_OUI_FROM_DATABASE=Private - -OUI:000D4C* - ID_OUI_FROM_DATABASE=Outline Electronics Ltd. - -OUI:000D53* - ID_OUI_FROM_DATABASE=Beijing 5w Communication Corp. - -OUI:000D3F* - ID_OUI_FROM_DATABASE=VTI Instruments Corporation - -OUI:000D44* - ID_OUI_FROM_DATABASE=Audio BU - Logitech - -OUI:000D38* - ID_OUI_FROM_DATABASE=NISSIN INC. - -OUI:000CD1* - ID_OUI_FROM_DATABASE=SFOM Technology Corp. - -OUI:000CD6* - ID_OUI_FROM_DATABASE=PARTNER TECH - -OUI:000CDD* - ID_OUI_FROM_DATABASE=AOS technologies AG - -OUI:000CCA* - ID_OUI_FROM_DATABASE=HGST a Western Digital Company - -OUI:000CC4* - ID_OUI_FROM_DATABASE=Tiptel AG - -OUI:000D00* - ID_OUI_FROM_DATABASE=Seaway Networks Inc. - -OUI:000D06* - ID_OUI_FROM_DATABASE=Compulogic Limited - -OUI:000CFA* - ID_OUI_FROM_DATABASE=Digital Systems Corp - -OUI:000CFF* - ID_OUI_FROM_DATABASE=MRO-TEK LIMITED - -OUI:000CED* - ID_OUI_FROM_DATABASE=Real Digital Media - -OUI:000CEE* - ID_OUI_FROM_DATABASE=jp-embedded - -OUI:000CF3* - ID_OUI_FROM_DATABASE=CALL IMAGE SA - -OUI:000CE7* - ID_OUI_FROM_DATABASE=MediaTek Inc. - -OUI:000CE3* - ID_OUI_FROM_DATABASE=Option International N.V. - -OUI:000B01* - ID_OUI_FROM_DATABASE=DAIICHI ELECTRONICS CO., LTD. +OUI:000BD3* + ID_OUI_FROM_DATABASE=cd3o OUI:000AF0* ID_OUI_FROM_DATABASE=SHIN-OH ELECTRONICS CO., LTD. R&D @@ -39377,234 +40697,12 @@ OUI:000ACD* OUI:000AD4* ID_OUI_FROM_DATABASE=CoreBell Systems Inc. -OUI:000B5E* - ID_OUI_FROM_DATABASE=Audio Engineering Society Inc. - -OUI:000B63* - ID_OUI_FROM_DATABASE=Kaleidescape - -OUI:000B55* - ID_OUI_FROM_DATABASE=ADInstruments - -OUI:000B5A* - ID_OUI_FROM_DATABASE=HyperEdge - -OUI:000B52* - ID_OUI_FROM_DATABASE=JOYMAX ELECTRONICS CO. LTD. - -OUI:000B4D* - ID_OUI_FROM_DATABASE=Emuzed - -OUI:000B41* - ID_OUI_FROM_DATABASE=Ing. Büro Dr. Beutlhauser - -OUI:000B46* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:000B33* - ID_OUI_FROM_DATABASE=Vivato Technologies - -OUI:000B3A* - ID_OUI_FROM_DATABASE=QuStream Corporation - -OUI:000B3F* - ID_OUI_FROM_DATABASE=Anthology Solutions Inc. - -OUI:000B95* - ID_OUI_FROM_DATABASE=eBet Gaming Systems Pty Ltd - -OUI:000B8F* - ID_OUI_FROM_DATABASE=AKITA ELECTRONICS SYSTEMS CO.,LTD. - -OUI:000B89* - ID_OUI_FROM_DATABASE=Top Global Technology, Ltd. - -OUI:000B8E* - ID_OUI_FROM_DATABASE=Ascent Corporation - -OUI:000B90* - ID_OUI_FROM_DATABASE=ADVA Optical Networking Ltd. - -OUI:000B7D* - ID_OUI_FROM_DATABASE=SOLOMON EXTREME INTERNATIONAL LTD. - -OUI:000B82* - ID_OUI_FROM_DATABASE=Grandstream Networks, Inc. - -OUI:000B6F* - ID_OUI_FROM_DATABASE=Media Streaming Networks Inc - -OUI:000B76* - ID_OUI_FROM_DATABASE=ET&T Technology Co. Ltd. - OUI:000AC1* ID_OUI_FROM_DATABASE=Futuretel OUI:000AC6* ID_OUI_FROM_DATABASE=Overture Networks. -OUI:000AAE* - ID_OUI_FROM_DATABASE=Rosemount Process Analytical - -OUI:000AB3* - ID_OUI_FROM_DATABASE=Fa. GIRA - -OUI:000AB5* - ID_OUI_FROM_DATABASE=Digital Electronic Network - -OUI:000ABA* - ID_OUI_FROM_DATABASE=Arcon Technology Limited - -OUI:000AA2* - ID_OUI_FROM_DATABASE=SYSTEK INC. - -OUI:000AA7* - ID_OUI_FROM_DATABASE=FEI Electron Optics - -OUI:000A8F* - ID_OUI_FROM_DATABASE=Aska International Inc. - -OUI:000A94* - ID_OUI_FROM_DATABASE=ShangHai cellink CO., LTD - -OUI:000C4E* - ID_OUI_FROM_DATABASE=Winbest Technology CO,LT - -OUI:000C53* - ID_OUI_FROM_DATABASE=Private - -OUI:000C5A* - ID_OUI_FROM_DATABASE=IBSmm Embedded Electronics Consulting - -OUI:000C5F* - ID_OUI_FROM_DATABASE=Avtec, Inc. - -OUI:000C47* - ID_OUI_FROM_DATABASE=SK Teletech(R&D Planning Team) - -OUI:000C4C* - ID_OUI_FROM_DATABASE=Arcor AG&Co. - -OUI:000C3E* - ID_OUI_FROM_DATABASE=Crest Audio - -OUI:000C37* - ID_OUI_FROM_DATABASE=Geomation, Inc. - -OUI:000C2D* - ID_OUI_FROM_DATABASE=FullWave Technology Co., Ltd. - -OUI:000C1A* - ID_OUI_FROM_DATABASE=Quest Technical Solutions Inc. - -OUI:000C1E* - ID_OUI_FROM_DATABASE=Global Cache - -OUI:000C23* - ID_OUI_FROM_DATABASE=Beijing Lanchuan Tech. Co., Ltd. - -OUI:000C0E* - ID_OUI_FROM_DATABASE=XtremeSpectrum, Inc. - -OUI:000C15* - ID_OUI_FROM_DATABASE=CyberPower Systems, Inc. - -OUI:000C09* - ID_OUI_FROM_DATABASE=Hitachi IE Systems Co., Ltd - -OUI:000BD3* - ID_OUI_FROM_DATABASE=cd3o - -OUI:000BC7* - ID_OUI_FROM_DATABASE=ICET S.p.A. - -OUI:000BCE* - ID_OUI_FROM_DATABASE=Free2move AB - -OUI:000BC2* - ID_OUI_FROM_DATABASE=Corinex Communication Corp. - -OUI:000BBB* - ID_OUI_FROM_DATABASE=Etin Systems Co., Ltd - -OUI:000BC0* - ID_OUI_FROM_DATABASE=China IWNComm Co., Ltd. - -OUI:000BAF* - ID_OUI_FROM_DATABASE=WOOJU COMMUNICATIONS Co,.Ltd - -OUI:000BB4* - ID_OUI_FROM_DATABASE=RDC Semiconductor Inc., - -OUI:000BA5* - ID_OUI_FROM_DATABASE=Quasar Cipta Mandiri, PT - -OUI:000BAA* - ID_OUI_FROM_DATABASE=Aiphone co.,Ltd - -OUI:000B9E* - ID_OUI_FROM_DATABASE=Yasing Technology Corp. - -OUI:000B27* - ID_OUI_FROM_DATABASE=Scion Corporation - -OUI:000B2E* - ID_OUI_FROM_DATABASE=Cal-Comp Electronics (Thailand) Public Company Limited Taipe - -OUI:000B1B* - ID_OUI_FROM_DATABASE=Systronix, Inc. - -OUI:000B20* - ID_OUI_FROM_DATABASE=Hirata corporation - -OUI:000B22* - ID_OUI_FROM_DATABASE=Environmental Systems and Services - -OUI:000B14* - ID_OUI_FROM_DATABASE=ViewSonic Corporation - -OUI:000B0D* - ID_OUI_FROM_DATABASE=Air2U, Inc. - -OUI:000B0F* - ID_OUI_FROM_DATABASE=Bosch Rexroth - -OUI:000B08* - ID_OUI_FROM_DATABASE=Pillar Data Systems - -OUI:000AFC* - ID_OUI_FROM_DATABASE=Core Tec Communications, LLC - -OUI:000BF6* - ID_OUI_FROM_DATABASE=Nitgen Co., Ltd - -OUI:000BFB* - ID_OUI_FROM_DATABASE=D-NET International Corporation - -OUI:000C02* - ID_OUI_FROM_DATABASE=ABB Oy - -OUI:000BEA* - ID_OUI_FROM_DATABASE=Zultys Technologies - -OUI:000BEF* - ID_OUI_FROM_DATABASE=Code Corporation - -OUI:000BE3* - ID_OUI_FROM_DATABASE=Key Stream Co., Ltd. - -OUI:000BE8* - ID_OUI_FROM_DATABASE=AOIP - -OUI:000BE9* - ID_OUI_FROM_DATABASE=Actel Corporation - -OUI:000BD7* - ID_OUI_FROM_DATABASE=DORMA Time + Access GmbH - -OUI:000BDC* - ID_OUI_FROM_DATABASE=AKCP - OUI:000994* ID_OUI_FROM_DATABASE=Cronyx Engineering @@ -39635,11 +40733,35 @@ OUI:000968* OUI:000962* ID_OUI_FROM_DATABASE=Sonitor Technologies AS -OUI:000A9B* - ID_OUI_FROM_DATABASE=TB Group Inc +OUI:000967* + ID_OUI_FROM_DATABASE=Tachyon, Inc -OUI:000A9A* - ID_OUI_FROM_DATABASE=Aiptek International Inc +OUI:00096E* + ID_OUI_FROM_DATABASE=GIANT ELECTRONICS LTD. + +OUI:0009C3* + ID_OUI_FROM_DATABASE=NETAS + +OUI:0009B9* + ID_OUI_FROM_DATABASE=Action Imaging Solutions + +OUI:0009BA* + ID_OUI_FROM_DATABASE=MAKU Informationstechik GmbH + +OUI:0009AC* + ID_OUI_FROM_DATABASE=LANVOICE + +OUI:0009B3* + ID_OUI_FROM_DATABASE=MCM Systems Ltd + +OUI:0009A7* + ID_OUI_FROM_DATABASE=Bang & Olufsen A/S + +OUI:00099A* + ID_OUI_FROM_DATABASE=ELMO COMPANY, LIMITED + +OUI:0009A0* + ID_OUI_FROM_DATABASE=Microtechno Corporation OUI:000A80* ID_OUI_FROM_DATABASE=Telkonet Inc. @@ -39668,35 +40790,8 @@ OUI:000A61* OUI:000A68* ID_OUI_FROM_DATABASE=SolarFlare Communications, Inc. -OUI:0009C3* - ID_OUI_FROM_DATABASE=NETAS - -OUI:0009B9* - ID_OUI_FROM_DATABASE=Action Imaging Solutions - -OUI:0009BA* - ID_OUI_FROM_DATABASE=MAKU Informationstechik GmbH - -OUI:0009AC* - ID_OUI_FROM_DATABASE=LANVOICE - -OUI:0009B3* - ID_OUI_FROM_DATABASE=MCM Systems Ltd - -OUI:0009A7* - ID_OUI_FROM_DATABASE=Bang & Olufsen A/S - -OUI:00099A* - ID_OUI_FROM_DATABASE=ELMO COMPANY, LIMITED - -OUI:0009A0* - ID_OUI_FROM_DATABASE=Microtechno Corporation - -OUI:0009ED* - ID_OUI_FROM_DATABASE=CipherOptics - -OUI:0009F2* - ID_OUI_FROM_DATABASE=Cohu, Inc., Electronics Division +OUI:000A5C* + ID_OUI_FROM_DATABASE=Carel s.p.a. OUI:0009E6* ID_OUI_FROM_DATABASE=Cyber Switching Inc. @@ -39722,74 +40817,35 @@ OUI:0009CE* OUI:0009D3* ID_OUI_FROM_DATABASE=Western DataCom Co., Inc. -OUI:000901* - ID_OUI_FROM_DATABASE=Shenzhen Shixuntong Information & Technoligy Co +OUI:000AAE* + ID_OUI_FROM_DATABASE=Rosemount Process Analytical -OUI:0008FC* - ID_OUI_FROM_DATABASE=Gigaphoton Inc. +OUI:000AB3* + ID_OUI_FROM_DATABASE=Fa. GIRA -OUI:0008F9* - ID_OUI_FROM_DATABASE=Artesyn Embedded Technologies +OUI:000AB5* + ID_OUI_FROM_DATABASE=Digital Electronic Network -OUI:0008F4* - ID_OUI_FROM_DATABASE=Bluetake Technology Co., Ltd. +OUI:000ABA* + ID_OUI_FROM_DATABASE=Arcon Technology Limited -OUI:0008EB* - ID_OUI_FROM_DATABASE=ROMWin Co.,Ltd. +OUI:000AA2* + ID_OUI_FROM_DATABASE=SYSTEK INC. -OUI:0008E4* - ID_OUI_FROM_DATABASE=Envenergy Inc +OUI:000AA7* + ID_OUI_FROM_DATABASE=FEI Electron Optics -OUI:0008DF* - ID_OUI_FROM_DATABASE=Alistel Inc. +OUI:000A8F* + ID_OUI_FROM_DATABASE=Aska International Inc. -OUI:0008D8* - ID_OUI_FROM_DATABASE=Dowkey Microwave +OUI:000A94* + ID_OUI_FROM_DATABASE=ShangHai cellink CO., LTD -OUI:0008D2* - ID_OUI_FROM_DATABASE=ZOOM Networks Inc. +OUI:000A9B* + ID_OUI_FROM_DATABASE=TB Group Inc -OUI:0008CC* - ID_OUI_FROM_DATABASE=Remotec, Inc. - -OUI:0008D1* - ID_OUI_FROM_DATABASE=KAREL INC. - -OUI:000967* - ID_OUI_FROM_DATABASE=Tachyon, Inc - -OUI:00096E* - ID_OUI_FROM_DATABASE=GIANT ELECTRONICS LTD. - -OUI:00095E* - ID_OUI_FROM_DATABASE=Masstech Group Inc. - -OUI:000959* - ID_OUI_FROM_DATABASE=Sitecsoft - -OUI:00094D* - ID_OUI_FROM_DATABASE=Braintree Communications Pty Ltd - -OUI:000952* - ID_OUI_FROM_DATABASE=Auerswald GmbH & Co. KG - -OUI:000946* - ID_OUI_FROM_DATABASE=Cluster Labs GmbH - -OUI:000940* - ID_OUI_FROM_DATABASE=AGFEO GmbH & Co. KG - -OUI:00093F* - ID_OUI_FROM_DATABASE=Double-Win Enterpirse CO., LTD - -OUI:00093A* - ID_OUI_FROM_DATABASE=Molex Fiber Optics - -OUI:000933* - ID_OUI_FROM_DATABASE=Ophit Co.Ltd. - -OUI:000A5C* - ID_OUI_FROM_DATABASE=Carel s.p.a. +OUI:000A9A* + ID_OUI_FROM_DATABASE=Aiptek International Inc OUI:000A50* ID_OUI_FROM_DATABASE=REMOTEK CORPORATION @@ -39818,30 +40874,6 @@ OUI:000A3D* OUI:000A2F* ID_OUI_FROM_DATABASE=Artnix Inc. -OUI:000927* - ID_OUI_FROM_DATABASE=TOYOKEIKI CO.,LTD. - -OUI:00092E* - ID_OUI_FROM_DATABASE=B&Tech System Inc. - -OUI:000920* - ID_OUI_FROM_DATABASE=EpoX COMPUTER CO.,LTD. - -OUI:00091B* - ID_OUI_FROM_DATABASE=Digital Generation Inc. - -OUI:000914* - ID_OUI_FROM_DATABASE=COMPUTROLS INC. - -OUI:00090E* - ID_OUI_FROM_DATABASE=Helix Technology Inc. - -OUI:000908* - ID_OUI_FROM_DATABASE=VTech Technology Corp. - -OUI:00090D* - ID_OUI_FROM_DATABASE=LEADER ELECTRONICS CORP. - OUI:000A20* ID_OUI_FROM_DATABASE=SVA Networks, Inc. @@ -39869,164 +40901,38 @@ OUI:0009FC* OUI:000A03* ID_OUI_FROM_DATABASE=ENDESA SERVICIOS, S.L. -OUI:0006F4* - ID_OUI_FROM_DATABASE=Prime Electronics & Satellitics Inc. +OUI:0009ED* + ID_OUI_FROM_DATABASE=CipherOptics -OUI:000705* - ID_OUI_FROM_DATABASE=Endress & Hauser GmbH & Co +OUI:0009F2* + ID_OUI_FROM_DATABASE=Cohu, Inc., Electronics Division -OUI:0006F8* - ID_OUI_FROM_DATABASE=The Boeing Company +OUI:00095E* + ID_OUI_FROM_DATABASE=Masstech Group Inc. -OUI:0006FF* - ID_OUI_FROM_DATABASE=Sheba Systems Co., Ltd. +OUI:000959* + ID_OUI_FROM_DATABASE=Sitecsoft -OUI:0006FD* - ID_OUI_FROM_DATABASE=Comjet Information Systems Corp. +OUI:00094D* + ID_OUI_FROM_DATABASE=Braintree Communications Pty Ltd -OUI:0006E7* - ID_OUI_FROM_DATABASE=Bit Blitz Communications Inc. +OUI:000952* + ID_OUI_FROM_DATABASE=Auerswald GmbH & Co. KG -OUI:0006ED* - ID_OUI_FROM_DATABASE=Inara Networks +OUI:000946* + ID_OUI_FROM_DATABASE=Cluster Labs GmbH -OUI:0006DC* - ID_OUI_FROM_DATABASE=Syabas Technology (Amquest) +OUI:000940* + ID_OUI_FROM_DATABASE=AGFEO GmbH & Co. KG -OUI:0006E1* - ID_OUI_FROM_DATABASE=Techno Trade s.a +OUI:00093F* + ID_OUI_FROM_DATABASE=Double-Win Enterpirse CO., LTD -OUI:0006E6* - ID_OUI_FROM_DATABASE=DongYang Telecom Co., Ltd. +OUI:00093A* + ID_OUI_FROM_DATABASE=Molex Fiber Optics -OUI:0006CF* - ID_OUI_FROM_DATABASE=Thales Avionics In-Flight Systems, LLC - -OUI:0006D6* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:0006D5* - ID_OUI_FROM_DATABASE=Diamond Systems Corp. - -OUI:0006C9* - ID_OUI_FROM_DATABASE=Technical Marketing Research, Inc. - -OUI:0007B1* - ID_OUI_FROM_DATABASE=Equator Technologies - -OUI:0007B8* - ID_OUI_FROM_DATABASE=Corvalent Corporation - -OUI:0007B2* - ID_OUI_FROM_DATABASE=Transaccess S.A. - -OUI:0007A4* - ID_OUI_FROM_DATABASE=GN Netcom Ltd. - -OUI:0007AA* - ID_OUI_FROM_DATABASE=Quantum Data Inc. - -OUI:00079D* - ID_OUI_FROM_DATABASE=Musashi Co., Ltd. - -OUI:00079E* - ID_OUI_FROM_DATABASE=Ilinx Co., Ltd. - -OUI:000774* - ID_OUI_FROM_DATABASE=GuangZhou Thinker Technology Co. Ltd. - -OUI:000791* - ID_OUI_FROM_DATABASE=International Data Communications, Inc. - -OUI:000798* - ID_OUI_FROM_DATABASE=Selea SRL - -OUI:000797* - ID_OUI_FROM_DATABASE=Netpower Co., Ltd. - -OUI:00078B* - ID_OUI_FROM_DATABASE=Wegener Communications, Inc. - -OUI:000785* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00077B* - ID_OUI_FROM_DATABASE=Millimetrix Broadband Networks - -OUI:000856* - ID_OUI_FROM_DATABASE=Gamatronic Electronic Industries Ltd. - -OUI:00082D* - ID_OUI_FROM_DATABASE=Indus Teqsite Private Limited - -OUI:000821* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:000814* - ID_OUI_FROM_DATABASE=TIL Technologies - -OUI:00081A* - ID_OUI_FROM_DATABASE=Sanrad Intelligence Storage Communications (2000) Ltd. - -OUI:00080F* - ID_OUI_FROM_DATABASE=Proximion Fiber Optics AB - -OUI:000809* - ID_OUI_FROM_DATABASE=Systemonic AG - -OUI:000803* - ID_OUI_FROM_DATABASE=Cos Tron - -OUI:0007FF* - ID_OUI_FROM_DATABASE=Gluon Networks - -OUI:0007F9* - ID_OUI_FROM_DATABASE=Sensaphone - -OUI:000894* - ID_OUI_FROM_DATABASE=InnoVISION Multimedia Ltd. - -OUI:00088F* - ID_OUI_FROM_DATABASE=ADVANCED DIGITAL TECHNOLOGY - -OUI:000888* - ID_OUI_FROM_DATABASE=OULLIM Information Technology Inc,. - -OUI:000882* - ID_OUI_FROM_DATABASE=SIGMA CORPORATION - -OUI:00087C* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:000875* - ID_OUI_FROM_DATABASE=Acorp Electronics Corp. - -OUI:000870* - ID_OUI_FROM_DATABASE=Rasvia Systems, Inc. - -OUI:00086F* - ID_OUI_FROM_DATABASE=Resources Computer Network Ltd. - -OUI:000869* - ID_OUI_FROM_DATABASE=Command-e Technology Co.,Ltd. - -OUI:000863* - ID_OUI_FROM_DATABASE=Entrisphere Inc. - -OUI:00085D* - ID_OUI_FROM_DATABASE=Aastra - -OUI:000862* - ID_OUI_FROM_DATABASE=NEC Eluminant Technologies, Inc. - -OUI:000850* - ID_OUI_FROM_DATABASE=Arizona Instrument Corp. - -OUI:000738* - ID_OUI_FROM_DATABASE=Young Technology Co., Ltd. - -OUI:00073F* - ID_OUI_FROM_DATABASE=Woojyun Systec Co., Ltd. +OUI:000933* + ID_OUI_FROM_DATABASE=Ophit Co.Ltd. OUI:00072C* ID_OUI_FROM_DATABASE=Fabricom @@ -40064,38 +40970,47 @@ OUI:000702* OUI:0006F3* ID_OUI_FROM_DATABASE=AcceLight Networks -OUI:0006C3* - ID_OUI_FROM_DATABASE=Schindler Elevator Ltd. +OUI:0006F4* + ID_OUI_FROM_DATABASE=Prime Electronics & Satellitics Inc. -OUI:0006C8* - ID_OUI_FROM_DATABASE=Sumitomo Metal Micro Devices, Inc. +OUI:000705* + ID_OUI_FROM_DATABASE=Endress & Hauser GmbH & Co -OUI:0006BF* - ID_OUI_FROM_DATABASE=Accella Technologies Co., Ltd. +OUI:0006F8* + ID_OUI_FROM_DATABASE=The Boeing Company -OUI:0006B9* - ID_OUI_FROM_DATABASE=A5TEK Corp. +OUI:0006FF* + ID_OUI_FROM_DATABASE=Sheba Systems Co., Ltd. -OUI:0006B2* - ID_OUI_FROM_DATABASE=Linxtek Co. +OUI:0006FD* + ID_OUI_FROM_DATABASE=Comjet Information Systems Corp. -OUI:0006AC* - ID_OUI_FROM_DATABASE=Intersoft Co. +OUI:00082D* + ID_OUI_FROM_DATABASE=Indus Teqsite Private Limited -OUI:0006A6* - ID_OUI_FROM_DATABASE=Artistic Licence Engineering Ltd +OUI:000821* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:0006A2* - ID_OUI_FROM_DATABASE=Microtune, Inc. +OUI:000814* + ID_OUI_FROM_DATABASE=TIL Technologies -OUI:000695* - ID_OUI_FROM_DATABASE=Ensure Technologies, Inc. +OUI:00081A* + ID_OUI_FROM_DATABASE=Sanrad Intelligence Storage Communications (2000) Ltd. -OUI:00069C* - ID_OUI_FROM_DATABASE=Transmode Systems AB +OUI:00080F* + ID_OUI_FROM_DATABASE=Proximion Fiber Optics AB -OUI:000696* - ID_OUI_FROM_DATABASE=Advent Networks +OUI:000809* + ID_OUI_FROM_DATABASE=Systemonic AG + +OUI:000803* + ID_OUI_FROM_DATABASE=Cos Tron + +OUI:0007FF* + ID_OUI_FROM_DATABASE=Gluon Networks + +OUI:0007F9* + ID_OUI_FROM_DATABASE=Sensaphone OUI:0007F3* ID_OUI_FROM_DATABASE=Thinkengine Networks @@ -40106,6 +41021,111 @@ OUI:0007EC* OUI:0007F2* ID_OUI_FROM_DATABASE=IOA Corporation +OUI:0007B2* + ID_OUI_FROM_DATABASE=Transaccess S.A. + +OUI:0007A4* + ID_OUI_FROM_DATABASE=GN Netcom Ltd. + +OUI:0007AA* + ID_OUI_FROM_DATABASE=Quantum Data Inc. + +OUI:00079D* + ID_OUI_FROM_DATABASE=Musashi Co., Ltd. + +OUI:00079E* + ID_OUI_FROM_DATABASE=Ilinx Co., Ltd. + +OUI:000774* + ID_OUI_FROM_DATABASE=GuangZhou Thinker Technology Co. Ltd. + +OUI:000791* + ID_OUI_FROM_DATABASE=International Data Communications, Inc. + +OUI:000798* + ID_OUI_FROM_DATABASE=Selea SRL + +OUI:000797* + ID_OUI_FROM_DATABASE=Netpower Co., Ltd. + +OUI:00078B* + ID_OUI_FROM_DATABASE=Wegener Communications, Inc. + +OUI:000785* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00077B* + ID_OUI_FROM_DATABASE=Millimetrix Broadband Networks + +OUI:00077E* + ID_OUI_FROM_DATABASE=Elrest GmbH + +OUI:00076F* + ID_OUI_FROM_DATABASE=Synoptics Limited + +OUI:000888* + ID_OUI_FROM_DATABASE=OULLIM Information Technology Inc,. + +OUI:000882* + ID_OUI_FROM_DATABASE=SIGMA CORPORATION + +OUI:00087C* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:000875* + ID_OUI_FROM_DATABASE=Acorp Electronics Corp. + +OUI:000870* + ID_OUI_FROM_DATABASE=Rasvia Systems, Inc. + +OUI:00086F* + ID_OUI_FROM_DATABASE=Resources Computer Network Ltd. + +OUI:000869* + ID_OUI_FROM_DATABASE=Command-e Technology Co.,Ltd. + +OUI:000863* + ID_OUI_FROM_DATABASE=Entrisphere Inc. + +OUI:00085D* + ID_OUI_FROM_DATABASE=Aastra + +OUI:000862* + ID_OUI_FROM_DATABASE=NEC Eluminant Technologies, Inc. + +OUI:000850* + ID_OUI_FROM_DATABASE=Arizona Instrument Corp. + +OUI:000856* + ID_OUI_FROM_DATABASE=Gamatronic Electronic Industries Ltd. + +OUI:000927* + ID_OUI_FROM_DATABASE=TOYOKEIKI CO.,LTD. + +OUI:00092E* + ID_OUI_FROM_DATABASE=B&Tech System Inc. + +OUI:000920* + ID_OUI_FROM_DATABASE=EpoX COMPUTER CO.,LTD. + +OUI:00091B* + ID_OUI_FROM_DATABASE=Digital Generation Inc. + +OUI:000914* + ID_OUI_FROM_DATABASE=COMPUTROLS INC. + +OUI:00090E* + ID_OUI_FROM_DATABASE=Helix Technology Inc. + +OUI:000908* + ID_OUI_FROM_DATABASE=VTech Technology Corp. + +OUI:00090D* + ID_OUI_FROM_DATABASE=LEADER ELECTRONICS CORP. + +OUI:000901* + ID_OUI_FROM_DATABASE=Shenzhen Shixuntong Information & Technoligy Co + OUI:0007E6* ID_OUI_FROM_DATABASE=edgeflow Canada Inc. @@ -40130,11 +41150,11 @@ OUI:0007C4* OUI:0007BE* ID_OUI_FROM_DATABASE=DataLogic SpA -OUI:00077E* - ID_OUI_FROM_DATABASE=Elrest GmbH +OUI:0007B1* + ID_OUI_FROM_DATABASE=Equator Technologies -OUI:00076F* - ID_OUI_FROM_DATABASE=Synoptics Limited +OUI:0007B8* + ID_OUI_FROM_DATABASE=Corvalent Corporation OUI:00076E* ID_OUI_FROM_DATABASE=Sinetica Corporation Limited @@ -40166,8 +41186,11 @@ OUI:00074B* OUI:000745* ID_OUI_FROM_DATABASE=Radlan Computer Communications Ltd. -OUI:0008C2* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:000738* + ID_OUI_FROM_DATABASE=Young Technology Co., Ltd. + +OUI:00073F* + ID_OUI_FROM_DATABASE=Woojyun Systec Co., Ltd. OUI:0008BB* ID_OUI_FROM_DATABASE=NetExcell @@ -40193,8 +41216,44 @@ OUI:0008A3* OUI:00089C* ID_OUI_FROM_DATABASE=Elecs Industry Co., Ltd. -OUI:000690* - ID_OUI_FROM_DATABASE=Euracom Communication GmbH +OUI:000894* + ID_OUI_FROM_DATABASE=InnoVISION Multimedia Ltd. + +OUI:00088F* + ID_OUI_FROM_DATABASE=ADVANCED DIGITAL TECHNOLOGY + +OUI:0008FC* + ID_OUI_FROM_DATABASE=Gigaphoton Inc. + +OUI:0008F9* + ID_OUI_FROM_DATABASE=Artesyn Embedded Technologies + +OUI:0008F4* + ID_OUI_FROM_DATABASE=Bluetake Technology Co., Ltd. + +OUI:0008EB* + ID_OUI_FROM_DATABASE=ROMWin Co.,Ltd. + +OUI:0008E4* + ID_OUI_FROM_DATABASE=Envenergy Inc + +OUI:0008DF* + ID_OUI_FROM_DATABASE=Alistel Inc. + +OUI:0008D8* + ID_OUI_FROM_DATABASE=Dowkey Microwave + +OUI:0008D2* + ID_OUI_FROM_DATABASE=ZOOM Networks Inc. + +OUI:0008CC* + ID_OUI_FROM_DATABASE=Remotec, Inc. + +OUI:0008D1* + ID_OUI_FROM_DATABASE=KAREL INC. + +OUI:0008C2* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc OUI:00068F* ID_OUI_FROM_DATABASE=Telemonitor, Inc. @@ -40235,11 +41294,11 @@ OUI:00055A* OUI:00065C* ID_OUI_FROM_DATABASE=Malachite Technologies, Inc. -OUI:000610* - ID_OUI_FROM_DATABASE=Abeona Networks Inc +OUI:000650* + ID_OUI_FROM_DATABASE=Tiburon Networks, Inc. -OUI:000616* - ID_OUI_FROM_DATABASE=Tel Net Co., Ltd. +OUI:000656* + ID_OUI_FROM_DATABASE=Tactel AB OUI:00060A* ID_OUI_FROM_DATABASE=Blue2space @@ -40286,6 +41345,39 @@ OUI:0005CF* OUI:0005C9* ID_OUI_FROM_DATABASE=LG Innotek Co., Ltd. +OUI:0006E7* + ID_OUI_FROM_DATABASE=Bit Blitz Communications Inc. + +OUI:0006ED* + ID_OUI_FROM_DATABASE=Inara Networks + +OUI:0006DC* + ID_OUI_FROM_DATABASE=Syabas Technology (Amquest) + +OUI:0006E1* + ID_OUI_FROM_DATABASE=Techno Trade s.a + +OUI:0006E6* + ID_OUI_FROM_DATABASE=DongYang Telecom Co., Ltd. + +OUI:0006CF* + ID_OUI_FROM_DATABASE=Thales Avionics In-Flight Systems, LLC + +OUI:0006D6* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:0006D5* + ID_OUI_FROM_DATABASE=Diamond Systems Corp. + +OUI:0006C9* + ID_OUI_FROM_DATABASE=Technical Marketing Research, Inc. + +OUI:0006C3* + ID_OUI_FROM_DATABASE=Schindler Elevator Ltd. + +OUI:0006C8* + ID_OUI_FROM_DATABASE=Sumitomo Metal Micro Devices, Inc. + OUI:0005D5* ID_OUI_FROM_DATABASE=Speedcom Wireless @@ -40310,50 +41402,17 @@ OUI:0005A2* OUI:0005AC* ID_OUI_FROM_DATABASE=Northern Digital, Inc. -OUI:0004E5* - ID_OUI_FROM_DATABASE=Glonet Systems, Inc. +OUI:000589* + ID_OUI_FROM_DATABASE=National Datacomputer -OUI:0004D9* - ID_OUI_FROM_DATABASE=Titan Electronics, Inc. +OUI:000595* + ID_OUI_FROM_DATABASE=Alesis Corporation -OUI:0004D3* - ID_OUI_FROM_DATABASE=Toyokeiki Co., Ltd. +OUI:00058F* + ID_OUI_FROM_DATABASE=CLCsoft co. -OUI:0004CC* - ID_OUI_FROM_DATABASE=Peek Traffic B.V. - -OUI:0004C0* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:0004C6* - ID_OUI_FROM_DATABASE=Yamaha Motor Co., Ltd. - -OUI:0004B9* - ID_OUI_FROM_DATABASE=S.I. Soubou, Inc. - -OUI:0004BA* - ID_OUI_FROM_DATABASE=KDD Media Will Corporation - -OUI:0004AF* - ID_OUI_FROM_DATABASE=Digital Fountain, Inc. - -OUI:0004B4* - ID_OUI_FROM_DATABASE=CIAC - -OUI:0004B3* - ID_OUI_FROM_DATABASE=Videotek, Inc. - -OUI:0004A6* - ID_OUI_FROM_DATABASE=SAF Tehnika Ltd. - -OUI:0004A0* - ID_OUI_FROM_DATABASE=Verity Instruments, Inc. - -OUI:00050C* - ID_OUI_FROM_DATABASE=Network Photonics, Inc. - -OUI:000512* - ID_OUI_FROM_DATABASE=Zebra Technologies Inc +OUI:000596* + ID_OUI_FROM_DATABASE=Genotech Co., Ltd. OUI:000506* ID_OUI_FROM_DATABASE=Reddo Networks AB @@ -40379,11 +41438,47 @@ OUI:0004EF* OUI:0004DF* ID_OUI_FROM_DATABASE=Teracom Telematica Ltda. -OUI:000553* - ID_OUI_FROM_DATABASE=DVC Company, Inc. +OUI:0004E5* + ID_OUI_FROM_DATABASE=Glonet Systems, Inc. -OUI:000548* - ID_OUI_FROM_DATABASE=Disco Corporation +OUI:0004D9* + ID_OUI_FROM_DATABASE=Titan Electronics, Inc. + +OUI:00062D* + ID_OUI_FROM_DATABASE=TouchStar Technologies, L.L.C. + +OUI:000649* + ID_OUI_FROM_DATABASE=3M Deutschland GmbH + +OUI:000643* + ID_OUI_FROM_DATABASE=SONO Computer Co., Ltd. + +OUI:00064A* + ID_OUI_FROM_DATABASE=Honeywell Co., Ltd. (KOREA) + +OUI:00063F* + ID_OUI_FROM_DATABASE=Everex Communications Inc. + +OUI:000639* + ID_OUI_FROM_DATABASE=Newtec + +OUI:000633* + ID_OUI_FROM_DATABASE=Cross Match Technologies GmbH + +OUI:000626* + ID_OUI_FROM_DATABASE=MWE GmbH + +OUI:00061D* + ID_OUI_FROM_DATABASE=MIP Telecom, Inc. + +OUI:000623* + ID_OUI_FROM_DATABASE=MGE UPS Systems France + +OUI:000610* + ID_OUI_FROM_DATABASE=Abeona Networks Inc + +OUI:000616* + ID_OUI_FROM_DATABASE=Tel Net Co., Ltd. OUI:00054D* ID_OUI_FROM_DATABASE=Brans Technologies, Inc. @@ -40418,53 +41513,41 @@ OUI:00051C* OUI:000516* ID_OUI_FROM_DATABASE=SMART Modular Technologies -OUI:000650* - ID_OUI_FROM_DATABASE=Tiburon Networks, Inc. +OUI:00050C* + ID_OUI_FROM_DATABASE=Network Photonics, Inc. -OUI:000656* - ID_OUI_FROM_DATABASE=Tactel AB +OUI:000512* + ID_OUI_FROM_DATABASE=Zebra Technologies Inc -OUI:00062D* - ID_OUI_FROM_DATABASE=TouchStar Technologies, L.L.C. +OUI:0006BF* + ID_OUI_FROM_DATABASE=Accella Technologies Co., Ltd. -OUI:000649* - ID_OUI_FROM_DATABASE=3M Deutschland GmbH +OUI:0006B9* + ID_OUI_FROM_DATABASE=A5TEK Corp. -OUI:000643* - ID_OUI_FROM_DATABASE=SONO Computer Co., Ltd. +OUI:0006B2* + ID_OUI_FROM_DATABASE=Linxtek Co. -OUI:00064A* - ID_OUI_FROM_DATABASE=Honeywell Co., Ltd. (KOREA) +OUI:0006AC* + ID_OUI_FROM_DATABASE=Intersoft Co. -OUI:00063F* - ID_OUI_FROM_DATABASE=Everex Communications Inc. +OUI:0006A6* + ID_OUI_FROM_DATABASE=Artistic Licence Engineering Ltd -OUI:000639* - ID_OUI_FROM_DATABASE=Newtec +OUI:0006A2* + ID_OUI_FROM_DATABASE=Microtune, Inc. -OUI:000633* - ID_OUI_FROM_DATABASE=Cross Match Technologies GmbH +OUI:000695* + ID_OUI_FROM_DATABASE=Ensure Technologies, Inc. -OUI:000626* - ID_OUI_FROM_DATABASE=MWE GmbH +OUI:00069C* + ID_OUI_FROM_DATABASE=Transmode Systems AB -OUI:00061D* - ID_OUI_FROM_DATABASE=MIP Telecom, Inc. +OUI:000696* + ID_OUI_FROM_DATABASE=Advent Networks -OUI:000623* - ID_OUI_FROM_DATABASE=MGE UPS Systems France - -OUI:000589* - ID_OUI_FROM_DATABASE=National Datacomputer - -OUI:000595* - ID_OUI_FROM_DATABASE=Alesis Corporation - -OUI:00058F* - ID_OUI_FROM_DATABASE=CLCsoft co. - -OUI:000596* - ID_OUI_FROM_DATABASE=Genotech Co., Ltd. +OUI:000690* + ID_OUI_FROM_DATABASE=Euracom Communication GmbH OUI:00057D* ID_OUI_FROM_DATABASE=Sun Communications, Inc. @@ -40493,44 +41576,11 @@ OUI:000560* OUI:000559* ID_OUI_FROM_DATABASE=Intracom S.A. -OUI:0004A5* - ID_OUI_FROM_DATABASE=Barco Projection Systems NV +OUI:000553* + ID_OUI_FROM_DATABASE=DVC Company, Inc. -OUI:000499* - ID_OUI_FROM_DATABASE=Chino Corporation - -OUI:00048D* - ID_OUI_FROM_DATABASE=Teo Technologies, Inc - -OUI:000493* - ID_OUI_FROM_DATABASE=Tsinghua Unisplendour Co., Ltd. - -OUI:000484* - ID_OUI_FROM_DATABASE=Amann GmbH - -OUI:00048A* - ID_OUI_FROM_DATABASE=Temia Vertriebs GmbH - -OUI:00047A* - ID_OUI_FROM_DATABASE=AXXESSIT ASA - -OUI:000474* - ID_OUI_FROM_DATABASE=LEGRAND - -OUI:00046E* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:000473* - ID_OUI_FROM_DATABASE=Photonex Corporation - -OUI:000467* - ID_OUI_FROM_DATABASE=Wuhan Research Institute of MII - -OUI:000461* - ID_OUI_FROM_DATABASE=EPOX Computer Co., Ltd. - -OUI:0003D9* - ID_OUI_FROM_DATABASE=Secheron SA +OUI:000548* + ID_OUI_FROM_DATABASE=Disco Corporation OUI:0003D2* ID_OUI_FROM_DATABASE=Crossbeam Systems, Inc. @@ -40565,6 +41615,48 @@ OUI:0003A8* OUI:0003A1* ID_OUI_FROM_DATABASE=HIPER Information & Communication, Inc. +OUI:00044E* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00044F* + ID_OUI_FROM_DATABASE=Schubert System Elektronik Gmbh + +OUI:000454* + ID_OUI_FROM_DATABASE=Quadriga UK + +OUI:000445* + ID_OUI_FROM_DATABASE=LMS Skalar Instruments GmbH + +OUI:00044A* + ID_OUI_FROM_DATABASE=iPolicy Networks, Inc. + +OUI:000444* + ID_OUI_FROM_DATABASE=Western Multiplex Corporation + +OUI:00043E* + ID_OUI_FROM_DATABASE=Telencomm + +OUI:000438* + ID_OUI_FROM_DATABASE=Nortel Networks + +OUI:000432* + ID_OUI_FROM_DATABASE=Voyetra Turtle Beach, Inc. + +OUI:000437* + ID_OUI_FROM_DATABASE=Powin Information Technology, Inc. + +OUI:00042B* + ID_OUI_FROM_DATABASE=IT Access Co., Ltd. + +OUI:000425* + ID_OUI_FROM_DATABASE=Atmel Corporation + +OUI:000419* + ID_OUI_FROM_DATABASE=Fibercycle Networks, Inc. + +OUI:00041A* + ID_OUI_FROM_DATABASE=Ines Test and Measurement GmbH & CoKG + OUI:000399* ID_OUI_FROM_DATABASE=Dongju Informations & Communications Co., Ltd. @@ -40595,8 +41687,8 @@ OUI:000371* OUI:00036D* ID_OUI_FROM_DATABASE=Runtop, Inc. -OUI:0002E3* - ID_OUI_FROM_DATABASE=LITE-ON Communications, Inc. +OUI:000361* + ID_OUI_FROM_DATABASE=Widcomm, Inc. OUI:0002DE* ID_OUI_FROM_DATABASE=Astrodesign, Inc. @@ -40637,44 +41729,8 @@ OUI:0002AF* OUI:0002AA* ID_OUI_FROM_DATABASE=PLcom Co., Ltd. -OUI:00045B* - ID_OUI_FROM_DATABASE=Techsan Electronics Co., Ltd. - -OUI:00044E* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00044F* - ID_OUI_FROM_DATABASE=Schubert System Elektronik Gmbh - -OUI:000454* - ID_OUI_FROM_DATABASE=Quadriga UK - -OUI:000445* - ID_OUI_FROM_DATABASE=LMS Skalar Instruments GmbH - -OUI:00044A* - ID_OUI_FROM_DATABASE=iPolicy Networks, Inc. - -OUI:000444* - ID_OUI_FROM_DATABASE=Western Multiplex Corporation - -OUI:00043E* - ID_OUI_FROM_DATABASE=Telencomm - -OUI:000438* - ID_OUI_FROM_DATABASE=Nortel Networks - -OUI:000432* - ID_OUI_FROM_DATABASE=Voyetra Turtle Beach, Inc. - -OUI:000437* - ID_OUI_FROM_DATABASE=Powin Information Technology, Inc. - -OUI:00042B* - ID_OUI_FROM_DATABASE=IT Access Co., Ltd. - -OUI:000361* - ID_OUI_FROM_DATABASE=Widcomm, Inc. +OUI:0002A3* + ID_OUI_FROM_DATABASE=ABB Switzerland Ltd, Power Systems OUI:00035A* ID_OUI_FROM_DATABASE=Photron Limited @@ -40754,50 +41810,77 @@ OUI:0002F5* OUI:0002EA* ID_OUI_FROM_DATABASE=Focus Enhancements -OUI:000269* - ID_OUI_FROM_DATABASE=Nadatel Co., Ltd +OUI:0002E3* + ID_OUI_FROM_DATABASE=LITE-ON Communications, Inc. -OUI:000265* - ID_OUI_FROM_DATABASE=Virditech Co. Ltd. +OUI:0004D3* + ID_OUI_FROM_DATABASE=Toyokeiki Co., Ltd. -OUI:00025E* - ID_OUI_FROM_DATABASE=High Technology Ltd +OUI:0004CC* + ID_OUI_FROM_DATABASE=Peek Traffic B.V. -OUI:000261* - ID_OUI_FROM_DATABASE=Tilgin AB +OUI:0004C0* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc -OUI:000259* - ID_OUI_FROM_DATABASE=Tsann Kuen China (Shanghai)Enterprise Co., Ltd. IT Group +OUI:0004B9* + ID_OUI_FROM_DATABASE=S.I. Soubou, Inc. -OUI:000255* - ID_OUI_FROM_DATABASE=IBM Corp +OUI:0004BA* + ID_OUI_FROM_DATABASE=KDD Media Will Corporation -OUI:000249* - ID_OUI_FROM_DATABASE=Aviv Infocom Co, Ltd. +OUI:0004AF* + ID_OUI_FROM_DATABASE=Digital Fountain, Inc. -OUI:000250* - ID_OUI_FROM_DATABASE=Geyser Networks, Inc. +OUI:0004B4* + ID_OUI_FROM_DATABASE=CIAC -OUI:000242* - ID_OUI_FROM_DATABASE=Videoframe Systems +OUI:0004B3* + ID_OUI_FROM_DATABASE=Videotek, Inc. -OUI:000244* - ID_OUI_FROM_DATABASE=SURECOM Technology Co. +OUI:0004A6* + ID_OUI_FROM_DATABASE=SAF Tehnika Ltd. -OUI:00022C* - ID_OUI_FROM_DATABASE=ABB Bomem, Inc. +OUI:0004A0* + ID_OUI_FROM_DATABASE=Verity Instruments, Inc. -OUI:00023A* - ID_OUI_FROM_DATABASE=ZSK Stickmaschinen GmbH +OUI:0004A5* + ID_OUI_FROM_DATABASE=Barco Projection Systems NV -OUI:000425* - ID_OUI_FROM_DATABASE=Atmel Corporation +OUI:000499* + ID_OUI_FROM_DATABASE=Chino Corporation -OUI:000419* - ID_OUI_FROM_DATABASE=Fibercycle Networks, Inc. +OUI:00048D* + ID_OUI_FROM_DATABASE=Teo Technologies, Inc -OUI:00041A* - ID_OUI_FROM_DATABASE=Ines Test and Measurement GmbH & CoKG +OUI:000493* + ID_OUI_FROM_DATABASE=Tsinghua Unisplendour Co., Ltd. + +OUI:000484* + ID_OUI_FROM_DATABASE=Amann GmbH + +OUI:00048A* + ID_OUI_FROM_DATABASE=Temia Vertriebs GmbH + +OUI:00047A* + ID_OUI_FROM_DATABASE=AXXESSIT ASA + +OUI:000474* + ID_OUI_FROM_DATABASE=LEGRAND + +OUI:00046E* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:000473* + ID_OUI_FROM_DATABASE=Photonex Corporation + +OUI:000467* + ID_OUI_FROM_DATABASE=Wuhan Research Institute of MII + +OUI:000461* + ID_OUI_FROM_DATABASE=EPOX Computer Co., Ltd. + +OUI:00045B* + ID_OUI_FROM_DATABASE=Techsan Electronics Co., Ltd. OUI:000414* ID_OUI_FROM_DATABASE=Umezawa Musen Denki Co., Ltd. @@ -40826,38 +41909,77 @@ OUI:0003EB* OUI:0003E5* ID_OUI_FROM_DATABASE=Hermstedt SG -OUI:0002A3* - ID_OUI_FROM_DATABASE=ABB Switzerland Ltd, Power Systems +OUI:0003D9* + ID_OUI_FROM_DATABASE=Secheron SA -OUI:000298* - ID_OUI_FROM_DATABASE=Broadframe Corporation +OUI:00022F* + ID_OUI_FROM_DATABASE=P-Cube, Ltd. -OUI:000292* - ID_OUI_FROM_DATABASE=Logic Innovations, Inc. +OUI:000227* + ID_OUI_FROM_DATABASE=ESD Electronic System Design GmbH -OUI:00028D* - ID_OUI_FROM_DATABASE=Movita Technologies, Inc. +OUI:00021F* + ID_OUI_FROM_DATABASE=Aculab PLC -OUI:000283* - ID_OUI_FROM_DATABASE=Spectrum Controls, Inc. +OUI:00021B* + ID_OUI_FROM_DATABASE=Kollmorgen-Servotronix -OUI:000277* - ID_OUI_FROM_DATABASE=Cash Systemes Industrie +OUI:00020C* + ID_OUI_FROM_DATABASE=Metro-Optix -OUI:00027C* - ID_OUI_FROM_DATABASE=Trilithic, Inc. +OUI:000218* + ID_OUI_FROM_DATABASE=Advanced Scientific Corp -OUI:000275* - ID_OUI_FROM_DATABASE=SMART Technologies, Inc. +OUI:000213* + ID_OUI_FROM_DATABASE=S.D.E.L. -OUI:000270* - ID_OUI_FROM_DATABASE=Crewave Co., Ltd. +OUI:00020F* + ID_OUI_FROM_DATABASE=AATR -OUI:000104* - ID_OUI_FROM_DATABASE=DVICO Co., Ltd. +OUI:0001F9* + ID_OUI_FROM_DATABASE=TeraGlobal Communications Corp. -OUI:000110* - ID_OUI_FROM_DATABASE=Gotham Networks +OUI:000200* + ID_OUI_FROM_DATABASE=Net & Sys Co., Ltd. + +OUI:00015E* + ID_OUI_FROM_DATABASE=BEST TECHNOLOGY CO., LTD. + +OUI:000162* + ID_OUI_FROM_DATABASE=Cygnet Technologies, Inc. + +OUI:000169* + ID_OUI_FROM_DATABASE=Celestix Networks Pte Ltd. + +OUI:000175* + ID_OUI_FROM_DATABASE=Radiant Communications Corp. + +OUI:000159* + ID_OUI_FROM_DATABASE=S1 Corporation + +OUI:000165* + ID_OUI_FROM_DATABASE=AirSwitch Corporation + +OUI:000171* + ID_OUI_FROM_DATABASE=Allied Data Technologies + +OUI:000157* + ID_OUI_FROM_DATABASE=SYSWAVE CO., LTD + +OUI:000153* + ID_OUI_FROM_DATABASE=ARCHTEK TELECOM CORPORATION + +OUI:000144* + ID_OUI_FROM_DATABASE=EMC Corporation + +OUI:00014B* + ID_OUI_FROM_DATABASE=Ennovate Networks, Inc. + +OUI:00012C* + ID_OUI_FROM_DATABASE=Aravox Technologies, Inc. + +OUI:000138* + ID_OUI_FROM_DATABASE=XAVi Technologies Corp. OUI:00010C* ID_OUI_FROM_DATABASE=System Talks Inc. @@ -40892,41 +42014,32 @@ OUI:00B091* OUI:0030BE* ID_OUI_FROM_DATABASE=City-Net Technology, Inc. -OUI:000233* - ID_OUI_FROM_DATABASE=Mantra Communications, Inc. +OUI:00303E* + ID_OUI_FROM_DATABASE=Radcom Ltd. -OUI:00022F* - ID_OUI_FROM_DATABASE=P-Cube, Ltd. +OUI:0030D7* + ID_OUI_FROM_DATABASE=Innovative Systems, L.L.C. -OUI:000227* - ID_OUI_FROM_DATABASE=ESD Electronic System Design GmbH +OUI:0030FC* + ID_OUI_FROM_DATABASE=Terawave Communications, Inc. -OUI:00021F* - ID_OUI_FROM_DATABASE=Aculab PLC +OUI:00300F* + ID_OUI_FROM_DATABASE=IMT - Information Management T -OUI:00021B* - ID_OUI_FROM_DATABASE=Kollmorgen-Servotronix +OUI:003004* + ID_OUI_FROM_DATABASE=LEADTEK RESEARCH INC. -OUI:00020C* - ID_OUI_FROM_DATABASE=Metro-Optix +OUI:003018* + ID_OUI_FROM_DATABASE=Jetway Information Co., Ltd. -OUI:000218* - ID_OUI_FROM_DATABASE=Advanced Scientific Corp +OUI:003088* + ID_OUI_FROM_DATABASE=Ericsson -OUI:000213* - ID_OUI_FROM_DATABASE=S.D.E.L. +OUI:0030CA* + ID_OUI_FROM_DATABASE=Discovery Com -OUI:00020F* - ID_OUI_FROM_DATABASE=AATR - -OUI:0001F4* - ID_OUI_FROM_DATABASE=Enterasys Networks - -OUI:0001F9* - ID_OUI_FROM_DATABASE=TeraGlobal Communications Corp. - -OUI:000200* - ID_OUI_FROM_DATABASE=Net & Sys Co., Ltd. +OUI:00304F* + ID_OUI_FROM_DATABASE=PLANET Technology Corporation OUI:0001FC* ID_OUI_FROM_DATABASE=Keyence Corporation @@ -40961,81 +42074,45 @@ OUI:0001D1* OUI:0001B3* ID_OUI_FROM_DATABASE=Precision Electronic Manufacturing -OUI:000160* - ID_OUI_FROM_DATABASE=ELMEX Co., LTD. - -OUI:00015E* - ID_OUI_FROM_DATABASE=BEST TECHNOLOGY CO., LTD. - -OUI:000162* - ID_OUI_FROM_DATABASE=Cygnet Technologies, Inc. - -OUI:000169* - ID_OUI_FROM_DATABASE=Celestix Networks Pte Ltd. - -OUI:000175* - ID_OUI_FROM_DATABASE=Radiant Communications Corp. - -OUI:000159* - ID_OUI_FROM_DATABASE=S1 Corporation - -OUI:000165* - ID_OUI_FROM_DATABASE=AirSwitch Corporation - -OUI:000171* - ID_OUI_FROM_DATABASE=Allied Data Technologies - -OUI:000157* - ID_OUI_FROM_DATABASE=SYSWAVE CO., LTD - -OUI:000153* - ID_OUI_FROM_DATABASE=ARCHTEK TELECOM CORPORATION - -OUI:000144* - ID_OUI_FROM_DATABASE=EMC Corporation - -OUI:003038* - ID_OUI_FROM_DATABASE=XCP, INC. - -OUI:0030DB* - ID_OUI_FROM_DATABASE=Mindready Solutions, Inc. - -OUI:00306A* - ID_OUI_FROM_DATABASE=PENTA MEDIA CO., LTD. - -OUI:003021* - ID_OUI_FROM_DATABASE=HSING TECH. ENTERPRISE CO.,LTD - -OUI:0030EA* - ID_OUI_FROM_DATABASE=TeraForce Technology Corporation - -OUI:0030F4* - ID_OUI_FROM_DATABASE=STARDOT TECHNOLOGIES - -OUI:003087* - ID_OUI_FROM_DATABASE=VEGA GRIESHABER KG - -OUI:003000* - ID_OUI_FROM_DATABASE=ALLWELL TECHNOLOGY CORP. - -OUI:003034* - ID_OUI_FROM_DATABASE=SET ENGINEERING - -OUI:00308D* - ID_OUI_FROM_DATABASE=Pinnacle Systems, Inc. - -OUI:00304B* - ID_OUI_FROM_DATABASE=ORBACOM SYSTEMS, INC. - -OUI:0030FA* - ID_OUI_FROM_DATABASE=TELICA, INC. - OUI:0001B1* ID_OUI_FROM_DATABASE=General Bandwidth OUI:0001BB* ID_OUI_FROM_DATABASE=Frequentis +OUI:00025E* + ID_OUI_FROM_DATABASE=High Technology Ltd + +OUI:000261* + ID_OUI_FROM_DATABASE=Tilgin AB + +OUI:000259* + ID_OUI_FROM_DATABASE=Tsann Kuen China (Shanghai)Enterprise Co., Ltd. IT Group + +OUI:000255* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:000249* + ID_OUI_FROM_DATABASE=Aviv Infocom Co, Ltd. + +OUI:000250* + ID_OUI_FROM_DATABASE=Geyser Networks, Inc. + +OUI:000242* + ID_OUI_FROM_DATABASE=Videoframe Systems + +OUI:000244* + ID_OUI_FROM_DATABASE=SURECOM Technology Co. + +OUI:00022C* + ID_OUI_FROM_DATABASE=ABB Bomem, Inc. + +OUI:00023A* + ID_OUI_FROM_DATABASE=ZSK Stickmaschinen GmbH + +OUI:000233* + ID_OUI_FROM_DATABASE=Mantra Communications, Inc. + OUI:0001B7* ID_OUI_FROM_DATABASE=Centos, Inc. @@ -41078,41 +42155,38 @@ OUI:0030F5* OUI:000184* ID_OUI_FROM_DATABASE=SIEB & MEYER AG -OUI:00303E* - ID_OUI_FROM_DATABASE=Radcom Ltd. +OUI:000160* + ID_OUI_FROM_DATABASE=ELMEX Co., LTD. -OUI:0030D7* - ID_OUI_FROM_DATABASE=Innovative Systems, L.L.C. +OUI:000298* + ID_OUI_FROM_DATABASE=Broadframe Corporation -OUI:0030FC* - ID_OUI_FROM_DATABASE=Terawave Communications, Inc. +OUI:000292* + ID_OUI_FROM_DATABASE=Logic Innovations, Inc. -OUI:00300F* - ID_OUI_FROM_DATABASE=IMT - Information Management T +OUI:00028D* + ID_OUI_FROM_DATABASE=Movita Technologies, Inc. -OUI:003004* - ID_OUI_FROM_DATABASE=LEADTEK RESEARCH INC. +OUI:000283* + ID_OUI_FROM_DATABASE=Spectrum Controls, Inc. -OUI:003018* - ID_OUI_FROM_DATABASE=Jetway Information Co., Ltd. +OUI:000277* + ID_OUI_FROM_DATABASE=Cash Systemes Industrie -OUI:003088* - ID_OUI_FROM_DATABASE=Ericsson +OUI:00027C* + ID_OUI_FROM_DATABASE=Trilithic, Inc. -OUI:0030CA* - ID_OUI_FROM_DATABASE=Discovery Com +OUI:000275* + ID_OUI_FROM_DATABASE=SMART Technologies, Inc. -OUI:00304F* - ID_OUI_FROM_DATABASE=PLANET Technology Corporation +OUI:000270* + ID_OUI_FROM_DATABASE=Crewave Co., Ltd. -OUI:00014B* - ID_OUI_FROM_DATABASE=Ennovate Networks, Inc. +OUI:000269* + ID_OUI_FROM_DATABASE=Nadatel Co., Ltd -OUI:00012C* - ID_OUI_FROM_DATABASE=Aravox Technologies, Inc. - -OUI:000138* - ID_OUI_FROM_DATABASE=XAVi Technologies Corp. +OUI:000265* + ID_OUI_FROM_DATABASE=Virditech Co. Ltd. OUI:000134* ID_OUI_FROM_DATABASE=Selectron Systems AG @@ -41135,26 +42209,11 @@ OUI:000123* OUI:00011F* ID_OUI_FROM_DATABASE=RC Networks, Inc. -OUI:003045* - ID_OUI_FROM_DATABASE=Village Networks, Inc. (VNI) +OUI:000104* + ID_OUI_FROM_DATABASE=DVICO Co., Ltd. -OUI:0030BB* - ID_OUI_FROM_DATABASE=CacheFlow, Inc. - -OUI:003053* - ID_OUI_FROM_DATABASE=Basler AG - -OUI:003072* - ID_OUI_FROM_DATABASE=Intellibyte Inc. - -OUI:0030B1* - ID_OUI_FROM_DATABASE=TrunkNet - -OUI:0030A7* - ID_OUI_FROM_DATABASE=SCHWEITZER ENGINEERING - -OUI:00D086* - ID_OUI_FROM_DATABASE=FOVEON, INC. +OUI:000110* + ID_OUI_FROM_DATABASE=Gotham Networks OUI:00D05A* ID_OUI_FROM_DATABASE=SYMBIONICS, LTD. @@ -41201,51 +42260,48 @@ OUI:00D01E* OUI:00D0A9* ID_OUI_FROM_DATABASE=SHINANO KENSHI CO., LTD. +OUI:00D0F2* + ID_OUI_FROM_DATABASE=MONTEREY NETWORKS + +OUI:0030DB* + ID_OUI_FROM_DATABASE=Mindready Solutions, Inc. + +OUI:00306A* + ID_OUI_FROM_DATABASE=PENTA MEDIA CO., LTD. + +OUI:003021* + ID_OUI_FROM_DATABASE=HSING TECH. ENTERPRISE CO.,LTD + +OUI:0030EA* + ID_OUI_FROM_DATABASE=TeraForce Technology Corporation + +OUI:0030F4* + ID_OUI_FROM_DATABASE=STARDOT TECHNOLOGIES + +OUI:003087* + ID_OUI_FROM_DATABASE=VEGA GRIESHABER KG + +OUI:003000* + ID_OUI_FROM_DATABASE=ALLWELL TECHNOLOGY CORP. + +OUI:003034* + ID_OUI_FROM_DATABASE=SET ENGINEERING + +OUI:00308D* + ID_OUI_FROM_DATABASE=Pinnacle Systems, Inc. + +OUI:00304B* + ID_OUI_FROM_DATABASE=ORBACOM SYSTEMS, INC. + +OUI:0030FA* + ID_OUI_FROM_DATABASE=TELICA, INC. + OUI:0030E9* ID_OUI_FROM_DATABASE=GMA COMMUNICATION MANUFACT'G OUI:003027* ID_OUI_FROM_DATABASE=KERBANGO, INC. -OUI:0030F6* - ID_OUI_FROM_DATABASE=SECURELOGIX CORPORATION - -OUI:0030B6* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:0030B2* - ID_OUI_FROM_DATABASE=L-3 Sonoma EO - -OUI:0030D6* - ID_OUI_FROM_DATABASE=MSC VERTRIEBS GMBH - -OUI:003008* - ID_OUI_FROM_DATABASE=AVIO DIGITAL, INC. - -OUI:00306D* - ID_OUI_FROM_DATABASE=LUCENT TECHNOLOGIES - -OUI:0030E4* - ID_OUI_FROM_DATABASE=CHIYODA SYSTEM RIKEN - -OUI:00301A* - ID_OUI_FROM_DATABASE=SMARTBRIDGES PTE. LTD. - -OUI:0030CD* - ID_OUI_FROM_DATABASE=CONEXANT SYSTEMS, INC. - -OUI:003001* - ID_OUI_FROM_DATABASE=SMP - -OUI:0030E1* - ID_OUI_FROM_DATABASE=Network Equipment Technologies, Inc. - -OUI:0050A7* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00D0EE* - ID_OUI_FROM_DATABASE=DICTAPHONE CORPORATION - OUI:00D0B8* ID_OUI_FROM_DATABASE=Iomega Corporation @@ -41288,11 +42344,194 @@ OUI:0050A9* OUI:00503C* ID_OUI_FROM_DATABASE=TSINGHUA NOVEL ELECTRONICS -OUI:005030* - ID_OUI_FROM_DATABASE=FUTURE PLUS SYSTEMS +OUI:0050B6* + ID_OUI_FROM_DATABASE=GOOD WAY IND. CO., LTD. -OUI:005037* - ID_OUI_FROM_DATABASE=KOGA ELECTRONICS CO. +OUI:0050FF* + ID_OUI_FROM_DATABASE=HAKKO ELECTRONICS CO., LTD. + +OUI:005032* + ID_OUI_FROM_DATABASE=PICAZO COMMUNICATIONS, INC. + +OUI:0030F6* + ID_OUI_FROM_DATABASE=SECURELOGIX CORPORATION + +OUI:0030B6* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:0030B2* + ID_OUI_FROM_DATABASE=L-3 Sonoma EO + +OUI:0030D6* + ID_OUI_FROM_DATABASE=MSC VERTRIEBS GMBH + +OUI:003008* + ID_OUI_FROM_DATABASE=AVIO DIGITAL, INC. + +OUI:00306D* + ID_OUI_FROM_DATABASE=LUCENT TECHNOLOGIES + +OUI:0030E4* + ID_OUI_FROM_DATABASE=CHIYODA SYSTEM RIKEN + +OUI:00301A* + ID_OUI_FROM_DATABASE=SMARTBRIDGES PTE. LTD. + +OUI:0030CD* + ID_OUI_FROM_DATABASE=CONEXANT SYSTEMS, INC. + +OUI:003001* + ID_OUI_FROM_DATABASE=SMP + +OUI:0030E1* + ID_OUI_FROM_DATABASE=Network Equipment Technologies, Inc. + +OUI:0030D8* + ID_OUI_FROM_DATABASE=SITEK + +OUI:003062* + ID_OUI_FROM_DATABASE=IP Video Networks Inc + +OUI:003081* + ID_OUI_FROM_DATABASE=ALTOS C&C + +OUI:00D066* + ID_OUI_FROM_DATABASE=WINTRISS ENGINEERING CORP. + +OUI:00D06F* + ID_OUI_FROM_DATABASE=KMC CONTROLS + +OUI:00D04B* + ID_OUI_FROM_DATABASE=LA CIE GROUP S.A. + +OUI:00D060* + ID_OUI_FROM_DATABASE=Panasonic Europe Ltd. + +OUI:00D002* + ID_OUI_FROM_DATABASE=DITECH CORPORATION + +OUI:00D0A6* + ID_OUI_FROM_DATABASE=LANBIRD TECHNOLOGY CO., LTD. + +OUI:00D0DE* + ID_OUI_FROM_DATABASE=PHILIPS MULTIMEDIA NETWORK + +OUI:00D083* + ID_OUI_FROM_DATABASE=INVERTEX, INC. + +OUI:00D038* + ID_OUI_FROM_DATABASE=FIVEMERE, LTD. + +OUI:00D00C* + ID_OUI_FROM_DATABASE=SNIJDER MICRO SYSTEMS + +OUI:00D086* + ID_OUI_FROM_DATABASE=FOVEON, INC. + +OUI:00D03F* + ID_OUI_FROM_DATABASE=AMERICAN COMMUNICATION + +OUI:00D033* + ID_OUI_FROM_DATABASE=DALIAN DAXIAN NETWORK + +OUI:00D0CE* + ID_OUI_FROM_DATABASE=ASYST ELECTRONIC + +OUI:00D090* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00D0B6* + ID_OUI_FROM_DATABASE=CRESCENT NETWORKS, INC. + +OUI:00D0D2* + ID_OUI_FROM_DATABASE=EPILOG CORPORATION + +OUI:00D071* + ID_OUI_FROM_DATABASE=ECHELON CORP. + +OUI:00D07B* + ID_OUI_FROM_DATABASE=COMCAM INTERNATIONAL INC + +OUI:00D05D* + ID_OUI_FROM_DATABASE=INTELLIWORXX, INC. + +OUI:00D00D* + ID_OUI_FROM_DATABASE=MICROMERITICS INSTRUMENT + +OUI:00D04C* + ID_OUI_FROM_DATABASE=EUROTEL TELECOM LTD. + +OUI:00D0FD* + ID_OUI_FROM_DATABASE=OPTIMA TELE.COM, INC. + +OUI:0050A7* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:00D0EE* + ID_OUI_FROM_DATABASE=DICTAPHONE CORPORATION + +OUI:00D0B0* + ID_OUI_FROM_DATABASE=BITSWITCH LTD. + +OUI:00D044* + ID_OUI_FROM_DATABASE=ALIDIAN NETWORKS, INC. + +OUI:00D004* + ID_OUI_FROM_DATABASE=PENTACOM LTD. + +OUI:00D045* + ID_OUI_FROM_DATABASE=KVASER AB + +OUI:00D0D0* + ID_OUI_FROM_DATABASE=ZHONGXING TELECOM LTD. + +OUI:00D03E* + ID_OUI_FROM_DATABASE=ROCKETCHIPS, INC. + +OUI:003045* + ID_OUI_FROM_DATABASE=Village Networks, Inc. (VNI) + +OUI:0030BB* + ID_OUI_FROM_DATABASE=CacheFlow, Inc. + +OUI:003053* + ID_OUI_FROM_DATABASE=Basler AG + +OUI:003072* + ID_OUI_FROM_DATABASE=Intellibyte Inc. + +OUI:0030B1* + ID_OUI_FROM_DATABASE=TrunkNet + +OUI:0030A7* + ID_OUI_FROM_DATABASE=SCHWEITZER ENGINEERING + +OUI:003038* + ID_OUI_FROM_DATABASE=XCP, INC. + +OUI:00902C* + ID_OUI_FROM_DATABASE=DATA & CONTROL EQUIPMENT LTD. + +OUI:009049* + ID_OUI_FROM_DATABASE=ENTRIDIA CORPORATION + +OUI:009043* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:009076* + ID_OUI_FROM_DATABASE=FMT AIRCRAFT GATE SUPPORT SYSTEMS AB + +OUI:009017* + ID_OUI_FROM_DATABASE=Zypcom, Inc + +OUI:00907B* + ID_OUI_FROM_DATABASE=E-TECH, INC. + +OUI:00909D* + ID_OUI_FROM_DATABASE=NovaTech Process Solutions, LLC + +OUI:009038* + ID_OUI_FROM_DATABASE=FOUNTAIN TECHNOLOGIES, INC. OUI:00501F* ID_OUI_FROM_DATABASE=MRG SYSTEMS, LTD. @@ -41333,234 +42572,6 @@ OUI:005057* OUI:005087* ID_OUI_FROM_DATABASE=TERASAKI ELECTRIC CO., LTD. -OUI:00D03E* - ID_OUI_FROM_DATABASE=ROCKETCHIPS, INC. - -OUI:00D03F* - ID_OUI_FROM_DATABASE=AMERICAN COMMUNICATION - -OUI:00D033* - ID_OUI_FROM_DATABASE=DALIAN DAXIAN NETWORK - -OUI:00D0CE* - ID_OUI_FROM_DATABASE=ASYST ELECTRONIC - -OUI:00D090* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - -OUI:00D0B6* - ID_OUI_FROM_DATABASE=CRESCENT NETWORKS, INC. - -OUI:00D0D2* - ID_OUI_FROM_DATABASE=EPILOG CORPORATION - -OUI:0050B6* - ID_OUI_FROM_DATABASE=GOOD WAY IND. CO., LTD. - -OUI:0050FF* - ID_OUI_FROM_DATABASE=HAKKO ELECTRONICS CO., LTD. - -OUI:005032* - ID_OUI_FROM_DATABASE=PICAZO COMMUNICATIONS, INC. - -OUI:0050DA* - ID_OUI_FROM_DATABASE=3COM CORPORATION - -OUI:0050F9* - ID_OUI_FROM_DATABASE=Sensormatic Electronics LLC - -OUI:0050F6* - ID_OUI_FROM_DATABASE=PAN-INTERNATIONAL INDUSTRIAL CORP. - -OUI:00506C* - ID_OUI_FROM_DATABASE=Beijer Electronics Products AB - -OUI:0050A5* - ID_OUI_FROM_DATABASE=CAPITOL BUSINESS SYSTEMS, LTD. - -OUI:0050FC* - ID_OUI_FROM_DATABASE=EDIMAX TECHNOLOGY CO., LTD. - -OUI:005000* - ID_OUI_FROM_DATABASE=NEXO COMMUNICATIONS, INC. - -OUI:00D071* - ID_OUI_FROM_DATABASE=ECHELON CORP. - -OUI:00D066* - ID_OUI_FROM_DATABASE=WINTRISS ENGINEERING CORP. - -OUI:00D06F* - ID_OUI_FROM_DATABASE=KMC CONTROLS - -OUI:00D04B* - ID_OUI_FROM_DATABASE=LA CIE GROUP S.A. - -OUI:00D060* - ID_OUI_FROM_DATABASE=Panasonic Europe Ltd. - -OUI:00D002* - ID_OUI_FROM_DATABASE=DITECH CORPORATION - -OUI:00D0A6* - ID_OUI_FROM_DATABASE=LANBIRD TECHNOLOGY CO., LTD. - -OUI:00D0DE* - ID_OUI_FROM_DATABASE=PHILIPS MULTIMEDIA NETWORK - -OUI:00D083* - ID_OUI_FROM_DATABASE=INVERTEX, INC. - -OUI:00D038* - ID_OUI_FROM_DATABASE=FIVEMERE, LTD. - -OUI:00D00C* - ID_OUI_FROM_DATABASE=SNIJDER MICRO SYSTEMS - -OUI:00D0F2* - ID_OUI_FROM_DATABASE=MONTEREY NETWORKS - -OUI:00D07B* - ID_OUI_FROM_DATABASE=COMCAM INTERNATIONAL INC - -OUI:00D05D* - ID_OUI_FROM_DATABASE=INTELLIWORXX, INC. - -OUI:00D00D* - ID_OUI_FROM_DATABASE=MICROMERITICS INSTRUMENT - -OUI:00D04C* - ID_OUI_FROM_DATABASE=EUROTEL TELECOM LTD. - -OUI:00D0FD* - ID_OUI_FROM_DATABASE=OPTIMA TELE.COM, INC. - -OUI:0030D8* - ID_OUI_FROM_DATABASE=SITEK - -OUI:003062* - ID_OUI_FROM_DATABASE=IP Video Networks Inc - -OUI:003081* - ID_OUI_FROM_DATABASE=ALTOS C&C - -OUI:00D0B0* - ID_OUI_FROM_DATABASE=BITSWITCH LTD. - -OUI:00D044* - ID_OUI_FROM_DATABASE=ALIDIAN NETWORKS, INC. - -OUI:00D004* - ID_OUI_FROM_DATABASE=PENTACOM LTD. - -OUI:00D045* - ID_OUI_FROM_DATABASE=KVASER AB - -OUI:00D0D0* - ID_OUI_FROM_DATABASE=ZHONGXING TELECOM LTD. - -OUI:00902C* - ID_OUI_FROM_DATABASE=DATA & CONTROL EQUIPMENT LTD. - -OUI:009049* - ID_OUI_FROM_DATABASE=ENTRIDIA CORPORATION - -OUI:009043* - ID_OUI_FROM_DATABASE=Tattile SRL - -OUI:009076* - ID_OUI_FROM_DATABASE=FMT AIRCRAFT GATE SUPPORT SYSTEMS AB - -OUI:009017* - ID_OUI_FROM_DATABASE=Zypcom, Inc - -OUI:00907B* - ID_OUI_FROM_DATABASE=E-TECH, INC. - -OUI:00102A* - ID_OUI_FROM_DATABASE=ZF MICROSYSTEMS, INC. - -OUI:00107D* - ID_OUI_FROM_DATABASE=AURORA COMMUNICATIONS, LTD. - -OUI:00101C* - ID_OUI_FROM_DATABASE=OHM TECHNOLOGIES INTL, LLC - -OUI:00106C* - ID_OUI_FROM_DATABASE=EDNT GmbH - -OUI:0010D4* - ID_OUI_FROM_DATABASE=STORAGE COMPUTER CORPORATION - -OUI:0010BF* - ID_OUI_FROM_DATABASE=InterAir Wireless - -OUI:001036* - ID_OUI_FROM_DATABASE=INTER-TEL INTEGRATED SYSTEMS - -OUI:001026* - ID_OUI_FROM_DATABASE=ACCELERATED NETWORKS, INC. - -OUI:00104B* - ID_OUI_FROM_DATABASE=3COM CORPORATION - -OUI:000629* - ID_OUI_FROM_DATABASE=IBM Corp - -OUI:001004* - ID_OUI_FROM_DATABASE=THE BRANTLEY COILE COMPANY,INC - -OUI:00103A* - ID_OUI_FROM_DATABASE=DIAMOND NETWORK TECH - -OUI:0010D8* - ID_OUI_FROM_DATABASE=CALISTA - -OUI:001031* - ID_OUI_FROM_DATABASE=OBJECTIVE COMMUNICATIONS, INC. - -OUI:00107E* - ID_OUI_FROM_DATABASE=BACHMANN ELECTRONIC GmbH - -OUI:0010C0* - ID_OUI_FROM_DATABASE=ARMA, Inc. - -OUI:001016* - ID_OUI_FROM_DATABASE=T.SQWARE - -OUI:00103D* - ID_OUI_FROM_DATABASE=PHASECOM, LTD. - -OUI:0010C2* - ID_OUI_FROM_DATABASE=WILLNET, INC. - -OUI:00107A* - ID_OUI_FROM_DATABASE=AmbiCom, Inc. - -OUI:0010C4* - ID_OUI_FROM_DATABASE=MEDIA GLOBAL LINKS CO., LTD. - -OUI:0010EB* - ID_OUI_FROM_DATABASE=SELSIUS SYSTEMS, INC. - -OUI:0010FE* - ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION - -OUI:00102E* - ID_OUI_FROM_DATABASE=NETWORK SYSTEMS & TECHNOLOGIES PVT. LTD. - -OUI:0010C1* - ID_OUI_FROM_DATABASE=OI ELECTRIC CO., LTD. - -OUI:00103E* - ID_OUI_FROM_DATABASE=NETSCHOOLS CORPORATION - -OUI:001049* - ID_OUI_FROM_DATABASE=ShoreTel, Inc - -OUI:00105E* - ID_OUI_FROM_DATABASE=Spirent plc, Service Assurance Broadband - OUI:005088* ID_OUI_FROM_DATABASE=AMANO CORPORATION @@ -41591,6 +42602,30 @@ OUI:0050EB* OUI:0050BC* ID_OUI_FROM_DATABASE=HAMMER STORAGE SOLUTIONS +OUI:00900F* + ID_OUI_FROM_DATABASE=KAWASAKI HEAVY INDUSTRIES, LTD + +OUI:009036* + ID_OUI_FROM_DATABASE=ens, inc. + +OUI:0090E9* + ID_OUI_FROM_DATABASE=JANZ COMPUTER AG + +OUI:009032* + ID_OUI_FROM_DATABASE=PELCOMBE GROUP LTD. + +OUI:0090B8* + ID_OUI_FROM_DATABASE=ROHDE & SCHWARZ GMBH & CO. KG + +OUI:009058* + ID_OUI_FROM_DATABASE=Ultra Electronics Ltd., Command and Control Systems + +OUI:0090BE* + ID_OUI_FROM_DATABASE=IBC/INTEGRATED BUSINESS COMPUTERS + +OUI:009062* + ID_OUI_FROM_DATABASE=ICP VORTEX COMPUTERSYSTEME GmbH + OUI:0090C3* ID_OUI_FROM_DATABASE=TOPIC SEMICONDUCTOR CORP. @@ -41633,11 +42668,14 @@ OUI:0010D5* OUI:0010E5* ID_OUI_FROM_DATABASE=SOLECTRON TEXAS -OUI:00909D* - ID_OUI_FROM_DATABASE=NovaTech Process Solutions, LLC +OUI:00102A* + ID_OUI_FROM_DATABASE=ZF MICROSYSTEMS, INC. -OUI:009038* - ID_OUI_FROM_DATABASE=FOUNTAIN TECHNOLOGIES, INC. +OUI:00107D* + ID_OUI_FROM_DATABASE=AURORA COMMUNICATIONS, LTD. + +OUI:00101C* + ID_OUI_FROM_DATABASE=OHM TECHNOLOGIES INTL, LLC OUI:0090C5* ID_OUI_FROM_DATABASE=INTERNET MAGIC, INC. @@ -41696,29 +42734,164 @@ OUI:009098* OUI:0090CF* ID_OUI_FROM_DATABASE=NORTEL -OUI:00900F* - ID_OUI_FROM_DATABASE=KAWASAKI HEAVY INDUSTRIES, LTD +OUI:0050DA* + ID_OUI_FROM_DATABASE=3COM CORPORATION -OUI:009036* - ID_OUI_FROM_DATABASE=ens, inc. +OUI:0050F9* + ID_OUI_FROM_DATABASE=Sensormatic Electronics LLC -OUI:0090E9* - ID_OUI_FROM_DATABASE=JANZ COMPUTER AG +OUI:0050F6* + ID_OUI_FROM_DATABASE=PAN-INTERNATIONAL INDUSTRIAL CORP. -OUI:009032* - ID_OUI_FROM_DATABASE=PELCOMBE GROUP LTD. +OUI:00506C* + ID_OUI_FROM_DATABASE=Beijer Electronics Products AB -OUI:0090B8* - ID_OUI_FROM_DATABASE=ROHDE & SCHWARZ GMBH & CO. KG +OUI:0050A5* + ID_OUI_FROM_DATABASE=CAPITOL BUSINESS SYSTEMS, LTD. -OUI:009058* - ID_OUI_FROM_DATABASE=Ultra Electronics Ltd., Command and Control Systems +OUI:005000* + ID_OUI_FROM_DATABASE=NEXO COMMUNICATIONS, INC. -OUI:0090BE* - ID_OUI_FROM_DATABASE=IBC/INTEGRATED BUSINESS COMPUTERS +OUI:005030* + ID_OUI_FROM_DATABASE=FUTURE PLUS SYSTEMS -OUI:009062* - ID_OUI_FROM_DATABASE=ICP VORTEX COMPUTERSYSTEME GmbH +OUI:005037* + ID_OUI_FROM_DATABASE=KOGA ELECTRONICS CO. + +OUI:00106C* + ID_OUI_FROM_DATABASE=EDNT GmbH + +OUI:0010D4* + ID_OUI_FROM_DATABASE=STORAGE COMPUTER CORPORATION + +OUI:0010BF* + ID_OUI_FROM_DATABASE=InterAir Wireless + +OUI:001036* + ID_OUI_FROM_DATABASE=INTER-TEL INTEGRATED SYSTEMS + +OUI:001026* + ID_OUI_FROM_DATABASE=ACCELERATED NETWORKS, INC. + +OUI:00104B* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:000629* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:001004* + ID_OUI_FROM_DATABASE=THE BRANTLEY COILE COMPANY,INC + +OUI:00103A* + ID_OUI_FROM_DATABASE=DIAMOND NETWORK TECH + +OUI:0010D8* + ID_OUI_FROM_DATABASE=CALISTA + +OUI:001031* + ID_OUI_FROM_DATABASE=OBJECTIVE COMMUNICATIONS, INC. + +OUI:00103D* + ID_OUI_FROM_DATABASE=PHASECOM, LTD. + +OUI:0010C2* + ID_OUI_FROM_DATABASE=WILLNET, INC. + +OUI:00107A* + ID_OUI_FROM_DATABASE=AmbiCom, Inc. + +OUI:0010C4* + ID_OUI_FROM_DATABASE=MEDIA GLOBAL LINKS CO., LTD. + +OUI:0010EB* + ID_OUI_FROM_DATABASE=SELSIUS SYSTEMS, INC. + +OUI:0010FE* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:00102E* + ID_OUI_FROM_DATABASE=NETWORK SYSTEMS & TECHNOLOGIES PVT. LTD. + +OUI:0010C1* + ID_OUI_FROM_DATABASE=OI ELECTRIC CO., LTD. + +OUI:00103E* + ID_OUI_FROM_DATABASE=NETSCHOOLS CORPORATION + +OUI:001049* + ID_OUI_FROM_DATABASE=ShoreTel, Inc + +OUI:00105E* + ID_OUI_FROM_DATABASE=Spirent plc, Service Assurance Broadband + +OUI:0010B1* + ID_OUI_FROM_DATABASE=FOR-A CO., LTD. + +OUI:001041* + ID_OUI_FROM_DATABASE=BRISTOL BABCOCK, INC. + +OUI:0010F7* + ID_OUI_FROM_DATABASE=IRIICHI TECHNOLOGIES Inc. + +OUI:00E0FD* + ID_OUI_FROM_DATABASE=A-TREND TECHNOLOGY CO., LTD. + +OUI:00E0FB* + ID_OUI_FROM_DATABASE=LEIGHTRONIX, INC. + +OUI:00E0D3* + ID_OUI_FROM_DATABASE=DATENTECHNIK GmbH + +OUI:00E05E* + ID_OUI_FROM_DATABASE=JAPAN AVIATION ELECTRONICS INDUSTRY, LTD. + +OUI:00E0E5* + ID_OUI_FROM_DATABASE=CINCO NETWORKS, INC. + +OUI:00E0A1* + ID_OUI_FROM_DATABASE=HIMA PAUL HILDEBRANDT GmbH Co. KG + +OUI:00E028* + ID_OUI_FROM_DATABASE=APTIX CORPORATION + +OUI:00E0F2* + ID_OUI_FROM_DATABASE=ARLOTTO COMNET, INC. + +OUI:00E020* + ID_OUI_FROM_DATABASE=TECNOMEN OY + +OUI:00E046* + ID_OUI_FROM_DATABASE=BENTLY NEVADA CORP. + +OUI:00E015* + ID_OUI_FROM_DATABASE=HEIWA CORPORATION + +OUI:00E065* + ID_OUI_FROM_DATABASE=OPTICAL ACCESS INTERNATIONAL + +OUI:00E069* + ID_OUI_FROM_DATABASE=JAYCOR + +OUI:00E05C* + ID_OUI_FROM_DATABASE=Panasonic Healthcare Co., Ltd. + +OUI:00E087* + ID_OUI_FROM_DATABASE=LeCroy - Networking Productions Division + +OUI:00E049* + ID_OUI_FROM_DATABASE=MICROWI ELECTRONIC GmbH + +OUI:00E050* + ID_OUI_FROM_DATABASE=EXECUTONE INFORMATION SYSTEMS, INC. + +OUI:00E064* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRONICS + +OUI:00E012* + ID_OUI_FROM_DATABASE=PLUTO TECHNOLOGIES INTERNATIONAL INC. + +OUI:00E0D8* + ID_OUI_FROM_DATABASE=LANBit Computer, Inc. OUI:00108F* ID_OUI_FROM_DATABASE=RAPTOR SYSTEMS @@ -41756,41 +42929,14 @@ OUI:0010F1* OUI:001073* ID_OUI_FROM_DATABASE=TECHNOBOX, INC. -OUI:00E0C0* - ID_OUI_FROM_DATABASE=SEIWA ELECTRIC MFG. CO., LTD. +OUI:00107E* + ID_OUI_FROM_DATABASE=BACHMANN ELECTRONIC GmbH -OUI:00E046* - ID_OUI_FROM_DATABASE=BENTLY NEVADA CORP. +OUI:0010C0* + ID_OUI_FROM_DATABASE=ARMA, Inc. -OUI:00E015* - ID_OUI_FROM_DATABASE=HEIWA CORPORATION - -OUI:00E065* - ID_OUI_FROM_DATABASE=OPTICAL ACCESS INTERNATIONAL - -OUI:00E069* - ID_OUI_FROM_DATABASE=JAYCOR - -OUI:00E05C* - ID_OUI_FROM_DATABASE=Panasonic Healthcare Co., Ltd. - -OUI:00E087* - ID_OUI_FROM_DATABASE=LeCroy - Networking Productions Division - -OUI:00E049* - ID_OUI_FROM_DATABASE=MICROWI ELECTRONIC GmbH - -OUI:00E050* - ID_OUI_FROM_DATABASE=EXECUTONE INFORMATION SYSTEMS, INC. - -OUI:00E064* - ID_OUI_FROM_DATABASE=SAMSUNG ELECTRONICS - -OUI:00E012* - ID_OUI_FROM_DATABASE=PLUTO TECHNOLOGIES INTERNATIONAL INC. - -OUI:00E0D8* - ID_OUI_FROM_DATABASE=LANBit Computer, Inc. +OUI:001016* + ID_OUI_FROM_DATABASE=T.SQWARE OUI:00E02D* ID_OUI_FROM_DATABASE=InnoMediaLogic, Inc. @@ -41828,38 +42974,17 @@ OUI:00E0C7* OUI:00E0C4* ID_OUI_FROM_DATABASE=HORNER ELECTRIC, INC. -OUI:00E04D* - ID_OUI_FROM_DATABASE=INTERNET INITIATIVE JAPAN, INC +OUI:0010E6* + ID_OUI_FROM_DATABASE=APPLIED INTELLIGENT SYSTEMS, INC. -OUI:00607F* - ID_OUI_FROM_DATABASE=AURORA TECHNOLOGIES, INC. +OUI:00101E* + ID_OUI_FROM_DATABASE=MATSUSHITA ELECTRONIC INSTRUMENTS CORP. -OUI:00E039* - ID_OUI_FROM_DATABASE=PARADYNE CORP. +OUI:0010F2* + ID_OUI_FROM_DATABASE=ANTEC -OUI:006091* - ID_OUI_FROM_DATABASE=FIRST PACIFIC NETWORKS, INC. - -OUI:006002* - ID_OUI_FROM_DATABASE=SCREEN SUBTITLING SYSTEMS, LTD - -OUI:006061* - ID_OUI_FROM_DATABASE=WHISTLE COMMUNICATIONS CORP. - -OUI:0060BD* - ID_OUI_FROM_DATABASE=HUBBELL-PULSECOM - -OUI:00E0A1* - ID_OUI_FROM_DATABASE=HIMA PAUL HILDEBRANDT GmbH Co. KG - -OUI:00E028* - ID_OUI_FROM_DATABASE=APTIX CORPORATION - -OUI:00E0F2* - ID_OUI_FROM_DATABASE=ARLOTTO COMNET, INC. - -OUI:00E020* - ID_OUI_FROM_DATABASE=TECNOMEN OY +OUI:0010BE* + ID_OUI_FROM_DATABASE=MARCH NETWORKS CORPORATION OUI:00E0C5* ID_OUI_FROM_DATABASE=BCOM ELECTRONICS INC. @@ -41882,77 +43007,50 @@ OUI:00E0F0* OUI:00E0B7* ID_OUI_FROM_DATABASE=PI GROUP, LTD. -OUI:0010B1* - ID_OUI_FROM_DATABASE=FOR-A CO., LTD. +OUI:00E0C0* + ID_OUI_FROM_DATABASE=SEIWA ELECTRIC MFG. CO., LTD. -OUI:001041* - ID_OUI_FROM_DATABASE=BRISTOL BABCOCK, INC. +OUI:006098* + ID_OUI_FROM_DATABASE=HT COMMUNICATIONS -OUI:0010F7* - ID_OUI_FROM_DATABASE=IRIICHI TECHNOLOGIES Inc. +OUI:0060F7* + ID_OUI_FROM_DATABASE=DATAFUSION SYSTEMS -OUI:0010E6* - ID_OUI_FROM_DATABASE=APPLIED INTELLIGENT SYSTEMS, INC. +OUI:0060DE* + ID_OUI_FROM_DATABASE=Kayser-Threde GmbH -OUI:00101E* - ID_OUI_FROM_DATABASE=MATSUSHITA ELECTRONIC INSTRUMENTS CORP. +OUI:0060D0* + ID_OUI_FROM_DATABASE=SNMP RESEARCH INCORPORATED -OUI:0010F2* - ID_OUI_FROM_DATABASE=ANTEC +OUI:006079* + ID_OUI_FROM_DATABASE=Mainstream Data, Inc. -OUI:0010BE* - ID_OUI_FROM_DATABASE=MARCH NETWORKS CORPORATION +OUI:006020* + ID_OUI_FROM_DATABASE=PIVOTAL NETWORKING, INC. -OUI:006074* - ID_OUI_FROM_DATABASE=QSC AUDIO PRODUCTS +OUI:0005A8* + ID_OUI_FROM_DATABASE=WYLE ELECTRONICS -OUI:006058* - ID_OUI_FROM_DATABASE=COPPER MOUNTAIN COMMUNICATIONS, INC. +OUI:0060B7* + ID_OUI_FROM_DATABASE=CHANNELMATIC, INC. -OUI:00601B* - ID_OUI_FROM_DATABASE=MESA ELECTRONICS +OUI:0060A3* + ID_OUI_FROM_DATABASE=CONTINUUM TECHNOLOGY CORP. -OUI:0060FF* - ID_OUI_FROM_DATABASE=QuVis, Inc. +OUI:006050* + ID_OUI_FROM_DATABASE=INTERNIX INC. -OUI:006056* - ID_OUI_FROM_DATABASE=NETWORK TOOLS, INC. +OUI:0060E0* + ID_OUI_FROM_DATABASE=AXIOM TECHNOLOGY CO., LTD. -OUI:0060D8* - ID_OUI_FROM_DATABASE=ELMIC SYSTEMS, INC. +OUI:0060A8* + ID_OUI_FROM_DATABASE=TIDOMAT AB -OUI:00607A* - ID_OUI_FROM_DATABASE=DVS GMBH +OUI:00608E* + ID_OUI_FROM_DATABASE=HE ELECTRONICS, TECHNOLOGIE & SYSTEMTECHNIK GmbH -OUI:006097* - ID_OUI_FROM_DATABASE=3COM CORPORATION - -OUI:0060E3* - ID_OUI_FROM_DATABASE=ARBIN INSTRUMENTS - -OUI:00E0FD* - ID_OUI_FROM_DATABASE=A-TREND TECHNOLOGY CO., LTD. - -OUI:00E0FB* - ID_OUI_FROM_DATABASE=LEIGHTRONIX, INC. - -OUI:00E0D3* - ID_OUI_FROM_DATABASE=DATENTECHNIK GmbH - -OUI:00E05E* - ID_OUI_FROM_DATABASE=JAPAN AVIATION ELECTRONICS INDUSTRY, LTD. - -OUI:00E0E5* - ID_OUI_FROM_DATABASE=CINCO NETWORKS, INC. - -OUI:00E0CF* - ID_OUI_FROM_DATABASE=INTEGRATED DEVICE TECHNOLOGY, INC. - -OUI:00A0FD* - ID_OUI_FROM_DATABASE=SCITEX DIGITAL PRINTING, INC. - -OUI:00A0F5* - ID_OUI_FROM_DATABASE=RADGUARD LTD. +OUI:0060F0* + ID_OUI_FROM_DATABASE=JOHNSON & JOHNSON MEDICAL, INC OUI:00A022* ID_OUI_FROM_DATABASE=CENTRE FOR DEVELOPMENT OF ADVANCED COMPUTING @@ -41993,60 +43091,6 @@ OUI:00A065* OUI:00A044* ID_OUI_FROM_DATABASE=NTT IT CO., LTD. -OUI:006008* - ID_OUI_FROM_DATABASE=3COM CORPORATION - -OUI:0060EF* - ID_OUI_FROM_DATABASE=FLYTECH TECHNOLOGY CO., LTD. - -OUI:006098* - ID_OUI_FROM_DATABASE=HT COMMUNICATIONS - -OUI:0060F7* - ID_OUI_FROM_DATABASE=DATAFUSION SYSTEMS - -OUI:0060DE* - ID_OUI_FROM_DATABASE=Kayser-Threde GmbH - -OUI:0060D0* - ID_OUI_FROM_DATABASE=SNMP RESEARCH INCORPORATED - -OUI:006079* - ID_OUI_FROM_DATABASE=Mainstream Data, Inc. - -OUI:006020* - ID_OUI_FROM_DATABASE=PIVOTAL NETWORKING, INC. - -OUI:0005A8* - ID_OUI_FROM_DATABASE=WYLE ELECTRONICS - -OUI:0060B7* - ID_OUI_FROM_DATABASE=CHANNELMATIC, INC. - -OUI:0060A3* - ID_OUI_FROM_DATABASE=CONTINUUM TECHNOLOGY CORP. - -OUI:006050* - ID_OUI_FROM_DATABASE=INTERNIX INC. - -OUI:0060E0* - ID_OUI_FROM_DATABASE=AXIOM TECHNOLOGY CO., LTD. - -OUI:0060A8* - ID_OUI_FROM_DATABASE=TIDOMAT AB - -OUI:00A056* - ID_OUI_FROM_DATABASE=MICROPROSS - -OUI:00A051* - ID_OUI_FROM_DATABASE=ANGIA COMMUNICATIONS. INC. - -OUI:00A0A6* - ID_OUI_FROM_DATABASE=M.I. SYSTEMS, K.K. - -OUI:00A0B0* - ID_OUI_FROM_DATABASE=I-O DATA DEVICE, INC. - OUI:00A05F* ID_OUI_FROM_DATABASE=BTG Electronics Design BV @@ -42077,32 +43121,8 @@ OUI:00A0F7* OUI:00A09C* ID_OUI_FROM_DATABASE=Xyplex, Inc. -OUI:00A092* - ID_OUI_FROM_DATABASE=H. BOLLMANN MANUFACTURERS, LTD - -OUI:00A04D* - ID_OUI_FROM_DATABASE=EDA INSTRUMENTS, INC. - -OUI:00A0DB* - ID_OUI_FROM_DATABASE=FISHER & PAYKEL PRODUCTION - -OUI:00A0A5* - ID_OUI_FROM_DATABASE=TEKNOR MICROSYSTEME, INC. - -OUI:00A018* - ID_OUI_FROM_DATABASE=CREATIVE CONTROLLERS, INC. - -OUI:00A09F* - ID_OUI_FROM_DATABASE=COMMVISION CORP. - -OUI:00A06B* - ID_OUI_FROM_DATABASE=DMS DORSCH MIKROSYSTEM GMBH - -OUI:006051* - ID_OUI_FROM_DATABASE=QUALITY SEMICONDUCTOR - -OUI:00605E* - ID_OUI_FROM_DATABASE=LIBERTY TECHNOLOGY NETWORKING +OUI:00A0A0* + ID_OUI_FROM_DATABASE=COMPACT DATA, LTD. OUI:0060C6* ID_OUI_FROM_DATABASE=DCS AG @@ -42128,11 +43148,14 @@ OUI:00A039* OUI:00A06D* ID_OUI_FROM_DATABASE=MANNESMANN TALLY CORPORATION -OUI:00608E* - ID_OUI_FROM_DATABASE=HE ELECTRONICS, TECHNOLOGIE & SYSTEMTECHNIK GmbH +OUI:00A056* + ID_OUI_FROM_DATABASE=MICROPROSS -OUI:0060F0* - ID_OUI_FROM_DATABASE=JOHNSON & JOHNSON MEDICAL, INC +OUI:00A051* + ID_OUI_FROM_DATABASE=ANGIA COMMUNICATIONS. INC. + +OUI:00A0A6* + ID_OUI_FROM_DATABASE=M.I. SYSTEMS, K.K. OUI:0060D2* ID_OUI_FROM_DATABASE=LUCENT TECHNOLOGIES TAIWAN TELECOMMUNICATIONS CO., LTD. @@ -42152,15 +43175,306 @@ OUI:00608B* OUI:0060C3* ID_OUI_FROM_DATABASE=NETVISION CORPORATION -OUI:00A0A0* - ID_OUI_FROM_DATABASE=COMPACT DATA, LTD. +OUI:006051* + ID_OUI_FROM_DATABASE=QUALITY SEMICONDUCTOR -OUI:00A0A4* - ID_OUI_FROM_DATABASE=MICROS SYSTEMS, INC. +OUI:00605E* + ID_OUI_FROM_DATABASE=LIBERTY TECHNOLOGY NETWORKING + +OUI:006058* + ID_OUI_FROM_DATABASE=COPPER MOUNTAIN COMMUNICATIONS, INC. + +OUI:00601B* + ID_OUI_FROM_DATABASE=MESA ELECTRONICS + +OUI:0060FF* + ID_OUI_FROM_DATABASE=QuVis, Inc. + +OUI:006056* + ID_OUI_FROM_DATABASE=NETWORK TOOLS, INC. + +OUI:0060D8* + ID_OUI_FROM_DATABASE=ELMIC SYSTEMS, INC. + +OUI:00607A* + ID_OUI_FROM_DATABASE=DVS GMBH + +OUI:006097* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:0060E3* + ID_OUI_FROM_DATABASE=ARBIN INSTRUMENTS + +OUI:006008* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:0060EF* + ID_OUI_FROM_DATABASE=FLYTECH TECHNOLOGY CO., LTD. + +OUI:00E04D* + ID_OUI_FROM_DATABASE=INTERNET INITIATIVE JAPAN, INC + +OUI:00607F* + ID_OUI_FROM_DATABASE=AURORA TECHNOLOGIES, INC. + +OUI:00E039* + ID_OUI_FROM_DATABASE=PARADYNE CORP. + +OUI:006091* + ID_OUI_FROM_DATABASE=FIRST PACIFIC NETWORKS, INC. + +OUI:006002* + ID_OUI_FROM_DATABASE=SCREEN SUBTITLING SYSTEMS, LTD + +OUI:006061* + ID_OUI_FROM_DATABASE=WHISTLE COMMUNICATIONS CORP. + +OUI:0060BD* + ID_OUI_FROM_DATABASE=HUBBELL-PULSECOM + +OUI:006074* + ID_OUI_FROM_DATABASE=QSC AUDIO PRODUCTS OUI:00A024* ID_OUI_FROM_DATABASE=3COM CORPORATION +OUI:00A0FD* + ID_OUI_FROM_DATABASE=SCITEX DIGITAL PRINTING, INC. + +OUI:00A0F5* + ID_OUI_FROM_DATABASE=RADGUARD LTD. + +OUI:00201B* + ID_OUI_FROM_DATABASE=NORTHERN TELECOM/NETWORK + +OUI:0020C0* + ID_OUI_FROM_DATABASE=PULSE ELECTRONICS, INC. + +OUI:00208D* + ID_OUI_FROM_DATABASE=CMD TECHNOLOGY + +OUI:0020DD* + ID_OUI_FROM_DATABASE=Cybertec Pty Ltd + +OUI:0020BD* + ID_OUI_FROM_DATABASE=NIOBRARA R & D CORPORATION + +OUI:0020E6* + ID_OUI_FROM_DATABASE=LIDKOPING MACHINE TOOLS AB + +OUI:002047* + ID_OUI_FROM_DATABASE=STEINBRECHER CORP. + +OUI:0020B5* + ID_OUI_FROM_DATABASE=YASKAWA ELECTRIC CORPORATION + +OUI:002072* + ID_OUI_FROM_DATABASE=WORKLINK INNOVATIONS + +OUI:0020B8* + ID_OUI_FROM_DATABASE=PRIME OPTION, INC. + +OUI:002092* + ID_OUI_FROM_DATABASE=CHESS ENGINEERING B.V. + +OUI:0020B9* + ID_OUI_FROM_DATABASE=METRICOM, INC. + +OUI:00206B* + ID_OUI_FROM_DATABASE=KONICA MINOLTA HOLDINGS, INC. + +OUI:0020FC* + ID_OUI_FROM_DATABASE=MATROX + +OUI:002035* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:0020E2* + ID_OUI_FROM_DATABASE=INFORMATION RESOURCE ENGINEERING + +OUI:002058* + ID_OUI_FROM_DATABASE=ALLIED SIGNAL INC. + +OUI:00208C* + ID_OUI_FROM_DATABASE=GALAXY NETWORKS, INC. + +OUI:002063* + ID_OUI_FROM_DATABASE=WIPRO INFOTECH LTD. + +OUI:0020DC* + ID_OUI_FROM_DATABASE=DENSITRON TAIWAN LTD. + +OUI:002078* + ID_OUI_FROM_DATABASE=RUNTOP, INC. + +OUI:002042* + ID_OUI_FROM_DATABASE=DATAMETRICS CORP. + +OUI:0020F8* + ID_OUI_FROM_DATABASE=CARRERA COMPUTERS, INC. + +OUI:00200C* + ID_OUI_FROM_DATABASE=ADASTRA SYSTEMS CORP. + +OUI:0020C4* + ID_OUI_FROM_DATABASE=INET,INC. + +OUI:00C003* + ID_OUI_FROM_DATABASE=GLOBALNET COMMUNICATIONS + +OUI:00C0C3* + ID_OUI_FROM_DATABASE=ACUSON COMPUTED SONOGRAPHY + +OUI:00C04D* + ID_OUI_FROM_DATABASE=MITEC, INC. + +OUI:00C055* + ID_OUI_FROM_DATABASE=MODULAR COMPUTING TECHNOLOGIES + +OUI:00A0DB* + ID_OUI_FROM_DATABASE=FISHER & PAYKEL PRODUCTION + +OUI:00A0A5* + ID_OUI_FROM_DATABASE=TEKNOR MICROSYSTEME, INC. + +OUI:00A018* + ID_OUI_FROM_DATABASE=CREATIVE CONTROLLERS, INC. + +OUI:00A09F* + ID_OUI_FROM_DATABASE=COMMVISION CORP. + +OUI:00A06B* + ID_OUI_FROM_DATABASE=DMS DORSCH MIKROSYSTEM GMBH + +OUI:00209F* + ID_OUI_FROM_DATABASE=MERCURY COMPUTER SYSTEMS, INC. + +OUI:0020B7* + ID_OUI_FROM_DATABASE=NAMAQUA COMPUTERWARE + +OUI:00C005* + ID_OUI_FROM_DATABASE=LIVINGSTON ENTERPRISES, INC. + +OUI:00C064* + ID_OUI_FROM_DATABASE=GENERAL DATACOMM IND. INC. + +OUI:00C0C8* + ID_OUI_FROM_DATABASE=MICRO BYTE PTY. LTD. + +OUI:00C090* + ID_OUI_FROM_DATABASE=PRAIM S.R.L. + +OUI:00C011* + ID_OUI_FROM_DATABASE=INTERACTIVE COMPUTING DEVICES + +OUI:00C0FD* + ID_OUI_FROM_DATABASE=PROSUM + +OUI:00C041* + ID_OUI_FROM_DATABASE=DIGITAL TRANSMISSION SYSTEMS + +OUI:00C00F* + ID_OUI_FROM_DATABASE=QUANTUM SOFTWARE SYSTEMS LTD. + +OUI:00C076* + ID_OUI_FROM_DATABASE=I-DATA INTERNATIONAL A-S + +OUI:00C0C6* + ID_OUI_FROM_DATABASE=PERSONAL MEDIA CORP. + +OUI:00C03B* + ID_OUI_FROM_DATABASE=MULTIACCESS COMPUTING CORP. + +OUI:00C099* + ID_OUI_FROM_DATABASE=YOSHIKI INDUSTRIAL CO.,LTD. + +OUI:00C0FC* + ID_OUI_FROM_DATABASE=ELASTIC REALITY, INC. + +OUI:00C067* + ID_OUI_FROM_DATABASE=UNITED BARCODE INDUSTRIES + +OUI:00C0B4* + ID_OUI_FROM_DATABASE=MYSON TECHNOLOGY, INC. + +OUI:00C080* + ID_OUI_FROM_DATABASE=NETSTAR, INC. + +OUI:00C015* + ID_OUI_FROM_DATABASE=NEW MEDIA CORPORATION + +OUI:00C09F* + ID_OUI_FROM_DATABASE=QUANTA COMPUTER, INC. + +OUI:0070B3* + ID_OUI_FROM_DATABASE=DATA RECALL LTD. + +OUI:00E6D3* + ID_OUI_FROM_DATABASE=NIXDORF COMPUTER CORP. + +OUI:00C083* + ID_OUI_FROM_DATABASE=TRACE MOUNTAIN PRODUCTS, INC. + +OUI:002081* + ID_OUI_FROM_DATABASE=TITAN ELECTRONICS + +OUI:00201D* + ID_OUI_FROM_DATABASE=KATANA PRODUCTS + +OUI:0020CF* + ID_OUI_FROM_DATABASE=TEST & MEASUREMENT SYSTEMS INC + +OUI:002043* + ID_OUI_FROM_DATABASE=NEURON COMPANY LIMITED + +OUI:002018* + ID_OUI_FROM_DATABASE=CIS TECHNOLOGY INC. + +OUI:002031* + ID_OUI_FROM_DATABASE=Tattile SRL + +OUI:0020DE* + ID_OUI_FROM_DATABASE=JAPAN DIGITAL LABORAT'Y CO.LTD + +OUI:0020F7* + ID_OUI_FROM_DATABASE=CYBERDATA CORPORATION + +OUI:000267* + ID_OUI_FROM_DATABASE=NODE RUNNER, INC. + +OUI:002064* + ID_OUI_FROM_DATABASE=PROTEC MICROSYSTEMS, INC. + +OUI:002032* + ID_OUI_FROM_DATABASE=ALCATEL TAISEL + +OUI:002027* + ID_OUI_FROM_DATABASE=MING FORTUNE INDUSTRY CO., LTD + +OUI:0020ED* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO., LTD. + +OUI:00200E* + ID_OUI_FROM_DATABASE=SATELLITE TECHNOLOGY MGMT, INC + +OUI:002096* + ID_OUI_FROM_DATABASE=Invensys + +OUI:0020BB* + ID_OUI_FROM_DATABASE=ZAX CORPORATION + +OUI:00204D* + ID_OUI_FROM_DATABASE=INOVIS GMBH + +OUI:002089* + ID_OUI_FROM_DATABASE=T3PLUS NETWORKING, INC. + +OUI:00205F* + ID_OUI_FROM_DATABASE=GAMMADATA COMPUTER GMBH + +OUI:0020EE* + ID_OUI_FROM_DATABASE=GTECH CORPORATION + OUI:00A08B* ID_OUI_FROM_DATABASE=ASTON ELECTRONIC DESIGNS LTD. @@ -42179,17 +43493,29 @@ OUI:00A084* OUI:00A034* ID_OUI_FROM_DATABASE=AXEL -OUI:00C0BC* - ID_OUI_FROM_DATABASE=TELECOM AUSTRALIA/CSSC +OUI:00A092* + ID_OUI_FROM_DATABASE=H. BOLLMANN MANUFACTURERS, LTD -OUI:00C0EF* - ID_OUI_FROM_DATABASE=ABIT CORPORATION +OUI:00A04D* + ID_OUI_FROM_DATABASE=EDA INSTRUMENTS, INC. -OUI:00C03C* - ID_OUI_FROM_DATABASE=TOWER TECH S.R.L. +OUI:00207F* + ID_OUI_FROM_DATABASE=KYOEI SANGYO CO., LTD. -OUI:00C061* - ID_OUI_FROM_DATABASE=SOLECTEK CORPORATION +OUI:002077* + ID_OUI_FROM_DATABASE=KARDIOS SYSTEMS CORP. + +OUI:002068* + ID_OUI_FROM_DATABASE=ISDYNE + +OUI:00202A* + ID_OUI_FROM_DATABASE=N.V. DZINE + +OUI:0020F4* + ID_OUI_FROM_DATABASE=SPECTRIX CORPORATION + +OUI:00204E* + ID_OUI_FROM_DATABASE=NETWORK SECURITY SYSTEMS, INC. OUI:00C074* ID_OUI_FROM_DATABASE=TOYODA AUTOMATIC LOOM @@ -42245,305 +43571,68 @@ OUI:00C071* OUI:00C0AF* ID_OUI_FROM_DATABASE=TEKLOGIX INC. -OUI:00209F* - ID_OUI_FROM_DATABASE=MERCURY COMPUTER SYSTEMS, INC. +OUI:00C05D* + ID_OUI_FROM_DATABASE=L&N TECHNOLOGIES -OUI:0020B7* - ID_OUI_FROM_DATABASE=NAMAQUA COMPUTERWARE +OUI:00C0E4* + ID_OUI_FROM_DATABASE=SIEMENS BUILDING -OUI:00201B* - ID_OUI_FROM_DATABASE=NORTHERN TELECOM/NETWORK +OUI:0040C4* + ID_OUI_FROM_DATABASE=KINKEI SYSTEM CORPORATION -OUI:0020C0* - ID_OUI_FROM_DATABASE=PULSE ELECTRONICS, INC. +OUI:0040D1* + ID_OUI_FROM_DATABASE=FUKUDA DENSHI CO., LTD. -OUI:00208D* - ID_OUI_FROM_DATABASE=CMD TECHNOLOGY +OUI:004024* + ID_OUI_FROM_DATABASE=COMPAC INC. -OUI:0020DD* - ID_OUI_FROM_DATABASE=Cybertec Pty Ltd +OUI:0040B6* + ID_OUI_FROM_DATABASE=COMPUTERM CORPORATION -OUI:0020BD* - ID_OUI_FROM_DATABASE=NIOBRARA R & D CORPORATION +OUI:00403F* + ID_OUI_FROM_DATABASE=SSANGYONG COMPUTER SYSTEMS -OUI:0020E6* - ID_OUI_FROM_DATABASE=LIDKOPING MACHINE TOOLS AB +OUI:004003* + ID_OUI_FROM_DATABASE=Emerson Process Management Power & Water Solutions, Inc. -OUI:002047* - ID_OUI_FROM_DATABASE=STEINBRECHER CORP. +OUI:004090* + ID_OUI_FROM_DATABASE=ANSEL COMMUNICATIONS -OUI:0020B5* - ID_OUI_FROM_DATABASE=YASKAWA ELECTRIC CORPORATION +OUI:00409A* + ID_OUI_FROM_DATABASE=NETWORK EXPRESS, INC. -OUI:002072* - ID_OUI_FROM_DATABASE=WORKLINK INNOVATIONS +OUI:004055* + ID_OUI_FROM_DATABASE=METRONIX GMBH -OUI:0020B8* - ID_OUI_FROM_DATABASE=PRIME OPTION, INC. +OUI:00C01B* + ID_OUI_FROM_DATABASE=SOCKET COMMUNICATIONS, INC. -OUI:002092* - ID_OUI_FROM_DATABASE=CHESS ENGINEERING B.V. +OUI:00C06E* + ID_OUI_FROM_DATABASE=HAFT TECHNOLOGY, INC. -OUI:0020B9* - ID_OUI_FROM_DATABASE=METRICOM, INC. +OUI:00406F* + ID_OUI_FROM_DATABASE=SYNC RESEARCH INC. -OUI:00206B* - ID_OUI_FROM_DATABASE=KONICA MINOLTA HOLDINGS, INC. +OUI:00401F* + ID_OUI_FROM_DATABASE=COLORGRAPH LTD -OUI:0020FC* - ID_OUI_FROM_DATABASE=MATROX +OUI:0040CF* + ID_OUI_FROM_DATABASE=STRAWBERRY TREE, INC. -OUI:00C003* - ID_OUI_FROM_DATABASE=GLOBALNET COMMUNICATIONS +OUI:0040F7* + ID_OUI_FROM_DATABASE=Polaroid Corporation -OUI:00C0C3* - ID_OUI_FROM_DATABASE=ACUSON COMPUTED SONOGRAPHY +OUI:004037* + ID_OUI_FROM_DATABASE=SEA-ILAN, INC. -OUI:00C04D* - ID_OUI_FROM_DATABASE=MITEC, INC. +OUI:0040CC* + ID_OUI_FROM_DATABASE=SILCOM MANUF'G TECHNOLOGY INC. -OUI:00C055* - ID_OUI_FROM_DATABASE=MODULAR COMPUTING TECHNOLOGIES +OUI:00404C* + ID_OUI_FROM_DATABASE=HYPERTEC PTY LTD. -OUI:00C067* - ID_OUI_FROM_DATABASE=UNITED BARCODE INDUSTRIES - -OUI:00C0B4* - ID_OUI_FROM_DATABASE=MYSON TECHNOLOGY, INC. - -OUI:00C080* - ID_OUI_FROM_DATABASE=NETSTAR, INC. - -OUI:00C015* - ID_OUI_FROM_DATABASE=NEW MEDIA CORPORATION - -OUI:00C09F* - ID_OUI_FROM_DATABASE=QUANTA COMPUTER, INC. - -OUI:0070B3* - ID_OUI_FROM_DATABASE=DATA RECALL LTD. - -OUI:00E6D3* - ID_OUI_FROM_DATABASE=NIXDORF COMPUTER CORP. - -OUI:00C083* - ID_OUI_FROM_DATABASE=TRACE MOUNTAIN PRODUCTS, INC. - -OUI:00C005* - ID_OUI_FROM_DATABASE=LIVINGSTON ENTERPRISES, INC. - -OUI:00C064* - ID_OUI_FROM_DATABASE=GENERAL DATACOMM IND. INC. - -OUI:00C0C8* - ID_OUI_FROM_DATABASE=MICRO BYTE PTY. LTD. - -OUI:00C090* - ID_OUI_FROM_DATABASE=PRAIM S.R.L. - -OUI:00C011* - ID_OUI_FROM_DATABASE=INTERACTIVE COMPUTING DEVICES - -OUI:00C0FD* - ID_OUI_FROM_DATABASE=PROSUM - -OUI:00C041* - ID_OUI_FROM_DATABASE=DIGITAL TRANSMISSION SYSTEMS - -OUI:00C00F* - ID_OUI_FROM_DATABASE=QUANTUM SOFTWARE SYSTEMS LTD. - -OUI:00C076* - ID_OUI_FROM_DATABASE=I-DATA INTERNATIONAL A-S - -OUI:00C0C6* - ID_OUI_FROM_DATABASE=PERSONAL MEDIA CORP. - -OUI:00C03B* - ID_OUI_FROM_DATABASE=MULTIACCESS COMPUTING CORP. - -OUI:0020F4* - ID_OUI_FROM_DATABASE=SPECTRIX CORPORATION - -OUI:00204E* - ID_OUI_FROM_DATABASE=NETWORK SECURITY SYSTEMS, INC. - -OUI:002027* - ID_OUI_FROM_DATABASE=MING FORTUNE INDUSTRY CO., LTD - -OUI:0020ED* - ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO., LTD. - -OUI:00200E* - ID_OUI_FROM_DATABASE=SATELLITE TECHNOLOGY MGMT, INC - -OUI:002096* - ID_OUI_FROM_DATABASE=Invensys - -OUI:0020BB* - ID_OUI_FROM_DATABASE=ZAX CORPORATION - -OUI:00204D* - ID_OUI_FROM_DATABASE=INOVIS GMBH - -OUI:002089* - ID_OUI_FROM_DATABASE=T3PLUS NETWORKING, INC. - -OUI:00205F* - ID_OUI_FROM_DATABASE=GAMMADATA COMPUTER GMBH - -OUI:002035* - ID_OUI_FROM_DATABASE=IBM Corp - -OUI:0020E2* - ID_OUI_FROM_DATABASE=INFORMATION RESOURCE ENGINEERING - -OUI:002058* - ID_OUI_FROM_DATABASE=ALLIED SIGNAL INC. - -OUI:002081* - ID_OUI_FROM_DATABASE=TITAN ELECTRONICS - -OUI:00201D* - ID_OUI_FROM_DATABASE=KATANA PRODUCTS - -OUI:0020CF* - ID_OUI_FROM_DATABASE=TEST & MEASUREMENT SYSTEMS INC - -OUI:002043* - ID_OUI_FROM_DATABASE=NEURON COMPANY LIMITED - -OUI:002018* - ID_OUI_FROM_DATABASE=CIS TECHNOLOGY INC. - -OUI:002031* - ID_OUI_FROM_DATABASE=Tattile SRL - -OUI:0020DE* - ID_OUI_FROM_DATABASE=JAPAN DIGITAL LABORAT'Y CO.LTD - -OUI:0020F7* - ID_OUI_FROM_DATABASE=CYBERDATA CORPORATION - -OUI:0020EE* - ID_OUI_FROM_DATABASE=GTECH CORPORATION - -OUI:00208C* - ID_OUI_FROM_DATABASE=GALAXY NETWORKS, INC. - -OUI:002063* - ID_OUI_FROM_DATABASE=WIPRO INFOTECH LTD. - -OUI:0020DC* - ID_OUI_FROM_DATABASE=DENSITRON TAIWAN LTD. - -OUI:002078* - ID_OUI_FROM_DATABASE=RUNTOP, INC. - -OUI:002042* - ID_OUI_FROM_DATABASE=DATAMETRICS CORP. - -OUI:0020F8* - ID_OUI_FROM_DATABASE=CARRERA COMPUTERS, INC. - -OUI:00200C* - ID_OUI_FROM_DATABASE=ADASTRA SYSTEMS CORP. - -OUI:0020C4* - ID_OUI_FROM_DATABASE=INET,INC. - -OUI:00C099* - ID_OUI_FROM_DATABASE=YOSHIKI INDUSTRIAL CO.,LTD. - -OUI:00C0FC* - ID_OUI_FROM_DATABASE=ELASTIC REALITY, INC. - -OUI:00C0D0* - ID_OUI_FROM_DATABASE=RATOC SYSTEM INC. - -OUI:00C07A* - ID_OUI_FROM_DATABASE=PRIVA B.V. - -OUI:000701* - ID_OUI_FROM_DATABASE=RACAL-DATACOM - -OUI:00C09C* - ID_OUI_FROM_DATABASE=HIOKI E.E. CORPORATION - -OUI:00C004* - ID_OUI_FROM_DATABASE=JAPAN BUSINESS COMPUTER CO.LTD - -OUI:00C062* - ID_OUI_FROM_DATABASE=IMPULSE TECHNOLOGY - -OUI:000267* - ID_OUI_FROM_DATABASE=NODE RUNNER, INC. - -OUI:002064* - ID_OUI_FROM_DATABASE=PROTEC MICROSYSTEMS, INC. - -OUI:002032* - ID_OUI_FROM_DATABASE=ALCATEL TAISEL - -OUI:00207F* - ID_OUI_FROM_DATABASE=KYOEI SANGYO CO., LTD. - -OUI:002077* - ID_OUI_FROM_DATABASE=KARDIOS SYSTEMS CORP. - -OUI:002068* - ID_OUI_FROM_DATABASE=ISDYNE - -OUI:00202A* - ID_OUI_FROM_DATABASE=N.V. DZINE - -OUI:008006* - ID_OUI_FROM_DATABASE=COMPUADD CORPORATION - -OUI:0080EF* - ID_OUI_FROM_DATABASE=RATIONAL - -OUI:0080C4* - ID_OUI_FROM_DATABASE=DOCUMENT TECHNOLOGIES, INC. - -OUI:008095* - ID_OUI_FROM_DATABASE=BASIC MERTON HANDELSGES.M.B.H. - -OUI:008053* - ID_OUI_FROM_DATABASE=INTELLICOM, INC. - -OUI:008026* - ID_OUI_FROM_DATABASE=NETWORK PRODUCTS CORPORATION - -OUI:0080FE* - ID_OUI_FROM_DATABASE=AZURE TECHNOLOGIES, INC. - -OUI:008028* - ID_OUI_FROM_DATABASE=TRADPOST (HK) LTD - -OUI:0080B6* - ID_OUI_FROM_DATABASE=THEMIS COMPUTER - -OUI:008058* - ID_OUI_FROM_DATABASE=PRINTER SYSTEMS CORPORATION - -OUI:0080C0* - ID_OUI_FROM_DATABASE=PENRIL DATACOMM - -OUI:0080F5* - ID_OUI_FROM_DATABASE=Quantel Ltd - -OUI:00401D* - ID_OUI_FROM_DATABASE=INVISIBLE SOFTWARE, INC. - -OUI:0040BD* - ID_OUI_FROM_DATABASE=STARLIGHT NETWORKS, INC. - -OUI:00406D* - ID_OUI_FROM_DATABASE=LANCO, INC. - -OUI:00404D* - ID_OUI_FROM_DATABASE=TELECOMMUNICATIONS TECHNIQUES +OUI:00C0EE* + ID_OUI_FROM_DATABASE=KYOCERA CORPORATION OUI:0040A5* ID_OUI_FROM_DATABASE=CLINICOMP INTL. @@ -42578,29 +43667,170 @@ OUI:0040C2* OUI:00403C* ID_OUI_FROM_DATABASE=FORKS, INC. -OUI:0040C4* - ID_OUI_FROM_DATABASE=KINKEI SYSTEM CORPORATION +OUI:004004* + ID_OUI_FROM_DATABASE=ICM CO. LTD. -OUI:0040D1* - ID_OUI_FROM_DATABASE=FUKUDA DENSHI CO., LTD. +OUI:00C0CB* + ID_OUI_FROM_DATABASE=CONTROL TECHNOLOGY CORPORATION -OUI:004024* - ID_OUI_FROM_DATABASE=COMPAC INC. +OUI:00C09A* + ID_OUI_FROM_DATABASE=PHOTONICS CORPORATION -OUI:0040B6* - ID_OUI_FROM_DATABASE=COMPUTERM CORPORATION +OUI:00C01A* + ID_OUI_FROM_DATABASE=COROMETRICS MEDICAL SYSTEMS -OUI:00403F* - ID_OUI_FROM_DATABASE=SSANGYONG COMPUTER SYSTEMS +OUI:00404B* + ID_OUI_FROM_DATABASE=MAPLE COMPUTER SYSTEMS -OUI:004003* - ID_OUI_FROM_DATABASE=Emerson Process Management Power & Water Solutions, Inc. +OUI:00401D* + ID_OUI_FROM_DATABASE=INVISIBLE SOFTWARE, INC. -OUI:004090* - ID_OUI_FROM_DATABASE=ANSEL COMMUNICATIONS +OUI:0040BD* + ID_OUI_FROM_DATABASE=STARLIGHT NETWORKS, INC. -OUI:00409A* - ID_OUI_FROM_DATABASE=NETWORK EXPRESS, INC. +OUI:00406D* + ID_OUI_FROM_DATABASE=LANCO, INC. + +OUI:00404D* + ID_OUI_FROM_DATABASE=TELECOMMUNICATIONS TECHNIQUES + +OUI:00C0D0* + ID_OUI_FROM_DATABASE=RATOC SYSTEM INC. + +OUI:00C07A* + ID_OUI_FROM_DATABASE=PRIVA B.V. + +OUI:000701* + ID_OUI_FROM_DATABASE=RACAL-DATACOM + +OUI:00C09C* + ID_OUI_FROM_DATABASE=HIOKI E.E. CORPORATION + +OUI:00C004* + ID_OUI_FROM_DATABASE=JAPAN BUSINESS COMPUTER CO.LTD + +OUI:00C062* + ID_OUI_FROM_DATABASE=IMPULSE TECHNOLOGY + +OUI:00C0BC* + ID_OUI_FROM_DATABASE=TELECOM AUSTRALIA/CSSC + +OUI:00C0EF* + ID_OUI_FROM_DATABASE=ABIT CORPORATION + +OUI:00C03C* + ID_OUI_FROM_DATABASE=TOWER TECH S.R.L. + +OUI:00C061* + ID_OUI_FROM_DATABASE=SOLECTEK CORPORATION + +OUI:004045* + ID_OUI_FROM_DATABASE=TWINHEAD CORPORATION + +OUI:00409D* + ID_OUI_FROM_DATABASE=DIGIBOARD, INC. + +OUI:00401A* + ID_OUI_FROM_DATABASE=FUJI ELECTRIC CO., LTD. + +OUI:0040B9* + ID_OUI_FROM_DATABASE=MACQ ELECTRONIQUE SA + +OUI:0040C7* + ID_OUI_FROM_DATABASE=RUBY TECH CORPORATION + +OUI:004052* + ID_OUI_FROM_DATABASE=STAR TECHNOLOGIES, INC. + +OUI:00407A* + ID_OUI_FROM_DATABASE=SOCIETE D'EXPLOITATION DU CNIT + +OUI:004089* + ID_OUI_FROM_DATABASE=MEIDENSHA CORPORATION + +OUI:00405A* + ID_OUI_FROM_DATABASE=GOLDSTAR INFORMATION & COMM. + +OUI:004070* + ID_OUI_FROM_DATABASE=INTERWARE CO., LTD. + +OUI:008057* + ID_OUI_FROM_DATABASE=ADSOFT, LTD. + +OUI:00807A* + ID_OUI_FROM_DATABASE=AITECH SYSTEMS LTD. + +OUI:0080AA* + ID_OUI_FROM_DATABASE=MAXPEED + +OUI:00C0E7* + ID_OUI_FROM_DATABASE=FIBERDATA AB + +OUI:008095* + ID_OUI_FROM_DATABASE=BASIC MERTON HANDELSGES.M.B.H. + +OUI:008053* + ID_OUI_FROM_DATABASE=INTELLICOM, INC. + +OUI:008026* + ID_OUI_FROM_DATABASE=NETWORK PRODUCTS CORPORATION + +OUI:0080FE* + ID_OUI_FROM_DATABASE=AZURE TECHNOLOGIES, INC. + +OUI:008028* + ID_OUI_FROM_DATABASE=TRADPOST (HK) LTD + +OUI:0080B6* + ID_OUI_FROM_DATABASE=THEMIS COMPUTER + +OUI:008058* + ID_OUI_FROM_DATABASE=PRINTER SYSTEMS CORPORATION + +OUI:0080C0* + ID_OUI_FROM_DATABASE=PENRIL DATACOMM + +OUI:0080F5* + ID_OUI_FROM_DATABASE=Quantel Ltd + +OUI:00608C* + ID_OUI_FROM_DATABASE=3COM CORPORATION + +OUI:00804E* + ID_OUI_FROM_DATABASE=APEX COMPUTER COMPANY + +OUI:00800E* + ID_OUI_FROM_DATABASE=ATLANTIX CORPORATION + +OUI:0080DA* + ID_OUI_FROM_DATABASE=Bruel & Kjaer Sound & Vibration Measurement A/S + +OUI:0080BC* + ID_OUI_FROM_DATABASE=HITACHI ENGINEERING CO., LTD + +OUI:008000* + ID_OUI_FROM_DATABASE=MULTITECH SYSTEMS, INC. + +OUI:0080A1* + ID_OUI_FROM_DATABASE=MICROTEST, INC. + +OUI:0080D0* + ID_OUI_FROM_DATABASE=COMPUTER PERIPHERALS, INC. + +OUI:00807D* + ID_OUI_FROM_DATABASE=EQUINOX SYSTEMS INC. + +OUI:008063* + ID_OUI_FROM_DATABASE=Hirschmann Automation and Control GmbH + +OUI:008030* + ID_OUI_FROM_DATABASE=NEXUS ELECTRONICS + +OUI:008022* + ID_OUI_FROM_DATABASE=SCAN-OPTICS + +OUI:000041* + ID_OUI_FROM_DATABASE=ICE CORPORATION OUI:0040DE* ID_OUI_FROM_DATABASE=Elsag Datamat spa @@ -42629,101 +43859,29 @@ OUI:00805E* OUI:008093* ID_OUI_FROM_DATABASE=XYRON CORPORATION -OUI:00C05D* - ID_OUI_FROM_DATABASE=L&N TECHNOLOGIES +OUI:008006* + ID_OUI_FROM_DATABASE=COMPUADD CORPORATION -OUI:00C0E4* - ID_OUI_FROM_DATABASE=SIEMENS BUILDING +OUI:0080EF* + ID_OUI_FROM_DATABASE=RATIONAL -OUI:00C01B* - ID_OUI_FROM_DATABASE=SOCKET COMMUNICATIONS, INC. +OUI:0080C4* + ID_OUI_FROM_DATABASE=DOCUMENT TECHNOLOGIES, INC. -OUI:00C06E* - ID_OUI_FROM_DATABASE=HAFT TECHNOLOGY, INC. +OUI:00801D* + ID_OUI_FROM_DATABASE=INTEGRATED INFERENCE MACHINES -OUI:00406F* - ID_OUI_FROM_DATABASE=SYNC RESEARCH INC. +OUI:008015* + ID_OUI_FROM_DATABASE=SEIKO SYSTEMS, INC. -OUI:00401F* - ID_OUI_FROM_DATABASE=COLORGRAPH LTD +OUI:008034* + ID_OUI_FROM_DATABASE=SMT GOUPIL -OUI:0040CF* - ID_OUI_FROM_DATABASE=STRAWBERRY TREE, INC. +OUI:0080C9* + ID_OUI_FROM_DATABASE=ALBERTA MICROELECTRONIC CENTRE -OUI:0040F7* - ID_OUI_FROM_DATABASE=Polaroid Corporation - -OUI:004037* - ID_OUI_FROM_DATABASE=SEA-ILAN, INC. - -OUI:0040CC* - ID_OUI_FROM_DATABASE=SILCOM MANUF'G TECHNOLOGY INC. - -OUI:004052* - ID_OUI_FROM_DATABASE=STAR TECHNOLOGIES, INC. - -OUI:00407A* - ID_OUI_FROM_DATABASE=SOCIETE D'EXPLOITATION DU CNIT - -OUI:004089* - ID_OUI_FROM_DATABASE=MEIDENSHA CORPORATION - -OUI:00405A* - ID_OUI_FROM_DATABASE=GOLDSTAR INFORMATION & COMM. - -OUI:00404C* - ID_OUI_FROM_DATABASE=HYPERTEC PTY LTD. - -OUI:00C0EE* - ID_OUI_FROM_DATABASE=KYOCERA CORPORATION - -OUI:00C0CB* - ID_OUI_FROM_DATABASE=CONTROL TECHNOLOGY CORPORATION - -OUI:00C09A* - ID_OUI_FROM_DATABASE=PHOTONICS CORPORATION - -OUI:00C01A* - ID_OUI_FROM_DATABASE=COROMETRICS MEDICAL SYSTEMS - -OUI:00404B* - ID_OUI_FROM_DATABASE=MAPLE COMPUTER SYSTEMS - -OUI:004055* - ID_OUI_FROM_DATABASE=METRONIX GMBH - -OUI:004045* - ID_OUI_FROM_DATABASE=TWINHEAD CORPORATION - -OUI:00409D* - ID_OUI_FROM_DATABASE=DIGIBOARD, INC. - -OUI:00401A* - ID_OUI_FROM_DATABASE=FUJI ELECTRIC CO., LTD. - -OUI:0040B9* - ID_OUI_FROM_DATABASE=MACQ ELECTRONIQUE SA - -OUI:0040C7* - ID_OUI_FROM_DATABASE=RUBY TECH CORPORATION - -OUI:004004* - ID_OUI_FROM_DATABASE=ICM CO. LTD. - -OUI:004070* - ID_OUI_FROM_DATABASE=INTERWARE CO., LTD. - -OUI:008057* - ID_OUI_FROM_DATABASE=ADSOFT, LTD. - -OUI:00807A* - ID_OUI_FROM_DATABASE=AITECH SYSTEMS LTD. - -OUI:0080AA* - ID_OUI_FROM_DATABASE=MAXPEED - -OUI:00C0E7* - ID_OUI_FROM_DATABASE=FIBERDATA AB +OUI:00800B* + ID_OUI_FROM_DATABASE=CSK CORPORATION OUI:00800A* ID_OUI_FROM_DATABASE=JAPAN COMPUTER CORP. @@ -42734,75 +43892,6 @@ OUI:00806E* OUI:008010* ID_OUI_FROM_DATABASE=COMMODORE INTERNATIONAL -OUI:0080DA* - ID_OUI_FROM_DATABASE=Bruel & Kjaer Sound & Vibration Measurement A/S - -OUI:0080E5* - ID_OUI_FROM_DATABASE=NetApp, Inc - -OUI:0080BC* - ID_OUI_FROM_DATABASE=HITACHI ENGINEERING CO., LTD - -OUI:008000* - ID_OUI_FROM_DATABASE=MULTITECH SYSTEMS, INC. - -OUI:0080A1* - ID_OUI_FROM_DATABASE=MICROTEST, INC. - -OUI:0080D0* - ID_OUI_FROM_DATABASE=COMPUTER PERIPHERALS, INC. - -OUI:00807D* - ID_OUI_FROM_DATABASE=EQUINOX SYSTEMS INC. - -OUI:008063* - ID_OUI_FROM_DATABASE=Hirschmann Automation and Control GmbH - -OUI:00608C* - ID_OUI_FROM_DATABASE=3COM CORPORATION - -OUI:00804E* - ID_OUI_FROM_DATABASE=APEX COMPUTER COMPANY - -OUI:00800E* - ID_OUI_FROM_DATABASE=ATLANTIX CORPORATION - -OUI:00806F* - ID_OUI_FROM_DATABASE=ONELAN LTD. - -OUI:008098* - ID_OUI_FROM_DATABASE=TDK CORPORATION - -OUI:00809C* - ID_OUI_FROM_DATABASE=LUXCOM, INC. - -OUI:008065* - ID_OUI_FROM_DATABASE=CYBERGRAPHIC SYSTEMS PTY LTD. - -OUI:008016* - ID_OUI_FROM_DATABASE=WANDEL AND GOLTERMANN - -OUI:0080E6* - ID_OUI_FROM_DATABASE=PEER NETWORKS, INC. - -OUI:0080A2* - ID_OUI_FROM_DATABASE=CREATIVE ELECTRONIC SYSTEMS - -OUI:0080E0* - ID_OUI_FROM_DATABASE=XTP SYSTEMS, INC. - -OUI:008050* - ID_OUI_FROM_DATABASE=ZIATECH CORPORATION - -OUI:0000E0* - ID_OUI_FROM_DATABASE=QUADRAM CORP. - -OUI:000057* - ID_OUI_FROM_DATABASE=SCITEX CORPORATION LTD. - -OUI:0000D6* - ID_OUI_FROM_DATABASE=PUNCH LINE HOLDING - OUI:0000C8* ID_OUI_FROM_DATABASE=ALTOS COMPUTER SYSTEMS @@ -42830,6 +43919,132 @@ OUI:0000E7* OUI:0000F3* ID_OUI_FROM_DATABASE=GANDALF DATA LIMITED +OUI:00005C* + ID_OUI_FROM_DATABASE=TELEMATICS INTERNATIONAL INC. + +OUI:0000AC* + ID_OUI_FROM_DATABASE=CONWARE COMPUTER CONSULTING + +OUI:0000F2* + ID_OUI_FROM_DATABASE=SPIDER COMMUNICATIONS + +OUI:000030* + ID_OUI_FROM_DATABASE=VG LABORATORY SYSTEMS LTD + +OUI:000035* + ID_OUI_FROM_DATABASE=SPECTRAGRAPHICS CORPORATION + +OUI:0000E0* + ID_OUI_FROM_DATABASE=QUADRAM CORP. + +OUI:000057* + ID_OUI_FROM_DATABASE=SCITEX CORPORATION LTD. + +OUI:0000D6* + ID_OUI_FROM_DATABASE=PUNCH LINE HOLDING + +OUI:00806F* + ID_OUI_FROM_DATABASE=ONELAN LTD. + +OUI:008098* + ID_OUI_FROM_DATABASE=TDK CORPORATION + +OUI:00809C* + ID_OUI_FROM_DATABASE=LUXCOM, INC. + +OUI:008065* + ID_OUI_FROM_DATABASE=CYBERGRAPHIC SYSTEMS PTY LTD. + +OUI:008016* + ID_OUI_FROM_DATABASE=WANDEL AND GOLTERMANN + +OUI:0080E6* + ID_OUI_FROM_DATABASE=PEER NETWORKS, INC. + +OUI:0080A2* + ID_OUI_FROM_DATABASE=CREATIVE ELECTRONIC SYSTEMS + +OUI:0080E0* + ID_OUI_FROM_DATABASE=XTP SYSTEMS, INC. + +OUI:008050* + ID_OUI_FROM_DATABASE=ZIATECH CORPORATION + +OUI:0080FF* + ID_OUI_FROM_DATABASE=SOC. DE TELEINFORMATIQUE RTC + +OUI:000070* + ID_OUI_FROM_DATABASE=HCL LIMITED + +OUI:00008E* + ID_OUI_FROM_DATABASE=SOLBOURNE COMPUTER, INC. + +OUI:0000DC* + ID_OUI_FROM_DATABASE=HAYES MICROCOMPUTER PRODUCTS + +OUI:000024* + ID_OUI_FROM_DATABASE=CONNECT AS + +OUI:000048* + ID_OUI_FROM_DATABASE=SEIKO EPSON CORPORATION + +OUI:000016* + ID_OUI_FROM_DATABASE=DU PONT PIXEL SYSTEMS . + +OUI:00001E* + ID_OUI_FROM_DATABASE=TELSIST INDUSTRIA ELECTRONICA + +OUI:00807B* + ID_OUI_FROM_DATABASE=ARTEL COMMUNICATIONS CORP. + +OUI:00802E* + ID_OUI_FROM_DATABASE=CASTLE ROCK COMPUTING + +OUI:0080F9* + ID_OUI_FROM_DATABASE=HEURIKON CORPORATION + +OUI:008005* + ID_OUI_FROM_DATABASE=CACTUS COMPUTER INC. + +OUI:008008* + ID_OUI_FROM_DATABASE=DYNATECH COMPUTER SYSTEMS + +OUI:08005E* + ID_OUI_FROM_DATABASE=COUNTERPOINT COMPUTER INC. + +OUI:08005A* + ID_OUI_FROM_DATABASE=IBM Corp + +OUI:080056* + ID_OUI_FROM_DATABASE=STANFORD LINEAR ACCEL. CENTER + +OUI:080053* + ID_OUI_FROM_DATABASE=MIDDLE EAST TECH. UNIVERSITY + +OUI:08004F* + ID_OUI_FROM_DATABASE=CYGNET SYSTEMS + +OUI:080040* + ID_OUI_FROM_DATABASE=FERRANTI COMPUTER SYS. LIMITED + +OUI:08003B* + ID_OUI_FROM_DATABASE=TORUS SYSTEMS LIMITED + +OUI:08003D* + ID_OUI_FROM_DATABASE=CADNETIX CORPORATIONS + +OUI:080039* + ID_OUI_FROM_DATABASE=SPIDER SYSTEMS LIMITED + +OUI:00DD0C* + ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. + +OUI:000005* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + +OUI:0000AA* + ID_OUI_FROM_DATABASE=XEROX CORPORATION + OUI:000064* ID_OUI_FROM_DATABASE=Yokogawa Electric Corporation @@ -42857,6 +44072,51 @@ OUI:00007C* OUI:00008A* ID_OUI_FROM_DATABASE=DATAHOUSE INFORMATION SYSTEMS +OUI:080030* + ID_OUI_FROM_DATABASE=NETWORK RESEARCH CORPORATION + +OUI:080027* + ID_OUI_FROM_DATABASE=Cadmus Computer Systems + +OUI:020701* + ID_OUI_FROM_DATABASE=RACAL-DATACOM + +OUI:080011* + ID_OUI_FROM_DATABASE=TEKTRONIX INC. + +OUI:08007F* + ID_OUI_FROM_DATABASE=CARNEGIE-MELLON UNIVERSITY + +OUI:080082* + ID_OUI_FROM_DATABASE=VERITAS SOFTWARE + +OUI:08007B* + ID_OUI_FROM_DATABASE=SANYO ELECTRIC CO. LTD. + +OUI:080074* + ID_OUI_FROM_DATABASE=CASIO COMPUTER CO. LTD. + +OUI:00406B* + ID_OUI_FROM_DATABASE=SYSGEN + +OUI:AA0001* + ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION + +OUI:080001* + ID_OUI_FROM_DATABASE=COMPUTERVISION CORPORATION + +OUI:000053* + ID_OUI_FROM_DATABASE=COMPUCORP + +OUI:08004B* + ID_OUI_FROM_DATABASE=Planning Research Corp. + +OUI:080003* + ID_OUI_FROM_DATABASE=ADVANCED COMPUTER COMM. + +OUI:00009B* + ID_OUI_FROM_DATABASE=INFORMATION INTERNATIONAL, INC + OUI:000068* ID_OUI_FROM_DATABASE=ROSEMOUNT CONTROLS @@ -42878,110 +44138,8 @@ OUI:0000D0* OUI:000093* ID_OUI_FROM_DATABASE=PROTEON INC. -OUI:008008* - ID_OUI_FROM_DATABASE=DYNATECH COMPUTER SYSTEMS - -OUI:0080FF* - ID_OUI_FROM_DATABASE=SOC. DE TELEINFORMATIQUE RTC - -OUI:000070* - ID_OUI_FROM_DATABASE=HCL LIMITED - -OUI:00008E* - ID_OUI_FROM_DATABASE=SOLBOURNE COMPUTER, INC. - -OUI:0000DC* - ID_OUI_FROM_DATABASE=HAYES MICROCOMPUTER PRODUCTS - -OUI:000024* - ID_OUI_FROM_DATABASE=CONNECT AS - -OUI:000048* - ID_OUI_FROM_DATABASE=SEIKO EPSON CORPORATION - -OUI:008030* - ID_OUI_FROM_DATABASE=NEXUS ELECTRONICS - -OUI:008022* - ID_OUI_FROM_DATABASE=SCAN-OPTICS - -OUI:000041* - ID_OUI_FROM_DATABASE=ICE CORPORATION - -OUI:00001E* - ID_OUI_FROM_DATABASE=TELSIST INDUSTRIA ELECTRONICA - -OUI:00807B* - ID_OUI_FROM_DATABASE=ARTEL COMMUNICATIONS CORP. - -OUI:00802E* - ID_OUI_FROM_DATABASE=CASTLE ROCK COMPUTING - -OUI:0080F9* - ID_OUI_FROM_DATABASE=HEURIKON CORPORATION - -OUI:008005* - ID_OUI_FROM_DATABASE=CACTUS COMPUTER INC. - -OUI:00801D* - ID_OUI_FROM_DATABASE=INTEGRATED INFERENCE MACHINES - -OUI:008015* - ID_OUI_FROM_DATABASE=SEIKO SYSTEMS, INC. - -OUI:008034* - ID_OUI_FROM_DATABASE=SMT GOUPIL - -OUI:0080C9* - ID_OUI_FROM_DATABASE=ALBERTA MICROELECTRONIC CENTRE - -OUI:00800B* - ID_OUI_FROM_DATABASE=CSK CORPORATION - -OUI:000016* - ID_OUI_FROM_DATABASE=DU PONT PIXEL SYSTEMS . - -OUI:00005C* - ID_OUI_FROM_DATABASE=TELEMATICS INTERNATIONAL INC. - -OUI:0000AC* - ID_OUI_FROM_DATABASE=CONWARE COMPUTER CONSULTING - -OUI:0000F2* - ID_OUI_FROM_DATABASE=SPIDER COMMUNICATIONS - -OUI:000030* - ID_OUI_FROM_DATABASE=VG LABORATORY SYSTEMS LTD - -OUI:000035* - ID_OUI_FROM_DATABASE=SPECTRAGRAPHICS CORPORATION - -OUI:020701* - ID_OUI_FROM_DATABASE=RACAL-DATACOM - -OUI:080011* - ID_OUI_FROM_DATABASE=TEKTRONIX INC. - -OUI:080040* - ID_OUI_FROM_DATABASE=FERRANTI COMPUTER SYS. LIMITED - -OUI:08003B* - ID_OUI_FROM_DATABASE=TORUS SYSTEMS LIMITED - -OUI:08003D* - ID_OUI_FROM_DATABASE=CADNETIX CORPORATIONS - -OUI:080039* - ID_OUI_FROM_DATABASE=SPIDER SYSTEMS LIMITED - -OUI:080030* - ID_OUI_FROM_DATABASE=NETWORK RESEARCH CORPORATION - -OUI:080027* - ID_OUI_FROM_DATABASE=Cadmus Computer Systems - -OUI:00009B* - ID_OUI_FROM_DATABASE=INFORMATION INTERNATIONAL, INC +OUI:0000A0* + ID_OUI_FROM_DATABASE=SANYO Electric Co., Ltd. OUI:00DD0F* ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. @@ -43004,75 +44162,9 @@ OUI:00DD08* OUI:0000D8* ID_OUI_FROM_DATABASE=NOVELL, INC. -OUI:0000A0* - ID_OUI_FROM_DATABASE=SANYO Electric Co., Ltd. - -OUI:08007F* - ID_OUI_FROM_DATABASE=CARNEGIE-MELLON UNIVERSITY - -OUI:080082* - ID_OUI_FROM_DATABASE=VERITAS SOFTWARE - -OUI:08007B* - ID_OUI_FROM_DATABASE=SANYO ELECTRIC CO. LTD. - -OUI:00DD0C* - ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. - -OUI:000005* - ID_OUI_FROM_DATABASE=XEROX CORPORATION - -OUI:0000AA* - ID_OUI_FROM_DATABASE=XEROX CORPORATION - -OUI:00406B* - ID_OUI_FROM_DATABASE=SYSGEN - -OUI:AA0001* - ID_OUI_FROM_DATABASE=DIGITAL EQUIPMENT CORPORATION - -OUI:080001* - ID_OUI_FROM_DATABASE=COMPUTERVISION CORPORATION - -OUI:000053* - ID_OUI_FROM_DATABASE=COMPUCORP - -OUI:08004B* - ID_OUI_FROM_DATABASE=Planning Research Corp. - -OUI:080003* - ID_OUI_FROM_DATABASE=ADVANCED COMPUTER COMM. - -OUI:080074* - ID_OUI_FROM_DATABASE=CASIO COMPUTER CO. LTD. - -OUI:08005E* - ID_OUI_FROM_DATABASE=COUNTERPOINT COMPUTER INC. - -OUI:08005A* - ID_OUI_FROM_DATABASE=IBM Corp - -OUI:080056* - ID_OUI_FROM_DATABASE=STANFORD LINEAR ACCEL. CENTER - -OUI:080053* - ID_OUI_FROM_DATABASE=MIDDLE EAST TECH. UNIVERSITY - -OUI:08004F* - ID_OUI_FROM_DATABASE=CYGNET SYSTEMS - OUI:F8E71E* ID_OUI_FROM_DATABASE=Ruckus Wireless -OUI:00194B* - ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS - -OUI:001F95* - ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS - -OUI:000E59* - ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS - OUI:A01B29* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS @@ -43085,6 +44177,15 @@ OUI:ECDF3A* OUI:E45AA2* ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. +OUI:00194B* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + +OUI:001F95* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + +OUI:000E59* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + OUI:00235A* ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. @@ -43103,6 +44204,9 @@ OUI:94C150* OUI:60FE20* ID_OUI_FROM_DATABASE=2Wire Inc +OUI:D4AE52* + ID_OUI_FROM_DATABASE=Dell Inc. + OUI:989096* ID_OUI_FROM_DATABASE=Dell Inc. @@ -43115,6 +44219,12 @@ OUI:00D09E* OUI:000D72* ID_OUI_FROM_DATABASE=2Wire Inc +OUI:B0E754* + ID_OUI_FROM_DATABASE=2Wire Inc + +OUI:B8E625* + ID_OUI_FROM_DATABASE=2Wire Inc + OUI:000F1F* ID_OUI_FROM_DATABASE=Dell Inc. @@ -43124,15 +44234,6 @@ OUI:14FEB5* OUI:0015C5* ID_OUI_FROM_DATABASE=Dell Inc. -OUI:D4AE52* - ID_OUI_FROM_DATABASE=Dell Inc. - -OUI:B0E754* - ID_OUI_FROM_DATABASE=2Wire Inc - -OUI:B8E625* - ID_OUI_FROM_DATABASE=2Wire Inc - OUI:549F35* ID_OUI_FROM_DATABASE=Dell Inc. @@ -43160,12 +44261,12 @@ OUI:A4A1C2* OUI:348446* ID_OUI_FROM_DATABASE=Ericsson AB -OUI:AC2B6E* - ID_OUI_FROM_DATABASE=Intel Corporate - OUI:F8F1B6* ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company +OUI:AC2B6E* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:00216A* ID_OUI_FROM_DATABASE=Intel Corporate @@ -43178,6 +44279,15 @@ OUI:0016EB* OUI:0018DE* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:28B2BD* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:08D40C* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:843A4B* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:681729* ID_OUI_FROM_DATABASE=Intel Corporate @@ -43187,12 +44297,6 @@ OUI:5C514F* OUI:B808CF* ID_OUI_FROM_DATABASE=Intel Corporate -OUI:C8F733* - ID_OUI_FROM_DATABASE=Intel Corporate - -OUI:4851B7* - ID_OUI_FROM_DATABASE=Intel Corporate - OUI:5CC5D4* ID_OUI_FROM_DATABASE=Intel Corporate @@ -43202,16 +44306,7 @@ OUI:7CCCB8* OUI:F40669* ID_OUI_FROM_DATABASE=Intel Corporate -OUI:3CA9F4* - ID_OUI_FROM_DATABASE=Intel Corporate - -OUI:28B2BD* - ID_OUI_FROM_DATABASE=Intel Corporate - -OUI:08D40C* - ID_OUI_FROM_DATABASE=Intel Corporate - -OUI:843A4B* +OUI:C8F733* ID_OUI_FROM_DATABASE=Intel Corporate OUI:0CD292* @@ -43223,6 +44318,12 @@ OUI:78929C* OUI:6805CA* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:4851B7* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:3CA9F4* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:ACA31E* ID_OUI_FROM_DATABASE=Aruba Networks @@ -43241,6 +44342,9 @@ OUI:84D47E* OUI:A85840* ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd. +OUI:002423* + ID_OUI_FROM_DATABASE=AzureWave Technologies (Shanghai) Inc. + OUI:002243* ID_OUI_FROM_DATABASE=AzureWave Technology Inc. @@ -43262,23 +44366,14 @@ OUI:240A64* OUI:D0E782* ID_OUI_FROM_DATABASE=AzureWave Technology Inc. -OUI:0C4C39* - ID_OUI_FROM_DATABASE=MitraStar Technology Corp. - -OUI:002423* - ID_OUI_FROM_DATABASE=AzureWave Technologies (Shanghai) Inc. - OUI:A81D16* ID_OUI_FROM_DATABASE=AzureWave Technology Inc. OUI:38A53C* ID_OUI_FROM_DATABASE=COMECER Netherlands -OUI:001D8B* - ID_OUI_FROM_DATABASE=ADB Broadband Italia - -OUI:A4526F* - ID_OUI_FROM_DATABASE=ADB Broadband Italia +OUI:0C4C39* + ID_OUI_FROM_DATABASE=MitraStar Technology Corp. OUI:581243* ID_OUI_FROM_DATABASE=AcSiP Technology Corp. @@ -43292,15 +44387,18 @@ OUI:0030F1* OUI:001974* ID_OUI_FROM_DATABASE=16063 -OUI:ECF00E* - ID_OUI_FROM_DATABASE=AboCom - OUI:3039F2* ID_OUI_FROM_DATABASE=ADB Broadband Italia OUI:000827* ID_OUI_FROM_DATABASE=ADB Broadband Italia +OUI:001D8B* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + +OUI:A4526F* + ID_OUI_FROM_DATABASE=ADB Broadband Italia + OUI:001CA8* ID_OUI_FROM_DATABASE=AirTies Wireless Netowrks @@ -43313,6 +44411,12 @@ OUI:18FE34* OUI:54F6C5* ID_OUI_FROM_DATABASE=FUJIAN STAR-NET COMMUNICATION CO.,LTD +OUI:A43111* + ID_OUI_FROM_DATABASE=ZIV + +OUI:ECF00E* + ID_OUI_FROM_DATABASE=AboCom + OUI:28EF01* ID_OUI_FROM_DATABASE=Private @@ -43322,12 +44426,6 @@ OUI:5C338E* OUI:001AEB* ID_OUI_FROM_DATABASE=Allied Telesis R&D Center K.K. -OUI:747548* - ID_OUI_FROM_DATABASE=Amazon Technologies Inc. - -OUI:A43111* - ID_OUI_FROM_DATABASE=ZIV - OUI:5C93A2* ID_OUI_FROM_DATABASE=Liteon Technology Corporation @@ -43337,39 +44435,12 @@ OUI:E8C74F* OUI:E8F724* ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise -OUI:1C1448* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:747548* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. -OUI:707E43* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - -OUI:001AAD* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - -OUI:A47AA4* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - -OUI:701A04* - ID_OUI_FROM_DATABASE=Liteon Technology Corporation - -OUI:00D9D1* +OUI:080046* ID_OUI_FROM_DATABASE=Sony Corporation -OUI:48D224* - ID_OUI_FROM_DATABASE=Liteon Technology Corporation - -OUI:2CD05A* - ID_OUI_FROM_DATABASE=Liteon Technology Corporation - -OUI:74E543* - ID_OUI_FROM_DATABASE=Liteon Technology Corporation - -OUI:A4DB30* - ID_OUI_FROM_DATABASE=Liteon Technology Corporation - -OUI:B8EE65* - ID_OUI_FROM_DATABASE=Liteon Technology Corporation - OUI:001DBA* ID_OUI_FROM_DATABASE=Sony Corporation @@ -43391,6 +44462,24 @@ OUI:001B59* OUI:78843C* ID_OUI_FROM_DATABASE=Sony Corporation +OUI:701A04* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:48D224* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:2CD05A* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:74E543* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:A4DB30* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:B8EE65* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + OUI:0023F1* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB @@ -43400,29 +44489,17 @@ OUI:3017C8* OUI:18002D* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB -OUI:3C0771* - ID_OUI_FROM_DATABASE=Sony Corporation - -OUI:D8D43C* - ID_OUI_FROM_DATABASE=Sony Corporation - -OUI:0CFE45* - ID_OUI_FROM_DATABASE=Sony Corporation - -OUI:F8D0AC* - ID_OUI_FROM_DATABASE=Sony Corporation - OUI:04E676* ID_OUI_FROM_DATABASE=AMPAK Technology, Inc. OUI:0022F4* ID_OUI_FROM_DATABASE=AMPAK Technology, Inc. -OUI:00041F* - ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. +OUI:1C1448* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. -OUI:080046* - ID_OUI_FROM_DATABASE=Sony Corporation +OUI:707E43* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. OUI:0003E0* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -43433,6 +44510,12 @@ OUI:00128A* OUI:001225* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:001AAD* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:A47AA4* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + OUI:3C754A* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -43451,6 +44534,18 @@ OUI:002395* OUI:0023ED* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:745612* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:E46449* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:002493* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:40FC89* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + OUI:001B52* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -43469,27 +44564,9 @@ OUI:001BDD* OUI:001404* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. -OUI:745612* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - -OUI:E46449* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - -OUI:002493* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - -OUI:40FC89* - ID_OUI_FROM_DATABASE=ARRIS Group, Inc. - OUI:00195E* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. -OUI:000D92* - ID_OUI_FROM_DATABASE=ARIMA Communications Corp. - -OUI:009096* - ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP - OUI:0011F5* ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP @@ -43505,8 +44582,11 @@ OUI:000B6A* OUI:40BA61* ID_OUI_FROM_DATABASE=ARIMA Communications Corp. -OUI:841B5E* - ID_OUI_FROM_DATABASE=NETGEAR +OUI:000D92* + ID_OUI_FROM_DATABASE=ARIMA Communications Corp. + +OUI:009096* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP OUI:204E7F* ID_OUI_FROM_DATABASE=NETGEAR @@ -43523,11 +44603,8 @@ OUI:C03F0E* OUI:001F33* ID_OUI_FROM_DATABASE=NETGEAR -OUI:1883BF* - ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation - -OUI:9C80DF* - ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation +OUI:841B5E* + ID_OUI_FROM_DATABASE=NETGEAR OUI:001CCC* ID_OUI_FROM_DATABASE=BlackBerry RTS @@ -43535,18 +44612,6 @@ OUI:001CCC* OUI:94EBCD* ID_OUI_FROM_DATABASE=BlackBerry RTS -OUI:644FB0* - ID_OUI_FROM_DATABASE=Hyunjin.com - -OUI:001A2A* - ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation - -OUI:001D19* - ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation - -OUI:88252C* - ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation - OUI:A4E4B8* ID_OUI_FROM_DATABASE=BlackBerry RTS @@ -43559,6 +44624,24 @@ OUI:BC0543* OUI:002675* ID_OUI_FROM_DATABASE=Aztech Electronics Pte Ltd +OUI:001D19* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:88252C* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:1883BF* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:9C80DF* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + +OUI:644FB0* + ID_OUI_FROM_DATABASE=Hyunjin.com + +OUI:001A2A* + ID_OUI_FROM_DATABASE=Arcadyan Technology Corporation + OUI:001F3F* ID_OUI_FROM_DATABASE=AVM GmbH @@ -43571,63 +44654,108 @@ OUI:6CB0CE* OUI:100D7F* ID_OUI_FROM_DATABASE=NETGEAR -OUI:0020D6* - ID_OUI_FROM_DATABASE=Breezecom, Ltd. - OUI:001018* ID_OUI_FROM_DATABASE=Broadcom OUI:001BE9* ID_OUI_FROM_DATABASE=Broadcom -OUI:307C5E* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:0010DB* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:00121E* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:0014F6* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:EC3EF7* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:0C8610* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:40A677* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:841888* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:002688* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:0017CB* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:DC38E1* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:40B4F0* - ID_OUI_FROM_DATABASE=Juniper Networks +OUI:0020D6* + ID_OUI_FROM_DATABASE=Breezecom, Ltd. OUI:008077* ID_OUI_FROM_DATABASE=Brother industries, LTD. -OUI:029D8E* - ID_OUI_FROM_DATABASE=CARDIAC RECORDERS, INC. - OUI:FC2F40* ID_OUI_FROM_DATABASE=Calxeda, Inc. +OUI:029D8E* + ID_OUI_FROM_DATABASE=CARDIAC RECORDERS, INC. + OUI:0026E4* ID_OUI_FROM_DATABASE=Canal + +OUI:E458E7* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:8CBFA6* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:7840E4* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:9000DB* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:183A2D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:A89FBA* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:FC1910* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:083D88* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:5C2E59* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:646CB2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:A48431* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:E4F8EF* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:1867B0* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:F40E22* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:4CBCA5* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:78595E* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B0D09C* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:4CA56D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:08373D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:50F520* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:A4EBD3* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:28987B* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:9C3AAF* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:1432D1* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:F884F2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:14B484* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:608F5C* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:389496* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -43652,86 +44780,14 @@ OUI:0C8910* OUI:54FA3E* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd -OUI:A89FBA* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:702559* + ID_OUI_FROM_DATABASE=CyberTAN Technology Inc. -OUI:FC1910* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:0090D6* + ID_OUI_FROM_DATABASE=Crystal Group, Inc. -OUI:083D88* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:5C2E59* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:646CB2* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:F884F2* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:14B484* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:608F5C* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:4CBCA5* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:78595E* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:B0D09C* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:4CA56D* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:A48431* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:E4F8EF* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:1432D1* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:E458E7* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:8CBFA6* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:7840E4* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:9000DB* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:183A2D* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:08373D* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:50F520* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:A4EBD3* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:28987B* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:1867B0* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:F40E22* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd - -OUI:9C3AAF* - ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:02CF1C* + ID_OUI_FROM_DATABASE=Communication Machinery Corporation OUI:BCF2AF* ID_OUI_FROM_DATABASE=devolo AG @@ -43742,36 +44798,30 @@ OUI:0270B3* OUI:000FF6* ID_OUI_FROM_DATABASE=DARFON LIGHTING CORP -OUI:702559* - ID_OUI_FROM_DATABASE=CyberTAN Technology Inc. - -OUI:0090D6* - ID_OUI_FROM_DATABASE=Crystal Group, Inc. - OUI:001DAA* ID_OUI_FROM_DATABASE=DrayTek Corp. -OUI:02CF1C* - ID_OUI_FROM_DATABASE=Communication Machinery Corporation - OUI:0C75BD* ID_OUI_FROM_DATABASE=Cisco Systems, Inc OUI:38F0C8* ID_OUI_FROM_DATABASE=Livestream +OUI:0C1167* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:74EAE8* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. OUI:A811FC* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. -OUI:0C1167* - ID_OUI_FROM_DATABASE=Cisco Systems, Inc - OUI:001982* ID_OUI_FROM_DATABASE=SmarDTV +OUI:00904B* + ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. + OUI:10C6FC* ID_OUI_FROM_DATABASE=Garmin International @@ -43796,15 +44846,6 @@ OUI:002682* OUI:001A73* ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. -OUI:00904B* - ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. - -OUI:D86BF7* - ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. - -OUI:A4C0E1* - ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. - OUI:34AF2C* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. @@ -43820,12 +44861,6 @@ OUI:600194* OUI:F44D17* ID_OUI_FROM_DATABASE=GOLDCARD HIGH-TECH CO.,LTD. -OUI:001E35* - ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. - -OUI:001FC5* - ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. - OUI:0021BD* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. @@ -43835,7 +44870,10 @@ OUI:002709* OUI:E84ECE* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. -OUI:0009BF* +OUI:D86BF7* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:A4C0E1* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. OUI:001AE9* @@ -43844,6 +44882,15 @@ OUI:001AE9* OUI:001CBE* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. +OUI:001E35* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:001FC5* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + +OUI:0009BF* + ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. + OUI:002403* ID_OUI_FROM_DATABASE=Nokia Danmark A/S @@ -43853,42 +44900,6 @@ OUI:002265* OUI:0019B7* ID_OUI_FROM_DATABASE=Nokia Danmark A/S -OUI:002404* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:0002EE* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:001C9A* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:001F01* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:000EED* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:001E3A* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:001A89* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:0021AA* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:002669* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:0022FD* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:002109* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - -OUI:002108* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - OUI:001D6E* ID_OUI_FROM_DATABASE=Nokia Danmark A/S @@ -43904,6 +44915,426 @@ OUI:EC9B5B* OUI:BCC6DB* ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:0021AA* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002669* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0022FD* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002109* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002108* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001F01* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:000EED* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001E3A* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001A89* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:002404* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:0002EE* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:001C9A* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + +OUI:B83241* + ID_OUI_FROM_DATABASE=Wuhan Tianyu Information Industry Co., Ltd. + +OUI:9897D1* + ID_OUI_FROM_DATABASE=MitraStar Technology Corp. + +OUI:94C960* + ID_OUI_FROM_DATABASE=Zhongshan B&T technology.co.,ltd + +OUI:E04FBD* + ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + +OUI:001479* + ID_OUI_FROM_DATABASE=NEC Magnus Communications,Ltd. + +OUI:9C4FDA* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:1C5CF2* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:0821EF* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:B462AD* + ID_OUI_FROM_DATABASE=Elysia Germany GmbH + +OUI:747818* + ID_OUI_FROM_DATABASE=Jurumani Solutions + +OUI:A0CBFD* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:34145F* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:803896* + ID_OUI_FROM_DATABASE=SHARP Corporation + +OUI:00D9D1* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:F8D0AC* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:0CFE45* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:D8D43C* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:3C0771* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:686E23* + ID_OUI_FROM_DATABASE=Wi3 Inc. + +OUI:B8A175* + ID_OUI_FROM_DATABASE=Roku, Inc. + +OUI:80D160* + ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd. + +OUI:0080E5* + ID_OUI_FROM_DATABASE=NetApp + +OUI:E49A79* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:28A02B* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:B44BD2* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:002340* + ID_OUI_FROM_DATABASE=MiXTelematics + +OUI:B48B19* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:4CCC6A* + ID_OUI_FROM_DATABASE=Micro-Star INTL CO., LTD. + +OUI:00AF1F* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:245EBE* + ID_OUI_FROM_DATABASE=QNAP Systems, Inc. + +OUI:A89352* + ID_OUI_FROM_DATABASE=SHANGHAI ZHONGMI COMMUNICATION TECHNOLOGY CO.,LTD + +OUI:AC5F3E* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND) + +OUI:985BB0* + ID_OUI_FROM_DATABASE=KMDATA INC. + +OUI:6C8FB5* + ID_OUI_FROM_DATABASE=Microsoft Mobile Oy + +OUI:D4E33F* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:143E60* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:248A07* + ID_OUI_FROM_DATABASE=Mellanox Technologies, Inc. + +OUI:9C9D5D* + ID_OUI_FROM_DATABASE=Raden Inc + +OUI:B07FB9* + ID_OUI_FROM_DATABASE=NETGEAR + +OUI:70661B* + ID_OUI_FROM_DATABASE=Sonova AG + +OUI:1C98EC* + ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise + +OUI:EC438B* + ID_OUI_FROM_DATABASE=YAPTV + +OUI:E8FD72* + ID_OUI_FROM_DATABASE=SHANGHAI LINGUO TECHNOLOGY CO., LTD. + +OUI:98BB1E* + ID_OUI_FROM_DATABASE=BYD Precision Manufacture Company Ltd. + +OUI:001D0D* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:00041F* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:20A90E* + ID_OUI_FROM_DATABASE=TCT mobile ltd + +OUI:CCB11A* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:1866DA* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:981FB1* + ID_OUI_FROM_DATABASE=Shenzhen Lemon Network Technology Co.,Ltd + +OUI:40476A* + ID_OUI_FROM_DATABASE=AG Acquisition Corp. d.b.a. ASTRO Gaming + +OUI:A4BF01* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:0004C6* + ID_OUI_FROM_DATABASE=YAMAHA MOTOR CO.,LTD + +OUI:509EA7* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:DCCF96* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:64CC2E* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + +OUI:14D11F* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:54511B* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:68536C* + ID_OUI_FROM_DATABASE=SPnS Co.,Ltd + +OUI:005BA1* + ID_OUI_FROM_DATABASE=shanghai huayuan chuangxin software CO., LTD. + +OUI:B07E70* + ID_OUI_FROM_DATABASE=Zadara Storage Ltd. + +OUI:405EE1* + ID_OUI_FROM_DATABASE=Shenzhen H&T Intelligent Control Co.,Ltd. + +OUI:88795B* + ID_OUI_FROM_DATABASE=Konka Group Co., Ltd. + +OUI:10F005* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:BC9889* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:E42F26* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:344B3D* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:FCF647* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:1088CE* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:D463FE* + ID_OUI_FROM_DATABASE=Arcadyan Corporation + +OUI:9466E7* + ID_OUI_FROM_DATABASE=WOM Engineering + +OUI:F8A188* + ID_OUI_FROM_DATABASE=LED Roadway Lighting + +OUI:001174* + ID_OUI_FROM_DATABASE=Mojo Networks, Inc. + +OUI:BC15AC* + ID_OUI_FROM_DATABASE=Vodafone Italia S.p.A. + +OUI:1C740D* + ID_OUI_FROM_DATABASE=ZyXEL Communications Corporation + +OUI:140C5B* + ID_OUI_FROM_DATABASE=PLNetworks + +OUI:D0B0CD* + ID_OUI_FROM_DATABASE=Moen + +OUI:DCFE07* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:E47E66* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:9C741A* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:EC93ED* + ID_OUI_FROM_DATABASE=DDoS-Guard LTD + +OUI:4C72B9* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:0071C2* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:F462D0* + ID_OUI_FROM_DATABASE=Not for Radio, LLC + +OUI:94513D* + ID_OUI_FROM_DATABASE=iSmart Alarm, Inc. + +OUI:C89CDC* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:002511* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:000E03* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:001BB9* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:001921* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:00142A* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:0050FC* + ID_OUI_FROM_DATABASE=Edimax Technology Co. Ltd. + +OUI:200A5E* + ID_OUI_FROM_DATABASE=Xiangshan Giant Eagle Technology Developing Co., Ltd. + +OUI:0001F4* + ID_OUI_FROM_DATABASE=Enterasys + +OUI:487ADA* + ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited + +OUI:1C7370* + ID_OUI_FROM_DATABASE=Neotech + +OUI:30E37A* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:A08CFD* + ID_OUI_FROM_DATABASE=Hewlett Packard + +OUI:4CA003* + ID_OUI_FROM_DATABASE=T-21 Technologies LLC + +OUI:F0EE58* + ID_OUI_FROM_DATABASE=PACE Telematics GmbH + +OUI:001397* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:00A0A4* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:4000E0* + ID_OUI_FROM_DATABASE=Derek(Shaoguan)Limited + +OUI:A4E597* + ID_OUI_FROM_DATABASE=Gessler GmbH + +OUI:001A34* + ID_OUI_FROM_DATABASE=Konka Group Co., Ltd. + +OUI:0024F4* + ID_OUI_FROM_DATABASE=Kaminario, Ltd. + +OUI:001D08* + ID_OUI_FROM_DATABASE=Jiangsu Yinhe Electronics Co.,Ltd. + +OUI:0018D7* + ID_OUI_FROM_DATABASE=JAVAD GNSS, Inc. + +OUI:001C6C* + ID_OUI_FROM_DATABASE=30805 + +OUI:00A0B0* + ID_OUI_FROM_DATABASE=I-O DATA DEVICE, INC. + +OUI:00E0CF* + ID_OUI_FROM_DATABASE=INTEGRATED DEVICE + +OUI:547F54* + ID_OUI_FROM_DATABASE=INGENICO + +OUI:48C049* + ID_OUI_FROM_DATABASE=Broad Telecom SA + +OUI:DC38E1* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:40A677* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0C8610* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:EC3EF7* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0014F6* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:00121E* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0010DB* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:307C5E* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:002688* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:841888* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:40B4F0* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0017CB* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:E0A3AC* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:044E5A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:E00EDA* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:D86CE9* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS @@ -45236,12 +46667,6 @@ OUI:346C0F* OUI:3C912B* ID_OUI_FROM_DATABASE=Vexata Inc -OUI:F8C96C* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - -OUI:48555F* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:54369B* ID_OUI_FROM_DATABASE=1Verge Internet Technology (Beijing) Co., Ltd. @@ -45440,9 +46865,6 @@ OUI:14EDE4* OUI:3438AF* ID_OUI_FROM_DATABASE=Inlab Software GmbH -OUI:D897BA* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:049B9C* ID_OUI_FROM_DATABASE=Eadingcore Intelligent Technology Co., Ltd. @@ -45473,9 +46895,6 @@ OUI:EC59E7* OUI:08EFAB* ID_OUI_FROM_DATABASE=SAYME WIRELESS SENSOR NETWORK -OUI:BC52B4* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:C81B6B* ID_OUI_FROM_DATABASE=Innova Security @@ -45512,9 +46931,6 @@ OUI:2C600C* OUI:902CC7* ID_OUI_FROM_DATABASE=C-MAX Asia Limited -OUI:B8AEED* - ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co., Ltd. - OUI:1C965A* ID_OUI_FROM_DATABASE=Weifang goertek Electronics CO.,LTD @@ -45959,9 +47375,6 @@ OUI:7C9763* OUI:0444A1* ID_OUI_FROM_DATABASE=TELECON GALICIA,S.A. -OUI:C03FD5* - ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co., LTD - OUI:84569C* ID_OUI_FROM_DATABASE=Coho Data, Inc., @@ -46130,9 +47543,6 @@ OUI:C0C687* OUI:142BD2* ID_OUI_FROM_DATABASE=Armtel Ltd. -OUI:D4AD2D* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:F845AD* ID_OUI_FROM_DATABASE=Konka Group Co., Ltd. @@ -46196,9 +47606,6 @@ OUI:341B22* OUI:B4346C* ID_OUI_FROM_DATABASE=MATSUNICHI DIGITAL TECHNOLOGY (HONG KONG) LIMITED -OUI:4C55CC* - ID_OUI_FROM_DATABASE=ACKme Networks Pty Ltd - OUI:9C1465* ID_OUI_FROM_DATABASE=Edata Elektronik San. ve Tic. A.Ş. @@ -46343,12 +47750,6 @@ OUI:784B08* OUI:0C2D89* ID_OUI_FROM_DATABASE=QiiQ Communications Inc. -OUI:34BF90* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - -OUI:D467E7* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:604A1C* ID_OUI_FROM_DATABASE=SUYIN Corporation @@ -46406,9 +47807,6 @@ OUI:381766* OUI:204C6D* ID_OUI_FROM_DATABASE=Hugo Brennenstuhl Gmbh & Co. KG. -OUI:D49524* - ID_OUI_FROM_DATABASE=Clover Network, Inc. - OUI:DC825B* ID_OUI_FROM_DATABASE=JANUS, spol. s r.o. @@ -46580,9 +47978,6 @@ OUI:78995C* OUI:8CC5E1* ID_OUI_FROM_DATABASE=ShenZhen Konka Telecommunication Technology Co.,Ltd -OUI:7427EA* - ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co., Ltd. - OUI:6CB311* ID_OUI_FROM_DATABASE=Shenzhen Lianrui Electronics Co.,Ltd @@ -46730,9 +48125,6 @@ OUI:CC3A61* OUI:A00363* ID_OUI_FROM_DATABASE=Robert Bosch Healthcare GmbH -OUI:4C8FA5* - ID_OUI_FROM_DATABASE=Jastec - OUI:F0F644* ID_OUI_FROM_DATABASE=Whitesky Science & Technology Co.,Ltd. @@ -46808,9 +48200,6 @@ OUI:A854B2* OUI:98291D* ID_OUI_FROM_DATABASE=Jaguar de Mexico, SA de CV -OUI:8C3C4A* - ID_OUI_FROM_DATABASE=NAKAYO TELECOMMUNICATIONS,INC. - OUI:18863A* ID_OUI_FROM_DATABASE=DIGITAL ART SYSTEM @@ -46988,9 +48377,6 @@ OUI:E44F5F* OUI:08B738* ID_OUI_FROM_DATABASE=Lite-On Technogy Corp. -OUI:702526* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:9C6650* ID_OUI_FROM_DATABASE=Glodio Technolies Co.,Ltd Tianjin Branch @@ -47084,9 +48470,6 @@ OUI:346E8A* OUI:ACEE3B* ID_OUI_FROM_DATABASE=6harmonics Inc -OUI:04C1B9* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:681605* ID_OUI_FROM_DATABASE=Systems And Electronic Development FZCO @@ -47438,9 +48821,6 @@ OUI:DC3C2E* OUI:40BC8B* ID_OUI_FROM_DATABASE=itelio GmbH -OUI:903AA0* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:88C36E* ID_OUI_FROM_DATABASE=Beijing Ereneben lnformation Technology Limited @@ -47966,9 +49346,6 @@ OUI:20D5AB* OUI:F05849* ID_OUI_FROM_DATABASE=CareView Communications -OUI:E06995* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:BC15A6* ID_OUI_FROM_DATABASE=Taiwan Jantek Electronics,Ltd. @@ -47984,9 +49361,6 @@ OUI:F05D89* OUI:AC02CF* ID_OUI_FROM_DATABASE=RW Tecnologia Industria e Comercio Ltda -OUI:A0B662* - ID_OUI_FROM_DATABASE=Acutvista Innovation Co., Ltd. - OUI:9067B5* ID_OUI_FROM_DATABASE=Alcatel-Lucent @@ -48515,9 +49889,6 @@ OUI:E43593* OUI:E0BC43* ID_OUI_FROM_DATABASE=C2 Microsystems, Inc. -OUI:7071BC* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:7884EE* ID_OUI_FROM_DATABASE=INDRA ESPACIO S.A. @@ -48890,9 +50261,6 @@ OUI:0026A4* OUI:00269E* ID_OUI_FROM_DATABASE=Quanta Computer Inc -OUI:002697* - ID_OUI_FROM_DATABASE=Cheetah Technologies, L.P. - OUI:002698* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -48914,9 +50282,6 @@ OUI:002678* OUI:002672* ID_OUI_FROM_DATABASE=AAMP of America -OUI:00266C* - ID_OUI_FROM_DATABASE=Inventec - OUI:00266B* ID_OUI_FROM_DATABASE=SHINE UNION ENTERPRISE LIMITED @@ -49661,9 +51026,6 @@ OUI:002207* OUI:002202* ID_OUI_FROM_DATABASE=Excito Elektronik i Skåne AB -OUI:0021FD* - ID_OUI_FROM_DATABASE=DSTA S.L. - OUI:0021F9* ID_OUI_FROM_DATABASE=WIRECOM Technologies @@ -49739,9 +51101,6 @@ OUI:001E2C* OUI:001E20* ID_OUI_FROM_DATABASE=Intertain Inc. -OUI:001E25* - ID_OUI_FROM_DATABASE=Intek Digital Inc - OUI:001E19* ID_OUI_FROM_DATABASE=GTRI @@ -50489,9 +51848,6 @@ OUI:001990* OUI:001989* ID_OUI_FROM_DATABASE=Sonitrol Corporation -OUI:001A45* - ID_OUI_FROM_DATABASE=GN Netcom as - OUI:001A3E* ID_OUI_FROM_DATABASE=Faster Technology LLC @@ -50735,9 +52091,6 @@ OUI:00186B* OUI:001870* ID_OUI_FROM_DATABASE=E28 Shanghai Limited -OUI:00185C* - ID_OUI_FROM_DATABASE=EDS Lab Pte Ltd - OUI:001863* ID_OUI_FROM_DATABASE=Veritech Electronics Limited @@ -50924,9 +52277,6 @@ OUI:00169B* OUI:0016A2* ID_OUI_FROM_DATABASE=CentraLite Systems, Inc. -OUI:00168F* - ID_OUI_FROM_DATABASE=GN Netcom as - OUI:001696* ID_OUI_FROM_DATABASE=QDI Technology (H.K.) Limited @@ -51611,9 +52961,6 @@ OUI:001160* OUI:001154* ID_OUI_FROM_DATABASE=Webpro Technologies Inc. -OUI:00115B* - ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. (ECS) - OUI:00114B* ID_OUI_FROM_DATABASE=Francotyp-Postalia GmbH @@ -52172,9 +53519,6 @@ OUI:000E3A* OUI:000E2D* ID_OUI_FROM_DATABASE=Hyundai Digital Technology Co.,Ltd. -OUI:000E2E* - ID_OUI_FROM_DATABASE=EDIMAX TECHNOLOGY CO., LTD. - OUI:000CEA* ID_OUI_FROM_DATABASE=aphona Kommunikationssysteme @@ -52238,9 +53582,6 @@ OUI:000C5C* OUI:000C61* ID_OUI_FROM_DATABASE=AC Tech corporation DBA Advanced Digital -OUI:000C49* - ID_OUI_FROM_DATABASE=Dangaard Telecom RTC Division A/S - OUI:000CBA* ID_OUI_FROM_DATABASE=Jamex, Inc. @@ -52880,9 +54221,6 @@ OUI:0008AC* OUI:0008A5* ID_OUI_FROM_DATABASE=Peninsula Systems Inc. -OUI:00089F* - ID_OUI_FROM_DATABASE=EFM Networks - OUI:000899* ID_OUI_FROM_DATABASE=Netbind, Inc. @@ -52937,18 +54275,12 @@ OUI:0008B8* OUI:00079B* ID_OUI_FROM_DATABASE=Aurora Networks -OUI:000795* - ID_OUI_FROM_DATABASE=Elitegroup Computer System Co. (ECS) - OUI:00078F* ID_OUI_FROM_DATABASE=Emkay Innovative Products OUI:000788* ID_OUI_FROM_DATABASE=Clipcomm, Inc. -OUI:000782* - ID_OUI_FROM_DATABASE=Oracle Corporation - OUI:000779* ID_OUI_FROM_DATABASE=Sungil Telecom Co., Ltd. @@ -53843,9 +55175,6 @@ OUI:00016B* OUI:000167* ID_OUI_FROM_DATABASE=HIOKI E.E. CORPORATION -OUI:00020E* - ID_OUI_FROM_DATABASE=ECI Telecom, Ltd - OUI:000215* ID_OUI_FROM_DATABASE=Cotas Computer Technology A/B @@ -54551,9 +55880,6 @@ OUI:00106F* OUI:0010C6* ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. -OUI:00104F* - ID_OUI_FROM_DATABASE=Oracle Corporation - OUI:0010DA* ID_OUI_FROM_DATABASE=Kollmorgen Corp @@ -54722,9 +56048,6 @@ OUI:0060B5* OUI:006027* ID_OUI_FROM_DATABASE=Superior Modular Products -OUI:0060DC* - ID_OUI_FROM_DATABASE=Toyo Network Systems & System Integration Co. LTD - OUI:0060C1* ID_OUI_FROM_DATABASE=WaveSpan Corporation @@ -55058,9 +56381,6 @@ OUI:00A0FA* OUI:00A014* ID_OUI_FROM_DATABASE=CSIR -OUI:00A045* - ID_OUI_FROM_DATABASE=PHOENIX CONTACT GMBH & CO. - OUI:00A064* ID_OUI_FROM_DATABASE=KVB/ANALECT @@ -55427,9 +56747,6 @@ OUI:00C02C* OUI:00C0ED* ID_OUI_FROM_DATABASE=US ARMY ELECTRONIC -OUI:00C0F0* - ID_OUI_FROM_DATABASE=KINGSTON TECHNOLOGY CORP. - OUI:00C0D1* ID_OUI_FROM_DATABASE=COMTREE TECHNOLOGY CORPORATION @@ -55886,9 +57203,6 @@ OUI:00006F* OUI:00005A* ID_OUI_FROM_DATABASE=SysKonnect GmbH -OUI:0000C9* - ID_OUI_FROM_DATABASE=Emulex Corporation - OUI:000023* ID_OUI_FROM_DATABASE=ABB INDUSTRIAL SYSTEMS AB @@ -56231,12 +57545,6 @@ OUI:70F1A1* OUI:6CFAA7* ID_OUI_FROM_DATABASE=AMPAK Technology, Inc. -OUI:0015C1* - ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. - -OUI:0019C5* - ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. - OUI:0024EF* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB @@ -56246,9 +57554,6 @@ OUI:6C0E0D* OUI:B4527D* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB -OUI:280DFC* - ID_OUI_FROM_DATABASE=Sony Corporation - OUI:E063E5* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB @@ -56459,54 +57764,9 @@ OUI:000DB6* OUI:18C086* ID_OUI_FROM_DATABASE=Broadcom -OUI:80ACAC* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:003146* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:000585* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:F01C2D* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:5C4527* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:44F477* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:CCE17F* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:3C6104* - ID_OUI_FROM_DATABASE=Juniper Networks - OUI:C03E0F* ID_OUI_FROM_DATABASE=BSkyB Ltd -OUI:54E032* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:78FE3D* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:F8C001* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:50C58D* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:0024DC* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:001F12* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:0019E2* - ID_OUI_FROM_DATABASE=Juniper Networks - OUI:0020D4* ID_OUI_FROM_DATABASE=Cabletron Systems, Inc. @@ -56684,9 +57944,6 @@ OUI:14C126* OUI:4C2578* ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:001EA4* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - OUI:001262* ID_OUI_FROM_DATABASE=Nokia Danmark A/S @@ -56696,21 +57953,375 @@ OUI:00174B* OUI:002547* ID_OUI_FROM_DATABASE=Nokia Danmark A/S -OUI:001DE9* - ID_OUI_FROM_DATABASE=Nokia Danmark A/S - OUI:001D3B* ID_OUI_FROM_DATABASE=Nokia Danmark A/S OUI:0014A7* ID_OUI_FROM_DATABASE=Nokia Danmark A/S +OUI:001EA4* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + OUI:001CD6* ID_OUI_FROM_DATABASE=Nokia Danmark A/S +OUI:001DE9* + ID_OUI_FROM_DATABASE=Nokia Danmark A/S + OUI:D099D5* ID_OUI_FROM_DATABASE=Alcatel-Lucent +OUI:DC0077* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:0060DC* + ID_OUI_FROM_DATABASE=NEC Magnus Communications,Ltd. + +OUI:9CAED3* + ID_OUI_FROM_DATABASE=Seiko Epson Corporation + +OUI:F45C89* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:A41588* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:8C3C4A* + ID_OUI_FROM_DATABASE=NAKAYO TELECOMMUNICATIONS,INC + +OUI:0021FD* + ID_OUI_FROM_DATABASE=LACROIX TRAFFIC S.A.U + +OUI:4CB44A* + ID_OUI_FROM_DATABASE=NANOWAVE Technologies Inc. + +OUI:78C3E9* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:9C5C8E* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:102AB3* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + +OUI:70884D* + ID_OUI_FROM_DATABASE=JAPAN RADIO CO., LTD. + +OUI:4C55CC* + ID_OUI_FROM_DATABASE=Zentri Pty Ltd + +OUI:BCEC5D* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:DC415F* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:30636B* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:280DFC* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:84683E* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:C88722* + ID_OUI_FROM_DATABASE=Lumenpulse + +OUI:FC1A11* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + +OUI:30A9DE* + ID_OUI_FROM_DATABASE=LG Innotek + +OUI:702526* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:903AA0* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:E0CDFD* + ID_OUI_FROM_DATABASE=Beijing E3Control Technology Co, LTD + +OUI:BC52B4* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:08BE77* + ID_OUI_FROM_DATABASE=Green Electronics + +OUI:208B37* + ID_OUI_FROM_DATABASE=Skyworth Digital Technology(Shenzhen) Co.,Ltd + +OUI:280C28* + ID_OUI_FROM_DATABASE=Unigen DataStorage Corporation + +OUI:980CA5* + ID_OUI_FROM_DATABASE=Motorola (Wuhan) Mobility Technologies Communication Co., Ltd. + +OUI:1CC035* + ID_OUI_FROM_DATABASE=PLANEX COMMUNICATIONS INC. + +OUI:34543C* + ID_OUI_FROM_DATABASE=TAKAOKA TOKO CO.,LTD. + +OUI:D49524* + ID_OUI_FROM_DATABASE=Clover Network, Inc. + +OUI:0034DA* + ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) + +OUI:9046A2* + ID_OUI_FROM_DATABASE=Tedipay UK Ltd + +OUI:6479A7* + ID_OUI_FROM_DATABASE=Phison Electronics Corp. + +OUI:0019C5* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:0015C1* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:C83870* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:288335* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:44783E* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:202D07* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:FC2FAA* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:D4612E* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:1C6758* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:0452C7* + ID_OUI_FROM_DATABASE=Bose Corporation + +OUI:E85659* + ID_OUI_FROM_DATABASE=Advanced-Connectek Inc. + +OUI:34E70B* + ID_OUI_FROM_DATABASE=Beijing HAN Networks Co., Ltd + +OUI:8801F2* + ID_OUI_FROM_DATABASE=Vitec System Engineering Inc. + +OUI:FC084A* + ID_OUI_FROM_DATABASE=FUJITSU LIMITED + +OUI:847BEB* + ID_OUI_FROM_DATABASE=Dell Inc. + +OUI:F8C96C* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:34BF90* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:D467E7* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:04C1B9* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:689361* + ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd. + +OUI:D4AD2D* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:48555F* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:04A316* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:98072D* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:A082AC* + ID_OUI_FROM_DATABASE=Linear DMS Solutions Sdn. Bhd. + +OUI:705A9E* + ID_OUI_FROM_DATABASE=Technicolor CH USA Inc. + +OUI:002697* + ID_OUI_FROM_DATABASE=Alpha Technologies Inc. + +OUI:4CB8B5* + ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd + +OUI:1CABC0* + ID_OUI_FROM_DATABASE=Hitron Technologies. Inc + +OUI:84E323* + ID_OUI_FROM_DATABASE=Green Wave Telecommunication SDN BHD + +OUI:7071BC* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:44650D* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + +OUI:E06995* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:D897BA* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:54D9E4* + ID_OUI_FROM_DATABASE=BRILLIANTTS CO., LTD + +OUI:E4F3F5* + ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. + +OUI:00185C* + ID_OUI_FROM_DATABASE=EDSLAB Technologies + +OUI:000E2E* + ID_OUI_FROM_DATABASE=Edimax Technology Co. Ltd. + +OUI:00020E* + ID_OUI_FROM_DATABASE=ECI Telecom Ltd. + +OUI:0000C9* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:00115B* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:000795* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:B8AEED* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:C03FD5* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:7427EA* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:00089F* + ID_OUI_FROM_DATABASE=EFM Networks + +OUI:042AE2* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:001A45* + ID_OUI_FROM_DATABASE=GN Netcom A/S + +OUI:00168F* + ID_OUI_FROM_DATABASE=GN Netcom A/S + +OUI:00104F* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:000782* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:083FBC* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:903809* + ID_OUI_FROM_DATABASE=Ericsson AB + +OUI:1C1B0D* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + +OUI:E42F56* + ID_OUI_FROM_DATABASE=OptoMET GmbH + +OUI:00A045* + ID_OUI_FROM_DATABASE=PHOENIX CONTACT Electronics GmbH + +OUI:00266C* + ID_OUI_FROM_DATABASE=INVENTEC Corporation + +OUI:001E25* + ID_OUI_FROM_DATABASE=INTEK DIGITAL + +OUI:A0B662* + ID_OUI_FROM_DATABASE=Acutvista Innovation Co., Ltd. + +OUI:00C0F0* + ID_OUI_FROM_DATABASE=Kingston Technology Company, Inc. + +OUI:4C8FA5* + ID_OUI_FROM_DATABASE=Jastec + +OUI:000C49* + ID_OUI_FROM_DATABASE=Dangaard Telecom Denmark A/S + +OUI:CCE17F* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:44F477* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:5C4527* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:F01C2D* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:F8C001* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:78FE3D* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:54E032* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:3C6104* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0019E2* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:001F12* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:0024DC* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:50C58D* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:000585* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:003146* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:80ACAC* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:BC7574* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:20A680* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:50DD4F* + ID_OUI_FROM_DATABASE=Automation Components, Inc + +OUI:904D4A* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + +OUI:7C79E8* + ID_OUI_FROM_DATABASE=PayRange Inc. + OUI:2C3996* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS @@ -57812,9 +59423,6 @@ OUI:98E848* OUI:A0F9E0* ID_OUI_FROM_DATABASE=VIVATEL COMPANY LIMITED -OUI:0C54B9* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:F8C372* ID_OUI_FROM_DATABASE=TSUZUKI DENKI @@ -58118,9 +59726,6 @@ OUI:3C8375* OUI:C8458F* ID_OUI_FROM_DATABASE=Wyler AG -OUI:74852A* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:149A10* ID_OUI_FROM_DATABASE=Microsoft Corporation @@ -58592,9 +60197,6 @@ OUI:E4F4C6* OUI:DC663A* ID_OUI_FROM_DATABASE=Apacer Technology Inc. -OUI:FCF152* - ID_OUI_FROM_DATABASE=Sony Corporation - OUI:B009D3* ID_OUI_FROM_DATABASE=Avizia @@ -58640,9 +60242,6 @@ OUI:D896E0* OUI:300D2A* ID_OUI_FROM_DATABASE=Zhejiang Wellcom Technology Co.,Ltd. -OUI:C4084A* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:8496D8* ID_OUI_FROM_DATABASE=Pace plc @@ -58688,9 +60287,6 @@ OUI:345D10* OUI:58E326* ID_OUI_FROM_DATABASE=Compass Technologies Inc. -OUI:F08CFB* - ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Tech.Co.,Ltd. - OUI:848DC7* ID_OUI_FROM_DATABASE=Cisco SPVTG @@ -58820,9 +60416,6 @@ OUI:E0DB88* OUI:D86194* ID_OUI_FROM_DATABASE=Objetivos y Sevicios de Valor Añadido -OUI:FCF8B7* - ID_OUI_FROM_DATABASE=TRONTEQ Electronic - OUI:589CFC* ID_OUI_FROM_DATABASE=FreeBSD Foundation @@ -58832,9 +60425,6 @@ OUI:602103* OUI:085DDD* ID_OUI_FROM_DATABASE=Mercury Corporation -OUI:88B1E1* - ID_OUI_FROM_DATABASE=AirTight Networks, Inc. - OUI:98349D* ID_OUI_FROM_DATABASE=Krauss Maffei Technologies GmbH @@ -58922,9 +60512,6 @@ OUI:9486D4* OUI:F89550* ID_OUI_FROM_DATABASE=Proton Products Chengdu Ltd -OUI:943BB1* - ID_OUI_FROM_DATABASE=KAONMEDIA - OUI:447BC4* ID_OUI_FROM_DATABASE=DualShine Technology(SZ)Co.,Ltd @@ -59618,9 +61205,6 @@ OUI:5809E5* OUI:74ECF1* ID_OUI_FROM_DATABASE=Acumen -OUI:649968* - ID_OUI_FROM_DATABASE=Elentec - OUI:6815D3* ID_OUI_FROM_DATABASE=Zaklady Elektroniki i Mechaniki Precyzyjnej R&G S.A. @@ -60161,9 +61745,6 @@ OUI:F4044C* OUI:1CBBA8* ID_OUI_FROM_DATABASE=OJSC Ufimskiy Zavod Promsvyaz -OUI:34AA99* - ID_OUI_FROM_DATABASE=Alcatel-Lucent - OUI:506028* ID_OUI_FROM_DATABASE=Xirrus Inc. @@ -60212,9 +61793,6 @@ OUI:10F96F* OUI:B01C91* ID_OUI_FROM_DATABASE=Elim Co -OUI:ECA86B* - ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEMS CO., LTD. - OUI:0CA2F4* ID_OUI_FROM_DATABASE=Chameleon Technology (UK) Limited @@ -60458,15 +62036,9 @@ OUI:4C0289* OUI:C0E54E* ID_OUI_FROM_DATABASE=DENX Computer Systems GmbH -OUI:386077* - ID_OUI_FROM_DATABASE=PEGATRON CORPORATION - OUI:E435FB* ID_OUI_FROM_DATABASE=Sabre Technology (Hull) Ltd -OUI:146308* - ID_OUI_FROM_DATABASE=JABIL CIRCUIT (SHANGHAI) LTD. - OUI:28BE9B* ID_OUI_FROM_DATABASE=Technicolor USA Inc. @@ -60497,9 +62069,6 @@ OUI:68F125* OUI:706F81* ID_OUI_FROM_DATABASE=Private -OUI:9CDF03* - ID_OUI_FROM_DATABASE=Harman/Becker Automotive Systems GmbH - OUI:30E4DB* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -61394,9 +62963,6 @@ OUI:94592D* OUI:9CC077* ID_OUI_FROM_DATABASE=PrintCounts, LLC -OUI:4487FC* - ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM CO., LTD. - OUI:A85BB0* ID_OUI_FROM_DATABASE=Shenzhen Dehoo Technology Co.,Ltd @@ -61814,9 +63380,6 @@ OUI:0026FE* OUI:0026F8* ID_OUI_FROM_DATABASE=Golden Highway Industry Development Co., Ltd. -OUI:0026F7* - ID_OUI_FROM_DATABASE=Infosys Technologies Ltd. - OUI:0026F1* ID_OUI_FROM_DATABASE=ProCurve Networking by HP @@ -62306,9 +63869,6 @@ OUI:00237A* OUI:002377* ID_OUI_FROM_DATABASE=Isotek Electronics Ltd -OUI:002378* - ID_OUI_FROM_DATABASE=GN Netcom A/S - OUI:002371* ID_OUI_FROM_DATABASE=SOAM Systel @@ -62396,9 +63956,6 @@ OUI:0021A5* OUI:00219F* ID_OUI_FROM_DATABASE=SATEL OY -OUI:002197* - ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEM - OUI:00218A* ID_OUI_FROM_DATABASE=Electronic Design and Manufacturing Company @@ -62978,9 +64535,6 @@ OUI:001BFF* OUI:001BFA* ID_OUI_FROM_DATABASE=G.i.N. mbH -OUI:001BF3* - ID_OUI_FROM_DATABASE=TRANSRADIO SenderSysteme Berlin AG - OUI:001BE3* ID_OUI_FROM_DATABASE=Health Hero Network, Inc. @@ -63758,9 +65312,6 @@ OUI:0015FB* OUI:0015F6* ID_OUI_FROM_DATABASE=SCIENCE AND ENGINEERING SERVICES, INC. -OUI:00177D* - ID_OUI_FROM_DATABASE=IDT International Limited - OUI:001782* ID_OUI_FROM_DATABASE=LoBenn Inc. @@ -65366,9 +66917,6 @@ OUI:000B2D* OUI:000ABB* ID_OUI_FROM_DATABASE=Taiwan Secom Co,. Ltd -OUI:000AC2* - ID_OUI_FROM_DATABASE=FiberHome Telecommunication Technologies CO.,LTD - OUI:000AC7* ID_OUI_FROM_DATABASE=Unication Group @@ -65996,9 +67544,6 @@ OUI:0005AB* OUI:000588* ID_OUI_FROM_DATABASE=Sensoria Corp. -OUI:000594* - ID_OUI_FROM_DATABASE=HMS Technology Center Ravensburg GmbH - OUI:00058E* ID_OUI_FROM_DATABASE=Flextronics International GmbH & Co. Nfg. KG @@ -66602,9 +68147,6 @@ OUI:000168* OUI:000174* ID_OUI_FROM_DATABASE=CyberOptics Corporation -OUI:00015D* - ID_OUI_FROM_DATABASE=Oracle Corporation - OUI:000164* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -66968,9 +68510,6 @@ OUI:00D012* OUI:00D092* ID_OUI_FROM_DATABASE=GLENAYRE WESTERN MULTIPLEX -OUI:00D0EC* - ID_OUI_FROM_DATABASE=NAKAYO TELECOMMUNICATIONS, INC - OUI:00D0C5* ID_OUI_FROM_DATABASE=COMPUTATIONAL SYSTEMS, INC. @@ -67100,9 +68639,6 @@ OUI:009019* OUI:0090DC* ID_OUI_FROM_DATABASE=TECO INFORMATION SYSTEMS -OUI:00D0A2* - ID_OUI_FROM_DATABASE=INTEGRATED DEVICE - OUI:00D0AE* ID_OUI_FROM_DATABASE=ORESIS COMMUNICATIONS, INC. @@ -67196,9 +68732,6 @@ OUI:00900A* OUI:00904E* ID_OUI_FROM_DATABASE=DELEM BV -OUI:009050* - ID_OUI_FROM_DATABASE=TELESTE OY - OUI:00904A* ID_OUI_FROM_DATABASE=CONCUR SYSTEM TECHNOLOGIES @@ -67406,9 +68939,6 @@ OUI:009020* OUI:009065* ID_OUI_FROM_DATABASE=FINISAR CORPORATION -OUI:001035* - ID_OUI_FROM_DATABASE=ELITEGROUP COMPUTER SYSTEMS CO., LTD - OUI:001053* ID_OUI_FROM_DATABASE=COMPUTER TECHNOLOGY CORP. @@ -67508,9 +69038,6 @@ OUI:001008* OUI:0010CC* ID_OUI_FROM_DATABASE=CLP COMPUTER LOGISTIK PLANUNG GmbH -OUI:00109B* - ID_OUI_FROM_DATABASE=Emulex Corporation - OUI:001094* ID_OUI_FROM_DATABASE=Performance Analysis Broadband, Spirent plc @@ -67715,9 +69242,6 @@ OUI:0060AF* OUI:00601F* ID_OUI_FROM_DATABASE=STALLION TECHNOLOGIES -OUI:0060B1* - ID_OUI_FROM_DATABASE=INPUT/OUTPUT, INC. - OUI:00608F* ID_OUI_FROM_DATABASE=TEKRAM TECHNOLOGY CO., LTD. @@ -67811,9 +69335,6 @@ OUI:00E011* OUI:00E021* ID_OUI_FROM_DATABASE=FREEGATE CORP. -OUI:00E0D5* - ID_OUI_FROM_DATABASE=Emulex Corporation - OUI:00E0AB* ID_OUI_FROM_DATABASE=DIMAT S.A. @@ -67937,9 +69458,6 @@ OUI:0020A7* OUI:0020DA* ID_OUI_FROM_DATABASE=Alcatel North America ESD -OUI:0020F2* - ID_OUI_FROM_DATABASE=Oracle Corporation - OUI:002005* ID_OUI_FROM_DATABASE=SIMPLE TECHNOLOGY @@ -68057,9 +69575,6 @@ OUI:0020A2* OUI:002098* ID_OUI_FROM_DATABASE=HECTRONIC AB -OUI:00208F* - ID_OUI_FROM_DATABASE=ECI TELECOM LTD. - OUI:002065* ID_OUI_FROM_DATABASE=SUPERNET NETWORKING INC. @@ -68087,9 +69602,6 @@ OUI:0020E8* OUI:00204F* ID_OUI_FROM_DATABASE=DEUTSCHE AEROSPACE AG -OUI:002088* - ID_OUI_FROM_DATABASE=GLOBAL VILLAGE COMMUNICATION - OUI:00202E* ID_OUI_FROM_DATABASE=DAYSTAR DIGITAL @@ -68567,9 +70079,6 @@ OUI:008059* OUI:00806B* ID_OUI_FROM_DATABASE=SCHMID TELECOMMUNICATION -OUI:0080B8* - ID_OUI_FROM_DATABASE=B.U.G. MORISEIKI, INCORPORATED - OUI:00802C* ID_OUI_FROM_DATABASE=THE SAGE GROUP PLC @@ -68795,9 +70304,6 @@ OUI:080042* OUI:026086* ID_OUI_FROM_DATABASE=LOGIC REPLACEMENT TECH. LTD. -OUI:08000D* - ID_OUI_FROM_DATABASE=INTERNATIONAL COMPUTERS LTD. - OUI:00DD05* ID_OUI_FROM_DATABASE=UNGERMANN-BASS INC. @@ -69149,9 +70655,6 @@ OUI:ACD074* OUI:D05349* ID_OUI_FROM_DATABASE=Liteon Technology Corporation -OUI:0025DC* - ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd - OUI:00BB3A* ID_OUI_FROM_DATABASE=Private @@ -69167,9 +70670,6 @@ OUI:00014A* OUI:001CA4* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB -OUI:00248D* - ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. - OUI:002345* ID_OUI_FROM_DATABASE=Sony Mobile Communications AB @@ -69350,54 +70850,18 @@ OUI:001BA9* OUI:0011B6* ID_OUI_FROM_DATABASE=Open Systems International -OUI:002283* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:2C6BF5* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:64649B* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:541E56* - ID_OUI_FROM_DATABASE=Juniper Networks - OUI:E03E44* ID_OUI_FROM_DATABASE=Broadcom OUI:D40129* ID_OUI_FROM_DATABASE=Broadcom -OUI:544B8C* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:84B59C* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:100E7E* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:288A1C* - ID_OUI_FROM_DATABASE=Juniper Networks - OUI:FCB698* ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd. -OUI:3C94D5* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:B0A86E* - ID_OUI_FROM_DATABASE=Juniper Networks - -OUI:AC4BC8* - ID_OUI_FROM_DATABASE=Juniper Networks - OUI:00E03A* ID_OUI_FROM_DATABASE=Cabletron Systems, Inc. -OUI:002159* - ID_OUI_FROM_DATABASE=Juniper Networks - OUI:000117* ID_OUI_FROM_DATABASE=Canal + @@ -69605,9 +71069,6 @@ OUI:00BD3A* OUI:A04E04* ID_OUI_FROM_DATABASE=Nokia Corporation -OUI:001CFC* - ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd - OUI:001370* ID_OUI_FROM_DATABASE=Nokia Danmark A/S @@ -69646,3 +71107,339 @@ OUI:0026CC* OUI:240B0A* ID_OUI_FROM_DATABASE=Palo Alto Networks + +OUI:C4E510* + ID_OUI_FROM_DATABASE=Mechatro, Inc. + +OUI:74C330* + ID_OUI_FROM_DATABASE=SHENZHEN FAST TECHNOLOGIES CO.,LTD + +OUI:403F8C* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:14C3C2* + ID_OUI_FROM_DATABASE=K.A. Schmersal GmbH & Co. KG + +OUI:10785B* + ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc + +OUI:20768F* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:C0C522* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + +OUI:9C5CF9* + ID_OUI_FROM_DATABASE=Sony Mobile Communications AB + +OUI:88A084* + ID_OUI_FROM_DATABASE=Formation Data Systems + +OUI:0025DC* + ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd + +OUI:001CFC* + ID_OUI_FROM_DATABASE=Sumitomo Electric Industries,Ltd + +OUI:00D0EC* + ID_OUI_FROM_DATABASE=NAKAYO TELECOMMUNICATIONS,INC + +OUI:8CC661* + ID_OUI_FROM_DATABASE=Current, powered by GE + +OUI:009050* + ID_OUI_FROM_DATABASE=Teleste Corporation + +OUI:BC44B0* + ID_OUI_FROM_DATABASE=Elastifile + +OUI:7864E6* + ID_OUI_FROM_DATABASE=Green Motive Technology Limited + +OUI:743E2B* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:C0CCF8* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:80ED2C* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:E8B2AC* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:FCF152* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:0080B8* + ID_OUI_FROM_DATABASE=DMG MORI B.U.G. CO., LTD. + +OUI:8489AD* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:40B688* + ID_OUI_FROM_DATABASE=LEGIC Identsystems AG + +OUI:A09D91* + ID_OUI_FROM_DATABASE=SoundBridge + +OUI:30785C* + ID_OUI_FROM_DATABASE=Partow Tamas Novin (Parman) + +OUI:0C54B9* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:C4084A* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:34AA99* + ID_OUI_FROM_DATABASE=Alcatel-Lucent + +OUI:441102* + ID_OUI_FROM_DATABASE=EDMI Europe Ltd + +OUI:2C21D7* + ID_OUI_FROM_DATABASE=IMAX Corporation + +OUI:0026F7* + ID_OUI_FROM_DATABASE=Nivetti Systems Pvt. Ltd. + +OUI:24C3F9* + ID_OUI_FROM_DATABASE=Securitas Direct AB + +OUI:DC4D23* + ID_OUI_FROM_DATABASE=MRV Comunications + +OUI:085BDA* + ID_OUI_FROM_DATABASE=CliniCare LTD + +OUI:00248D* + ID_OUI_FROM_DATABASE=Sony Computer Entertainment Inc. + +OUI:0C5A9E* + ID_OUI_FROM_DATABASE=Wi-SUN Alliance + +OUI:00C164* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:10D0AB* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:C4BED4* + ID_OUI_FROM_DATABASE=Avaya Inc + +OUI:98E7F5* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:24BCF8* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:042DB4* + ID_OUI_FROM_DATABASE=First Property (Beijing) Co., Ltd Modern MOMA Branch + +OUI:202DF8* + ID_OUI_FROM_DATABASE=Digital Media Cartridge Ltd. + +OUI:008A96* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:007888* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:98DED0* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:30FC68* + ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. + +OUI:5CCA1A* + ID_OUI_FROM_DATABASE=Microsoft Mobile Oy + +OUI:000594* + ID_OUI_FROM_DATABASE=HMS Industrial Networks + +OUI:000AC2* + ID_OUI_FROM_DATABASE=Wuhan FiberHome Digital Technology Co.,Ltd. + +OUI:F08CFB* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:FCF8B7* + ID_OUI_FROM_DATABASE=TRONTEQ Electronic + +OUI:D4F207* + ID_OUI_FROM_DATABASE=DIAODIAO(Beijing)Technology CO.,Ltd + +OUI:D4883F* + ID_OUI_FROM_DATABASE=HDPRO CO., LTD. + +OUI:FC0F4B* + ID_OUI_FROM_DATABASE=Texas Instruments + +OUI:A86AC1* + ID_OUI_FROM_DATABASE=HanbitEDS Co., Ltd. + +OUI:40163B* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:001BF3* + ID_OUI_FROM_DATABASE=TRANSRADIO SenderSysteme Berlin AG + +OUI:E0071B* + ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise + +OUI:88B1E1* + ID_OUI_FROM_DATABASE=Mojo Networks, Inc. + +OUI:74DFBF* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + +OUI:FC3F7C* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:608334* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:84AD58* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:746FF7* + ID_OUI_FROM_DATABASE=Wistron Neweb Corporation + +OUI:B01BD2* + ID_OUI_FROM_DATABASE=Le Shi Zhi Xin Electronic Technology (Tianjin) Limited + +OUI:386077* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:74852A* + ID_OUI_FROM_DATABASE=PEGATRON CORPORATION + +OUI:60B4F7* + ID_OUI_FROM_DATABASE=Plume Design Inc + +OUI:A4D8CA* + ID_OUI_FROM_DATABASE=HONG KONG WATER WORLD TECHNOLOGY CO. LIMITED + +OUI:ECA86B* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:4487FC* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:002197* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:649968* + ID_OUI_FROM_DATABASE=Elentec + +OUI:00109B* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:00E0D5* + ID_OUI_FROM_DATABASE=Emulex Corporation + +OUI:001035* + ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. + +OUI:9CDF03* + ID_OUI_FROM_DATABASE=Harman/Becker Automotive Systems GmbH + +OUI:00208F* + ID_OUI_FROM_DATABASE=ECI Telecom Ltd. + +OUI:F0407B* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + +OUI:94885E* + ID_OUI_FROM_DATABASE=Surfilter Network Technology Co., Ltd. + +OUI:002378* + ID_OUI_FROM_DATABASE=GN Netcom A/S + +OUI:002088* + ID_OUI_FROM_DATABASE=GLOBAL VILLAGE COMMUNICATION + +OUI:BC6A44* + ID_OUI_FROM_DATABASE=Commend International GmbH + +OUI:90C7D8* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:F8DA0C* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. + +OUI:0020F2* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:00015D* + ID_OUI_FROM_DATABASE=Oracle Corporation + +OUI:943BB1* + ID_OUI_FROM_DATABASE=Kaonmedia CO., LTD. + +OUI:146308* + ID_OUI_FROM_DATABASE=JABIL CIRCUIT (SHANGHAI) LTD. + +OUI:08000D* + ID_OUI_FROM_DATABASE=International Computers, Ltd + +OUI:00D0A2* + ID_OUI_FROM_DATABASE=INTEGRATED DEVICE + +OUI:0060B1* + ID_OUI_FROM_DATABASE=Input/Output, Inc. + +OUI:00177D* + ID_OUI_FROM_DATABASE=IDT Technology Limited + +OUI:AC4BC8* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:B0A86E* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:3C94D5* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:288A1C* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:100E7E* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:84B59C* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:544B8C* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:541E56* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:64649B* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:2C6BF5* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:002283* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:F4CC55* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:EC13DB* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:002159* + ID_OUI_FROM_DATABASE=Juniper Networks + +OUI:5C70A3* + ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) + +OUI:3497F6* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + +OUI:50680A* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD diff --git a/hwdb/20-bluetooth-vendor-product.hwdb b/hwdb/20-bluetooth-vendor-product.hwdb index a825e744e..516abad24 100644 --- a/hwdb/20-bluetooth-vendor-product.hwdb +++ b/hwdb/20-bluetooth-vendor-product.hwdb @@ -1654,7 +1654,7 @@ bluetooth:v0224* ID_VENDOR_FROM_DATABASE=Comarch SA bluetooth:v0225* - ID_VENDOR_FROM_DATABASE=Nestl Nespresso S.A. + ID_VENDOR_FROM_DATABASE=Nestlé Nespresso S.A. bluetooth:v0226* ID_VENDOR_FROM_DATABASE=Merlinia A/S @@ -1780,7 +1780,7 @@ bluetooth:v024E* ID_VENDOR_FROM_DATABASE=Microtronics Engineering GmbH bluetooth:v024F* - ID_VENDOR_FROM_DATABASE=Schneider Schreibgerte GmbH + ID_VENDOR_FROM_DATABASE=Schneider Schreibgeräte GmbH bluetooth:v0250* ID_VENDOR_FROM_DATABASE=Sapphire Circuits LLC @@ -1897,7 +1897,7 @@ bluetooth:v0275* ID_VENDOR_FROM_DATABASE=Geotab bluetooth:v0276* - ID_VENDOR_FROM_DATABASE=E.G.O. Elektro-Gertebau GmbH + ID_VENDOR_FROM_DATABASE=E.G.O. Elektro-Gerätebau GmbH bluetooth:v0277* ID_VENDOR_FROM_DATABASE=bewhere inc @@ -2066,3 +2066,168 @@ bluetooth:v02AD* bluetooth:v02AE* ID_VENDOR_FROM_DATABASE=WeatherFlow, Inc. + +bluetooth:v02AF* + ID_VENDOR_FROM_DATABASE=Technicolor USA Inc. + +bluetooth:v02B0* + ID_VENDOR_FROM_DATABASE=Bestechnic(Shanghai),Ltd + +bluetooth:v02B1* + ID_VENDOR_FROM_DATABASE=Raden Inc + +bluetooth:v02B2* + ID_VENDOR_FROM_DATABASE=JouZen Oy + +bluetooth:v02B3* + ID_VENDOR_FROM_DATABASE=CLABER S.P.A. + +bluetooth:v02B4* + ID_VENDOR_FROM_DATABASE=Hyginex, Inc. + +bluetooth:v02B5* + ID_VENDOR_FROM_DATABASE=HANSHIN ELECTRIC RAILWAY CO.,LTD. + +bluetooth:v02B6* + ID_VENDOR_FROM_DATABASE=Schneider Electric + +bluetooth:v02B7* + ID_VENDOR_FROM_DATABASE=Oort Technologies LLC + +bluetooth:v02B8* + ID_VENDOR_FROM_DATABASE=Chrono Therapeutics + +bluetooth:v02B9* + ID_VENDOR_FROM_DATABASE=Rinnai Corporation + +bluetooth:v02BA* + ID_VENDOR_FROM_DATABASE=Swissprime Technologies AG + +bluetooth:v02BB* + ID_VENDOR_FROM_DATABASE=Koha.,Co.Ltd + +bluetooth:v02BC* + ID_VENDOR_FROM_DATABASE=Genevac Ltd + +bluetooth:v02BD* + ID_VENDOR_FROM_DATABASE=Chemtronics + +bluetooth:v02BE* + ID_VENDOR_FROM_DATABASE=Seguro Technology Sp. z o.o. + +bluetooth:v02BF* + ID_VENDOR_FROM_DATABASE=Redbird Flight Simulations + +bluetooth:v02C0* + ID_VENDOR_FROM_DATABASE=Dash Robotics + +bluetooth:v02C1* + ID_VENDOR_FROM_DATABASE=LINE Corporation + +bluetooth:v02C2* + ID_VENDOR_FROM_DATABASE=Guillemot Corporation + +bluetooth:v02C3* + ID_VENDOR_FROM_DATABASE=Techtronic Power Tools Technology Limited + +bluetooth:v02C4* + ID_VENDOR_FROM_DATABASE=Wilson Sporting Goods + +bluetooth:v02C5* + ID_VENDOR_FROM_DATABASE=Lenovo (Singapore) Pte Ltd. ( 联想(新加坡) ) + +bluetooth:v02C6* + ID_VENDOR_FROM_DATABASE=Ayatan Sensors + +bluetooth:v02C7* + ID_VENDOR_FROM_DATABASE=Electronics Tomorrow Limited + +bluetooth:v02C8* + ID_VENDOR_FROM_DATABASE=VASCO Data Security International, Inc. + +bluetooth:v02C9* + ID_VENDOR_FROM_DATABASE=PayRange Inc. + +bluetooth:v02CA* + ID_VENDOR_FROM_DATABASE=ABOV Semiconductor + +bluetooth:v02CB* + ID_VENDOR_FROM_DATABASE=AINA-Wireless Inc. + +bluetooth:v02CC* + ID_VENDOR_FROM_DATABASE=Eijkelkamp Soil & Water + +bluetooth:v02CD* + ID_VENDOR_FROM_DATABASE=BMA ergonomics b.v. + +bluetooth:v02CE* + ID_VENDOR_FROM_DATABASE=Teva Branded Pharmaceutical Products R&D, Inc. + +bluetooth:v02CF* + ID_VENDOR_FROM_DATABASE=Anima + +bluetooth:v02D0* + ID_VENDOR_FROM_DATABASE=3M + +bluetooth:v02D1* + ID_VENDOR_FROM_DATABASE=Empatica Srl + +bluetooth:v02D2* + ID_VENDOR_FROM_DATABASE=Afero, Inc. + +bluetooth:v02D3* + ID_VENDOR_FROM_DATABASE=Powercast Corporation + +bluetooth:v02D4* + ID_VENDOR_FROM_DATABASE=Secuyou ApS + +bluetooth:v02D5* + ID_VENDOR_FROM_DATABASE=OMRON Corporation + +bluetooth:v02D6* + ID_VENDOR_FROM_DATABASE=Send Solutions + +bluetooth:v02D7* + ID_VENDOR_FROM_DATABASE=NIPPON SYSTEMWARE CO.,LTD. + +bluetooth:v02D8* + ID_VENDOR_FROM_DATABASE=Neosfar + +bluetooth:v02D9* + ID_VENDOR_FROM_DATABASE=Fliegl Agrartechnik GmbH + +bluetooth:v02DA* + ID_VENDOR_FROM_DATABASE=Gilvader + +bluetooth:v02DB* + ID_VENDOR_FROM_DATABASE=Digi International Inc (R) + +bluetooth:v02DC* + ID_VENDOR_FROM_DATABASE=DeWalch Technologies, Inc. + +bluetooth:v02DD* + ID_VENDOR_FROM_DATABASE=Flint Rehabilitation Devices, LLC + +bluetooth:v02DE* + ID_VENDOR_FROM_DATABASE=Samsung SDS Co., Ltd. + +bluetooth:v02DF* + ID_VENDOR_FROM_DATABASE=Blur Product Development + +bluetooth:v02E0* + ID_VENDOR_FROM_DATABASE=University of Michigan + +bluetooth:v02E1* + ID_VENDOR_FROM_DATABASE=Victron Energy BV + +bluetooth:v02E2* + ID_VENDOR_FROM_DATABASE=NTT docomo + +bluetooth:v02E3* + ID_VENDOR_FROM_DATABASE=Carmanah Technologies Corp. + +bluetooth:v02E4* + ID_VENDOR_FROM_DATABASE=Bytestorm Ltd. + +bluetooth:v02E5* + ID_VENDOR_FROM_DATABASE=Espressif Incorporated ( 乐鑫信息科技(上海)有限公司 ) diff --git a/hwdb/20-pci-vendor-model.hwdb b/hwdb/20-pci-vendor-model.hwdb index 695409086..91c784b89 100644 --- a/hwdb/20-pci-vendor-model.hwdb +++ b/hwdb/20-pci-vendor-model.hwdb @@ -1016,6 +1016,9 @@ pci:v00001000d0000005Fsv00001028sd00001F4D* pci:v00001000d0000005Fsv00001054sd0000306A* ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3008 [Fury] (SAS 3004 iMR ROMB) +pci:v00001000d0000005Fsv00001D49sd000004DB* + ID_MODEL_FROM_DATABASE=MegaRAID SAS-3 3008 [Fury] (ServeRAID M1210 SAS/SATA Controller) + pci:v00001000d00000060* ID_MODEL_FROM_DATABASE=MegaRAID SAS 1078 @@ -4496,6 +4499,24 @@ pci:v00001002d0000665Fsv00001682sd00007360* pci:v00001002d00006660* ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] +pci:v00001002d00006660sv00001028sd000005EA* + ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] (Radeon HD 8670M) + +pci:v00001002d00006660sv00001028sd000006BF* + ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] (Radeon R5 M335) + +pci:v00001002d00006660sv0000103Csd00001970* + ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] (Radeon HD 8670M) + +pci:v00001002d00006660sv0000103Csd000080BE* + ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] (Radeon R5 M330) + +pci:v00001002d00006660sv0000103Csd00008136* + ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] (Radeon R5 M330) + +pci:v00001002d00006660sv000017AAsd00003804* + ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] (Radeon R5 M330) + pci:v00001002d00006660sv000017AAsd00003809* ID_MODEL_FROM_DATABASE=Sun XT [Radeon HD 8670A/8670M/8690M / R5 M330] (Radeon R5 M330) @@ -8199,7 +8220,10 @@ pci:v00001002d0000692F* ID_MODEL_FROM_DATABASE=Tonga XTV GL [FirePro S7150V] pci:v00001002d00006938* - ID_MODEL_FROM_DATABASE=Amethyst XT [Radeon R9 M295X Mac Edition] + ID_MODEL_FROM_DATABASE=Tonga XT / Amethyst XT [Radeon R9 380X / R9 M295X Mac Edition] + +pci:v00001002d00006938sv0000174Bsd0000E308* + ID_MODEL_FROM_DATABASE=Tonga XT / Amethyst XT [Radeon R9 380X / R9 M295X Mac Edition] (Radeon R9 380X Nitro 4G D5) pci:v00001002d00006939* ID_MODEL_FROM_DATABASE=Tonga PRO [Radeon R9 285/380] @@ -8207,6 +8231,9 @@ pci:v00001002d00006939* pci:v00001002d00006939sv0000148Csd00009380* ID_MODEL_FROM_DATABASE=Tonga PRO [Radeon R9 285/380] (Radeon R9 380) +pci:v00001002d00006939sv0000174Bsd0000E308* + ID_MODEL_FROM_DATABASE=Tonga PRO [Radeon R9 285/380] (Radeon R9 380 Nitro 4G D5) + pci:v00001002d0000700F* ID_MODEL_FROM_DATABASE=RS100 AGP Bridge @@ -9437,6 +9464,12 @@ pci:v00001002d00009918* pci:v00001002d00009919* ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7500G] +pci:v00001002d00009920* + ID_MODEL_FROM_DATABASE=Liverpool Graphics + +pci:v00001002d00009921* + ID_MODEL_FROM_DATABASE=Liverpool HDMI/DP Audio Controller + pci:v00001002d00009990* ID_MODEL_FROM_DATABASE=Trinity [Radeon HD 7520G] @@ -9575,6 +9608,12 @@ pci:v00001002d0000AAC0* pci:v00001002d0000AAC8* ID_MODEL_FROM_DATABASE=Hawaii HDMI Audio +pci:v00001002d0000AAD8* + ID_MODEL_FROM_DATABASE=Tonga HDMI Audio [Radeon R9 285/380] + +pci:v00001002d0000AAD8sv0000174Bsd0000AAD8* + ID_MODEL_FROM_DATABASE=Tonga HDMI Audio [Radeon R9 285/380] (Radeon R9 285/380 HDMI Audio) + pci:v00001002d0000AC00* ID_MODEL_FROM_DATABASE=Theater 600 Pro @@ -10820,7 +10859,7 @@ pci:v00001014d0000034Asv00001014sd000004C7* pci:v00001014d0000034Asv00001014sd000004C8* ID_MODEL_FROM_DATABASE=PCI-E IPR SAS Adapter (ASIC) (PCIe3 x 8 Cache SAS RAID Internal Adapter 6GB(2CD2)) -pci:v00001014d0000034Asv00001014sd00000C49* +pci:v00001014d0000034Asv00001014sd000004C9* ID_MODEL_FROM_DATABASE=PCI-E IPR SAS Adapter (ASIC) (PCIe3 x 8 Cache SAS RAID Internal Adapter 6GB(2CCD)) pci:v00001014d0000044B* @@ -10829,6 +10868,15 @@ pci:v00001014d0000044B* pci:v00001014d000004AA* ID_MODEL_FROM_DATABASE=Flash Adapter 90 (PCIe2 0.9TB) +pci:v00001014d000004DA* + ID_MODEL_FROM_DATABASE=PCI-E IPR SAS+ Adapter (ASIC) + +pci:v00001014d000004DAsv00001014sd000004FB* + ID_MODEL_FROM_DATABASE=PCI-E IPR SAS+ Adapter (ASIC) (PCIe3 x16 20GB Cache 12Gb Quad SAS RAID+ Adapter(580B)) + +pci:v00001014d000004DAsv00001014sd000004FC* + ID_MODEL_FROM_DATABASE=PCI-E IPR SAS+ Adapter (ASIC) (PCIe3 x8 12Gb Quad SAS RAID+ Adapter(580A)) + pci:v00001014d00003022* ID_MODEL_FROM_DATABASE=QLA3022 Network Adapter @@ -11165,6 +11213,15 @@ pci:v00001022d00001423* pci:v00001022d00001426* ID_MODEL_FROM_DATABASE=Family 15h (Models 30h-3fh) Processor Root Port +pci:v00001022d00001436* + ID_MODEL_FROM_DATABASE=Liverpool Processor Root Complex + +pci:v00001022d00001437* + ID_MODEL_FROM_DATABASE=Liverpool I/O Memory Management Unit + +pci:v00001022d00001438* + ID_MODEL_FROM_DATABASE=Liverpool Processor Root Port + pci:v00001022d00001439* ID_MODEL_FROM_DATABASE=Family 16h Processor Functions 5:1 @@ -15353,6 +15410,9 @@ pci:v0000104Cd0000803Bsv0000103Csd0000309F* pci:v0000104Cd0000803Bsv0000103Csd000030A3* ID_MODEL_FROM_DATABASE=5-in-1 Multimedia Card Reader (SD/MMC/MS/MS PRO/xD) (Compaq nw8440) +pci:v0000104Cd0000803Bsv0000104Dsd00008212* + ID_MODEL_FROM_DATABASE=5-in-1 Multimedia Card Reader (SD/MMC/MS/MS PRO/xD) (VAIO VGN-N21E) + pci:v0000104Cd0000803Bsv0000104Dsd0000902D* ID_MODEL_FROM_DATABASE=5-in-1 Multimedia Card Reader (SD/MMC/MS/MS PRO/xD) (VAIO VGN-NR120E) @@ -15446,6 +15506,9 @@ pci:v0000104Cd00008400sv000016ABsd00008501* pci:v0000104Cd00008401* ID_MODEL_FROM_DATABASE=ACX 100 22Mbps Wireless Interface +pci:v0000104Cd00008888* + ID_MODEL_FROM_DATABASE=Multicore DSP+ARM KeyStone II SOC + pci:v0000104Cd00009000* ID_MODEL_FROM_DATABASE=Wireless Interface (of unknown type) @@ -15812,6 +15875,30 @@ pci:v0000104Dd0000808A* pci:v0000104Dd000081CE* ID_MODEL_FROM_DATABASE=SxS Pro memory card +pci:v0000104Dd0000908F* + ID_MODEL_FROM_DATABASE=Aeolia ACPI + +pci:v0000104Dd0000909E* + ID_MODEL_FROM_DATABASE=Aeolia Ethernet Controller (Marvell Yukon 2 Family) + +pci:v0000104Dd0000909F* + ID_MODEL_FROM_DATABASE=Aeolia SATA AHCI Controller + +pci:v0000104Dd000090A0* + ID_MODEL_FROM_DATABASE=Aeolia SD/MMC Host Controller + +pci:v0000104Dd000090A1* + ID_MODEL_FROM_DATABASE=Aeolia PCI Express Glue and Miscellaneous Devices + +pci:v0000104Dd000090A2* + ID_MODEL_FROM_DATABASE=Aeolia DMA Controller + +pci:v0000104Dd000090A3* + ID_MODEL_FROM_DATABASE=Aeolia Memory (DDR3/SPM) + +pci:v0000104Dd000090A4* + ID_MODEL_FROM_DATABASE=Aeolia USB 3.0 xHCI Host Controller + pci:v0000104E* ID_VENDOR_FROM_DATABASE=Oak Technology, Inc @@ -17247,10 +17334,10 @@ pci:v00001077d00001664* ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) pci:v00001077d00001664sv00001077sd0000E4F1* - ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45412H 40GbE Adapter (SR-IOV VF)) + ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45462H 40GbE Adapter (SR-IOV VF)) pci:v00001077d00001664sv00001077sd0000E4F2* - ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45412H 40GbE Adapter (SR-IOV VF)) + ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45461H 40GbE Adapter (SR-IOV VF)) pci:v00001077d00001664sv00001077sd0000E4F3* ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45412H 40GbE Adapter (SR-IOV VF)) @@ -17259,10 +17346,10 @@ pci:v00001077d00001664sv00001077sd0000E4F4* ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45411H 40GbE Adapter (SR-IOV VF)) pci:v00001077d00001664sv00001077sd0000E4F6* - ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45411H 25GbE Adapter (SR-IOV VF)) + ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45211H 25GbE Adapter (SR-IOV VF)) pci:v00001077d00001664sv00001077sd0000E4F7* - ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45412H 25GbE Adapter (SR-IOV VF)) + ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45212H 25GbE Adapter (SR-IOV VF)) pci:v00001077d00001664sv00001077sd0000E4F8* ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45611H 100GbE Adapter (SR-IOV VF)) @@ -17273,9 +17360,21 @@ pci:v00001077d00002020* pci:v00001077d00002031* ID_MODEL_FROM_DATABASE=ISP8324-based 16Gb Fibre Channel to PCI Express Adapter +pci:v00001077d00002031sv0000103Csd000017E7* + ID_MODEL_FROM_DATABASE=ISP8324-based 16Gb Fibre Channel to PCI Express Adapter (HP SN1000Q 16Gb Single Port Fibre Channel Adapter) + +pci:v00001077d00002031sv0000103Csd000017E8* + ID_MODEL_FROM_DATABASE=ISP8324-based 16Gb Fibre Channel to PCI Express Adapter (HP SN1000Q 16Gb Dual Port Fibre Channel Adapter) + +pci:v00001077d00002031sv0000103Csd00001939* + ID_MODEL_FROM_DATABASE=ISP8324-based 16Gb Fibre Channel to PCI Express Adapter (HP QMH2672 16Gb Dual Port Fibre Channel Adapter) + pci:v00001077d00002031sv0000103Csd00008002* ID_MODEL_FROM_DATABASE=ISP8324-based 16Gb Fibre Channel to PCI Express Adapter (3830C 16G Fibre Channel Host Bus Adapter) +pci:v00001077d00002071* + ID_MODEL_FROM_DATABASE=ISP2714-based 16/32Gb Fibre Channel to PCIe Adapter + pci:v00001077d00002100* ID_MODEL_FROM_DATABASE=QLA2100 64-bit Fibre Channel Adapter @@ -17288,6 +17387,15 @@ pci:v00001077d00002200* pci:v00001077d00002200sv00001077sd00000002* ID_MODEL_FROM_DATABASE=QLA2200 64-bit Fibre Channel Adapter (QLA2200) +pci:v00001077d00002261* + ID_MODEL_FROM_DATABASE=ISP2722-based 16/32Gb Fibre Channel to PCIe Adapter + +pci:v00001077d00002261sv00001590sd000000F9* + ID_MODEL_FROM_DATABASE=ISP2722-based 16/32Gb Fibre Channel to PCIe Adapter (HPE StoreFabric SN1100Q 16Gb Single Port Fibre Channel Host Bus Adapter) + +pci:v00001077d00002261sv00001590sd000000FA* + ID_MODEL_FROM_DATABASE=ISP2722-based 16/32Gb Fibre Channel to PCIe Adapter (HPE StoreFabric SN1100Q 16Gb Dual Port Fibre Channel Host Bus Adapter) + pci:v00001077d00002300* ID_MODEL_FROM_DATABASE=QLA2300 64-bit Fibre Channel Adapter @@ -17327,6 +17435,9 @@ pci:v00001077d00002532sv0000103Csd00003262* pci:v00001077d00002532sv00001077sd00000167* ID_MODEL_FROM_DATABASE=ISP2532-based 8Gb Fibre Channel to PCI Express HBA (QME2572 Dual Port FC8 HBA Mezzanine) +pci:v00001077d00002532sv00001590sd000000FC* + ID_MODEL_FROM_DATABASE=ISP2532-based 8Gb Fibre Channel to PCI Express HBA (HPE StoreFabric 84Q 8Gb Quad Port Fibre Channel Host Bus Adapter) + pci:v00001077d00003022* ID_MODEL_FROM_DATABASE=ISP4022-based Ethernet NIC @@ -17972,6 +18083,9 @@ pci:v00001093d00000160* pci:v00001093d00000162* ID_MODEL_FROM_DATABASE=PCI-MIO-16XE-50 +pci:v00001093d00000FE1* + ID_MODEL_FROM_DATABASE=PXI-8320 + pci:v00001093d00001150* ID_MODEL_FROM_DATABASE=PCI-6533 (PCI-DIO-32HS) @@ -18245,9 +18359,18 @@ pci:v00001093d0000700B* pci:v00001093d0000700C* ID_MODEL_FROM_DATABASE=PCI-5421 +pci:v00001093d0000701A* + ID_MODEL_FROM_DATABASE=VXIpc-87xB + +pci:v00001093d0000701B* + ID_MODEL_FROM_DATABASE=VXIpc-770 + pci:v00001093d00007023* ID_MODEL_FROM_DATABASE=PXI-2593 +pci:v00001093d00007027* + ID_MODEL_FROM_DATABASE=PCI-MXI-2 Universal + pci:v00001093d0000702C* ID_MODEL_FROM_DATABASE=PXI-7831R @@ -19052,6 +19175,9 @@ pci:v00001093d00007322* pci:v00001093d00007327* ID_MODEL_FROM_DATABASE=PXI-6529 +pci:v00001093d0000732C* + ID_MODEL_FROM_DATABASE=VXI-8360T + pci:v00001093d00007331* ID_MODEL_FROM_DATABASE=PXIe-5602 @@ -19469,6 +19595,9 @@ pci:v00001093d000075E6* pci:v00001093d000075EF* ID_MODEL_FROM_DATABASE=PXIe-5632 +pci:v00001093d0000761C* + ID_MODEL_FROM_DATABASE=VXI-8360LT + pci:v00001093d0000761F* ID_MODEL_FROM_DATABASE=PXI-2540 @@ -19559,6 +19688,9 @@ pci:v00001093d000076A4* pci:v00001093d000076A5* ID_MODEL_FROM_DATABASE=PXIe-6537B +pci:v00001093d0000783E* + ID_MODEL_FROM_DATABASE=PXI-8368 + pci:v00001093d00009020* ID_MODEL_FROM_DATABASE=PXI-2501 @@ -19586,6 +19718,9 @@ pci:v00001093d00009090* pci:v00001093d000090A0* ID_MODEL_FROM_DATABASE=PXI-4021 +pci:v00001093d0000A001* + ID_MODEL_FROM_DATABASE=PCI-MXI-2 + pci:v00001093d0000B001* ID_MODEL_FROM_DATABASE=PCI-1408 @@ -19853,9 +19988,15 @@ pci:v00001093d0000C4C4sv00001093sd0000762C* pci:v00001093d0000C4C4sv00001093sd0000762D* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4145) +pci:v00001093d0000C4C4sv00001093sd0000762E* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5606) + pci:v00001093d0000C4C4sv00001093sd00007644* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4841) +pci:v00001093d0000C4C4sv00001093sd0000764A* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-8237R-S) + pci:v00001093d0000C4C4sv00001093sd00007658* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5162 (4CH)) @@ -19877,6 +20018,12 @@ pci:v00001093d0000C4C4sv00001093sd000076B6* pci:v00001093d0000C4C4sv00001093sd000076B7* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7975R) +pci:v00001093d0000C4C4sv00001093sd000076B8* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5696) + +pci:v00001093d0000C4C4sv00001093sd000076B9* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5654) + pci:v00001093d0000C4C4sv00001093sd000076C8* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6614) @@ -19889,6 +20036,9 @@ pci:v00001093d0000C4C4sv00001093sd000076CB* pci:v00001093d0000C4C4sv00001093sd000076CC* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5162 (2CH)) +pci:v00001093d0000C4C4sv00001093sd000076CE* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (CVS-1459) + pci:v00001093d0000C4C4sv00001093sd000076D0* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5160 (2CH)) @@ -19898,9 +20048,33 @@ pci:v00001093d0000C4C4sv00001093sd000076D1* pci:v00001093d0000C4C4sv00001093sd000076DC* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4610) +pci:v00001093d0000C4C4sv00001093sd000076EC* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-2524) + +pci:v00001093d0000C4C4sv00001093sd000076ED* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-2525) + +pci:v00001093d0000C4C4sv00001093sd000076EE* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-2526) + +pci:v00001093d0000C4C4sv00001093sd000076EF* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-2737) + +pci:v00001093d0000C4C4sv00001093sd000076F0* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-2738) + +pci:v00001093d0000C4C4sv00001093sd000076F1* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-2739) + pci:v00001093d0000C4C4sv00001093sd000076FB* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-1473R-LX110) +pci:v00001093d0000C4C4sv00001093sd000076FC* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5105) + +pci:v00001093d0000C4C4sv00001093sd000076FD* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5114) + pci:v00001093d0000C4C4sv00001093sd000076FE* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5644R) @@ -19925,15 +20099,24 @@ pci:v00001093d0000C4C4sv00001093sd0000770C* pci:v00001093d0000C4C4sv00001093sd00007711* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4464) +pci:v00001093d0000C4C4sv00001093sd00007712* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4463) + pci:v00001093d0000C4C4sv00001093sd00007716* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PCIe-6612) +pci:v00001093d0000C4C4sv00001093sd0000771D* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (Unconfigured CA4 Switch) + pci:v00001093d0000C4C4sv00001093sd0000771E* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4339) pci:v00001093d0000C4C4sv00001093sd00007735* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9033) +pci:v00001093d0000C4C4sv00001093sd0000773E* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5624R) + pci:v00001093d0000C4C4sv00001093sd0000774B* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9031) @@ -19943,6 +20126,15 @@ pci:v00001093d0000C4C4sv00001093sd0000774D* pci:v00001093d0000C4C4sv00001093sd00007755* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9030) +pci:v00001093d0000C4C4sv00001093sd00007768* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-2747) + +pci:v00001093d0000C4C4sv00001093sd00007769* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-2748) + +pci:v00001093d0000C4C4sv00001093sd0000776A* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-2746) + pci:v00001093d0000C4C4sv00001093sd00007777* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7976R) @@ -19955,6 +20147,15 @@ pci:v00001093d0000C4C4sv00001093sd00007783* pci:v00001093d0000C4C4sv00001093sd00007784* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5646R) +pci:v00001093d0000C4C4sv00001093sd00007790* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5170R (4CH)) + +pci:v00001093d0000C4C4sv00001093sd00007791* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5170R (8CH)) + +pci:v00001093d0000C4C4sv00001093sd00007793* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5171R (8CH)) + pci:v00001093d0000C4C4sv00001093sd000077A5* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6345) @@ -19967,6 +20168,12 @@ pci:v00001093d0000C4C4sv00001093sd000077A7* pci:v00001093d0000C4C4sv00001093sd000077A8* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6375) +pci:v00001093d0000C4C4sv00001093sd000077AA* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (CVS-1458) + +pci:v00001093d0000C4C4sv00001093sd000077AD* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (IC-3173) + pci:v00001093d0000C4C4sv00001093sd000077B4* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-7820R) @@ -19979,6 +20186,48 @@ pci:v00001093d0000C4C4sv00001093sd000077B6* pci:v00001093d0000C4C4sv00001093sd000077B9* ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9038) +pci:v00001093d0000C4C4sv00001093sd000077BA* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4136) + +pci:v00001093d0000C4C4sv00001093sd000077BB* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4137) + +pci:v00001093d0000C4C4sv00001093sd000077C0* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5624R) + +pci:v00001093d0000C4C4sv00001093sd000077C1* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5624R) + +pci:v00001093d0000C4C4sv00001093sd000077C2* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-5624R) + +pci:v00001093d0000C4C4sv00001093sd000077CA* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6738) + +pci:v00001093d0000C4C4sv00001093sd000077CB* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-6739) + +pci:v00001093d0000C4C4sv00001093sd000077DB* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9035) + +pci:v00001093d0000C4C4sv00001093sd000077DC* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9036) + +pci:v00001093d0000C4C4sv00001093sd000077DD* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (cRIO-9039) + +pci:v00001093d0000C4C4sv00001093sd00007802* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4302) + +pci:v00001093d0000C4C4sv00001093sd00007803* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4303) + +pci:v00001093d0000C4C4sv00001093sd00007805* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4305) + +pci:v00001093d0000C4C4sv00001093sd0000788E* + ID_MODEL_FROM_DATABASE=PXIe/PCIe Device (PXIe-4304) + pci:v00001093d0000C801* ID_MODEL_FROM_DATABASE=PCI-GPIB @@ -20090,6 +20339,27 @@ pci:v00001093d0000E261* pci:v00001093d0000E271* ID_MODEL_FROM_DATABASE=PXI-8462 +pci:v00001093d0000F110* + ID_MODEL_FROM_DATABASE=VMEpc-650 + +pci:v00001093d0000F120* + ID_MODEL_FROM_DATABASE=VXIpc-650 + +pci:v00001093d0000FE00* + ID_MODEL_FROM_DATABASE=VXIpc-87x + +pci:v00001093d0000FE41* + ID_MODEL_FROM_DATABASE=VXIpc-860 + +pci:v00001093d0000FE51* + ID_MODEL_FROM_DATABASE=VXIpc-74x + +pci:v00001093d0000FE61* + ID_MODEL_FROM_DATABASE=VXIpc-850 + +pci:v00001093d0000FE70* + ID_MODEL_FROM_DATABASE=VXIpc-880 + pci:v00001094* ID_VENDOR_FROM_DATABASE=First International Computers [FIC] @@ -21152,6 +21422,9 @@ pci:v000010B5d00008747* pci:v000010B5d000087B0* ID_MODEL_FROM_DATABASE=PEX 8732 32-lane, 8-Port PCI Express Gen 3 (8.0 GT/s) Switch +pci:v000010B5d000087B0sv00001093sd00007761* + ID_MODEL_FROM_DATABASE=PEX 8732 32-lane, 8-Port PCI Express Gen 3 (8.0 GT/s) Switch (PXIe-8830mc) + pci:v000010B5d00009016* ID_MODEL_FROM_DATABASE=PLX 9016 8-port serial controller @@ -21185,6 +21458,9 @@ pci:v000010B5d00009030sv000010B5sd00003068* pci:v000010B5d00009030sv000010B5sd00003463* ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge (Alpermann+Velte PCL PCI D (v2) (3V/5V): Timecode Reader Board) +pci:v000010B5d00009030sv000010B5sd00003591* + ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge (PLURA PCL PCI L (v2) (3.3V/5V): Time Code Reader Board) + pci:v000010B5d00009030sv000012FEsd00000111* ID_MODEL_FROM_DATABASE=PCI9030 32-bit 33MHz PCI <-> IOBus Bridge (CPCI-ASIO4 (ESD 4-port Serial Interface Board)) @@ -28619,6 +28895,9 @@ pci:v000010DEd00000F01* pci:v000010DEd00000F02* ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 730] +pci:v000010DEd00000F06* + ID_MODEL_FROM_DATABASE=GF108 [GeForce GT 730] + pci:v000010DEd00000FBB* ID_MODEL_FROM_DATABASE=GM204 High Definition Audio Controller @@ -28748,6 +29027,9 @@ pci:v000010DEd00000FEC* pci:v000010DEd00000FED* ID_MODEL_FROM_DATABASE=GK107M [GeForce 820M] +pci:v000010DEd00000FEE* + ID_MODEL_FROM_DATABASE=GK107M [GeForce 810M] + pci:v000010DEd00000FEF* ID_MODEL_FROM_DATABASE=GK107GL [GRID K340] @@ -29108,6 +29390,9 @@ pci:v000010DEd000010D8* pci:v000010DEd00001140* ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] +pci:v000010DEd00001140sv00001019sd00000799* + ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + pci:v000010DEd00001140sv00001019sd0000999F* ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) @@ -29405,6 +29690,9 @@ pci:v000010DEd00001140sv00001028sd00000662* pci:v000010DEd00001140sv00001028sd0000068D* ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) +pci:v000010DEd00001140sv00001028sd000006C1* + ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + pci:v000010DEd00001140sv0000103Csd000018EF* ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 630M) @@ -30023,6 +30311,12 @@ pci:v000010DEd00001140sv00001854sd00000190* pci:v000010DEd00001140sv00001854sd00000192* ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) +pci:v000010DEd00001140sv00001854sd00000224* + ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + +pci:v000010DEd00001140sv00001B0Asd000001C0* + ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + pci:v000010DEd00001140sv00001B0Asd000020DD* ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 620M) @@ -30041,6 +30335,18 @@ pci:v000010DEd00001140sv00001B0Asd000090D7* pci:v000010DEd00001140sv00001B0Asd000090DD* ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) +pci:v000010DEd00001140sv00001B50sd00005530* + ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + +pci:v000010DEd00001140sv00001B6Csd00005531* + ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce GT 720M) + +pci:v000010DEd00001140sv00001BABsd00000106* + ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 820M) + +pci:v000010DEd00001140sv00001D05sd00001013* + ID_MODEL_FROM_DATABASE=GF117M [GeForce 610M/710M/810M/820M / GT 620M/625M/630M/720M] (GeForce 810M) + pci:v000010DEd00001180* ID_MODEL_FROM_DATABASE=GK104 [GeForce GTX 680] @@ -30527,6 +30833,9 @@ pci:v000010DEd00001346* pci:v000010DEd00001347* ID_MODEL_FROM_DATABASE=GM108M [GeForce 940M] +pci:v000010DEd0000134D* + ID_MODEL_FROM_DATABASE=GM108M [GeForce 940MX] + pci:v000010DEd0000137A* ID_MODEL_FROM_DATABASE=GM108GLM [Quadro K620M] @@ -30569,9 +30878,27 @@ pci:v000010DEd00001398* pci:v000010DEd0000139A* ID_MODEL_FROM_DATABASE=GM107M [GeForce GTX 950M] +pci:v000010DEd0000139Asv000017AAsd0000362C* + ID_MODEL_FROM_DATABASE=GM107M [GeForce GTX 950M] (GeForce GTX 950A) + +pci:v000010DEd0000139Asv000017AAsd0000362F* + ID_MODEL_FROM_DATABASE=GM107M [GeForce GTX 950M] (GeForce GTX 950A) + +pci:v000010DEd0000139Asv000017AAsd0000363F* + ID_MODEL_FROM_DATABASE=GM107M [GeForce GTX 950M] (GeForce GTX 950A) + +pci:v000010DEd0000139Asv000017AAsd00003640* + ID_MODEL_FROM_DATABASE=GM107M [GeForce GTX 950M] (GeForce GTX 950A) + +pci:v000010DEd0000139Asv000017AAsd000036B9* + ID_MODEL_FROM_DATABASE=GM107M [GeForce GTX 950M] (GeForce GTX 950A) + pci:v000010DEd0000139B* ID_MODEL_FROM_DATABASE=GM107M [GeForce GTX 960M] +pci:v000010DEd0000139Bsv0000103Csd00002B4C* + ID_MODEL_FROM_DATABASE=GM107M [GeForce GTX 960M] (GeForce GTX 960A) + pci:v000010DEd0000139C* ID_MODEL_FROM_DATABASE=GM107M [GeForce 940M] @@ -30587,6 +30914,9 @@ pci:v000010DEd000013B2* pci:v000010DEd000013B3* ID_MODEL_FROM_DATABASE=GM107GLM [Quadro K2200M] +pci:v000010DEd000013B9* + ID_MODEL_FROM_DATABASE=GM107GL [NVS 810] + pci:v000010DEd000013BA* ID_MODEL_FROM_DATABASE=GM107GL [Quadro K2200] @@ -30623,6 +30953,9 @@ pci:v000010DEd000013D8* pci:v000010DEd000013D9* ID_MODEL_FROM_DATABASE=GM204M [GeForce GTX 965M] +pci:v000010DEd000013DA* + ID_MODEL_FROM_DATABASE=GM204M [GeForce GTX 980] + pci:v000010DEd000013F0* ID_MODEL_FROM_DATABASE=GM204GL [Quadro M5000] @@ -30647,6 +30980,12 @@ pci:v000010DEd00001401* pci:v000010DEd00001402* ID_MODEL_FROM_DATABASE=GM206 [GeForce GTX 950] +pci:v000010DEd00001407* + ID_MODEL_FROM_DATABASE=GM206 [GeForce GTX 750 v2] + +pci:v000010DEd00001427* + ID_MODEL_FROM_DATABASE=GM206M [GeForce GTX 965M] + pci:v000010DEd00001617* ID_MODEL_FROM_DATABASE=GM204M [GeForce GTX 980M] @@ -30656,6 +30995,9 @@ pci:v000010DEd00001618* pci:v000010DEd00001619* ID_MODEL_FROM_DATABASE=GM204M [GeForce GTX 965M] +pci:v000010DEd0000161A* + ID_MODEL_FROM_DATABASE=GM204M [GeForce GTX 980] + pci:v000010DEd000017C2* ID_MODEL_FROM_DATABASE=GM200 [GeForce GTX TITAN X] @@ -30665,6 +31007,9 @@ pci:v000010DEd000017C8* pci:v000010DEd000017F0* ID_MODEL_FROM_DATABASE=GM200GL [Quadro M6000] +pci:v000010DEd000017FD* + ID_MODEL_FROM_DATABASE=GM200GL [Tesla M40] + pci:v000010DF* ID_VENDOR_FROM_DATABASE=Emulex Corporation @@ -31142,15 +31487,24 @@ pci:v000010ECd00005229sv0000103Csd0000194E* pci:v000010ECd00005229sv0000103Csd00001985* ID_MODEL_FROM_DATABASE=RTS5229 PCI Express Card Reader (Pavilion 17-e163sg Notebook PC) +pci:v000010ECd0000522A* + ID_MODEL_FROM_DATABASE=RTS522A PCI Express Card Reader + pci:v000010ECd00005249* ID_MODEL_FROM_DATABASE=RTS5249 PCI Express Card Reader pci:v000010ECd00005249sv0000103Csd00001909* ID_MODEL_FROM_DATABASE=RTS5249 PCI Express Card Reader (ZBook 15) +pci:v000010ECd0000524A* + ID_MODEL_FROM_DATABASE=RTS524A PCI Express Card Reader + pci:v000010ECd00005250* ID_MODEL_FROM_DATABASE=RTS5250 PCI Express Card Reader +pci:v000010ECd0000525A* + ID_MODEL_FROM_DATABASE=RTS525A PCI Express Card Reader + pci:v000010ECd00005286* ID_MODEL_FROM_DATABASE=RTS5286 PCI Express Card Reader @@ -35789,6 +36143,9 @@ pci:v00001137d00000040sv00001137sd0000012E* pci:v00001137d00000040sv00001137sd00000137* ID_MODEL_FROM_DATABASE=VIC PCIe Upstream Port (VIC 1380 Dual 40Gb Mezzanine) +pci:v00001137d00000040sv00001137sd0000014D* + ID_MODEL_FROM_DATABASE=VIC PCIe Upstream Port (VIC 1385 Dual 40Gb PCIe) + pci:v00001137d00000041* ID_MODEL_FROM_DATABASE=VIC PCIe Downstream Port @@ -35810,6 +36167,9 @@ pci:v00001137d00000042sv00001137sd000000CE* pci:v00001137d00000042sv00001137sd0000012E* ID_MODEL_FROM_DATABASE=VIC Management Controller (VIC 1227 PCIe Management Controller) +pci:v00001137d00000042sv00001137sd0000014D* + ID_MODEL_FROM_DATABASE=VIC Management Controller (VIC 1385 PCIe Management Controller) + pci:v00001137d00000043* ID_MODEL_FROM_DATABASE=VIC Ethernet NIC @@ -35885,6 +36245,9 @@ pci:v00001137d00000044sv00001137sd0000012E* pci:v00001137d00000044sv00001137sd00000137* ID_MODEL_FROM_DATABASE=VIC Ethernet NIC Dynamic (VIC 1380 Mezzanine Ethernet NIC Dynamic) +pci:v00001137d00000044sv00001137sd0000014D* + ID_MODEL_FROM_DATABASE=VIC Ethernet NIC Dynamic (VIC 1385 PCIe Ethernet NIC Dynamic) + pci:v00001137d00000045* ID_MODEL_FROM_DATABASE=VIC FCoE HBA @@ -35921,6 +36284,9 @@ pci:v00001137d00000045sv00001137sd0000012E* pci:v00001137d00000045sv00001137sd00000137* ID_MODEL_FROM_DATABASE=VIC FCoE HBA (VIC 1380 Mezzanine FCoE HBA) +pci:v00001137d00000045sv00001137sd0000014D* + ID_MODEL_FROM_DATABASE=VIC FCoE HBA (VIC 1385 PCIe FCoE HBA) + pci:v00001137d00000046* ID_MODEL_FROM_DATABASE=VIC SCSI Controller @@ -35945,6 +36311,9 @@ pci:v00001137d0000007Asv00001137sd0000012C* pci:v00001137d0000007Asv00001137sd00000137* ID_MODEL_FROM_DATABASE=VIC 1300 PCIe Upstream Port (VIC 1380 Dual 40Gb Mezzanine) +pci:v00001137d0000007Asv00001137sd0000014D* + ID_MODEL_FROM_DATABASE=VIC 1300 PCIe Upstream Port (VIC 1385 Dual 40Gb PCIe) + pci:v00001137d000000CF* ID_MODEL_FROM_DATABASE=VIC Userspace NIC @@ -45239,9 +45608,6 @@ pci:v00001412d00001712* pci:v00001412d00001712sv00001412sd00001712* ID_MODEL_FROM_DATABASE=ICE1712 [Envy24] PCI Multi-Channel I/O Controller (Hoontech ST Audio DSP 24) -pci:v00001412d00001712sv00001412sd00003632* - ID_MODEL_FROM_DATABASE=ICE1712 [Envy24] PCI Multi-Channel I/O Controller (M-Audio Delta Audiophile 192) - pci:v00001412d00001712sv00001412sd0000D630* ID_MODEL_FROM_DATABASE=ICE1712 [Envy24] PCI Multi-Channel I/O Controller (M-Audio Delta 1010) @@ -45314,6 +45680,9 @@ pci:v00001412d00001724sv00001412sd00003630* pci:v00001412d00001724sv00001412sd00003631* ID_MODEL_FROM_DATABASE=VT1720/24 [Envy24PT/HT] PCI Multi-Channel Audio Controller (M-Audio Revolution 5.1) +pci:v00001412d00001724sv00001412sd00003632* + ID_MODEL_FROM_DATABASE=VT1720/24 [Envy24PT/HT] PCI Multi-Channel Audio Controller (M-Audio Audiophile 192) + pci:v00001412d00001724sv0000153Bsd00001145* ID_MODEL_FROM_DATABASE=VT1720/24 [Envy24PT/HT] PCI Multi-Channel Audio Controller (Aureon 7.1 Space) @@ -46118,6 +46487,18 @@ pci:v00001425d00005096* pci:v00001425d00005097* ID_MODEL_FROM_DATABASE=T520-5097 Unified Wire Ethernet Controller +pci:v00001425d00005098* + ID_MODEL_FROM_DATABASE=T580-5098 Unified Wire Ethernet Controller + +pci:v00001425d00005099* + ID_MODEL_FROM_DATABASE=T580-5099 Unified Wire Ethernet Controller + +pci:v00001425d0000509A* + ID_MODEL_FROM_DATABASE=T520-509A Unified Wire Ethernet Controller + +pci:v00001425d0000509B* + ID_MODEL_FROM_DATABASE=T540-509B Unified Wire Ethernet Controller + pci:v00001425d00005401* ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller @@ -46241,6 +46622,18 @@ pci:v00001425d00005496* pci:v00001425d00005497* ID_MODEL_FROM_DATABASE=T520-5097 Unified Wire Ethernet Controller +pci:v00001425d00005498* + ID_MODEL_FROM_DATABASE=T580-5098 Unified Wire Ethernet Controller + +pci:v00001425d00005499* + ID_MODEL_FROM_DATABASE=T580-5099 Unified Wire Ethernet Controller + +pci:v00001425d0000549A* + ID_MODEL_FROM_DATABASE=T520-509A Unified Wire Ethernet Controller + +pci:v00001425d0000549B* + ID_MODEL_FROM_DATABASE=T540-509B Unified Wire Ethernet Controller + pci:v00001425d00005501* ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller @@ -46364,6 +46757,18 @@ pci:v00001425d00005596* pci:v00001425d00005597* ID_MODEL_FROM_DATABASE=T520-5097 Unified Wire Storage Controller +pci:v00001425d00005598* + ID_MODEL_FROM_DATABASE=T580-5098 Unified Wire Storage Controller + +pci:v00001425d00005599* + ID_MODEL_FROM_DATABASE=T580-5099 Unified Wire Storage Controller + +pci:v00001425d0000559A* + ID_MODEL_FROM_DATABASE=T520-509A Unified Wire Storage Controller + +pci:v00001425d0000559B* + ID_MODEL_FROM_DATABASE=T540-509B Unified Wire Storage Controller + pci:v00001425d00005601* ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Storage Controller @@ -46487,6 +46892,18 @@ pci:v00001425d00005696* pci:v00001425d00005697* ID_MODEL_FROM_DATABASE=T520-5097 Unified Wire Storage Controller +pci:v00001425d00005698* + ID_MODEL_FROM_DATABASE=T580-5098 Unified Wire Storage Controller + +pci:v00001425d00005699* + ID_MODEL_FROM_DATABASE=T580-5099 Unified Wire Storage Controller + +pci:v00001425d0000569A* + ID_MODEL_FROM_DATABASE=T520-509A Unified Wire Storage Controller + +pci:v00001425d0000569B* + ID_MODEL_FROM_DATABASE=T540-509B Unified Wire Storage Controller + pci:v00001425d00005701* ID_MODEL_FROM_DATABASE=T520-CR Unified Wire Ethernet Controller @@ -46727,6 +47144,18 @@ pci:v00001425d00005896* pci:v00001425d00005897* ID_MODEL_FROM_DATABASE=T520-5097 Unified Wire Ethernet Controller [VF] +pci:v00001425d00005898* + ID_MODEL_FROM_DATABASE=T580-5098 Unified Wire Ethernet Controller [VF] + +pci:v00001425d00005899* + ID_MODEL_FROM_DATABASE=T580-5099 Unified Wire Ethernet Controller [VF] + +pci:v00001425d0000589A* + ID_MODEL_FROM_DATABASE=T520-509A Unified Wire Ethernet Controller [VF] + +pci:v00001425d0000589B* + ID_MODEL_FROM_DATABASE=T540-509B Unified Wire Ethernet Controller [VF] + pci:v00001425d0000A000* ID_MODEL_FROM_DATABASE=PE10K Unified Wire Ethernet Controller @@ -46928,6 +47357,9 @@ pci:v0000144Dd00001600* pci:v0000144Dd0000A800* ID_MODEL_FROM_DATABASE=XP941 PCIe SSD +pci:v0000144Dd0000A802* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller + pci:v0000144Dd0000A820* ID_MODEL_FROM_DATABASE=NVMe SSD Controller 171X @@ -48155,6 +48587,9 @@ pci:v000014E4d00001657* pci:v000014E4d00001657sv0000103Csd0000169D* ID_MODEL_FROM_DATABASE=NetXtreme BCM5719 Gigabit Ethernet PCIe (Ethernet 1Gb 4-port 331FLR Adapter) +pci:v000014E4d00001657sv0000103Csd000022BE* + ID_MODEL_FROM_DATABASE=NetXtreme BCM5719 Gigabit Ethernet PCIe (Ethernet 1Gb 4-port 331i Adapter) + pci:v000014E4d00001659* ID_MODEL_FROM_DATABASE=NetXtreme BCM5721 Gigabit Ethernet PCI Express @@ -48833,6 +49268,30 @@ pci:v000014E4d000016C7sv000014E4sd00000009* pci:v000014E4d000016C7sv000014E4sd0000000A* ID_MODEL_FROM_DATABASE=NetXtreme BCM5703 Gigabit Ethernet (NetXtreme BCM5703 1000Base-SX) +pci:v000014E4d000016C8* + ID_MODEL_FROM_DATABASE=BCM57301 NetXtreme-C Single-port 10Gb Ethernet + +pci:v000014E4d000016C9* + ID_MODEL_FROM_DATABASE=BCM57302 NetXtreme-C Dual-port 10Gb/25Gb Ethernet + +pci:v000014E4d000016CA* + ID_MODEL_FROM_DATABASE=BCM57304 NetXtreme-C Dual-port 10Gb/25Gb/40Gb/50Gb Ethernet + +pci:v000014E4d000016CB* + ID_MODEL_FROM_DATABASE=BCM57304 NetXtreme-C Ethernet Virtual Function + +pci:v000014E4d000016D0* + ID_MODEL_FROM_DATABASE=BCM57402 NetXtreme-E Dual-port 10Gb Ethernet + +pci:v000014E4d000016D1* + ID_MODEL_FROM_DATABASE=BCM57404 NetXtreme-E Dual-port 10Gb/25Gb Ethernet + +pci:v000014E4d000016D2* + ID_MODEL_FROM_DATABASE=BCM57406 NetXtreme-E Dual-port 10GBase-T Ethernet + +pci:v000014E4d000016D3* + ID_MODEL_FROM_DATABASE=BCM57404 NetXtreme-E Ethernet Virtual Function + pci:v000014E4d000016DD* ID_MODEL_FROM_DATABASE=NetLink BCM5781 Gigabit Ethernet PCI Express @@ -49433,6 +49892,9 @@ pci:v000014E4d000043A1* pci:v000014E4d000043A2* ID_MODEL_FROM_DATABASE=BCM4360 802.11ac Wireless Network Adapter +pci:v000014E4d000043A3* + ID_MODEL_FROM_DATABASE=BCM4350 802.11ac Wireless Network Adapter + pci:v000014E4d000043A9* ID_MODEL_FROM_DATABASE=BCM43217 802.11b/g/n @@ -49475,6 +49937,9 @@ pci:v000014E4d00004401sv00001025sd00000035* pci:v000014E4d00004401sv00001025sd00000064* ID_MODEL_FROM_DATABASE=BCM4401 100Base-T (Extensa 3000 series laptop) +pci:v000014E4d00004401sv00001028sd00008127* + ID_MODEL_FROM_DATABASE=BCM4401 100Base-T (Dimension 2400) + pci:v000014E4d00004401sv0000103Csd000008B0* ID_MODEL_FROM_DATABASE=BCM4401 100Base-T (tc1100 tablet) @@ -51569,6 +52034,12 @@ pci:v000015B3d0000020B* pci:v000015B3d0000020D* ID_MODEL_FROM_DATABASE=MT28800 Family [ConnectX-5 Flash Recovery] +pci:v000015B3d00000262* + ID_MODEL_FROM_DATABASE=MT27710 [ConnectX-4 Lx Programmable] EN + +pci:v000015B3d00000263* + ID_MODEL_FROM_DATABASE=MT27710 [ConnectX-4 Lx Programmable Virtual Function] EN + pci:v000015B3d00001002* ID_MODEL_FROM_DATABASE=MT25400 Family [ConnectX-2 Virtual Function] @@ -51608,6 +52079,9 @@ pci:v000015B3d00001007sv0000103Csd000022F3* pci:v000015B3d00001007sv0000103Csd000022F4* ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] (InfiniBand FDR/Ethernet 10Gb/40Gb 2-port 544+FLR-QSFP Adapter) +pci:v000015B3d00001007sv0000103Csd0000801F* + ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] (Ethernet 10G 2-port 546SFP+ Adapter) + pci:v000015B3d00001007sv0000117Csd00000090* ID_MODEL_FROM_DATABASE=MT27520 Family [ConnectX-3 Pro] (FastFrame NQ41) @@ -51663,7 +52137,7 @@ pci:v000015B3d00001016* ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx Virtual Function] pci:v000015B3d00001017* - ID_MODEL_FROM_DATABASE=MT28800 Family [ConnectX-4] + ID_MODEL_FROM_DATABASE=MT28800 Family [ConnectX-5] pci:v000015B3d00001018* ID_MODEL_FROM_DATABASE=MT28800 Family [ConnectX-5 Virtual Function] @@ -53276,12 +53750,18 @@ pci:v0000168Cd00000030sv00001A56sd00002001* pci:v0000168Cd00000032* ID_MODEL_FROM_DATABASE=AR9485 Wireless Network Adapter +pci:v0000168Cd00000032sv00001028sd00000208* + ID_MODEL_FROM_DATABASE=AR9485 Wireless Network Adapter (Wireless 1506 WLAN Half Mini-Card) + pci:v0000168Cd00000032sv0000103Csd00001838* ID_MODEL_FROM_DATABASE=AR9485 Wireless Network Adapter (AR9485/HB125 802.11bgn 1×1 Wi-Fi Adapter) pci:v0000168Cd00000032sv0000105Bsd0000E044* ID_MODEL_FROM_DATABASE=AR9485 Wireless Network Adapter (Unex DHXA-225) +pci:v0000168Cd00000032sv00001A3Bsd00001186* + ID_MODEL_FROM_DATABASE=AR9485 Wireless Network Adapter (AW-NE186H) + pci:v0000168Cd00000033* ID_MODEL_FROM_DATABASE=AR9580 Wireless Network Adapter @@ -54155,6 +54635,9 @@ pci:v00001797d00006816* pci:v00001797d00006817* ID_MODEL_FROM_DATABASE=TW6816 multimedia video controller +pci:v00001797d00006864* + ID_MODEL_FROM_DATABASE=TW6864 multimedia video controller + pci:v00001799* ID_VENDOR_FROM_DATABASE=Belkin @@ -55550,6 +56033,15 @@ pci:v00001912d00000014* pci:v00001912d00000015* ID_MODEL_FROM_DATABASE=uPD720202 USB 3.0 Host Controller +pci:v00001912d0000001A* + ID_MODEL_FROM_DATABASE=SH7758 PCIe-PCI Bridge [PPB] + +pci:v00001912d0000001B* + ID_MODEL_FROM_DATABASE=SH7758 PCIe End-Point [PBI] + +pci:v00001912d0000001D* + ID_MODEL_FROM_DATABASE=SH7758 PCIe Switch [PS] + pci:v00001919* ID_VENDOR_FROM_DATABASE=Soltek Computer Inc. @@ -55805,6 +56297,9 @@ pci:v00001924d00000903sv00001924sd0000800C* pci:v00001924d00000903sv00001924sd0000800D* ID_MODEL_FROM_DATABASE=SFC9120 (SFN7x02F-R3 Flareon 7000 Series 10G Adapter) +pci:v00001924d00000903sv00001924sd00008010* + ID_MODEL_FROM_DATABASE=SFC9120 (SFA7942Q-R1 QSFP+ AOE Adapter) + pci:v00001924d00000923* ID_MODEL_FROM_DATABASE=SFC9140 @@ -55817,6 +56312,15 @@ pci:v00001924d00000923sv00001924sd0000800E* pci:v00001924d00000923sv00001924sd0000800F* ID_MODEL_FROM_DATABASE=SFC9140 (SFN7xx4F-R1 Flareon Ultra 7000 Series 10G Adapter) +pci:v00001924d00000A03* + ID_MODEL_FROM_DATABASE=SFC9220 + +pci:v00001924d00000A03sv00001924sd00008012* + ID_MODEL_FROM_DATABASE=SFC9220 (SFN8522-R1 Flareon Ultra 8000 Series 10G Adapter) + +pci:v00001924d00000A03sv00001924sd00008014* + ID_MODEL_FROM_DATABASE=SFC9220 (SFN8542-R1 Flareon Ultra 8000 Series 10/40G Adapter) + pci:v00001924d00001803* ID_MODEL_FROM_DATABASE=SFC9020 Virtual Function [Solarstorm] @@ -56309,6 +56813,9 @@ pci:v00001969d00001083* pci:v00001969d00001090* ID_MODEL_FROM_DATABASE=AR8162 Fast Ethernet +pci:v00001969d00001090sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=AR8162 Fast Ethernet (VivoBook X202E, X202EV) + pci:v00001969d00001091* ID_MODEL_FROM_DATABASE=AR8161 Gigabit Ethernet @@ -56516,6 +57023,9 @@ pci:v0000199Fd00008521* pci:v000019A2* ID_VENDOR_FROM_DATABASE=Emulex Corporation +pci:v000019A2d00000120* + ID_MODEL_FROM_DATABASE=x1 PCIe Gen2 Bridge[Pilot4] + pci:v000019A2d00000200* ID_MODEL_FROM_DATABASE=BladeEngine 10Gb PCI-E iSCSI adapter @@ -57482,6 +57992,12 @@ pci:v00001B85d00001041* pci:v00001B85d00008788* ID_MODEL_FROM_DATABASE=RevoDrive Hybrid +pci:v00001B94* + ID_VENDOR_FROM_DATABASE=Signatec / Dynamic Signals Corp + +pci:v00001B94d0000E400* + ID_MODEL_FROM_DATABASE=PX14400 Dual Xilinx Virtex5 based Digitizer + pci:v00001B96* ID_VENDOR_FROM_DATABASE=Western Digital @@ -57668,6 +58184,12 @@ pci:v00001C2Cd000000A5* pci:v00001C2Cd000000A6* ID_MODEL_FROM_DATABASE=FBC1CG Capture 1x100Gb +pci:v00001C2Cd000000A9* + ID_MODEL_FROM_DATABASE=FBC2XGHH Capture 2x10Gb + +pci:v00001C2Cd000000AF* + ID_MODEL_FROM_DATABASE=Capture slave device + pci:v00001C32* ID_VENDOR_FROM_DATABASE=Highland Technology, Inc. @@ -57695,6 +58217,12 @@ pci:v00001C58* pci:v00001C58d00000003* ID_MODEL_FROM_DATABASE=Ultrastar SN100 Series NVMe SSD +pci:v00001C58d00000003sv00001014sd000004F5* + ID_MODEL_FROM_DATABASE=Ultrastar SN100 Series NVMe SSD (PCIe3 1.6TB NVMe Adapter) + +pci:v00001C58d00000003sv00001014sd000004F6* + ID_MODEL_FROM_DATABASE=Ultrastar SN100 Series NVMe SSD (PCIe3 3.2TB NVMe Adapter) + pci:v00001C7E* ID_VENDOR_FROM_DATABASE=TTTech Computertechnik AG @@ -57752,6 +58280,12 @@ pci:v00001CE4d00000002* pci:v00001CE4d00000003* ID_MODEL_FROM_DATABASE=ExaNIC X10 +pci:v00001CE4d00000004* + ID_MODEL_FROM_DATABASE=ExaNIC X10-GM + +pci:v00001CE4d00000005* + ID_MODEL_FROM_DATABASE=ExaNIC X40 + pci:v00001CF7* ID_VENDOR_FROM_DATABASE=Subspace Dynamics @@ -57761,6 +58295,9 @@ pci:v00001D00* pci:v00001D1D* ID_VENDOR_FROM_DATABASE=CNEX Labs +pci:v00001D1Dd00001F1F* + ID_MODEL_FROM_DATABASE=QEMU NVM Express LightNVM Controller + pci:v00001D1Dd00002807* ID_MODEL_FROM_DATABASE=8800 series NVMe SSD @@ -57785,6 +58322,9 @@ pci:v00001D44* pci:v00001D44d0000A400* ID_MODEL_FROM_DATABASE=PM2x24/PM3224 +pci:v00001D49* + ID_VENDOR_FROM_DATABASE=Lenovo + pci:v00001D5C* ID_VENDOR_FROM_DATABASE=Fantasia Trading LLC @@ -57959,6 +58499,9 @@ pci:v00001FC9d00004025sv00001FC9sd00003015* pci:v00001FC9d00004026* ID_MODEL_FROM_DATABASE=TN9610 10GbE SFP+ Ethernet Adapter +pci:v00001FC9d00004027* + ID_MODEL_FROM_DATABASE=TN9710 10GBase-T/NBASE-T Ethernet Adapter + pci:v00001FCC* ID_VENDOR_FROM_DATABASE=StreamLabs @@ -58046,6 +58589,9 @@ pci:v00002BD8* pci:v00003000* ID_VENDOR_FROM_DATABASE=Hansol Electronics Inc. +pci:v00003112* + ID_VENDOR_FROM_DATABASE=Satelco Ingenieria S.A. + pci:v00003142* ID_VENDOR_FROM_DATABASE=Post Impression Systems. @@ -58166,6 +58712,9 @@ pci:v000037D9d00001140* pci:v000037D9d00001141* ID_MODEL_FROM_DATABASE=PCI-485(422) +pci:v000037D9d00001142* + ID_MODEL_FROM_DATABASE=PCI-CAN2 + pci:v00003842* ID_VENDOR_FROM_DATABASE=eVga.com. Corp. @@ -59495,6 +60044,18 @@ pci:v0000544C* pci:v0000544Cd00000350* ID_MODEL_FROM_DATABASE=TL880-based HDTV/ATSC tuner +pci:v0000544D* + ID_VENDOR_FROM_DATABASE=TBS Technologies + +pci:v0000544Dd00006178* + ID_MODEL_FROM_DATABASE=DVB-S2 4 Tuner PCIe Card + +pci:v0000544Dd00006178sv0000544Dsd00006904* + ID_MODEL_FROM_DATABASE=DVB-S2 4 Tuner PCIe Card (TBS6904 DVB-S2 Quad Tuner PCIe Card) + +pci:v0000544Dd00006178sv0000544Dsd00006905* + ID_MODEL_FROM_DATABASE=DVB-S2 4 Tuner PCIe Card (TBS6905 DVB-S2 Quad Tuner PCIe Card) + pci:v00005452* ID_VENDOR_FROM_DATABASE=SCANLAB AG @@ -60080,6 +60641,9 @@ pci:v00008086d00000154sv00001025sd00000813* pci:v00008086d00000154sv0000103Csd000017F6* ID_MODEL_FROM_DATABASE=3rd Gen Core processor DRAM Controller (ProBook 4540s) +pci:v00008086d00000154sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=3rd Gen Core processor DRAM Controller (VivoBook X202EV) + pci:v00008086d00000154sv00001043sd00001477* ID_MODEL_FROM_DATABASE=3rd Gen Core processor DRAM Controller (N56VZ) @@ -60095,6 +60659,9 @@ pci:v00008086d00000155sv00008086sd00002010* pci:v00008086d00000156* ID_MODEL_FROM_DATABASE=3rd Gen Core processor Graphics Controller +pci:v00008086d00000156sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=3rd Gen Core processor Graphics Controller (VivoBook X202EV) + pci:v00008086d00000158* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v2/Ivy Bridge DRAM Controller @@ -60920,6 +61487,12 @@ pci:v00008086d00000953sv00008086sd00003709* pci:v00008086d00000953sv00008086sd0000370A* ID_MODEL_FROM_DATABASE=PCIe Data Center SSD (DC P3600 SSD [2.5" SFF]) +pci:v00008086d00000953sv00008086sd0000370D* + ID_MODEL_FROM_DATABASE=PCIe Data Center SSD (SSD 750 Series [Add-in Card]) + +pci:v00008086d00000953sv00008086sd0000370E* + ID_MODEL_FROM_DATABASE=PCIe Data Center SSD (SSD 750 Series [2.5" SFF]) + pci:v00008086d0000095A* ID_MODEL_FROM_DATABASE=Wireless 7265 @@ -61806,7 +62379,10 @@ pci:v00008086d00000F34* ID_MODEL_FROM_DATABASE=Atom Processor Z36xxx/Z37xxx Series USB EHCI pci:v00008086d00000F35* - ID_MODEL_FROM_DATABASE=Atom Processor Z36xxx/Z37xxx Series USB xHCI + ID_MODEL_FROM_DATABASE=Atom Processor Z36xxx/Z37xxx, Celeron N2000 Series USB xHCI + +pci:v00008086d00000F35sv00001025sd00000936* + ID_MODEL_FROM_DATABASE=Atom Processor Z36xxx/Z37xxx, Celeron N2000 Series USB xHCI (Aspire ES1) pci:v00008086d00000F37* ID_MODEL_FROM_DATABASE=Atom Processor Z36xxx/Z37xxx Series OTG USB Device @@ -63303,7 +63879,7 @@ pci:v00008086d00001130sv0000104Dsd000080DF* ID_MODEL_FROM_DATABASE=82815 815 Chipset Host Bridge and Memory Controller Hub (Vaio PCG-FX403) pci:v00008086d00001130sv00008086sd00004532* - ID_MODEL_FROM_DATABASE=82815 815 Chipset Host Bridge and Memory Controller Hub (D815EEA2 mainboard) + ID_MODEL_FROM_DATABASE=82815 815 Chipset Host Bridge and Memory Controller Hub (Desktop Board D815EEA2/D815EFV) pci:v00008086d00001130sv00008086sd00004557* ID_MODEL_FROM_DATABASE=82815 815 Chipset Host Bridge and Memory Controller Hub (D815EGEW Mainboard) @@ -63324,7 +63900,7 @@ pci:v00008086d00001132sv0000104Dsd000080DF* ID_MODEL_FROM_DATABASE=82815 Chipset Graphics Controller (CGC) (Vaio PCG-FX403) pci:v00008086d00001132sv00008086sd00004532* - ID_MODEL_FROM_DATABASE=82815 Chipset Graphics Controller (CGC) (D815EEA2 Mainboard) + ID_MODEL_FROM_DATABASE=82815 Chipset Graphics Controller (CGC) (Desktop Board D815EEA2/D815EFV) pci:v00008086d00001132sv00008086sd00004541* ID_MODEL_FROM_DATABASE=82815 Chipset Graphics Controller (CGC) (D815EEA Motherboard) @@ -64502,6 +65078,9 @@ pci:v00008086d00001572sv00008086sd00004005* pci:v00008086d00001572sv00008086sd00004006* ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ +pci:v00008086d00001578* + ID_MODEL_FROM_DATABASE=DSL6540 Thunderbolt [Alpine Ridge] + pci:v00008086d0000157B* ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection @@ -64664,6 +65243,9 @@ pci:v00008086d000015AD* pci:v00008086d000015AE* ID_MODEL_FROM_DATABASE=Ethernet Connection X552 1000BASE-T +pci:v00008086d000015B6* + ID_MODEL_FROM_DATABASE=DSL6540 USB 3.1 Controller [Alpine Ridge] + pci:v00008086d000015B7* ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I219-LM @@ -64682,6 +65264,18 @@ pci:v00008086d000015D1sv00008086sd00000002* pci:v00008086d000015D1sv00008086sd000000A2* ID_MODEL_FROM_DATABASE=Ethernet Controller 10G X550T (Ethernet Converged Network Adapter X550-T1) +pci:v00008086d000015D6* + ID_MODEL_FROM_DATABASE=Ethernet Connection (5) I219-V + +pci:v00008086d000015D7* + ID_MODEL_FROM_DATABASE=Ethernet Connection (4) I219-LM + +pci:v00008086d000015D8* + ID_MODEL_FROM_DATABASE=Ethernet Connection (4) I219-V + +pci:v00008086d000015E3* + ID_MODEL_FROM_DATABASE=Ethernet Connection (5) I219-LM + pci:v00008086d00001600* ID_MODEL_FROM_DATABASE=Broadwell-U Host Bridge -OPI @@ -64692,7 +65286,7 @@ pci:v00008086d00001602* ID_MODEL_FROM_DATABASE=Broadwell-U Integrated Graphics pci:v00008086d00001603* - ID_MODEL_FROM_DATABASE=Broadwell-U Camarillo Device + ID_MODEL_FROM_DATABASE=Broadwell-U Processor Thermal Subsystem pci:v00008086d00001604* ID_MODEL_FROM_DATABASE=Broadwell-U Host Bridge -OPI @@ -64797,61 +65391,67 @@ pci:v00008086d0000163E* ID_MODEL_FROM_DATABASE=Broadwell-U Integrated Graphics pci:v00008086d00001900* - ID_MODEL_FROM_DATABASE=Sky Lake Host Bridge/DRAM Registers + ID_MODEL_FROM_DATABASE=Skylake Host Bridge/DRAM Registers pci:v00008086d00001901* - ID_MODEL_FROM_DATABASE=Sky Lake PCIe Controller (x16) + ID_MODEL_FROM_DATABASE=Skylake PCIe Controller (x16) + +pci:v00008086d00001903* + ID_MODEL_FROM_DATABASE=Skylake Processor Thermal Subsystem pci:v00008086d00001904* - ID_MODEL_FROM_DATABASE=Sky Lake Host Bridge/DRAM Registers + ID_MODEL_FROM_DATABASE=Skylake Host Bridge/DRAM Registers pci:v00008086d00001905* - ID_MODEL_FROM_DATABASE=Sky Lake PCIe Controller (x8) + ID_MODEL_FROM_DATABASE=Skylake PCIe Controller (x8) pci:v00008086d00001908* - ID_MODEL_FROM_DATABASE=Sky Lake Host Bridge/DRAM Registers + ID_MODEL_FROM_DATABASE=Skylake Host Bridge/DRAM Registers pci:v00008086d00001909* - ID_MODEL_FROM_DATABASE=Sky Lake PCIe Controller (x4) + ID_MODEL_FROM_DATABASE=Skylake PCIe Controller (x4) pci:v00008086d0000190C* - ID_MODEL_FROM_DATABASE=Sky Lake Host Bridge/DRAM Registers + ID_MODEL_FROM_DATABASE=Skylake Host Bridge/DRAM Registers pci:v00008086d0000190F* - ID_MODEL_FROM_DATABASE=Sky Lake Host Bridge/DRAM Registers + ID_MODEL_FROM_DATABASE=Skylake Host Bridge/DRAM Registers pci:v00008086d00001910* - ID_MODEL_FROM_DATABASE=Sky Lake Host Bridge/DRAM Registers + ID_MODEL_FROM_DATABASE=Skylake Host Bridge/DRAM Registers pci:v00008086d00001911* - ID_MODEL_FROM_DATABASE=Sky Lake Gaussian Mixture Model + ID_MODEL_FROM_DATABASE=Skylake Gaussian Mixture Model pci:v00008086d00001912* - ID_MODEL_FROM_DATABASE=Sky Lake Integrated Graphics + ID_MODEL_FROM_DATABASE=Skylake Integrated Graphics pci:v00008086d00001916* - ID_MODEL_FROM_DATABASE=Sky Lake Integrated Graphics + ID_MODEL_FROM_DATABASE=Skylake Integrated Graphics pci:v00008086d00001918* - ID_MODEL_FROM_DATABASE=Sky Lake Host Bridge/DRAM Registers + ID_MODEL_FROM_DATABASE=Skylake Host Bridge/DRAM Registers pci:v00008086d00001919* - ID_MODEL_FROM_DATABASE=Sky Lake Imaging Unit + ID_MODEL_FROM_DATABASE=Skylake Imaging Unit + +pci:v00008086d0000191B* + ID_MODEL_FROM_DATABASE=Skylake Integrated Graphics pci:v00008086d0000191E* - ID_MODEL_FROM_DATABASE=Sky Lake Integrated Graphics + ID_MODEL_FROM_DATABASE=Skylake Integrated Graphics pci:v00008086d0000191F* - ID_MODEL_FROM_DATABASE=Sky Lake Host Bridge/DRAM Registers + ID_MODEL_FROM_DATABASE=Skylake Host Bridge/DRAM Registers pci:v00008086d00001926* - ID_MODEL_FROM_DATABASE=Sky Lake Integrated Graphics + ID_MODEL_FROM_DATABASE=Skylake Integrated Graphics pci:v00008086d00001932* - ID_MODEL_FROM_DATABASE=Sky Lake Integrated Graphics + ID_MODEL_FROM_DATABASE=Skylake Integrated Graphics pci:v00008086d0000193B* - ID_MODEL_FROM_DATABASE=Sky Lake Integrated Graphics + ID_MODEL_FROM_DATABASE=Skylake Integrated Graphics pci:v00008086d00001960* ID_MODEL_FROM_DATABASE=80960RP (i960RP) Microprocessor @@ -65582,6 +66182,9 @@ pci:v00008086d00001E02sv00001849sd00001E02* pci:v00008086d00001E03* ID_MODEL_FROM_DATABASE=7 Series Chipset Family 6-port SATA Controller [AHCI mode] +pci:v00008086d00001E03sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family 6-port SATA Controller [AHCI mode] (VivoBook X202EV) + pci:v00008086d00001E03sv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series Chipset Family 6-port SATA Controller [AHCI mode] (N56VZ) @@ -65612,6 +66215,9 @@ pci:v00008086d00001E0E* pci:v00008086d00001E10* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 1 +pci:v00008086d00001E10sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 1 (VivoBook X202EV) + pci:v00008086d00001E10sv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 1 (N56VZ) @@ -65627,6 +66233,9 @@ pci:v00008086d00001E10sv00001849sd00001E10* pci:v00008086d00001E12* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 2 +pci:v00008086d00001E12sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 2 (VivoBook X202EV) + pci:v00008086d00001E12sv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 2 (N56VZ) @@ -65639,6 +66248,9 @@ pci:v00008086d00001E14* pci:v00008086d00001E16* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 4 +pci:v00008086d00001E16sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 4 (VivoBook X202EV) + pci:v00008086d00001E16sv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family PCI Express Root Port 4 (N56VZ) @@ -65672,6 +66284,9 @@ pci:v00008086d00001E1Esv00001849sd00001E1E* pci:v00008086d00001E20* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family High Definition Audio Controller +pci:v00008086d00001E20sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family High Definition Audio Controller (VivoBook X202EV) + pci:v00008086d00001E20sv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family High Definition Audio Controller (N56VZ) @@ -65690,6 +66305,9 @@ pci:v00008086d00001E20sv00001849sd00001898* pci:v00008086d00001E22* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family SMBus Controller +pci:v00008086d00001E22sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family SMBus Controller (VivoBook X202EV) + pci:v00008086d00001E22sv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family SMBus Controller (N56VZ) @@ -65714,6 +66332,9 @@ pci:v00008086d00001E25* pci:v00008086d00001E26* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1 +pci:v00008086d00001E26sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1 (VivoBook X202EV) + pci:v00008086d00001E26sv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB Enhanced Host Controller #1 (N56VZ) @@ -65729,6 +66350,9 @@ pci:v00008086d00001E26sv00001849sd00001E26* pci:v00008086d00001E2D* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2 +pci:v00008086d00001E2Dsv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2 (VivoBook X202EV) + pci:v00008086d00001E2Dsv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB Enhanced Host Controller #2 (N56VZ) @@ -65747,6 +66371,9 @@ pci:v00008086d00001E31* pci:v00008086d00001E31sv0000103Csd000017AB* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB xHCI Host Controller (ProBook 6570b) +pci:v00008086d00001E31sv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB xHCI Host Controller (VivoBook X202EV) + pci:v00008086d00001E31sv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family USB xHCI Host Controller (N56VZ) @@ -65765,6 +66392,9 @@ pci:v00008086d00001E33* pci:v00008086d00001E3A* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family MEI Controller #1 +pci:v00008086d00001E3Asv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family MEI Controller #1 (VivoBook X202EV) + pci:v00008086d00001E3Asv00001043sd00001477* ID_MODEL_FROM_DATABASE=7 Series/C210 Series Chipset Family MEI Controller #1 (N56VZ) @@ -65891,6 +66521,9 @@ pci:v00008086d00001E5D* pci:v00008086d00001E5E* ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller +pci:v00008086d00001E5Esv00001043sd0000108D* + ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller (VivoBook X202EV) + pci:v00008086d00001E5F* ID_MODEL_FROM_DATABASE=7 Series Chipset Family LPC Controller @@ -66411,7 +67044,7 @@ pci:v00008086d00002442sv0000147Bsd00000507* ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (TH7II-RAID) pci:v00008086d00002442sv00008086sd00004532* - ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (D815EEA2 mainboard) + ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (Desktop Board D815EEA2/D815EFV) pci:v00008086d00002442sv00008086sd00004557* ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (D815EGEW Mainboard) @@ -66456,7 +67089,7 @@ pci:v00008086d00002443sv000015D9sd00003280* ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller (Supermicro P4SBE Mainboard) pci:v00008086d00002443sv00008086sd00004532* - ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller (D815EEA2 mainboard) + ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller (Desktop Board D815EEA2/D815EFV) pci:v00008086d00002443sv00008086sd00004557* ID_MODEL_FROM_DATABASE=82801BA/BAM SMBus Controller (D815EGEW Mainboard) @@ -66495,7 +67128,7 @@ pci:v00008086d00002444sv0000147Bsd00000507* ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (TH7II-RAID) pci:v00008086d00002444sv00008086sd00004532* - ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (D815EEA2 mainboard) + ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (Desktop Board D815EEA2/D815EFV) pci:v00008086d00002444sv00008086sd00005744* ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #2 (S845WD1-E mainboard) @@ -66536,6 +67169,9 @@ pci:v00008086d00002445sv0000147Bsd00000507* pci:v00008086d00002445sv00008086sd00004557* ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Audio Controller (D815EGEW Mainboard) +pci:v00008086d00002445sv00008086sd00004656* + ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Audio Controller (Desktop Board D815EFV) + pci:v00008086d00002446* ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Modem Controller @@ -66744,7 +67380,7 @@ pci:v00008086d0000244Bsv000015D9sd00003280* ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (Supermicro P4SBE Mainboard) pci:v00008086d0000244Bsv00008086sd00004532* - ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (D815EEA2 mainboard) + ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (Desktop Board D815EEA2/D815EFV) pci:v00008086d0000244Bsv00008086sd00004557* ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (D815EGEW Mainboard) @@ -67022,6 +67658,9 @@ pci:v00008086d000024C2sv00001025sd00000064* pci:v00008086d000024C2sv00001028sd00000126* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 (Optiplex GX260) +pci:v00008086d000024C2sv00001028sd00000160* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 (Dimension 2400) + pci:v00008086d000024C2sv00001028sd00000163* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #1 (Latitude D505) @@ -67103,6 +67742,9 @@ pci:v00008086d000024C3sv00001028sd00000126* pci:v00008086d000024C3sv00001028sd0000014F* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller (Latitude X300) +pci:v00008086d000024C3sv00001028sd00000160* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller (Dimension 2400) + pci:v00008086d000024C3sv00001028sd0000018D* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) SMBus Controller (Inspiron 700m/710m) @@ -67166,6 +67808,9 @@ pci:v00008086d000024C4sv00001025sd00000064* pci:v00008086d000024C4sv00001028sd00000126* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 (Optiplex GX260) +pci:v00008086d000024C4sv00001028sd00000160* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 (Dimension 2400) + pci:v00008086d000024C4sv00001028sd00000163* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #2 (Latitude D505) @@ -67247,6 +67892,9 @@ pci:v00008086d000024C5sv00001028sd0000014F* pci:v00008086d000024C5sv00001028sd00000152* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (Latitude D500) +pci:v00008086d000024C5sv00001028sd00000160* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (Dimension 2400) + pci:v00008086d000024C5sv00001028sd00000163* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (Latitude D505) @@ -67295,9 +67943,6 @@ pci:v00008086d000024C5sv00001734sd00001005* pci:v00008086d000024C5sv00001734sd00001055* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (Amilo M1420) -pci:v00008086d000024C5sv00008086sd000024C5* - ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Audio Controller (Dell Dimension 2400) - pci:v00008086d000024C6* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) AC'97 Modem Controller @@ -67370,6 +68015,9 @@ pci:v00008086d000024C7sv00001025sd00000064* pci:v00008086d000024C7sv00001028sd00000126* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 (Optiplex GX260) +pci:v00008086d000024C7sv00001028sd00000160* + ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 (Dimension 2400) + pci:v00008086d000024C7sv00001028sd00000163* ID_MODEL_FROM_DATABASE=82801DB/DBL/DBM (ICH4/ICH4-L/ICH4-M) USB UHCI Controller #3 (Latitude D505) @@ -67478,6 +68126,9 @@ pci:v00008086d000024CBsv00001014sd00000267* pci:v00008086d000024CBsv00001028sd00000126* ID_MODEL_FROM_DATABASE=82801DB (ICH4) IDE Controller (Optiplex GX260) +pci:v00008086d000024CBsv00001028sd00000160* + ID_MODEL_FROM_DATABASE=82801DB (ICH4) IDE Controller (Dimension 2400) + pci:v00008086d000024CBsv00001043sd00008089* ID_MODEL_FROM_DATABASE=82801DB (ICH4) IDE Controller (P4B533) @@ -67538,6 +68189,9 @@ pci:v00008086d000024CDsv00001028sd00000139* pci:v00008086d000024CDsv00001028sd00000152* ID_MODEL_FROM_DATABASE=82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller (Latitude D500) +pci:v00008086d000024CDsv00001028sd00000160* + ID_MODEL_FROM_DATABASE=82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller (Dimension 2400) + pci:v00008086d000024CDsv00001028sd00000163* ID_MODEL_FROM_DATABASE=82801DB/DBM (ICH4/ICH4-M) USB2 EHCI Controller (Latitude D505) @@ -68165,6 +68819,18 @@ pci:v00008086d000024F0sv000010A9sd0000802E* pci:v00008086d000024F0sv000010A9sd0000802F* ID_MODEL_FROM_DATABASE=Omni-Path HFI Silicon 100 Series [discrete] (Omni-path HFI 100 Series, 2-port) +pci:v00008086d000024F0sv00008086sd00002628* + ID_MODEL_FROM_DATABASE=Omni-Path HFI Silicon 100 Series [discrete] (Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16) + +pci:v00008086d000024F0sv00008086sd00002629* + ID_MODEL_FROM_DATABASE=Omni-Path HFI Silicon 100 Series [discrete] (Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x8) + +pci:v00008086d000024F0sv00008086sd0000262A* + ID_MODEL_FROM_DATABASE=Omni-Path HFI Silicon 100 Series [discrete] (Omni-Path HFI Adapter 100 Series, 2 Ports, Split PCIe x16) + +pci:v00008086d000024F0sv00008086sd0000262D* + ID_MODEL_FROM_DATABASE=Omni-Path HFI Silicon 100 Series [discrete] (Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16, IO Module AHWKPTP100HF) + pci:v00008086d000024F1* ID_MODEL_FROM_DATABASE=Omni-Path HFI Silicon 100 Series [integrated] @@ -68321,6 +68987,9 @@ pci:v00008086d00002562sv00000E11sd000000B9* pci:v00008086d00002562sv00001014sd00000267* ID_MODEL_FROM_DATABASE=82845G/GL[Brookdale-G]/GE Chipset Integrated Graphics Device (NetVista A30p) +pci:v00008086d00002562sv00001028sd00000160* + ID_MODEL_FROM_DATABASE=82845G/GL[Brookdale-G]/GE Chipset Integrated Graphics Device (Dimension 2400) + pci:v00008086d00002562sv00001734sd00001003* ID_MODEL_FROM_DATABASE=82845G/GL[Brookdale-G]/GE Chipset Integrated Graphics Device (D1521 Mainboard (Fujitsu-Siemens)) @@ -73613,6 +74282,9 @@ pci:v00008086d00003165sv00008086sd00004010* pci:v00008086d00003165sv00008086sd00004210* ID_MODEL_FROM_DATABASE=Wireless 3165 (Dual Band Wireless AC 3165) +pci:v00008086d00003166* + ID_MODEL_FROM_DATABASE=Intel Dual Band Wireless-AC 3165 Plus Bluetooth + pci:v00008086d00003200* ID_MODEL_FROM_DATABASE=GD31244 PCI-X SATA HBA @@ -77747,6 +78419,9 @@ pci:v00008086d00009C31* pci:v00008086d00009C31sv000017AAsd00002214* ID_MODEL_FROM_DATABASE=8 Series USB xHCI HC (ThinkPad X240) +pci:v00008086d00009C31sv00008086sd00007270* + ID_MODEL_FROM_DATABASE=8 Series USB xHCI HC (Apple MacBookAir6,2 / MacBookPro11,1) + pci:v00008086d00009C35* ID_MODEL_FROM_DATABASE=8 Series SDIO Controller @@ -77921,6 +78596,75 @@ pci:v00008086d00009CE5* pci:v00008086d00009CE6* ID_MODEL_FROM_DATABASE=Wildcat Point-LP Serial IO GSPI Controller #1 +pci:v00008086d00009D03* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP SATA Controller [AHCI mode] + +pci:v00008086d00009D14* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #5 + +pci:v00008086d00009D15* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #6 + +pci:v00008086d00009D21* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC + +pci:v00008086d00009D23* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP SMBus + +pci:v00008086d00009D27* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO UART Controller #0 + +pci:v00008086d00009D28* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO UART Controller #1 + +pci:v00008086d00009D29* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO SPI Controller #0 + +pci:v00008086d00009D2A* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO SPI Controller #1 + +pci:v00008086d00009D2D* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Secure Digital IO Controller + +pci:v00008086d00009D2F* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller + +pci:v00008086d00009D31* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Thermal subsystem + +pci:v00008086d00009D3A* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP CSME HECI #1 + +pci:v00008086d00009D48* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP LPC Controller + +pci:v00008086d00009D60* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #0 + +pci:v00008086d00009D60sv00008086sd00009D60* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #0 (100 Series PCH/Sunrise Point PCH I2C0 [Skylake/Kaby Lake LPSS I2C]) + +pci:v00008086d00009D61* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #1 + +pci:v00008086d00009D62* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #2 + +pci:v00008086d00009D63* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #3 + +pci:v00008086d00009D64* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #4 + +pci:v00008086d00009D65* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #5 + +pci:v00008086d00009D66* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO UART Controller #2 + +pci:v00008086d00009D70* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio + pci:v00008086d0000A000* ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge @@ -78057,16 +78801,16 @@ pci:v00008086d0000A126* ID_MODEL_FROM_DATABASE=Sunrise Point-H Northpeak pci:v00008086d0000A127* - ID_MODEL_FROM_DATABASE=Sunrise Point-H LPSS UART #0 + ID_MODEL_FROM_DATABASE=Sunrise Point-H Serial IO UART #0 pci:v00008086d0000A128* - ID_MODEL_FROM_DATABASE=Sunrise Point-H LPSS UART #1 + ID_MODEL_FROM_DATABASE=Sunrise Point-H Serial IO UART #1 pci:v00008086d0000A129* - ID_MODEL_FROM_DATABASE=Sunrise Point-H LPSS SPI #0 + ID_MODEL_FROM_DATABASE=Sunrise Point-H Serial IO SPI #0 pci:v00008086d0000A12A* - ID_MODEL_FROM_DATABASE=Sunrise Point-H LPSS SPI #1 + ID_MODEL_FROM_DATABASE=Sunrise Point-H Serial IO SPI #1 pci:v00008086d0000A12F* ID_MODEL_FROM_DATABASE=Sunrise Point-H USB 3.0 xHCI Controller @@ -78195,13 +78939,13 @@ pci:v00008086d0000A15F* ID_MODEL_FROM_DATABASE=Sunrise Point-H LPC Controller pci:v00008086d0000A160* - ID_MODEL_FROM_DATABASE=Sunrise Point-H LPSS I2C Controller #0 + ID_MODEL_FROM_DATABASE=Sunrise Point-H Serial IO I2C Controller #0 pci:v00008086d0000A161* - ID_MODEL_FROM_DATABASE=Sunrise Point-H LPSS I2C Controller #1 + ID_MODEL_FROM_DATABASE=Sunrise Point-H Serial IO I2C Controller #1 pci:v00008086d0000A166* - ID_MODEL_FROM_DATABASE=Sunrise Point-H LPSS UART Controller #2 + ID_MODEL_FROM_DATABASE=Sunrise Point-H Serial IO UART Controller #2 pci:v00008086d0000A167* ID_MODEL_FROM_DATABASE=Sunrise Point-H PCI Root Port #17 diff --git a/hwdb/20-usb-vendor-model.hwdb b/hwdb/20-usb-vendor-model.hwdb index 803c2c21f..46b7ed9ab 100644 --- a/hwdb/20-usb-vendor-model.hwdb +++ b/hwdb/20-usb-vendor-model.hwdb @@ -465,7 +465,7 @@ usb:v03F0p011D* ID_MODEL_FROM_DATABASE=Bluetooth 1.2 Interface [Broadcom BCM2035] usb:v03F0p0121* - ID_MODEL_FROM_DATABASE=HP49g+ Calculator + ID_MODEL_FROM_DATABASE=HP 39g+ [F2224A], 39gs [F2223A], 40gs [F2225A], 48gII [F2226A], 49g+ [F2228A], 50g [F2229A, NW240AA] usb:v03F0p0122* ID_MODEL_FROM_DATABASE=HID Internet Keyboard @@ -567,7 +567,7 @@ usb:v03F0p042A* ID_MODEL_FROM_DATABASE=LaserJet M1132 MFP usb:v03F0p0441* - ID_MODEL_FROM_DATABASE=HP Prime Calculator + ID_MODEL_FROM_DATABASE=Prime [NW280AA, G8X92AA] usb:v03F0p0504* ID_MODEL_FROM_DATABASE=DeskJet 885c @@ -632,6 +632,9 @@ usb:v03F0p0712* usb:v03F0p0714* ID_MODEL_FROM_DATABASE=Printing Support +usb:v03F0p0741* + ID_MODEL_FROM_DATABASE=Prime Wireless Kit [FOK65AA] + usb:v03F0p0801* ID_MODEL_FROM_DATABASE=ScanJet 7400c @@ -833,6 +836,9 @@ usb:v03F0p1524* usb:v03F0p1539* ID_MODEL_FROM_DATABASE=Mini Magnetic Stripe Reader +usb:v03F0p1541* + ID_MODEL_FROM_DATABASE=Prime [G8X92AA] + usb:v03F0p1602* ID_MODEL_FROM_DATABASE=PhotoSmart 330 series @@ -1130,6 +1136,9 @@ usb:v03F0p2A11* usb:v03F0p2A17* ID_MODEL_FROM_DATABASE=LaserJet 2430 +usb:v03F0p2A1D* + ID_MODEL_FROM_DATABASE=Integrated Module with Bluetooth 2.1 Wireless technology + usb:v03F0p2B11* ID_MODEL_FROM_DATABASE=PSC 2170 series @@ -1898,6 +1907,9 @@ usb:v03F0pC802* usb:v03F0pD104* ID_MODEL_FROM_DATABASE=Bluetooth Dongle +usb:v03F0pD507* + ID_MODEL_FROM_DATABASE=39gII [NW249AA] + usb:v03F0pEFBE* ID_MODEL_FROM_DATABASE=NEC Picty900 @@ -3719,6 +3731,9 @@ usb:v041Ep3090* usb:v041Ep30D3* ID_MODEL_FROM_DATABASE=Sound Blaster Play! +usb:v041Ep3100* + ID_MODEL_FROM_DATABASE=IR Receiver (SB0540) + usb:v041Ep3121* ID_MODEL_FROM_DATABASE=WoW tap chat @@ -5627,6 +5642,9 @@ usb:v0458p0083* usb:v0458p0087* ID_MODEL_FROM_DATABASE=Ergo 525V Laser Mouse +usb:v0458p0089* + ID_MODEL_FROM_DATABASE=Genius Traveler 350 + usb:v0458p00CA* ID_MODEL_FROM_DATABASE=Pen Mouse @@ -7031,6 +7049,9 @@ usb:v046Ap0081* usb:v046Ap0106* ID_MODEL_FROM_DATABASE=R-300 Wireless Mouse Receiver +usb:v046Ap010D* + ID_MODEL_FROM_DATABASE=MX-Board 3.0 Keyboard + usb:v046B* ID_VENDOR_FROM_DATABASE=American Megatrends, Inc. @@ -11898,7 +11919,7 @@ usb:v04B3p4484* ID_MODEL_FROM_DATABASE=SMSC USB20H04 3-Port Hub [ThinkPad X4 UltraBase, Wistron S Note-3 Media Slice] usb:v04B3p4485* - ID_MODEL_FROM_DATABASE=Serial Converter + ID_MODEL_FROM_DATABASE=ThinkPad Dock Hub usb:v04B3p4524* ID_MODEL_FROM_DATABASE=40 Character Vacuum Fluorescent Display @@ -12570,7 +12591,7 @@ usb:v04B8p087C* ID_MODEL_FROM_DATABASE=PX-1700F usb:v04B8p087D* - ID_MODEL_FROM_DATABASE=PX-B750F + ID_MODEL_FROM_DATABASE=PX-B750F/WP-4525 Series usb:v04B8p087F* ID_MODEL_FROM_DATABASE=PX-403A @@ -15071,6 +15092,9 @@ usb:v04F3p0103* usb:v04F3p01A4* ID_MODEL_FROM_DATABASE=Wireless Keyboard +usb:v04F3p0201* + ID_MODEL_FROM_DATABASE=Touchscreen + usb:v04F3p0210* ID_MODEL_FROM_DATABASE=Optical Mouse @@ -16406,6 +16430,9 @@ usb:v04F9p035D* usb:v04F9p035E* ID_MODEL_FROM_DATABASE=MFC-1910NW +usb:v04F9p0360* + ID_MODEL_FROM_DATABASE=DCP-1618W + usb:v04F9p0361* ID_MODEL_FROM_DATABASE=MFC-1919NW @@ -18795,61 +18822,61 @@ usb:v056Ap0010* ID_MODEL_FROM_DATABASE=ET-0405 [Graphire] usb:v056Ap0011* - ID_MODEL_FROM_DATABASE=Graphire 2 4x5 + ID_MODEL_FROM_DATABASE=ET-0405A [Graphire2 (4x5)] usb:v056Ap0012* - ID_MODEL_FROM_DATABASE=Graphire 2 5x7 + ID_MODEL_FROM_DATABASE=ET-0507A [Graphire2 (5x7)] usb:v056Ap0013* - ID_MODEL_FROM_DATABASE=Graphire 3 4x5 + ID_MODEL_FROM_DATABASE=CTE-430 [Graphire3 (4x5)] usb:v056Ap0014* - ID_MODEL_FROM_DATABASE=Graphire 3 6x8 + ID_MODEL_FROM_DATABASE=CTE-630 [Graphire3 (6x8)] usb:v056Ap0015* - ID_MODEL_FROM_DATABASE=Graphire 4 4x5 + ID_MODEL_FROM_DATABASE=CTE-440 [Graphire4 (4x5)] usb:v056Ap0016* - ID_MODEL_FROM_DATABASE=Graphire 4 6x8 + ID_MODEL_FROM_DATABASE=CTE-640 [Graphire4 (6x8)] usb:v056Ap0017* - ID_MODEL_FROM_DATABASE=CTE-450 [Bamboo Fun] + ID_MODEL_FROM_DATABASE=CTE-450 [Bamboo Fun (small)] usb:v056Ap0018* - ID_MODEL_FROM_DATABASE=Bamboo Fun 6x8 + ID_MODEL_FROM_DATABASE=CTE-650 [Bamboo Fun (medium)] usb:v056Ap0019* - ID_MODEL_FROM_DATABASE=Bamboo One Medium + ID_MODEL_FROM_DATABASE=CTE-631 [Bamboo One] usb:v056Ap0020* - ID_MODEL_FROM_DATABASE=Intuos 4x5 + ID_MODEL_FROM_DATABASE=GD-0405 [Intuos (4x5)] usb:v056Ap0021* - ID_MODEL_FROM_DATABASE=Intuos 6x8 + ID_MODEL_FROM_DATABASE=GD-0608 [Intuos (6x8)] usb:v056Ap0022* - ID_MODEL_FROM_DATABASE=Intuos 9x12 + ID_MODEL_FROM_DATABASE=GD-0912 [Intuos (9x12)] usb:v056Ap0023* - ID_MODEL_FROM_DATABASE=Intuos 12x12 + ID_MODEL_FROM_DATABASE=GD-1212 [Intuos (12x12)] usb:v056Ap0024* - ID_MODEL_FROM_DATABASE=Intuos 12x18 + ID_MODEL_FROM_DATABASE=GD-1218 [Intuos (12x18)] usb:v056Ap0026* - ID_MODEL_FROM_DATABASE=Intuos5 touch S + ID_MODEL_FROM_DATABASE=PTH-450 [Intuos5 touch (S)] usb:v056Ap0027* - ID_MODEL_FROM_DATABASE=Intuos5 touch M + ID_MODEL_FROM_DATABASE=PTH-650 [Intuos5 touch (M)] usb:v056Ap0028* - ID_MODEL_FROM_DATABASE=Intuos5 touch L + ID_MODEL_FROM_DATABASE=PTH-850 [Intuos5 touch (L)] usb:v056Ap0029* - ID_MODEL_FROM_DATABASE=Intuos5 S + ID_MODEL_FROM_DATABASE=PTK-450 [Intuos5 (S)] usb:v056Ap002A* - ID_MODEL_FROM_DATABASE=Intuos5 M + ID_MODEL_FROM_DATABASE=PTK-650 [Intuos5 (M)] usb:v056Ap0030* ID_MODEL_FROM_DATABASE=PL400 @@ -18879,49 +18906,70 @@ usb:v056Ap0039* ID_MODEL_FROM_DATABASE=DTU-710 usb:v056Ap003F* - ID_MODEL_FROM_DATABASE=Cintiq 21UX (DTZ-2100) + ID_MODEL_FROM_DATABASE=DTZ-2100 [Cintiq 21UX] usb:v056Ap0041* - ID_MODEL_FROM_DATABASE=Intuos2 4x5 + ID_MODEL_FROM_DATABASE=XD-0405-U [Intuos2 (4x5)] usb:v056Ap0042* - ID_MODEL_FROM_DATABASE=Intuos2 6x8 + ID_MODEL_FROM_DATABASE=XD-0608-U [Intuos2 (6x8)] usb:v056Ap0043* - ID_MODEL_FROM_DATABASE=Intuos2 9x12 + ID_MODEL_FROM_DATABASE=XD-0912-U [Intuos2 (9x12)] usb:v056Ap0044* - ID_MODEL_FROM_DATABASE=Intuos2 12x12 + ID_MODEL_FROM_DATABASE=XD-1212-U [Intuos2 (12x12)] usb:v056Ap0045* - ID_MODEL_FROM_DATABASE=Intuos2 12x18 + ID_MODEL_FROM_DATABASE=XD-1218-U [Intuos2 (12x18)] usb:v056Ap0047* ID_MODEL_FROM_DATABASE=Intuos2 6x8 +usb:v056Ap0057* + ID_MODEL_FROM_DATABASE=DTK-2241 + +usb:v056Ap0059* + ID_MODEL_FROM_DATABASE=DTH-2242 tablet + +usb:v056Ap005B* + ID_MODEL_FROM_DATABASE=DTH-2200 [Cintiq 22HD Touch] tablet + +usb:v056Ap005D* + ID_MODEL_FROM_DATABASE=DTH-2242 touchscreen + +usb:v056Ap005E* + ID_MODEL_FROM_DATABASE=DTH-2200 [Cintiq 22HD Touch] touchscreen + usb:v056Ap0060* - ID_MODEL_FROM_DATABASE=Volito + ID_MODEL_FROM_DATABASE=FT-0405 [Volito, PenPartner, PenStation (4x5)] usb:v056Ap0061* - ID_MODEL_FROM_DATABASE=PenStation2 + ID_MODEL_FROM_DATABASE=FT-0203 [Volito, PenPartner, PenStation (2x3)] usb:v056Ap0062* - ID_MODEL_FROM_DATABASE=Volito2 4x5 + ID_MODEL_FROM_DATABASE=CTF-420 [Volito2] usb:v056Ap0063* - ID_MODEL_FROM_DATABASE=Volito2 2x3 + ID_MODEL_FROM_DATABASE=CTF-220 [BizTablet] usb:v056Ap0064* - ID_MODEL_FROM_DATABASE=PenPartner2 + ID_MODEL_FROM_DATABASE=CTF-221 [PenPartner2] usb:v056Ap0065* - ID_MODEL_FROM_DATABASE=Bamboo + ID_MODEL_FROM_DATABASE=MTE-450 [Bamboo] usb:v056Ap0069* - ID_MODEL_FROM_DATABASE=Bamboo One + ID_MODEL_FROM_DATABASE=CTF-430 [Bamboo One] + +usb:v056Ap006A* + ID_MODEL_FROM_DATABASE=CTE-460 [Bamboo One Pen (S)] + +usb:v056Ap006B* + ID_MODEL_FROM_DATABASE=CTE-660 [Bamboo One Pen (M)] usb:v056Ap0081* - ID_MODEL_FROM_DATABASE=Graphire Wireless 6x8 + ID_MODEL_FROM_DATABASE=CTE-630BT [Graphire Wireless (6x8)] usb:v056Ap0084* ID_MODEL_FROM_DATABASE=Wireless adapter for Bamboo tablets @@ -18932,41 +18980,44 @@ usb:v056Ap0090* usb:v056Ap0093* ID_MODEL_FROM_DATABASE=TPC93 +usb:v056Ap0097* + ID_MODEL_FROM_DATABASE=TPC97 + usb:v056Ap009A* ID_MODEL_FROM_DATABASE=TPC9A usb:v056Ap00B0* - ID_MODEL_FROM_DATABASE=Intuos3 4x5 + ID_MODEL_FROM_DATABASE=PTZ-430 [Intuos3 (4x5)] usb:v056Ap00B1* - ID_MODEL_FROM_DATABASE=Intuos3 6x18 + ID_MODEL_FROM_DATABASE=PTZ-630 [Intuos3 (6x8)] usb:v056Ap00B2* - ID_MODEL_FROM_DATABASE=Intuos3 9x12 + ID_MODEL_FROM_DATABASE=PTZ-930 [Intuos3 (9x12)] usb:v056Ap00B3* - ID_MODEL_FROM_DATABASE=Intuos3 12x12 + ID_MODEL_FROM_DATABASE=PTZ-1230 [Intuos3 (12x12)] usb:v056Ap00B4* - ID_MODEL_FROM_DATABASE=Intuos3 12x19 + ID_MODEL_FROM_DATABASE=PTZ-1231W [Intuos3 (12x19)] usb:v056Ap00B5* - ID_MODEL_FROM_DATABASE=Intuos3 6x11 (PTZ-631W) + ID_MODEL_FROM_DATABASE=PTZ-631W [Intuos3 (6x11)] usb:v056Ap00B7* - ID_MODEL_FROM_DATABASE=Intuos3 4x6 + ID_MODEL_FROM_DATABASE=PTZ-431W [Intuos3 (4x6)] usb:v056Ap00B8* - ID_MODEL_FROM_DATABASE=Intuos4 4x6 + ID_MODEL_FROM_DATABASE=PTK-440 [Intuos4 (4x6)] usb:v056Ap00B9* - ID_MODEL_FROM_DATABASE=Intuos4 6x9 + ID_MODEL_FROM_DATABASE=PTK-640 [Intuos4 (6x9)] usb:v056Ap00BA* - ID_MODEL_FROM_DATABASE=Intuos4 8x13 + ID_MODEL_FROM_DATABASE=PTK-840 [Intuos4 (8x13)] usb:v056Ap00BB* - ID_MODEL_FROM_DATABASE=Intuos4 12x19 + ID_MODEL_FROM_DATABASE=PTK-1240 [Intuos4 (12x19)] usb:v056Ap00C0* ID_MODEL_FROM_DATABASE=DTF-521 @@ -18975,64 +19026,181 @@ usb:v056Ap00C4* ID_MODEL_FROM_DATABASE=DTF-720 usb:v056Ap00C5* - ID_MODEL_FROM_DATABASE=Cintiq 20WSX + ID_MODEL_FROM_DATABASE=DTZ-20WSX [Cintiq 20WSX] usb:v056Ap00C6* - ID_MODEL_FROM_DATABASE=Cintiq 12WX + ID_MODEL_FROM_DATABASE=DTZ-12WX [Cintiq 12WX] usb:v056Ap00C7* ID_MODEL_FROM_DATABASE=DTU-1931 usb:v056Ap00CC* - ID_MODEL_FROM_DATABASE=Cintiq 21UX (DTK-2100) + ID_MODEL_FROM_DATABASE=DTK-2100 [Cintiq 21UX] + +usb:v056Ap00CE* + ID_MODEL_FROM_DATABASE=DTU-2231 + +usb:v056Ap00D0* + ID_MODEL_FROM_DATABASE=CTT-460 [Bamboo Touch] usb:v056Ap00D1* - ID_MODEL_FROM_DATABASE=Bamboo Pen & Touch (CTH-460-DE) + ID_MODEL_FROM_DATABASE=CTH-460 [Bamboo Pen & Touch] + +usb:v056Ap00D2* + ID_MODEL_FROM_DATABASE=CTH-461 [Bamboo Fun/Craft/Comic Pen & Touch (S)] usb:v056Ap00D3* - ID_MODEL_FROM_DATABASE=Bamboo Fun (CTH-661) + ID_MODEL_FROM_DATABASE=CTH-661 [Bamboo Fun/Comic Pen & Touch (M)] usb:v056Ap00D4* - ID_MODEL_FROM_DATABASE=Bamboo Pen (CTL-460) + ID_MODEL_FROM_DATABASE=CTL-460 [Bamboo Pen (S)] + +usb:v056Ap00D5* + ID_MODEL_FROM_DATABASE=CTL-660 [Bamboo Pen (M)] usb:v056Ap00D6* - ID_MODEL_FROM_DATABASE=Bamboo Pen & Touch (CTH-460) + ID_MODEL_FROM_DATABASE=CTH-460 [Bamboo Pen & Touch] + +usb:v056Ap00D7* + ID_MODEL_FROM_DATABASE=CTH-461 [Bamboo Fun/Craft/Comic Pen & Touch (S)] + +usb:v056Ap00D8* + ID_MODEL_FROM_DATABASE=CTH-661 [Bamboo Fun/Comic Pen & Touch (M)] + +usb:v056Ap00D9* + ID_MODEL_FROM_DATABASE=CTT-460 [Bamboo Touch] + +usb:v056Ap00DA* + ID_MODEL_FROM_DATABASE=CTH-461SE [Bamboo Pen & Touch Special Edition (S)] usb:v056Ap00DB* - ID_MODEL_FROM_DATABASE=Bamboo Fun (CTH-661SE-NL) + ID_MODEL_FROM_DATABASE=CTH-661SE [Bamboo Pen & Touch Special Edition (M)] + +usb:v056Ap00DC* + ID_MODEL_FROM_DATABASE=CTT-470 [Bamboo Touch] usb:v056Ap00DD* - ID_MODEL_FROM_DATABASE=Bamboo Pen (CTL-470) + ID_MODEL_FROM_DATABASE=CTL-470 [Bamboo Connect] usb:v056Ap00DE* ID_MODEL_FROM_DATABASE=CTH-470 [Bamboo Fun Pen & Touch] +usb:v056Ap00DF* + ID_MODEL_FROM_DATABASE=CTH-670 [Bamboo Create/Fun] + +usb:v056Ap00E2* + ID_MODEL_FROM_DATABASE=TPCE2 + +usb:v056Ap00E3* + ID_MODEL_FROM_DATABASE=TPCE3 + +usb:v056Ap00E5* + ID_MODEL_FROM_DATABASE=TPCE5 + +usb:v056Ap00E6* + ID_MODEL_FROM_DATABASE=TPCE6 + +usb:v056Ap00EC* + ID_MODEL_FROM_DATABASE=TPCEC + +usb:v056Ap00ED* + ID_MODEL_FROM_DATABASE=TPCED + +usb:v056Ap00EF* + ID_MODEL_FROM_DATABASE=TPCEF + +usb:v056Ap00F4* + ID_MODEL_FROM_DATABASE=DTK-2400 [Cintiq 24HD] tablet + usb:v056Ap00F6* - ID_MODEL_FROM_DATABASE=Cintiq 24HD touch (DTH-2400) touchscreen + ID_MODEL_FROM_DATABASE=DTH-2400 [Cintiq 24HD touch] touchscreen usb:v056Ap00F8* - ID_MODEL_FROM_DATABASE=Cintiq 24HD touch (DTH-2400) tablet + ID_MODEL_FROM_DATABASE=DTH-2400 [Cintiq 24HD touch] tablet + +usb:v056Ap00FA* + ID_MODEL_FROM_DATABASE=DTK-2200 [Cintiq 22HD] tablet + +usb:v056Ap00FB* + ID_MODEL_FROM_DATABASE=DTU-1031 + +usb:v056Ap0100* + ID_MODEL_FROM_DATABASE=TPC100 + +usb:v056Ap0101* + ID_MODEL_FROM_DATABASE=TPC101 + +usb:v056Ap010D* + ID_MODEL_FROM_DATABASE=TPC10D + +usb:v056Ap010E* + ID_MODEL_FROM_DATABASE=TPC10E + +usb:v056Ap010F* + ID_MODEL_FROM_DATABASE=TPC10F + +usb:v056Ap0116* + ID_MODEL_FROM_DATABASE=TPC116 + +usb:v056Ap012C* + ID_MODEL_FROM_DATABASE=TPC12C + +usb:v056Ap0300* + ID_MODEL_FROM_DATABASE=CTL-471 [Bamboo Splash, One by Wacom (S)] + +usb:v056Ap0301* + ID_MODEL_FROM_DATABASE=CTL-671 [One by Wacom (M)] usb:v056Ap0302* - ID_MODEL_FROM_DATABASE=Intuos CTH480S2 [Manga] + ID_MODEL_FROM_DATABASE=CTH-480 [Intuos Pen & Touch (S)] + +usb:v056Ap0303* + ID_MODEL_FROM_DATABASE=CTH-680 [Intuos Pen & Touch (M)] + +usb:v056Ap0304* + ID_MODEL_FROM_DATABASE=DTK-1300 [Cintiq 13HD] usb:v056Ap0307* - ID_MODEL_FROM_DATABASE=Cintiq Companion Hybrid 13HD (DTH-A1300) tablet + ID_MODEL_FROM_DATABASE=DTH-A1300 [Cintiq Companion Hybrid] tablet usb:v056Ap0309* - ID_MODEL_FROM_DATABASE=Cintiq Companion Hybrid 13HD (DTH-A1300) touchscreen + ID_MODEL_FROM_DATABASE=DTH-A1300 [Cintiq Companion Hybrid] touchscreen usb:v056Ap030E* - ID_MODEL_FROM_DATABASE=Intuos Pen Small (CTL480) + ID_MODEL_FROM_DATABASE=CTL-480 [Intuos Pen (S)] + +usb:v056Ap0314* + ID_MODEL_FROM_DATABASE=PTH-451 [Intuos pro (S)] + +usb:v056Ap0315* + ID_MODEL_FROM_DATABASE=PTH-651 [Intuos pro (M)] + +usb:v056Ap0317* + ID_MODEL_FROM_DATABASE=PTH-851 [Intuos pro (L)] + +usb:v056Ap032F* + ID_MODEL_FROM_DATABASE=DTU-1031X usb:v056Ap0400* ID_MODEL_FROM_DATABASE=PenPartner 4x5 +usb:v056Ap4001* + ID_MODEL_FROM_DATABASE=TPC4001 + +usb:v056Ap4004* + ID_MODEL_FROM_DATABASE=TPC4004 + usb:v056Ap4850* ID_MODEL_FROM_DATABASE=PenPartner 6x8 +usb:v056Ap5000* + ID_MODEL_FROM_DATABASE=TPC5000 + +usb:v056Ap5002* + ID_MODEL_FROM_DATABASE=TPC5002 + usb:v056Ap5010* - ID_MODEL_FROM_DATABASE=Thinkpad T550 touchscreen + ID_MODEL_FROM_DATABASE=TPC5010 usb:v056B* ID_VENDOR_FROM_DATABASE=Decicon, Inc. @@ -20546,6 +20714,9 @@ usb:v058Fp6387* usb:v058Fp6390* ID_MODEL_FROM_DATABASE=USB 2.0-IDE bridge +usb:v058Fp6391* + ID_MODEL_FROM_DATABASE=IDE Bridge + usb:v058Fp9213* ID_MODEL_FROM_DATABASE=MacAlly Kbd Hub @@ -20588,6 +20759,9 @@ usb:v058Fp9368* usb:v058Fp9380* ID_MODEL_FROM_DATABASE=Flash Drive +usb:v058Fp9381* + ID_MODEL_FROM_DATABASE=Flash Drive + usb:v058Fp9382* ID_MODEL_FROM_DATABASE=Acer/Sweex Flash drive @@ -21563,6 +21737,9 @@ usb:v05ACp8281* usb:v05ACp8286* ID_MODEL_FROM_DATABASE=Bluetooth Host Controller +usb:v05ACp828C* + ID_MODEL_FROM_DATABASE=Bluetooth Host Controller + usb:v05ACp8300* ID_MODEL_FROM_DATABASE=Built-in iSight (no firmware loaded) @@ -21950,6 +22127,9 @@ usb:v05CAp1812* usb:v05CAp1814* ID_MODEL_FROM_DATABASE=HD Webcam +usb:v05CAp1815* + ID_MODEL_FROM_DATABASE=Dell Laptop Integrated Webcam + usb:v05CAp1820* ID_MODEL_FROM_DATABASE=Integrated Webcam @@ -22367,6 +22547,9 @@ usb:v05DAp20ED* usb:v05DAp20EE* ID_MODEL_FROM_DATABASE=Micortek ScanMaker X12USL +usb:v05DAp2838* + ID_MODEL_FROM_DATABASE=RT2832U + usb:v05DAp3008* ID_MODEL_FROM_DATABASE=Scanner @@ -33638,6 +33821,90 @@ usb:v0A85* usb:v0A86* ID_VENDOR_FROM_DATABASE=NITGen Co., Ltd +usb:v0A89* + ID_VENDOR_FROM_DATABASE=Aktiv + +usb:v0A89p0001* + ID_MODEL_FROM_DATABASE=Guardant Stealth/Net + +usb:v0A89p0002* + ID_MODEL_FROM_DATABASE=Guardant ID + +usb:v0A89p0003* + ID_MODEL_FROM_DATABASE=Guardant Stealth 2 + +usb:v0A89p0004* + ID_MODEL_FROM_DATABASE=Rutoken + +usb:v0A89p0005* + ID_MODEL_FROM_DATABASE=Guardant Fidus + +usb:v0A89p0006* + ID_MODEL_FROM_DATABASE=Guardant Stealth 3 + +usb:v0A89p0007* + ID_MODEL_FROM_DATABASE=Guardant Stealth 2 + +usb:v0A89p0008* + ID_MODEL_FROM_DATABASE=Guardant Stealth 3 Sign/Time + +usb:v0A89p0009* + ID_MODEL_FROM_DATABASE=Guardant Code + +usb:v0A89p000A* + ID_MODEL_FROM_DATABASE=Guardant Sign Pro + +usb:v0A89p000B* + ID_MODEL_FROM_DATABASE=Guardant Sign Pro HID + +usb:v0A89p000C* + ID_MODEL_FROM_DATABASE=Guardant Stealth 3 Sign/Time + +usb:v0A89p000D* + ID_MODEL_FROM_DATABASE=Guardant Code HID + +usb:v0A89p000F* + ID_MODEL_FROM_DATABASE=Guardant System Firmware Update + +usb:v0A89p0020* + ID_MODEL_FROM_DATABASE=Rutoken S + +usb:v0A89p0025* + ID_MODEL_FROM_DATABASE=Rutoken lite + +usb:v0A89p0026* + ID_MODEL_FROM_DATABASE=Rutoken lite HID + +usb:v0A89p002A* + ID_MODEL_FROM_DATABASE=Rutoken Mass Storage + +usb:v0A89p002B* + ID_MODEL_FROM_DATABASE=Guardant Mass Storage + +usb:v0A89p0030* + ID_MODEL_FROM_DATABASE=Rutoken ECP + +usb:v0A89p0040* + ID_MODEL_FROM_DATABASE=Rutoken ECP HID + +usb:v0A89p0060* + ID_MODEL_FROM_DATABASE=Rutoken Magistra + +usb:v0A89p0061* + ID_MODEL_FROM_DATABASE=Rutoken Magistra + +usb:v0A89p0069* + ID_MODEL_FROM_DATABASE=Reader + +usb:v0A89p0080* + ID_MODEL_FROM_DATABASE=Rutoken PinPad Ex + +usb:v0A89p0081* + ID_MODEL_FROM_DATABASE=Rutoken PinPad In + +usb:v0A89p0082* + ID_MODEL_FROM_DATABASE=Rutoken PinPad 2 + usb:v0A8D* ID_VENDOR_FROM_DATABASE=Picturetel @@ -48467,6 +48734,9 @@ usb:v1871* usb:v1871p0101* ID_MODEL_FROM_DATABASE=UVC camera (Bresser microscope) +usb:v1871p0141* + ID_MODEL_FROM_DATABASE=Camera + usb:v1871p0D01* ID_MODEL_FROM_DATABASE=USB2.0 Camera @@ -48548,6 +48818,9 @@ usb:v18A5p0216* usb:v18A5p0218* ID_MODEL_FROM_DATABASE=External Hard Drive +usb:v18A5p0224* + ID_MODEL_FROM_DATABASE=Store 'n' Go Micro Plus + usb:v18A5p0227* ID_MODEL_FROM_DATABASE=Pocket Hard Drive @@ -48555,11 +48828,20 @@ usb:v18A5p022B* ID_MODEL_FROM_DATABASE=Portable Hard Drive (Store'n'Go) usb:v18A5p0237* - ID_MODEL_FROM_DATABASE=Portable Harddrive (500 GB) + ID_MODEL_FROM_DATABASE=Portable Harddrive + +usb:v18A5p0243* + ID_MODEL_FROM_DATABASE=Flash Drive (Store'n'Go) usb:v18A5p0302* ID_MODEL_FROM_DATABASE=Flash Drive +usb:v18A5p0304* + ID_MODEL_FROM_DATABASE=Store 'n' Go + +usb:v18A5p4123* + ID_MODEL_FROM_DATABASE=Store N Go + usb:v18B1* ID_VENDOR_FROM_DATABASE=Petalynx @@ -48611,6 +48893,18 @@ usb:v18CDpCAFE* usb:v18D1* ID_VENDOR_FROM_DATABASE=Google Inc. +usb:v18D1p0001* + ID_MODEL_FROM_DATABASE=Onda V972 (storage access) + +usb:v18D1p0003* + ID_MODEL_FROM_DATABASE=Android-powered device using AllWinner Technology SoC + +usb:v18D1p0006* + ID_MODEL_FROM_DATABASE=Onda V972 MTP + +usb:v18D1p0008* + ID_MODEL_FROM_DATABASE=Onda V972 PTP (camera) + usb:v18D1p0D02* ID_MODEL_FROM_DATABASE=Celkon A88 @@ -48641,6 +48935,9 @@ usb:v18D1p4E22* usb:v18D1p4E24* ID_MODEL_FROM_DATABASE=Nexus S (tether) +usb:v18D1p4E30* + ID_MODEL_FROM_DATABASE=Galaxy Nexus (fastboot) + usb:v18D1p4E40* ID_MODEL_FROM_DATABASE=Nexus 7 (fastboot) @@ -48653,17 +48950,29 @@ usb:v18D1p4E42* usb:v18D1p4E43* ID_MODEL_FROM_DATABASE=Nexus 7 (PTP) +usb:v18D1p4E44* + ID_MODEL_FROM_DATABASE=Nexus 7 2012 (PTP) + +usb:v18D1p4EE0* + ID_MODEL_FROM_DATABASE=Nexus 4 (bootloader) + usb:v18D1p4EE1* - ID_MODEL_FROM_DATABASE=Nexus 4 / 10 + ID_MODEL_FROM_DATABASE=Nexus Device (MTP) usb:v18D1p4EE2* - ID_MODEL_FROM_DATABASE=Nexus 4 (debug) + ID_MODEL_FROM_DATABASE=Nexus Device (debug) usb:v18D1p4EE3* - ID_MODEL_FROM_DATABASE=Nexus 4 (tether) + ID_MODEL_FROM_DATABASE=Nexus 4/5/7/10 (tether) usb:v18D1p4EE4* - ID_MODEL_FROM_DATABASE=Nexus 4 (debug + tether) + ID_MODEL_FROM_DATABASE=Nexus 4/5/7/10 (debug + tether) + +usb:v18D1p4EE5* + ID_MODEL_FROM_DATABASE=Nexus 4 (PTP) + +usb:v18D1p4EE6* + ID_MODEL_FROM_DATABASE=Nexus 4/5 (PTP + debug) usb:v18D1p7102* ID_MODEL_FROM_DATABASE=Toshiba Thrive tablet @@ -48671,6 +48980,12 @@ usb:v18D1p7102* usb:v18D1pB004* ID_MODEL_FROM_DATABASE=Pandigital / B&N Novel 9" tablet +usb:v18D1pD001* + ID_MODEL_FROM_DATABASE=Nexus 4 (fastboot) + +usb:v18D1pD002* + ID_MODEL_FROM_DATABASE=Nexus 4 (debug) + usb:v18D1pD109* ID_MODEL_FROM_DATABASE=LG G2x MTP @@ -52358,6 +52673,12 @@ usb:v2478* usb:v2478p2008* ID_MODEL_FROM_DATABASE=U209-000-R Serial Port +usb:v248A* + ID_VENDOR_FROM_DATABASE=Maxxter + +usb:v248Ap8366* + ID_MODEL_FROM_DATABASE=Wireless Optical Mouse ACT-MUSW-002 + usb:v249C* ID_VENDOR_FROM_DATABASE=M2Tech s.r.l. diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb index f7a82ee26..d060d81f6 100644 --- a/hwdb/60-evdev.hwdb +++ b/hwdb/60-evdev.hwdb @@ -25,8 +25,7 @@ # https://github.com/systemd/systemd # or create a bug report on https://github.com/systemd/systemd/issues and # include your new rules, a description of the device, and the output of -# udevadm info /dev/input/eventXX -# (or /dev/input/event*). +# udevadm info /dev/input/eventXX. # # Allowed properties are: # EVDEV_ABS_=:::: @@ -115,6 +114,13 @@ evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnInsp EVDEV_ABS_35=25:2000:22 EVDEV_ABS_36=0:1351:28 +# Dell Latitude E6220 +evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6220* + EVDEV_ABS_00=76:1815:22 + EVDEV_ABS_01=131:1330:30 + EVDEV_ABS_35=76:1815:22 + EVDEV_ABS_36=131:1330:30 + ######################################### # Google ######################################### @@ -126,6 +132,17 @@ evdev:name:Atmel maXTouch Touch*:dmi:bvn*:bvr*:bd*:svnGOOGLE:pnSamus* EVDEV_ABS_35=::10 EVDEV_ABS_36=::10 +######################################### +# HP +######################################### + +# HP Pavilion dm4 +evdev:name:SynPS/2 Synaptics TouchPad*:dmi:*svnHewlett-Packard:pnHPPaviliondm4* + EVDEV_ABS_00=1360:5563:47 + EVDEV_ABS_01=1269:4618:61 + EVDEV_ABS_35=1360:5563:47 + EVDEV_ABS_36=1269:4618:61 + ######################################### # Lenovo ######################################### @@ -141,3 +158,14 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*svnLENOVO*:pn*ThinkPad*T510* EVDEV_ABS_01=841:5330:100 EVDEV_ABS_35=778:6239:72 EVDEV_ABS_36=841:5330:100 + +######################################### +# Samsung +######################################### + +# Samsung 305V4 +evdev:name:ETPS/2 Elantech Touchpad:dmi:*svnSAMSUNGELECTRONICSCO.,LTD.:pn305V4A/305V5A* + EVDEV_ABS_00=0:2480:28 + EVDEV_ABS_01=0:1116:24 + EVDEV_ABS_35=0:2480:28 + EVDEV_ABS_36=0:1116:24 diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb index 94906abcb..01213b606 100644 --- a/hwdb/60-keyboard.hwdb +++ b/hwdb/60-keyboard.hwdb @@ -56,8 +56,7 @@ # https://github.com/systemd/systemd # or create a bug report on https://github.com/systemd/systemd/issues and # include your new rules, a description of the device, and the output of -# udevadm info /dev/input/eventXX -# (or /dev/input/event*). +# udevadm info /dev/input/eventXX. ########################################## # Acer @@ -499,6 +498,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPProBook450G0:pvr* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard:pnHPProBook6555b:* KEYBOARD_KEY_b2=www # Earth +# HP ProBook 440 G3 +evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHP*ProBook*440*G3* + KEYBOARD_KEY_92=brightnessdown + KEYBOARD_KEY_97=brightnessup + KEYBOARD_KEY_ee=switchvideomode + KEYBOARD_KEY_81=f20 # micmute + ########################################################### # IBM ########################################################### @@ -652,6 +658,11 @@ evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr* KEYBOARD_KEY_f1=f21 +# Lenovo Thinkcentre M800z AIO machine +# key_scancode 00 is KEY_MICMUTE +keyboard:name:Microphone Mute Button:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn* + KEYBOARD_KEY_00=f20 + # enhanced USB keyboard evdev:input:b0003v04B3p301B* KEYBOARD_KEY_90001=prog1 # ThinkVantage diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb index 2383d586a..54ace7cbc 100644 --- a/hwdb/70-mouse.hwdb +++ b/hwdb/70-mouse.hwdb @@ -41,8 +41,7 @@ # https://github.com/systemd/systemd # or create a bug report on https://github.com/systemd/systemd/issues and # include your new rules, a description of the device, and the output of -# udevadm info /dev/input/eventXX -# (or /dev/input/event*). +# udevadm info /dev/input/eventXX. # # Allowed properties are: # MOUSE_DPI @@ -309,6 +308,8 @@ mouse:usb:v046dpc046:name:Logitech USB Optical Mouse: mouse:usb:v046dpc05a:name:Logitech USB Optical Mouse: # Logitech USB Laser Mouse M-U0011-O rebranded as "terra Laser" mouse:usb:v046dpc065:name:Logitech USB Laser Mouse: +# Logitech USB Laser Mouse M-U0007 [M500] +mouse:usb:v046dpc069:name:Logitech USB Laser Mouse: # Logitech V500 Cordless Notebook Mouse mouse:usb:v046dpc510:name:Logitech USB Receiver: # Logitech M560 Wireless Mouse @@ -340,8 +341,6 @@ mouse:usb:v046dp1024:name:Logitech M310: # Logitech USB Laser Mouse M-UAS144 [LS1 Laser Mouse] mouse:usb:v046dpc062:name:Logitech USB Laser Mouse: -# Logitech USB Laser Mouse M-U0007 -mouse:usb:v046dpc069:name:Logitech USB Laser Mouse: MOUSE_DPI=1200@125 # Logitech T620 (or, the soap) diff --git a/hwdb/70-pointingstick.hwdb b/hwdb/70-pointingstick.hwdb index 9d288e38f..b2af467d5 100644 --- a/hwdb/70-pointingstick.hwdb +++ b/hwdb/70-pointingstick.hwdb @@ -37,8 +37,7 @@ # https://github.com/systemd/systemd # or create a bug report on https://github.com/systemd/systemd/issues and # include your new rules, a description of the device, and the output of -# udevadm info /dev/input/eventXX -# (or /dev/input/event*). +# udevadm info /dev/input/eventXX. # # Allowed properties are: # POINTINGSTICK_CONST_ACCEL @@ -80,6 +79,10 @@ evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeD620*:pvr* POINTINGSTICK_CONST_ACCEL=0.5 +# Latitude E6320 +evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6320*:pvr* + POINTINGSTICK_CONST_ACCEL=2.0 + # Latitude E6400 evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6400*:pvr* POINTINGSTICK_CONST_ACCEL=1.5 diff --git a/m4/attributes.m4 b/m4/attributes.m4 index db5df250f..51ac88be6 100644 --- a/m4/attributes.m4 +++ b/m4/attributes.m4 @@ -43,7 +43,7 @@ AC_DEFUN([CC_CHECK_FLAG_APPEND], [ AC_CACHE_CHECK([if $CC supports flag $3 in envvar $2], AS_TR_SH([cc_cv_$2_$3]), [eval "AS_TR_SH([cc_save_$2])='${$2}'" - eval "AS_TR_SH([$2])='-Werror `echo "$3" | sed 's/^-Wno-/-W/'`'" + eval "AS_TR_SH([$2])='${cc_save_$2} -Werror `echo "$3" | sed 's/^-Wno-/-W/'`'" AC_LINK_IFELSE([AC_LANG_SOURCE(ifelse([$4], [], [int main(void) { return 0; } ], [$4]))], diff --git a/man/.gitignore b/man/.gitignore index bf5eeab93..d928e5a83 100644 --- a/man/.gitignore +++ b/man/.gitignore @@ -1,4 +1,5 @@ /systemd.directives.xml /systemd.index.xml /*.[13578] +/*.html /custom-entities.ent diff --git a/man/busctl.xml b/man/busctl.xml index d8c108502..26d778d4d 100644 --- a/man/busctl.xml +++ b/man/busctl.xml @@ -448,7 +448,7 @@ ARRAY "s" { Invoking a Method - The following command invokes a the + The following command invokes the StartUnit method on the org.freedesktop.systemd1.Manager interface of the diff --git a/man/custom-html.xsl b/man/custom-html.xsl index 84c23014e..e89d73e7f 100644 --- a/man/custom-html.xsl +++ b/man/custom-html.xsl @@ -37,7 +37,8 @@ - .html + .html# + diff --git a/man/dnssec-trust-anchors.d.xml b/man/dnssec-trust-anchors.d.xml new file mode 100644 index 000000000..4bdc167f7 --- /dev/null +++ b/man/dnssec-trust-anchors.d.xml @@ -0,0 +1,200 @@ + + + + + + + + dnssec-trust-anchors.d + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + dnssec-trust-anchors.d + 5 + + + + dnssec-trust-anchors.d + systemd.positive + systemd.negative + DNSSEC trust anchor configuration files + + + + /etc/dnssec-trust-anchors.d/*.positive + /run/dnssec-trust-anchors.d/*.positive + /usr/lib/dnssec-trust-anchors.d/*.positive + /etc/dnssec-trust-anchors.d/*.negative + /run/dnssec-trust-anchors.d/*.negative + /usr/lib/dnssec-trust-anchors.d/*.negative + + + + Description + + The DNSSEC trust anchor configuration files define positive + and negative trust anchors + systemd-resolved.service8 + bases DNSSEC integrity proofs on. + + + + Positive Trust Anchors + + Positive trust anchor configuration files contain DNSKEY and + DS resource record definitions to use as base for DNSSEC integrity + proofs. See RFC 4035, + Section 4.4 for more information about DNSSEC trust + anchors. + + Positive trust anchors are read from files with the suffix + .positive located in + /etc/dnssec-trust-anchors.d/, + /run/dnssec-trust-anchors.d/ and + /usr/lib/dnssec-trust-anchors.d/. These + directories are searched in the specified order, and a trust + anchor file of the same name in an earlier path overrides a trust + anchor files in a later path. To disable a trust anchor file + shipped in /usr/lib/dnssec-trust-anchors.d/ + it is sufficient to provide an identically-named file in + /etc/dnssec-trust-anchors.d/ or + /run/dnssec-trust-anchors.d/ that is either + empty or a symlink to /dev/null ("masked"). + + Positive trust anchor files are simple text files resembling + DNS zone files, as documented in RFC 1035, Section + 5. One DS or DNSKEY resource record may be listed per + line. Empty lines and lines starting with a semicolon + (;) are ignored and considered comments. A DS + resource record is specified like in the following example: + + . IN DS 19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5 + + The first word specifies the domain, use + . for the root domain. The domain may be + specified with or without trailing dot, which is considered + equivalent. The second word must be IN the + third word DS. The following words specify the + key tag, signature algorithm, digest algorithm, followed by the + hex-encoded key fingerprint. See RFC 4034, + Section 5 for details about the precise syntax and meaning + of these fields. + + Alternatively, DNSKEY resource records may be used to define + trust anchors, like in the following example: + + . IN DNSKEY 257 3 8 AwEAAagAIKlVZrpC6Ia7gEzahOR+9W29euxhJhVVLOyQbSEW0O8gcCjFFVQUTf6v58fLjwBd0YI0EzrAcQqBGCzh/RStIoO8g0NfnfL2MTJRkxoXbfDaUeVPQuYEhg37NZWAJQ9VnMVDxP/VHL496M/QZxkjf5/Efucp2gaDX6RS6CXpoY68LsvPVjR0ZSwzz1apAzvN9dlzEheX7ICJBBtuA6G3LQpzW5hOA2hzCTMjJPJ8LbqF6dsV6DoBQzgul0sGIcGOYl7OyQdXfZ57relSQageu+ipAdTTJ25AsRTAoub8ONGcLmqrAmRLKBP1dfwhYB4N7knNnulqQxA+Uk1ihz0= + + The first word specifies the domain again, the second word + must be IN, followed by + DNSKEY. The subsequent words encode the DNSKEY + flags, protocol and algorithm fields, followed by the key data + encoded in Base64. See RFC 4034, + Section 2 for details about the precise syntax and meaning + of these fields. + + If multiple DS or DNSKEY records are defined for the same + domain (possibly even in different trust anchor files), all keys + are used and are considered equivalent as base for DNSSEC + proofs. + + Note that systemd-resolved will + automatically use a built-in trust anchor key for the Internet + root domain if no positive trust anchors are defined for the root + domain. In most cases it is hence unnecessary to define an + explicit key with trust anchor files. The built-in key is disabled + as soon as at least one trust anchor key for the root domain is + defined in trust anchor files. + + It is generally recommended to encode trust anchors in DS + resource records, rather than DNSKEY resource records. + + If a trust anchor specified via a DS record is found revoked + it is automatically removed from the trust anchor database for the + runtime. See RFC + 5011 for details about revoked trust anchors. Note that + systemd-resolved will not update its trust + anchor database from DNS servers automatically. Instead, it is + recommended to update the resolver software or update the new + trust anchor via adding in new trust anchor files. + + The current DNSSEC trust anchor for the Internet's root + domain is available at the IANA + Trust Anchor and Keys page. + + + + Negative Trust Anchors + + Negative trust anchors define domains where DNSSEC + validation shall be turned off. Negative trust anchor files are + found at the same location as positive trust anchor files, and + follow the same overriding rules. They are text files with the + .negative suffix. Empty lines and lines whose + first character is ; are ignored. Each line + specifies one domain name where DNSSEC validation shall be + disabled on. + + Negative trust anchors are useful to support private DNS + subtrees that are not referenced from the Internet DNS hierarchy, + and not signed. + + RFC + 7646 for details on negative trust anchors. + + If no negative trust anchor files are configured a built-in + set of well-known private DNS zone domains is used as negative + trust anchors. + + It is also possibly to define per-interface negative trust + anchors using the DNSSECNegativeTrustAnchors= + setting in + systemd.network5 + files. + + + + See Also + + systemd1, + systemd-resolved.service8, + resolved.conf5, + systemd.network5 + + + + diff --git a/man/file-hierarchy.xml b/man/file-hierarchy.xml index 345c56cef..538a592f8 100644 --- a/man/file-hierarchy.xml +++ b/man/file-hierarchy.xml @@ -63,7 +63,7 @@ and restrictions systemd makes on the file system hierarchy. - Many of the paths described here are queriable + Many of the paths described here can be queried with the systemd-path1 tool. diff --git a/man/hostname.xml b/man/hostname.xml index 9688450e1..8a4c0d5ac 100644 --- a/man/hostname.xml +++ b/man/hostname.xml @@ -64,10 +64,6 @@ for DNS domain name labels, even though this is not a strict requirement. - Depending on the operating system, other configuration files - might be checked for configuration of the hostname as well, - however only as fallback. - You may use hostnamectl1 to change the value of this file during runtime from the command diff --git a/man/hostnamectl.xml b/man/hostnamectl.xml index b1f038156..60004e9d0 100644 --- a/man/hostnamectl.xml +++ b/man/hostnamectl.xml @@ -66,10 +66,10 @@ high-level "pretty" hostname which might include all kinds of special characters (e.g. "Lennart's Laptop"), the static hostname which is used to initialize the kernel hostname at boot (e.g. - "lennarts-laptop"), and the transient hostname which is a default - received from network configuration. If a static hostname is set, - and is valid (something other than localhost), then the transient - hostname is not used. + "lennarts-laptop"), and the transient hostname which is a fallback + value received from network configuration. If a static hostname is + set, and is valid (something other than localhost), then the + transient hostname is not used. Note that the pretty hostname has little restrictions on the characters used, while the static and transient hostnames are diff --git a/man/journal-remote.conf.xml b/man/journal-remote.conf.xml index fc60258d0..2d345963d 100644 --- a/man/journal-remote.conf.xml +++ b/man/journal-remote.conf.xml @@ -72,6 +72,13 @@ [Remote] section: + + Seal= + + Periodically sign the data in the journal using Forward Secure Sealing. + + + SplitMode= @@ -105,7 +112,7 @@ See Also - systemd-journal-remote1, + systemd-journal-remote8, systemd1, systemd-journald.service8 diff --git a/man/journalctl.xml b/man/journalctl.xml index b57afb6eb..b281f26b4 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -91,8 +91,14 @@ paths may be specified. If a file path refers to an executable file, this is equivalent to an _EXE= match for the canonicalized binary path. Similarly, if a path refers - to a device node, this is equivalent to a - _KERNEL_DEVICE= match for the device. + to a device node then match is added for the kernel name of the + device (_KERNEL_DEVICE=). Also, matches for the + kernel names of all the parent devices are added automatically. + Device node paths are not stable across reboots, therefore match + for the current boot id (_BOOT_ID=) is + always added as well. Note that only the log entries for + the existing device nodes maybe queried by providing path to + the device node. Additional constraints may be added using options , , etc., to @@ -571,6 +577,13 @@ field can take in all entries of the journal. + + + + + Print all field names currently used in all entries of the journal. + + diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 309220632..42d5e006b 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -91,6 +91,7 @@ systemd.default_standard_output= systemd.default_standard_error= systemd.setenv= + systemd.machine_id= Parameters understood by the system and service manager to control system behavior. For details, see diff --git a/man/logind.conf.xml b/man/logind.conf.xml index 94376656d..597759e33 100644 --- a/man/logind.conf.xml +++ b/man/logind.conf.xml @@ -288,21 +288,17 @@ TasksMax= setting of the per-user slice unit, see systemd.resource-control5 - for details. Defaults to 4096. + for details. Defaults to 12288 (12K). RemoveIPC= - Controls whether System V and POSIX IPC - objects belonging to the user shall be removed when the user - fully logs out. Takes a boolean argument. If enabled, the user - may not consume IPC resources after the last of the user's - sessions terminated. This covers System V semaphores, shared - memory and message queues, as well as POSIX shared memory and - message queues. Note that IPC objects of the root user are - excluded from the effect of this setting. Defaults to - yes. + Controls whether System V and POSIX IPC objects belonging to the user shall be removed when the + user fully logs out. Takes a boolean argument. If enabled, the user may not consume IPC resources after the + last of the user's sessions terminated. This covers System V semaphores, shared memory and message queues, as + well as POSIX shared memory and message queues. Note that IPC objects of the root user and other system users + are excluded from the effect of this setting. Defaults to yes. diff --git a/man/machine-id.xml b/man/machine-id.xml index db72c2a01..d318ec54e 100644 --- a/man/machine-id.xml +++ b/man/machine-id.xml @@ -84,6 +84,12 @@ at install time. Use systemd-firstboot1 to initialize it on mounted (but not booted) system images. + + The machine-id may also be set, for example when network + booting, by setting the systemd.machine_id= + kernel command line parameter or passing the option + to systemd. A machine-id may not + be set to all zeros. diff --git a/man/machinectl.xml b/man/machinectl.xml index 0e1895370..0e07c201b 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -247,7 +247,7 @@ checksum is specified, the download is checked for integrity after the transfer is complete, but no signatures are verified. If signature is - specified, the checksum is verified and the images's signature + specified, the checksum is verified and the image's signature is checked against a local keyring of trustable vendors. It is strongly recommended to set this option to signature if the server and protocol @@ -264,16 +264,6 @@ image. - - - - Specifies the index server to use for - downloading dkr images with the - pull-dkr. Takes a - http://, https:// - URL. - - @@ -760,42 +750,6 @@ below. - - pull-dkr REMOTE [NAME] - - Downloads a dkr container - image and makes it available locally. The remote name refers - to a dkr container name. If omitted, the - local machine name is derived from the dkr - container name. - - Image verification is not available for - dkr containers, and thus - must always be specified with - this command. - - This command downloads all (missing) layers for the - specified container and places them in read-only subvolumes in - /var/lib/machines/. A writable snapshot - of the newest layer is then created under the specified local - machine name. To omit creation of this writable snapshot, pass - - as local machine name. - - The read-only layer subvolumes are prefixed with - .dkr-, and thus not shown by - list-images, unless - is passed. - - To specify the dkr index server to - use for looking up the specified container, use - . - - Note that pressing C-c during execution of this command - will not abort the download. Use - cancel-transfer, described - below. - - import-tar FILE [NAME] import-raw FILE [NAME] @@ -814,10 +768,9 @@ image is read from standard input, in which case the second argument is mandatory. - Similar as with pull-tar, - pull-raw the file system - /var/lib/machines.raw is increased in - size of necessary and appropriate. Optionally, the + Both pull-tar and pull-raw + will resize /var/lib/machines.raw and the + filesystem therein as necessary. Optionally, the switch may be used to create a read-only container or VM image. No cryptographic validation is done when importing the images. @@ -926,12 +879,12 @@ Note that many image operations are only supported, efficient or atomic on btrfs file systems. Due to this, if the pull-tar, pull-raw, - pull-dkr, import-tar, - import-raw and set-limit - commands notice that /var/lib/machines is - empty and not located on btrfs, they will implicitly set up a - loopback file /var/lib/machines.raw - containing a btrfs file system that is mounted to + import-tar, import-raw and + set-limit commands notice that + /var/lib/machines is empty and not located on + btrfs, they will implicitly set up a loopback file + /var/lib/machines.raw containing a btrfs file + system that is mounted to /var/lib/machines. The size of this loopback file may be controlled dynamically with set-limit. @@ -994,18 +947,6 @@ login prompt into the container is requested. - - Download a Fedora <literal>dkr</literal> image - - # machinectl pull-dkr --verify=no mattdm/fedora -# systemd-nspawn -M fedora - - Downloads a dkr image and opens a shell - in it. Note that the specified download command might require an - index server to be specified with the - --dkr-index-url=. - - Exports a container image as tar file diff --git a/man/nss-myhostname.xml b/man/nss-myhostname.xml index 859bec29e..251bdecba 100644 --- a/man/nss-myhostname.xml +++ b/man/nss-myhostname.xml @@ -71,9 +71,9 @@ is on the local loopback) and the IPv6 address ::1 (which is the local host). - The hostname localhost is - resolved to the IP addresses 127.0.0.1 and - ::1. + The hostname localhost (as well as any hostname ending in + .localhost, .localdomain or equal to localdomain) is + resolved to the IP addresses 127.0.0.1 and ::1. The hostname gateway is resolved to all current default routing gateway addresses, diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 811e33f4f..920ce9e89 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -1,4 +1,4 @@ - + @@ -68,33 +68,46 @@ Options + The following options are available in the [Resolve] section: + DNS= - A space-separated list of IPv4 and IPv6 - addresses to be used as system DNS servers. DNS requests are - sent to one of the listed DNS servers in parallel to any - per-interface DNS servers acquired from - systemd-networkd.service8. - For compatibility reasons, if set to the empty list, the DNS - servers listed in /etc/resolv.conf are - used, if any are configured there. This setting defaults to - the empty list. + A space-separated list of IPv4 and IPv6 addresses to use as system DNS servers. DNS requests + are sent to one of the listed DNS servers in parallel to suitable per-link DNS servers acquired from + systemd-networkd.service8 or + set at runtime by external applications. For compatibility reasons, if this setting is not specified, the DNS + servers listed in /etc/resolv.conf are used instead, if that file exists and any servers + are configured in it. This setting defaults to the empty list. FallbackDNS= - A space-separated list of IPv4 and IPv6 - addresses to be used as the fallback DNS servers. Any - per-interface DNS servers obtained from + A space-separated list of IPv4 and IPv6 addresses to use as the fallback DNS servers. Any + per-link DNS servers obtained from systemd-networkd.service8 - take precedence over this setting, as do any servers set via - DNS= above or - /etc/resolv.conf. This setting is hence - only used if no other DNS server information is known. If this - option is not given, a compiled-in list of DNS servers is used - instead. + take precedence over this setting, as do any servers set via DNS= above or + /etc/resolv.conf. This setting is hence only used if no other DNS server information is + known. If this option is not given, a compiled-in list of DNS servers is used instead. + + + + Domains= + A space-separated list of domains. These domains are used as search suffixes when resolving + single-label host names (domain names which contain no dot), in order to qualify them into fully-qualified + domain names (FQDNs). Search domains are strictly processed in the order they are specified, until the name + with the suffix appended is found. For compatibility reasons, if this setting is not specified, the search + domains listed in /etc/resolv.conf are used instead, if that file exists and any domains + are configured in it. This setting defaults to the empty list. + + Specified domain names may optionally be prefixed with ~. In this case they do not + define a search path, but preferably direct DNS queries for the indicated domains to the DNS servers configured + with the system DNS= setting (see above), in case additional, suitable per-link DNS servers + are known. If no per-link DNS servers are known using the ~ syntax has no effect. Use the + construct ~. (which is composed of ~ to indicate a routing domain and + . to indicate the DNS root domain that is the implied suffix of all DNS domains) to use the + system DNS server defined with DNS= preferably for all domains. @@ -108,11 +121,87 @@ resolve, only resolution support is enabled, but responding is disabled. Note that systemd-networkd.service8 - also maintains per-interface LLMNR settings. LLMNR will be - enabled on an interface only if the per-interface and the + also maintains per-link LLMNR settings. LLMNR will be + enabled on a link only if the per-link and the global setting is on. + + DNSSEC= + Takes a boolean argument or + allow-downgrade. If true all DNS lookups are + DNSSEC-validated locally (excluding LLMNR and Multicast + DNS). If the response to a lookup request is detected to be invalid + a lookup failure is returned to applications. Note that + this mode requires a DNS server that supports DNSSEC. If the + DNS server does not properly support DNSSEC all validations + will fail. If set to allow-downgrade DNSSEC + validation is attempted, but if the server does not support + DNSSEC properly, DNSSEC mode is automatically disabled. Note + that this mode makes DNSSEC validation vulnerable to + "downgrade" attacks, where an attacker might be able to + trigger a downgrade to non-DNSSEC mode by synthesizing a DNS + response that suggests DNSSEC was not supported. If set to + false, DNS lookups are not DNSSEC validated. + + Note that DNSSEC validation requires retrieval of + additional DNS data, and thus results in a small DNS look-up + time penalty. + + DNSSEC requires knowledge of "trust anchors" to prove + data integrity. The trust anchor for the Internet root domain + is built into the resolver, additional trust anchors may be + defined with + dnssec-trust-anchors.d5. + Trust anchors may change at regular intervals, and old trust + anchors may be revoked. In such a case DNSSEC validation is + not possible until new trust anchors are configured locally or + the resolver software package is updated with the new root + trust anchor. In effect, when the built-in trust anchor is + revoked and DNSSEC= is true, all further + lookups will fail, as it cannot be proved anymore whether + lookups are correctly signed, or validly unsigned. If + DNSSEC= is set to + allow-downgrade the resolver will + automatically turn off DNSSEC validation in such a case. + + Client programs looking up DNS data will be informed + whether lookups could be verified using DNSSEC, or whether the + returned data could not be verified (either because the data + was found unsigned in the DNS, or the DNS server did not + support DNSSEC or no appropriate trust anchors were known). In + the latter case it is assumed that client programs employ a + secondary scheme to validate the returned DNS data, should + this be required. + + It is recommended to set DNSSEC= to + true on systems where it is known that the DNS server supports + DNSSEC correctly, and where software or trust anchor updates + happen regularly. On other systems it is recommended to set + DNSSEC= to + allow-downgrade. + + In addition to this global DNSSEC setting + systemd-networkd.service8 + also maintains per-link DNSSEC settings. For system DNS + servers (see above), only the global DNSSEC setting is in + effect. For per-link DNS servers the per-link + setting is in effect, unless it is unset in which case the + global setting is used instead. + + Site-private DNS zones generally conflict with DNSSEC + operation, unless a negative (if the private zone is not + signed) or positive (if the private zone is signed) trust + anchor is configured for them. If + allow-downgrade mode is selected, it is + attempted to detect site-private DNS zones using top-level + domains (TLDs) that are not known by the DNS root server. This + logic does not work in all private zone setups. + + Defaults to off. + + + @@ -122,7 +211,8 @@ systemd1, systemd-resolved.service8, systemd-networkd.service8, - resolv.conf4 + dnssec-trust-anchors.d5, + resolv.conf4 diff --git a/man/sd-bus.xml b/man/sd-bus.xml new file mode 100644 index 000000000..336dd33ea --- /dev/null +++ b/man/sd-bus.xml @@ -0,0 +1,123 @@ + + + + + + + + + sd-bus + systemd + + + + Documentation + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + sd-bus + 3 + + + + sd-bus + A lightweight D-Bus and kdbus client library + + + + + #include <systemd/sd-bus.h> + + + + pkg-config --cflags --libs libsystemd + + + + + + Description + + sd-bus.h provides an implementation + of a D-Bus client. It can interoperate both with the traditional + dbus-daemon1, + and with kdbus. See + + for more information about the big picture. + + + + Interfaces described here have not been declared stable yet, + and are not accessible from libsystemd.so. + This documentation is provided in hope it might be useful for + developers, without any guarantees of availability or stability. + + + + See + sd_bus_default3, + sd_bus_new3, + sd_bus_request_name3, + sd_bus_start3, + sd_bus_message_append3, + sd_bus_message_append_basic3, + sd_bus_message_append_array3, + sd_bus_message_append_string_memfd3, + sd_bus_message_append_strv3, + sd_bus_message_can_send3, + sd_bus_message_get_cookie3, + sd_bus_message_get_monotonic_usec3, + sd_bus_send3, + sd_bus_set_address3, + sd_bus_set_description3, + sd_bus_set_prepare3, + sd_bus_creds_get_pid3, + sd_bus_creds_new_from_pid3, + sd_bus_get_name_creds3, + sd_bus_get_owner_creds3, + sd_bus_negotiate_fds3, + sd_bus_path_encode3, + sd-bus-errors3, + sd_bus_error3, + sd_bus_error_add_map3, + sd_bus_set_allow_interactive_authorization3 + for more information about the functions available. + + + + + + See Also + + systemd1, + sd-event3, + dbus-daemon1, + dbus-send1, + gdbus + + + + diff --git a/man/sd-daemon.xml b/man/sd-daemon.xml index b7ba36365..b06d99f34 100644 --- a/man/sd-daemon.xml +++ b/man/sd-daemon.xml @@ -71,10 +71,10 @@ Description - sd-daemon.h provide APIs for new-style + sd-daemon.h provides APIs for new-style daemons, as implemented by the systemd1 - init system. + service manager. See sd_listen_fds3, diff --git a/man/sd-event.xml b/man/sd-event.xml new file mode 100644 index 000000000..fc615f090 --- /dev/null +++ b/man/sd-event.xml @@ -0,0 +1,187 @@ + + + + + + + + + sd-event + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd-event + 3 + + + + sd-event + A generic event loop implementation + + + + + #include <systemd/sd-event.h> + + + + pkg-config --cflags --libs libsystemd + + + + + + Description + + sd-event.h provides a generic event + loop implementation, based on Linux epoll7. + + + See + sd_event_new3, + sd_event_run3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_signal3, + sd_event_add_child3, + sd_event_add_defer3, + sd_event_source_unref3, + sd_event_source_set_priority3, + sd_event_source_set_enabled3, + sd_event_source_set_userdata3, + sd_event_source_get_event3, + sd_event_source_get_pending3, + sd_event_source_set_description3, + sd_event_source_set_prepare3, + sd_event_wait3, + sd_event_get_fd3, + sd_event_set_watchdog3, + sd_event_exit3, + sd_event_now3 + for more information about the functions available. + + The event loop design is targeted on running a separate + instance of the event loop in each thread; it has no concept of + distributing events from a single event loop instance onto + multiple worker threads. Dispatching events is strictly ordered + and subject to configurable priorities. In each event loop + iteration a single event source is dispatched. Each time an event + source is dispatched the kernel is polled for new events, before + the next event source is dispatched. The event loop is designed to + honour priorities and provide fairness within each priority. It is + not designed to provide optimal throughput, as this contradicts + these goals due the limitations of the underlying epoll7 + primitives. + + The event loop implementation provides the following features: + + + I/O event sources, based on epoll7's + file descriptor watching, including edge triggered events (EPOLLET). See sd_event_add_io3. + + Timer event sources, based on timerfd_create2, + supporting the CLOCK_MONOTONIC, + CLOCK_REALTIME, + CLOCK_BOOTIME clocks, as well as the + CLOCK_REALTIME_ALARM and + CLOCK_BOOTTIME_ALARM clocks that can resume + the system from suspend. When creating timer events a required + accuracy parameter may be specified which allows coalescing of + timer events to minimize power consumption. See sd_event_add_time3. + + UNIX process signal events, based on + signalfd2, + including full support for real-time signals, and queued parameters. See sd_event_add_signal3. + + Child process state change events, based on + waitid2. See sd_event_add_child3. + + Static event sources, of three types: defer, + post and exit, for invoking calls in each event loop, after + other event sources or at event loop termination. See + sd_event_add_defer3. + + Event sources may be assigned a 64bit priority + value, that controls the order in which event sources are + dispatched if multiple are pending simultaneously. See + sd_event_source_set_priority3. + + The event loop may automatically send watchdog + notification messages to the service manager. See + sd_event_set_watchdog3. + + The event loop may be integrated into foreign + event loops, such as the GLib one. See + sd_event_get_fd3 + for an example. + + + + + + + + See Also + + systemd1, + sd_event_new3, + sd_event_run3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_signal3, + sd_event_add_child3, + sd_event_add_defer3, + sd_event_source_unref3, + sd_event_source_set_priority3, + sd_event_source_set_enabled3, + sd_event_source_set_userdata3, + sd_event_source_get_event3, + sd_event_source_get_pending3, + sd_event_source_set_description3, + sd_event_source_set_prepare3, + sd_event_wait3, + sd_event_get_fd3, + sd_event_set_watchdog3, + sd_event_exit3, + sd_event_now3, + epoll7, + timerfd_create2, + signalfd2, + waitid2 + + + + diff --git a/man/sd-journal.xml b/man/sd-journal.xml index 9b1a52207..09747a480 100644 --- a/man/sd-journal.xml +++ b/man/sd-journal.xml @@ -77,13 +77,17 @@ sd_journal_get_realtime_usec3, sd_journal_add_match3, sd_journal_seek_head3, + sd_journal_query_enumerate3, + sd_journal_enumerate_fields3, sd_journal_get_cursor3, sd_journal_get_cutoff_realtime_usec3, sd_journal_get_cutoff_monotonic_usec3, sd_journal_get_usage3, - sd_journal_get_catalog3 + sd_journal_get_catalog3, + sd_journal_get_fd3, + sd_journal_has_runtime_files3 and - sd_journal_get_fd3 + sd_journal_has_persistent_files3 for more information about the functions implemented. Command line access for submitting entries to the journal is @@ -109,6 +113,8 @@ sd_journal_get_realtime_usec3, sd_journal_add_match3, sd_journal_seek_head3, + sd_journal_query_enumerate3, + sd_journal_enumerate_fields3, sd_journal_get_cursor3, sd_journal_get_cutoff_realtime_usec3, sd_journal_get_cutoff_monotonic_usec3, @@ -116,6 +122,8 @@ sd_journal_get_fd3, sd_journal_query_unique3, sd_journal_get_catalog3, + sd_journal_has_runtime_files3, + sd_journal_has_persistent_files3, journalctl1, sd-id1283, pkg-config1 diff --git a/man/sd_bus_creds_get_pid.xml b/man/sd_bus_creds_get_pid.xml index aec12bda1..3bcda4665 100644 --- a/man/sd_bus_creds_get_pid.xml +++ b/man/sd_bus_creds_get_pid.xml @@ -470,7 +470,7 @@ modified by the caller. All functions that take a char*** - parameter will store the answer there as an address of a an array + parameter will store the answer there as an address of an array of strings. Each individual string is NUL-terminated, and the array is NULL-terminated as a whole. It will be valid as long as c remains valid, and should not be freed or diff --git a/man/sd_bus_creds_new_from_pid.xml b/man/sd_bus_creds_new_from_pid.xml index 84dd50974..082f7b67d 100644 --- a/man/sd_bus_creds_new_from_pid.xml +++ b/man/sd_bus_creds_new_from_pid.xml @@ -48,6 +48,7 @@ sd_bus_creds_get_augmented_mask sd_bus_creds_ref sd_bus_creds_unref + sd_bus_creds_unrefp Retrieve credentials object for the specified PID @@ -82,6 +83,11 @@ sd_bus_creds *sd_bus_creds_unref sd_bus_creds *c + + + void sd_bus_creds_unrefp + sd_bus_creds **c + @@ -235,6 +241,21 @@ sd_bus_creds_unref() destroys a reference to c. + + sd_bus_creds_unrefp() is similar to + sd_bus_creds_unref() but takes a pointer to a + pointer to an sd_bus_creds object. This call is useful in + conjunction with GCC's and LLVM's Clean-up + Variable Attribute. Note that this function is defined as + inline function. + + sd_bus_creds_ref(), + sd_bus_creds_unref() and + sd_bus_creds_unrefp() execute no operation if + the passed in bus credentials object is + NULL. + diff --git a/man/sd_bus_new.xml b/man/sd_bus_new.xml index e1cab6e56..d281b5dd4 100644 --- a/man/sd_bus_new.xml +++ b/man/sd_bus_new.xml @@ -46,6 +46,7 @@ sd_bus_new sd_bus_ref sd_bus_unref + sd_bus_unrefp Create a new bus object and create or destroy references to it @@ -68,6 +69,11 @@ sd_bus *sd_bus_unref sd_bus *bus + + + void sd_bus_unrefp + sd_bus **bus + @@ -93,14 +99,40 @@ only allocate a bus object but also start the connection to a well-known bus in a single function invocation. - sd_bus_ref() creates a new reference to - bus. + sd_bus_ref() increases the reference + counter of bus by one. - sd_bus_unref() destroys a reference to - bus. Once the reference count has dropped - to zero, bus cannot be used anymore, so - further calls to sd_bus_ref() or + sd_bus_unref() decreases the reference + counter of bus by one. Once the reference + count has dropped to zero, bus is destroyed + and cannot be used anymore, so further calls to + sd_bus_ref() or sd_bus_unref() are illegal. + + sd_bus_unrefp() is similar to + sd_bus_unref() but takes a pointer to a + pointer to an sd_bus object. This call is useful in + conjunction with GCC's and LLVM's Clean-up + Variable Attribute. Note that this function is defined as + inline function. Use a declaration like the following, in order to + allocate a bus object that is freed automatically as the code + block is left: + + { + __attribute__((cleanup(sd_bus_unrefp)) sd_bus *bus = NULL; + int r; + … + r = sd_bus_default(&bus); + if (r < 0) + fprintf(stderr, "Failed to allocate bus: %s\n", strerror(-r)); + … +} + + sd_bus_ref(), + sd_bus_unref() and + sd_bus_unrefp() execute no operation if the + passed in bus object is NULL. @@ -110,10 +142,10 @@ positive integer. On failure, it returns a negative errno-style error code. - sd_bus_ref always returns the argument. + sd_bus_ref() always returns the argument. - sd_bus_unref always returns + sd_bus_unref() always returns NULL. diff --git a/man/sd_event_add_child.xml b/man/sd_event_add_child.xml index 77bec4e70..bc732db7f 100644 --- a/man/sd_event_add_child.xml +++ b/man/sd_event_add_child.xml @@ -21,7 +21,7 @@ along with systemd; If not, see . --> - + sd_event_add_child @@ -45,13 +45,23 @@ sd_event_add_child sd_event_source_get_child_pid + sd_event_child_handler_t - Add a child state change event source to an event loop + Add a child process state change event source to an event loop - #include <systemd/sd-bus.h> + #include <systemd/sd-event.h> + + typedef struct sd_event_source sd_event_source; + + + typedef int (*sd_event_child_handler_t) + sd_event_source *s + const siginfo_t *si + void *userdata + int sd_event_add_child @@ -63,13 +73,6 @@ void *userdata - - typedef int (*sd_event_child_handler_t) - sd_event_source *s - const siginfo_t *si - void *userdata - - int sd_event_source_get_child_pid sd_event_source *source @@ -83,42 +86,75 @@ Description sd_event_add_child() adds a new child - state change event source to an event loop object. The event loop - is specified in event, the event source is - returned in the source parameter. The - pid parameter specifies the process to - watch. The handler must reference a - function to call when the process changes state. The handler - function will be passed the userdata - pointer, which may be chosen freely by the caller. The handler - also receives a pointer to a const - siginfo_t structure containing the information about - the event. The options parameter determines - which state changes will be watched for. It must contain an OR-ed - mask of WEXITED (watch for the child + process state change event source to an event loop. The event loop + object is specified in the event parameter, + the event source object is returned in the + source parameter. The + pid parameter specifies the PID of the + process to watch. The handler must + reference a function to call when the process changes state. The + handler function will be passed the + userdata pointer, which may be chosen + freely by the caller. The handler also receives a pointer to a + siginfo_t structure containing + information about the child process event. The + options parameter determines which state + changes will be watched for. It must contain an OR-ed mask of + WEXITED (watch for the child process terminating), WSTOPPED (watch for the child - being stopped by a signal), and WCONTINUED - (watch for the child being resumed by a signal). See - waitid2 + process being stopped by a signal), and + WCONTINUED (watch for the child process being + resumed by a signal). See waitid2 for further information. Only a single handler may be installed for a specific - child. The handler is enabled - for a single event (SD_EVENT_ONESHOT), - but this may be - changed with + child process. The handler is enabled for a single event + (SD_EVENT_ONESHOT), but this may be changed + with sd_event_source_set_enabled3. If the handler function returns a negative error code, it will be - disabled after the invocation, even if - SD_EVENT_ON mode is set. + disabled after the invocation, even if the + SD_EVENT_ON mode was requested before. + To destroy an event source object use + sd_event_source_unref3, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even when there's still a + reference to it kept, consider setting the event source to + SD_EVENT_OFF with + sd_event_source_set_enabled3. + + If the second parameter of + sd_event_add_child() is passed as NULL no + reference to the event source object is returned. In this case the + event source is considered "floating", and will be destroyed + implicitly when the event loop itself is destroyed. + + Note that the handler function is + invoked at a time where the child process is not reaped yet (and + thus still is exposed as a zombie process by the kernel). However, + the child will be reaped automatically after the function + returns. Child processes for which no child process state change + event sources are installed will not be reaped by the event loop + implementation. + + If both a child process state change event source and a + SIGCHLD signal event source is installed in + the same event loop, the configured event source priorities decide + which event source is dispatched first. If the signal handler is + processed first, it should leave the child processes for which + child process state change event sources are installed unreaped. + sd_event_source_get_child_pid() - retrieves the configured pid of a child - state change event source created previously with + retrieves the configured PID of a child process state change event + source created previously with sd_event_add_child(). It takes the event source object as the source parameter and a - pointer to pid_t to return the result in. + pointer to a pid_t variable to return the process ID + in. @@ -158,7 +194,7 @@ -EBUSY A handler is already installed for this - child. + child process. @@ -176,18 +212,16 @@ + + -EDOM + + The passed event source is not a child process event source. + + - - Notes - - sd_event_add_child() and the other functions - described here are available as a shared library, which can be - compiled and linked to with the - libsystemd pkg-config1 - file. - + See Also @@ -196,10 +230,16 @@ systemd1, sd-event3, sd_event_new3, + sd_event_now3, + sd_event_add_io3, sd_event_add_time3, sd_event_add_signal3, sd_event_add_defer3, - sd_event_source_set_enabled3 + sd_event_source_set_enabled3, + sd_event_source_set_priority3, + sd_event_source_set_userdata3, + sd_event_source_set_description3, + waitid2 diff --git a/man/sd_event_add_defer.xml b/man/sd_event_add_defer.xml index 826f2fd22..d9ebd3b17 100644 --- a/man/sd_event_add_defer.xml +++ b/man/sd_event_add_defer.xml @@ -21,7 +21,7 @@ along with systemd; If not, see . --> - + sd_event_add_defer @@ -46,13 +46,22 @@ sd_event_add_defer sd_event_add_post sd_event_add_exit + sd_event_handler_t Add static event sources to an event loop - #include <systemd/sd-bus.h> + #include <systemd/sd-event.h> + + typedef struct sd_event_source sd_event_source; + + + typedef int (*sd_event_handler_t) + sd_event_source *s + void *userdata + int sd_event_add_defer @@ -78,49 +87,67 @@ void *userdata - - typedef int (*sd_event_handler_t) - sd_event_source *s - void *userdata - - Description - These three functions add new event sources to an event loop - object. The event loop is specified in - event, the event source is returned in the - source parameter. The event sources are - enabled statically and will "fire" when the event loop is run and - the conditions described below are met. The handler function will - be passed the userdata pointer, which may - be chosen freely by the caller. + These three functions add new static event sources to an + event loop. The event loop object is specified in the + event parameter, the event source object is + returned in the source parameter. The event + sources are enabled statically and will "fire" when the event loop + is run and the conditions described below are met. The handler + function will be passed the userdata + pointer, which may be chosen freely by the caller. sd_event_add_defer() adds a new event - source that will "fire" the next time the event loop is run. By - default, the handler will be called once - (SD_EVENT_ONESHOT). + source that will be dispatched instantly, before the event loop + goes to sleep again and waits for new events. By default, the + handler will be called once + (SD_EVENT_ONESHOT). Note that if the event + source is set to SD_EVENT_ON the event loop + will never go to sleep again, but continuously call the handler, + possibly interleaved with other event sources. sd_event_add_post() adds a new event - source that will "fire" if any event handlers are invoked whenever - the event loop is run. By default, the source is enabled - permanently (SD_EVENT_ON). + source that is run before the event loop will sleep and wait + for new events, but only after at least one other non-post event + source was dispatched. By default, the source is enabled + permanently (SD_EVENT_ON). Note that this + event source type will still allow the event loop to go to sleep + again, even if set to SD_EVENT_ON, as long as + no other event source is ever triggered. sd_event_add_exit() adds a new event - source that will "fire" when the event loop is terminated - with sd_event_exit(). + source that will be dispatched when the event loop is terminated + with sd_event_exit3. The sd_event_source_set_enabled3 function may be used to enable the event source permanently (SD_EVENT_ON) or to make it fire just once - (SD_EVENT_ONESHOT). If the handler function - returns a negative error code, it will be disabled after the - invocation, even if SD_EVENT_ON mode is - set. + (SD_EVENT_ONESHOT). + + If the handler function returns a negative error code, it + will be disabled after the invocation, even if the + SD_EVENT_ON mode was requested before. + + To destroy an event source object use + sd_event_source_unref3, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even when there's still a + reference to it kept, consider setting the event source to + SD_EVENT_OFF with + sd_event_source_set_enabled3. + + If the second parameter of these functions is passed as + NULL no reference to the event source object is returned. In this + case the event source is considered "floating", and will be + destroyed implicitly when the event loop itself is + destroyed. @@ -164,15 +191,7 @@ - - Notes - - Functions described here are available as a shared library, - which can be compiled and linked to with the - libsystemd pkg-config1 - file. - + See Also @@ -181,10 +200,16 @@ systemd1, sd-event3, sd_event_new3, + sd_event_now3, + sd_event_add_io3, sd_event_add_time3, sd_event_add_signal3, sd_event_add_child3, - sd_event_source_set_enabled3 + sd_event_source_set_enabled3, + sd_event_source_set_priority3, + sd_event_source_set_userdata3, + sd_event_source_set_description3, + sd_event_exit3 diff --git a/man/sd_event_add_io.xml b/man/sd_event_add_io.xml new file mode 100644 index 000000000..c3749164c --- /dev/null +++ b/man/sd_event_add_io.xml @@ -0,0 +1,300 @@ + + + + + + + + + sd_event_add_io + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_add_io + 3 + + + + sd_event_add_io + sd_event_source_get_io_events + sd_event_source_set_io_events + sd_event_source_get_io_revents + sd_event_source_get_io_fd + sd_event_source_set_io_fd + sd_event_source + sd_event_io_handler_t + + Add an I/O event source to an event loop + + + + + #include <systemd/sd-event.h> + + typedef struct sd_event_source sd_event_source; + + + typedef int (*sd_event_io_handler_t) + sd_event_source *s + int fd + uint32_t revents + void *userdata + + + + int sd_event_add_io + sd_event *event + sd_event_source **source + int fd + uint32_t events + sd_event_io_handler_t handler + void *userdata + + + + int sd_event_source_get_io_events + sd_event_source *source + uint32_t *events + + + + int sd_event_source_set_io_events + sd_event_source *source + uint32_t events + + + + int sd_event_source_get_io_revents + sd_event_source *source + uint32_t *revents + + + + int sd_event_source_get_io_fd + sd_event_source *source + + + + int sd_event_source_set_io_fd + sd_event_source *source + int fd + + + + + + + Description + + sd_event_add_io() adds a new I/O event + source to an event loop. The event loop object is specified in the + event parameter, the event source object is + returned in the source parameter. The + fd parameter takes the UNIX file descriptor + to watch, which may refer to a socket, a FIFO, a message queue, a + serial connection, a character device, or any other file descriptor + compatible with Linux + epoll7. The + events parameter takes a bit mask of events + to watch for, a combination of the following event flags: + EPOLLIN, EPOLLOUT, + EPOLLRDHUP, EPOLLPRI, + and EPOLLET, see + epoll_ctl2 + for details. The handler shall reference a + function to call when the event source is triggered. The + userdata pointer will be passed to the + handler function, and may be chosen freely by the caller. The + handler will also be passed the file descriptor the event was seen + on, as well as the actual event flags. It's generally a subset of + the events watched, however may additionally include + EPOLLERR and EPOLLHUP. + + + By default, an event source will stay enabled + continuously (SD_EVENT_ON), but this may be + changed with + sd_event_source_set_enabled3. + If the handler function returns a negative error code, it will be + disabled after the invocation, even if the + SD_EVENT_ON mode was requested before. Note + that an event source set to SD_EVENT_ON will + fire continuously unless data is read from or written to the file + descriptor to reset the mask of events seen. + + + Setting the I/O event mask to watch for to 0 does not mean + that the event source won't be triggered anymore, as + EPOLLHUP and EPOLLERR + may be triggered even with a zero event mask. To temporarily + disable an I/O event source use + sd_event_source_set_enabled3 + with SD_EVENT_OFF instead. + + To destroy an event source object use + sd_event_source_unref3, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even if it is still referenced, + disable the event source using + sd_event_source_set_enabled3 + with SD_EVENT_OFF. + + If the second parameter of + sd_event_add_io() is + NULL no reference to the event source object + is returned. In this case the event source is considered + "floating", and will be destroyed implicitly when the event loop + itself is destroyed. + + It is recommended to use + sd_event_add_io() only in conjunction with + file descriptors that have O_NONBLOCK set, to + ensure that all I/O operations from invoked handlers are properly + asynchronous and non-blocking. Using file descriptors without + O_NONBLOCK might result in unexpected + starvation of other event sources. See + fcntl2 + for details on enabling O_NONBLOCK mode. + + sd_event_source_get_io_events() retrieves + the configured mask of watched I/O events of an event source created + previously with sd_event_add_io(). It takes + the event source object and a pointer to a variable to store the + mask in. + + sd_event_source_set_io_events() + configures the mask of watched I/O events of an event source created + previously with sd_event_add_io(). It takes the + event source object and the new event mask. + + sd_event_source_get_io_revents() + retrieves the I/O event mask of currently seen but undispatched + events from an event source created previously with + sd_event_add_io(). It takes the event source + object and a pointer to a variable to store the event mask + in. When called from a handler function on the handler's event + source object this will return the same mask as passed to the + handler's revents parameter. This call is + primarily useful to check for undispatched events of an event + source from the handler of an unrelated (possibly higher priority) + event source. Note the relation between + sd_event_source_get_pending() and + sd_event_source_get_io_revents(): both + functions will report non-zero results when there's an event + pending for the event source, but the former applies to all event + source types, the latter only to I/O event sources. + + sd_event_source_get_io_fd() retrieves + the UNIX file descriptor of an event source created previously + with sd_event_add_io(). It takes the event + source object and returns the non-negative file descriptor + or a negative error number on error (see below). + + sd_event_source_set_io_fd() + changes the UNIX file descriptor of an I/O event source created + previously with sd_event_add_io(). It takes + the event source object and the new file descriptor. + + + + Return Value + + On success, these functions return 0 or a positive + integer. On failure, they return a negative errno-style error + code. + + + + Errors + + Returned values may indicate the following problems: + + + + -ENOMEM + + Not enough memory to allocate an object. + + + + -EINVAL + + An invalid argument has been passed. + + + + + -ESTALE + + The event loop is already terminated. + + + + + -ECHILD + + The event loop has been created in a different process. + + + + -EDOM + + The passed event source is not an I/O event source. + + + + + + + + See Also + + + systemd1, + sd-event3, + sd_event_new3, + sd_event_now3, + sd_event_add_time3, + sd_event_add_signal3, + sd_event_add_child3, + sd_event_add_defer3, + sd_event_source_set_enabled3, + sd_event_source_set_priority3, + sd_event_source_set_userdata3, + sd_event_source_set_description3, + sd_event_source_get_pending3, + epoll_ctl3, + epoll7 + + + + diff --git a/man/sd_event_add_signal.xml b/man/sd_event_add_signal.xml index 0923fe0ae..e98f1d268 100644 --- a/man/sd_event_add_signal.xml +++ b/man/sd_event_add_signal.xml @@ -21,7 +21,7 @@ along with systemd; If not, see . --> - + sd_event_add_signal @@ -45,13 +45,24 @@ sd_event_add_signal sd_event_source_get_signal + sd_event_signal_handler_t - Add a signal event source to an event loop + Add a UNIX process signal event source to an event + loop - #include <systemd/sd-bus.h> + #include <systemd/sd-event.h> + + typedef struct sd_event_source sd_event_source; + + + typedef int (*sd_event_signal_handler_t) + sd_event_source *s + const struct signalfd_siginfo *si + void *userdata + int sd_event_add_signal @@ -62,13 +73,6 @@ void *userdata - - typedef int (*sd_event_signal_handler_t) - sd_event_source *s - const struct signalfd_siginfo *si - void *userdata - - int sd_event_source_get_signal sd_event_source *source @@ -80,43 +84,62 @@ Description - sd_event_add_signal() adds a new signal - event source to an event loop object. The event loop is specified - in event, and the event source is returned in - the source parameter. The - signal parameter specifies the signal to be handled - (see - signal7). - The handler must reference a function to - call when the signal is delivered or be NULL. - The handler function will be passed the - userdata pointer, which may be chosen + sd_event_add_signal() adds a new UNIX + process signal event source to an event loop. The event loop + object is specified in the event parameter, + and the event source object is returned in the + source parameter. The + signal parameter specifies the numeric + signal to be handled (see signal7). + The handler parameter must reference a + function to call when the signal is received or be + NULL. The handler function will be passed + the userdata pointer, which may be chosen freely by the caller. The handler also receives a pointer to a - const struct signalfd_siginfo containing - the information about the received signal. See - signalfd2 + signalfd_siginfo structure containing + information about the received signal. See signalfd2 for further information. Only a single handler may be installed for a specific - signal. The signal will be unblocked, and must be - blocked when the function is called. If the handler is not - specified (handler is + signal. The signal will be unblocked by this call, and must be + blocked before this function is called in all threads (using + sigprocmask2). If + the handler is not specified (handler is NULL), a default handler which causes the - program to exit will be used. By default, the handler is enabled - permanently (SD_EVENT_ON), but this may be - changed with + program to exit cleanly will be used. + + By default, the event source is enabled permanently + (SD_EVENT_ON), but this may be changed with sd_event_source_set_enabled3. If the handler function returns a negative error code, it will be - disabled after the invocation, even if - SD_EVENT_ON mode is set. + disabled after the invocation, even if the + SD_EVENT_ON mode was requested before. - sd_event_source_get_signal() retrieves - the configured signal number of a signal event source created - previously with sd_event_add_signal(). It - takes the event source object as the source - parameter. + To destroy an event source object use + sd_event_source_unref3, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even if it is still referenced, + disable the event source using + sd_event_source_set_enabled3 + with SD_EVENT_OFF. + If the second parameter of + sd_event_add_signal() is + NULL no reference to the event source object + is returned. In this case the event source is considered + "floating", and will be destroyed implicitly when the event loop + itself is destroyed. + + sd_event_source_get_signal() returns + the configured signal number of an event source created previously + with sd_event_add_signal(). It takes the + event source object as the source + parameter. @@ -124,7 +147,7 @@ On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style error - code. + code. @@ -143,7 +166,6 @@ -EINVAL An invalid argument has been passed. - @@ -151,35 +173,30 @@ A handler is already installed for this signal or the signal was not blocked previously. - -ESTALE The event loop is already terminated. - -ECHILD The event loop has been created in a different process. + + + -EDOM + + The passed event source is not a signal event source. - - Notes - - sd_event_add_signal() and the other functions - described here are available as a shared library, which can be - compiled and linked to with the - libsystemd pkg-config1 - file. - + See Also @@ -188,10 +205,16 @@ systemd1, sd-event3, sd_event_new3, + sd_event_now3, + sd_event_add_io3, sd_event_add_time3, sd_event_add_child3, sd_event_add_defer3, - sd_event_source_set_enabled3 + sd_event_source_set_enabled3, + sd_event_source_set_description3, + sd_event_source_set_userdata3, + signal7, + signalfd2 diff --git a/man/sd_event_add_time.xml b/man/sd_event_add_time.xml index c5f7aee19..a2c0d54b5 100644 --- a/man/sd_event_add_time.xml +++ b/man/sd_event_add_time.xml @@ -21,7 +21,7 @@ along with systemd; If not, see . --> - + sd_event_add_time @@ -49,13 +49,23 @@ sd_event_source_get_time_accuracy sd_event_source_set_time_accuracy sd_event_source_get_time_clock + sd_event_time_handler_t Add a timer event source to an event loop - #include <systemd/sd-bus.h> + #include <systemd/sd-event.h> + + typedef struct sd_event_source sd_event_source; + + + typedef int (*sd_event_time_handler_t) + sd_event_source *s + uint64_t usec + void *userdata + int sd_event_add_time @@ -68,35 +78,28 @@ void *userdata - - typedef int (*sd_event_time_handler_t) - sd_event_source *s - uint64_t usec - void *userdata - - int sd_event_source_get_time sd_event_source *source - usec_t *usec + uint64_t *usec int sd_event_source_set_time sd_event_source *source - usec_t usec + uint64_t usec int sd_event_source_get_time_accuracy sd_event_source *source - usec_t *usec + uint64_t *usec int sd_event_source_set_time_accuracy sd_event_source *source - usec_t usec + uint64_t usec @@ -111,74 +114,120 @@ Description - sd_event_add_time() adds a new timer - event source to an event loop object. The event loop is specified - in event, the event source is returned in - the source parameter. The - clock parameter takes a clock identifier, - one of CLOCK_REALTIME, - CLOCK_MONOTONIC and - CLOCK_BOOTTIME_ALARM. See - timerfd_create2 - for details regarding the various types of clocks. The - usec parameter takes a time value in - microseconds, relative to the clock's epoch specifying when the - timer shall elapse the earliest. The - accuracy parameter takes an additional - accuracy value in microseconds specifying a time the timer event - may be delayed. Specify 0 for selecting the default accuracy - (250ms). Specify 1 for most accurate timers. Consider specifying - 60000000 or larger (1h) for long-running events that may be - delayed substantially. Picking higher accuracy values allows the - system to coalesce timer events more aggressively, thus improving - power efficiency. The handler shall - reference a function to call when the timer elapses. The handler - function will be passed the userdata - pointer, which may be chosen freely by the caller. The handler is - also passed the configured time it was triggered, however it might - actually have been called at a slightly later time, subject to the - specified accuracy value, the kernel timer slack (see - prctl2) - and additional scheduling latencies. + sd_event_add_time() adds a new timer event source to an event loop. The event loop + object is specified in the event parameter, the event source object is returned in the + source parameter. The clock parameter takes a clock identifier, one + of CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME, + CLOCK_REALTIME_ALARM, or CLOCK_BOOTTIME_ALARM. See + timerfd_create2 for details + regarding the various types of clocks. The usec parameter specifies the earliest time, in + microseconds (µs), relative to the clock's epoch, when the timer shall be triggered. If a time already in the past + is specified (including 0), this timer source "fires" immediately and is ready to be + dispatched. If the paramater is specified as UINT64_MAX the timer event will never elapse, + which may be used as an alternative to explicitly disabling a timer event source with + sd_event_source_set_enabled3. The + accuracy parameter specifies an additional accuracy value in µs specifying how much the + timer event may be delayed. Use 0 to select the default accuracy (250ms). Use 1µs for maximum + accuracy. Consider specifying 60000000µs (1min) or larger for long-running events that may be delayed + substantially. Picking higher accuracy values allows the system to coalesce timer events more aggressively, + improving power efficiency. The handler parameter shall reference a function to call when + the timer elapses. The handler function will be passed the userdata pointer, which may be + chosen freely by the caller. The handler is also passed the configured trigger time, even if it is actually called + slightly later, subject to the specified accuracy value, the kernel timer slack (see + prctl2), and additional + scheduling latencies. To query the actual time the handler was called use + sd_event_now3. By default, the timer will elapse once (SD_EVENT_ONESHOT), but this may be changed with sd_event_source_set_enabled3. If the handler function returns a negative error code, it will be - disabled after the invocation, even if - SD_EVENT_ON mode is set. + disabled after the invocation, even if the + SD_EVENT_ON mode was requested before. Note + that a timer event set to SD_EVENT_ON will + fire continuously unless its configured time is updated using + sd_event_source_set_time(). + To destroy an event source object use + sd_event_source_unref3, + but note that the event source is only removed from the event loop + when all references to the event source are dropped. To make sure + an event source does not fire anymore, even if it is still referenced, + disable the event source using + sd_event_source_set_enabled3 + with SD_EVENT_OFF. + + If the second parameter of + sd_event_add_time() is + NULL no reference to the event source object + is returned. In this case the event source is considered + "floating", and will be destroyed implicitly when the event loop + itself is destroyed. + + If the handler to + sd_event_add_time() is + NULL, and the event source fires, this will + be considered a request to exit the event loop. In this case, the + userdata parameter, cast to an integer, is + used for the exit code passed to + sd_event_exit3. + + Use CLOCK_BOOTTIME_ALARM and + CLOCK_REALTIME_ALARM to define event sources + that may wake up the system from suspend. + + In order to set up relative timers (that is, relative to the + current time), retrieve the current time via + sd_event_now3, + add the desired timespan to it, and use the result as + the usec parameter to + sd_event_add_time(). + + In order to set up repetitive timers (that is, timers that + are triggered in regular intervals), set up the timer normally, + for the first invocation. Each time the event handler is invoked, + update the timer's trigger time with + sd_event_source_set_time3 for the next timer + iteration, and reenable the timer using + sd_event_source_set_enabled(). To calculate + the next point in time to pass to + sd_event_source_set_time(), either use as + base the usec parameter passed to the timer + callback, or the timestamp returned by + sd_event_now(). In the former case timer + events will be regular, while in the latter case the scheduling + latency will keep accumulating on the timer. + sd_event_source_get_time() retrieves - the configured time value of a timer event source created + the configured time value of an event source created previously with sd_event_add_time(). It takes the event source object and a pointer to a variable to store the - time in microseconds in. + time in, relative to the selected clock's epoch, in µs. sd_event_source_set_time() changes the - configured time value of a timer event source created previously - with sd_event_add_time(). It takes the event - source object and a time relative to the selected clock's - epoch, in microseconds. + time of an event source created previously with + sd_event_add_time(). It takes the event + source object and a time relative to the selected clock's epoch, + in µs. sd_event_source_get_time_accuracy() - retrieves the configured accuracy value of a timer event source + retrieves the configured accuracy value of a event source created previously with sd_event_add_time(). It takes the event source object and a pointer to a variable to store - the accuracy in microseconds in. + the accuracy in. The accuracy is specified in µs. sd_event_source_set_time_accuracy() changes the configured accuracy of a timer event source created previously with sd_event_add_time(). It takes - the event source object and an accuracy, in microseconds. + the event source object and accuracy, in µs. sd_event_source_get_time_clock() - retrieves the configured clock of a timer event source created + retrieves the configured clock of a event source created previously with sd_event_add_time(). It takes the event source object and a pointer to a variable to store the clock identifier in. - @@ -192,7 +241,7 @@ Errors - Returned errors may indicate the following problems: + Returned values may indicate the following problems: @@ -228,18 +277,16 @@ The selected clock is not supported by the event loop implementation. + + + -EDOM + + The passed event source is not a timer event source. + - - Notes - - sd_event_add_time() and the other functions - described here are available as a shared library, which can be - compiled and linked to with the - libsystemd pkg-config1 - file. - + See Also @@ -248,11 +295,18 @@ systemd1, sd-event3, sd_event_new3, + sd_event_now3, + sd_event_add_io3, sd_event_add_signal3, sd_event_add_child3, sd_event_add_defer3, - clock_gettime2, - sd_event_source_set_enabled3 + sd_event_source_set_enabled3, + sd_event_source_set_priority3, + sd_event_source_set_userdata3, + sd_event_source_set_description3, + clock_gettime2, + timerfd_create2, + prctl2 diff --git a/man/sd_event_exit.xml b/man/sd_event_exit.xml new file mode 100644 index 000000000..9846a3eaf --- /dev/null +++ b/man/sd_event_exit.xml @@ -0,0 +1,163 @@ + + + + + + + + + sd_event_exit + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_exit + 3 + + + + sd_event_exit + sd_event_get_exit_code + + Ask the event loop to exit + + + + + #include <systemd/sd-event.h> + + + int sd_event_exit + sd_event *event + int code + + + + int sd_event_get_exit_code + sd_event *event + int *code + + + + + + + Description + + sd_event_exit() requests the event loop + specified in the event event loop object to + exit. The code parameter may be any integer + value and is returned as-is by + sd_event_loop3 + after the last event loop iteration. It may also be queried + using sd_event_get_exit_code(), see + below. + + When exiting is requested the event loop will stop listening + for and dispatching regular event sources. Instead it will proceed + with executing only event sources registered with + sd_event_add_exit3 + in the order defined by their priority. After all exit event + sources have been dispatched the event loop is terminated. + + If sd_event_exit() is invoked a second + time while the event loop is still processing exit event sources, + the exit code stored in the event loop object is updated, but + otherwise no further operation is executed. + + sd_event_get_exit_code() may be used to + query the exit code passed into + sd_event_exit() earlier. + + While the full positive and negative integer ranges may be used + for the exit code, care should be taken not pick exit codes that + conflict with regular exit codes returned by + sd_event_loop(), if these exit codes shall be + distinguishable. + + + + Return Value + + On success, sd_event_exit() and + sd_event_get_exit_code() return 0 or a positive + integer. On failure, they return a negative errno-style error + code. + + + + Errors + + Returned errors may indicate the following problems: + + + + + -EINVAL + + The event loop object or error code pointer are invalid. + + + + + -ECHILD + + The event loop was created in a different process. + + + + -ESTALE + + The event loop has exited already and all exit handlers are already processed. + + + + -ENODATA + + The event loop has not been requested to exit yet. + + + + + + + + + See Also + + + systemd1, + sd-event3, + sd_event_new3, + sd_event_add_exit3 + + + + diff --git a/man/sd_event_get_fd.xml b/man/sd_event_get_fd.xml index ecdbe76ec..f68752dd0 100644 --- a/man/sd_event_get_fd.xml +++ b/man/sd_event_get_fd.xml @@ -21,8 +21,7 @@ along with systemd; If not, see . --> - + sd_event_get_fd @@ -51,11 +50,11 @@ - #include <systemd/sd-bus.h> + #include <systemd/sd-event.h> int sd_event_get_fd - sd_bus *event + sd_event *event @@ -65,19 +64,29 @@ Description sd_event_get_fd() returns the file - descriptor that the event loop object returned by the + descriptor that an event loop object returned by the sd_event_new3 - function uses to wait for events. This file descriptor can be - polled for events. This makes it possible to embed the + function uses to wait for events. This file descriptor may itself + be polled for + POLLIN/EPOLLIN + events. This makes it possible to embed an sd-event3 - event loop inside of another event loop. + event loop into another, possibly foreign, event loop. + + The returned file descriptor refers to an epoll7 + object. It is recommended not to alter it by invoking + epoll_ctl2 + on it, in order to avoid interference with the event loop's inner + logic and assumptions. Return Value On success, sd_event_get_fd() returns a - non-negative integer. On failure, it returns a negative + non-negative file descriptor. On failure, it returns a negative errno-style error code. @@ -108,21 +117,13 @@ Examples - Integration in glib event loop + Integration in the GLib event loop - - Notes - - sd_event_get_fd() is available as a - shared library, which can be compiled and linked to with the - libsystemd pkg-config1 - file. - + See Also @@ -130,7 +131,9 @@ sd-event3, sd_event_new3, - sd_event_ref3 + sd_event_wait3, + epoll_ctl3, + epoll7 diff --git a/man/sd_event_new.xml b/man/sd_event_new.xml index f6c5d3981..2c23b00a8 100644 --- a/man/sd_event_new.xml +++ b/man/sd_event_new.xml @@ -21,7 +21,7 @@ along with systemd; If not, see . --> - + sd_event_new @@ -47,32 +47,48 @@ sd_event_default sd_event_ref sd_event_unref + sd_event_unrefp + sd_event_get_tid + sd_event Acquire and release an event loop object - #include <systemd/sd-bus.h> + #include <systemd/sd-event.h> + + typedef struct sd_event sd_event; int sd_event_new - sd_bus **event + sd_event **event int sd_event_default - sd_bus **event + sd_event **event - sd_bus *sd_event_ref - sd_bus *event + sd_event *sd_event_ref + sd_event *event - sd_bus *sd_event_unref - sd_bus *event + sd_event *sd_event_unref + sd_event *event + + + + void sd_event_unrefp + sd_event **event + + + + int sd_event_get_tid + sd_event *event + pid_t *tid @@ -103,6 +119,17 @@ thread. All threads have exactly either zero or one default event loop objects associated, but never more. + After allocating an event loop object, add event sources to + it with + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_signal3, + sd_event_add_child3 + or + sd_event_add_defer3, + and then execute the event loop using + sd_event_run3. + sd_event_ref() increases the reference count of the specified event loop object by one. @@ -117,6 +144,40 @@ distinct objects. Note that, in order to free an event loop object, all remaining event sources of the event loop also need to be freed as each keeps a reference to it. + + sd_event_unrefp() is similar to + sd_event_unref() but takes a pointer to a + pointer to an sd_event object. This call is useful in + conjunction with GCC's and LLVM's Clean-up + Variable Attribute. Note that this function is defined as + inline function. Use a declaration like the following, + in order to allocate an event loop object that is freed + automatically as the code block is left: + + { + __attribute__((cleanup(sd_event_unrefp)) sd_event *event = NULL; + int r; + … + r = sd_event_default(&event); + if (r < 0) + fprintf(stderr, "Failed to allocate event loop: %s\n", strerror(-r)); + … +} + + sd_event_ref(), + sd_event_unref() and + sd_event_unrefp() execute no operation if the + passed in event loop object is NULL. + + sd_event_get_tid() retrieves the thread + identifier ("TID") of the thread the specified event loop object + is associated with. This call is only supported for event loops + allocated with sd_event_default(), and + returns the identifier for the thread the event loop is the + default event loop of. See gettid2 + for more information on thread identifiers. @@ -149,18 +210,19 @@ The maximum number of event loops has been allocated. + + + -ENXIO + + sd_event_get_tid() was + invoked on an event loop object that was not allocated with + sd_event_default(). + + - - Notes - - sd_event_new() and the other functions - described here are available as a shared library, which can be - compiled and linked to with the - libsystemd pkg-config1 - file. - + See Also @@ -174,7 +236,9 @@ sd_event_add_child3, sd_event_add_defer3, sd_event_add_post3, - sd_event_add_exit3 + sd_event_add_exit3, + sd_event_run3, + gettid2 diff --git a/man/sd_event_now.xml b/man/sd_event_now.xml new file mode 100644 index 000000000..2c83b0bcb --- /dev/null +++ b/man/sd_event_now.xml @@ -0,0 +1,146 @@ + + + + + + + + + sd_event_now + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_now + 3 + + + + sd_event_now + + Retrieve current event loop iteration timestamp + + + + + #include <systemd/sd-event.h> + + + int sd_event_now + sd_event *event + clockid_t clock + uint64_t *usec + + + + + + + Description + + sd_event_now() returns the time when + the most recent event loop iteration began. A timestamp + is taken right after returning from the event sleep, and before + dispatching any event sources. The event + parameter specifies the event loop object to retrieve the timestamp + from. The clock parameter specifies the clock to + retrieve the timestamp for, and is one of + CLOCK_REALTIME (or equivalently + CLOCK_REALTIME_ALARM), + CLOCK_MONOTONIC, or + CLOCK_BOOTTIME (or equivalently + CLOCK_BOOTTIME_ALARM), see + clock_gettime2 + for more information on the various clocks. The retrieved + timestamp is stored in the usec parameter, + in µs since the clock's epoch. If this function is invoked before + the first event loop iteration, the current time is returned, as + reported by clock_gettime(). To distinguish + this case from a regular invocation the return value will be + positive, and zero when the returned timestamp refers to an actual + event loop iteration. + + + + Return Value + + If the first event loop iteration has not run yet + sd_event_now() writes current time to + usec and returns a positive return value. + Otherwise, it will write the requested timestamp to usec + and return 0. On failure, the call returns a negative errno-style + error code. + + + + Errors + + Returned values may indicate the following problems: + + + + -EINVAL + + An invalid parameter was + passed. + + + + + -EOPNOTSUPP + + Unsupported clock type. + + + + + -ECHILD + + The event loop object was created in a + different process. + + + + + + + + See Also + + + systemd1, + sd-event3, + sd_event_new3, + sd_event_add_time3, + clock_gettime2 + + + + diff --git a/man/sd_event_run.xml b/man/sd_event_run.xml index 06236fcd1..5b6895916 100644 --- a/man/sd_event_run.xml +++ b/man/sd_event_run.xml @@ -21,7 +21,7 @@ along with systemd; If not, see . --> - + sd_event_run @@ -46,7 +46,7 @@ sd_event_run sd_event_loop - Run the libsystemd event loop + Run an event loop @@ -56,7 +56,7 @@ int sd_event_run sd_event *event - uint64_t timeout + uint64_t usec @@ -69,47 +69,60 @@ Description - sd_event_run() can be used to run one - iteration of the event loop of libsystemd. This function waits - until an event to process is available, and dispatches a handler - for it. The timeout parameter specifices the - maximum time (in microseconds) to wait. (uint64_t) - -1 may be used to specify an infinite timeout. + sd_event_run() may be used to run a single + iteration of the event loop specified in the + event parameter. The function waits until an event to + process is available, and dispatches the registered handler for + it. The usec parameter specifies the + maximum time (in microseconds) to wait for an event. Use + (uint64_t) -1 to specify an infinite + timeout. - sd_event_loop runs - sd_event_wait in a loop with a timeout of - infinity. This makes it suitable for the main event loop of a - program. + sd_event_loop() invokes + sd_event_run() in a loop, thus implementing + the actual event loop. The call returns as soon as exiting was + requested using + sd_event_exit3. The event loop object event is created with - sd_event_new. - Events to wait for and their handlers can be registered with - sd_event_add_time, - sd_event_add_child, - sd_event_add_signal, - sd_event_add_defer, - sd_event_add_exit, + sd_event_new3. + Events sources to wait for and their handlers may be registered + with + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_signal3, + sd_event_add_child3, + sd_event_add_defer3, + sd_event_add_post3 and - sd_event_add_post. + sd_event_add_exit3. - For more fine-grained control, - sd_event_prepare, - sd_event_wait, and - sd_event_dispatch may be used. Along with - sd_event_get_fd, those functions make it - possible to integrate the libsystemd loop inside of another event - loop. + For low-level control of event loop execution, use + sd_event_prepare3, + sd_event_wait3 + and + sd_event_dispatch3 + which are wrapped by sd_event_run(). Along + with + sd_event_get_fd3, + these functions allow integration of an + sd-event3 + event loop into foreign event loop implementations. Return Value - On success, these functions return 0 or a positive integer. - On failure, they return a negative errno-style error code. - sd_event_run returns 0 if the event loop is - finished, and a positive value if it can be continued. + On failure, these functions return a negative errno-style + error code. sd_event_run() returns a + positive, non-zero integer if an event source was dispatched, and + zero when the specified timeout hit before an event source has + seen any event, and hence no event source was + dispatched. sd_event_loop() returns the exit + code specified when invoking + sd_event_exit(). @@ -122,7 +135,7 @@ -EINVAL The event parameter is - NULL. + invalid or NULL. @@ -153,15 +166,7 @@ Other errors are possible, too. - - Notes - - sd_event_run() and - sd_event_loop() are available - as a shared library, which can be compiled and linked to with the - libsystemd pkg-config1 - file. - + See Also @@ -169,13 +174,15 @@ systemd1, sd_event_new3, - sd_event_wait3, sd_event_add_io3, sd_event_add_time3, sd_event_add_signal3, sd_event_add_defer3, sd_event_add_exit3, sd_event_add_post3, + sd_event_exit3, + sd_event_get_fd3, + sd_event_wait3, GLib Main Event Loop. diff --git a/man/sd_event_set_name.xml b/man/sd_event_set_name.xml deleted file mode 100644 index 1471e12e5..000000000 --- a/man/sd_event_set_name.xml +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - - - - sd_event_set_name - systemd - - - - More text - Zbigniew - Jędrzejewski-Szmek - zbyszek@in.waw.pl - - - - - - sd_event_set_name - 3 - - - - sd_event_set_name - sd_event_get_name - - Set human-readable names for event sources - - - - - #include <systemd/sd-bus.h> - - - int sd_event_set_name - sd_event_source *source - const char *name - - - - int sd_event_get_name - sd_event_source *source - const char **name - - - - - - - Description - - sd_event_set_name() can be used to set - an arbitrary name for the event source - source. This name will be used in error - messages generated by - sd-event3 - for this source. The name must point - to a NUL-terminated string or be - NULL. In the latter case, the name will be - unset. The string is copied internally, so the - name argument is not referenced after the - function returns. - - sd_event_set_name() can be used to - query the current name assigned to source - source. It returns a pointer to the current - name (possibly NULL) in - name. - - - - Return Value - - On success, sd_event_set_name() and - sd_event_get_name() return a - non-negative integer. On failure, they return a negative - errno-style error code. - - - - Errors - - Returned errors may indicate the following problems: - - - - -EINVAL - - source is not a valid - pointer to an sd_event_source - structure or the name argument for - sd_event_get_name() is - NULL. - - - - -ENOMEM - - Not enough memory to copy the - name. - - - - - - Notes - - The functions described here are available as a - shared library, which can be compiled and linked to with the - libsystemd pkg-config1 - file. - - - - See Also - - - sd-event3, - sd_event_add_time3, - sd_event_add_child3, - sd_event_add_signal3, - sd_event_add_defer3, - sd_event_run3 - - - - diff --git a/man/sd_event_set_watchdog.xml b/man/sd_event_set_watchdog.xml new file mode 100644 index 000000000..cbc5bc083 --- /dev/null +++ b/man/sd_event_set_watchdog.xml @@ -0,0 +1,177 @@ + + + + + + + + + sd_event_set_watchdog + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_set_watchdog + 3 + + + + sd_event_set_watchdog + sd_event_get_watchdog + + Enable event loop watchdog support + + + + + #include <systemd/sd-event.h> + + + int sd_event_set_watchdog + sd_event *event + int b + + + + int sd_event_get_watchdog + sd_event *event + + + + + + + Description + + sd_event_set_watchdog() may be used to + enable or disable automatic watchdog notification support in the + event loop object specified in the event + parameter. Specifically, depending on the b + boolean argument this will make sure the event loop wakes up in + regular intervals and sends watchdog notification messages to the + service manager, if this was requested by the service + manager. Watchdog support is determined with + sd_watchdog_enabled3, + and watchdog messages are sent with + sd_notify3. See + the WatchdogSec= setting in + systemd.service5 + for details on how to enable watchdog support for a service and + the protocol used. The wake-up interval is chosen as half the + watchdog timeout declared by the service manager via the + $WATCHDOG_USEC environment variable. If the + service manager did not request watchdog notifications, or if the + process was not invoked by the service manager this call with a + true b parameter executes no + operation. Passing a false b parameter will + disable the automatic sending of watchdog notification messages if + it was enabled before. Newly allocated event loop objects have + this feature disabled. + + The first watchdog notification message is sent immediately + when set_event_set_watchdog() is invoked with + a true b parameter. + + The watchdog logic is designed to allow the service manager + to automatically detect services that ceased processing of + incoming events, and thus appear "hung". Watchdog notifications + are sent out only at the beginning of each event loop + iteration. If an event source dispatch function blocks for an + excessively long time and does not return execution to the event + loop quickly, this might hence cause the notification message to + be delayed, and possibly result in abnormal program termination, + as configured in the service unit file. + + sd_event_get_watchdog() may be used to + determine whether watchdog support was previously requested by a + call to sd_event_set_watchdog() with a true + b parameter and successfully + enabled. + + + + Return Value + + On success, sd_event_set_watchdog() and + sd_event_get_watchdog() return a non-zero + positive integer if the service manager requested watchdog support + and watchdog support was successfully enabled. They return zero if + the service manager did not request watchdog support, or if + watchdog support was explicitly disabled with a false + b parameter. On failure, they return a + negative errno-style error + code. + + + + Errors + + Returned errors may indicate the following problems: + + + + + -ECHILD + + The event loop has been created in a different process. + + + + -EINVAL + + The passed event loop object was invalid. + + + + + + + + + See Also + + + systemd1, + sd-event3, + sd_event_new3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_signal3, + sd_event_add_child3, + sd_event_add_defer3, + sd_event_add_post3, + sd_event_add_exit3, + sd_watchdog_enabled3, + sd_notify3, + systemd.service5 + + + + diff --git a/man/sd_event_source_get_event.xml b/man/sd_event_source_get_event.xml new file mode 100644 index 000000000..2fdbd411b --- /dev/null +++ b/man/sd_event_source_get_event.xml @@ -0,0 +1,100 @@ + + + + + + + + + sd_event_source_get_event + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_source_get_event + 3 + + + + sd_event_source_get_event + + Retrieve the event loop of an event source + + + + + #include <systemd/sd-event.h> + + + sd_event* sd_event_source_get_event + sd_event_source *source + + + + + + + Description + + sd_event_source_get_event() may be used + to retrieve the event loop object the event source object specified + as source is associated with. The event + loop object is specified when creating an event source object with + calls such as + sd_event_add_io3 + or + sd_event_add_time3. + + + + Return Value + + On success, sd_event_source_get_event() + returns the associated event loop object. On failure, it returns + NULL. + + + + + + See Also + + + sd-event3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_child3, + sd_event_add_signal3, + sd_event_add_defer3, + sd_event_source_set_userdata3 + + + + diff --git a/man/sd_event_source_get_pending.xml b/man/sd_event_source_get_pending.xml new file mode 100644 index 000000000..7f88bd1b8 --- /dev/null +++ b/man/sd_event_source_get_pending.xml @@ -0,0 +1,167 @@ + + + + + + + + + sd_event_source_get_pending + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_source_get_pending + 3 + + + + sd_event_source_get_pending + + Determine pending state of event sources + + + + + #include <systemd/sd-event.h> + + + int sd_event_source_get_pending + sd_event_source *source + + + + + + + Description + + sd_event_source_get_pending() may be + used to determine whether the event source object specified as + source has seen events but has not been + dispatched yet (and thus is marked "pending"). + + Event source objects initially are not marked pending, when + they are created with calls such as + sd_event_add_io3, + sd_event_add_time3, + with the exception of those created with + sd_event_add_defer3 + which are immediately marked pending, and + sd_event_add_exit3 + for which the "pending" concept is not defined. For details see + the respective manual pages. + + In each event loop iteration one event source of those + marked pending is dispatched, in the order defined by the event + source priority, as set with + sd_event_source_set_priority3. + + For I/O event sources, as created with + sd_event_add_io3, + the call + sd_event_source_get_io_revents3 + may be used to query the type of event pending in more + detail. + + + + + Return Value + + On success, + sd_event_source_get_pending() returns an + integer greater than zero when the event source is marked pending, + and zero when the event source is not marked pending. On failure, + it returns a negative errno-style error code. + + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + source is not a valid + pointer to an sd_event_source + object. + + + + -EDOM + + source refers to an + event source object created with + sd_event_add_exit3. + + + + -ENOMEM + + Not enough memory. + + + + -ESTALE + + The event loop is already terminated. + + + + + -ECHILD + + The event loop has been created in a different process. + + + + + + + + + + See Also + + + sd-event3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_child3, + sd_event_add_signal3, + sd_event_add_defer3, + sd_event_source_unref3 + + + + diff --git a/man/sd_event_source_set_description.xml b/man/sd_event_source_set_description.xml new file mode 100644 index 000000000..b9488a622 --- /dev/null +++ b/man/sd_event_source_set_description.xml @@ -0,0 +1,170 @@ + + + + + + + + + sd_event_source_set_description + systemd + + + + More text + Zbigniew + Jędrzejewski-Szmek + zbyszek@in.waw.pl + + + + + + sd_event_source_set_description + 3 + + + + sd_event_source_set_description + sd_event_source_get_description + + Set or retrieve descriptive names of event sources + + + + + #include <systemd/sd-event.h> + + + int sd_event_source_set_description + sd_event_source *source + const char *description + + + + int sd_event_source_get_description + sd_event_source *source + const char **description + + + + + + + Description + + sd_event_source_set_description() may + be used to set an arbitrary descriptive name for the event source + object specified as source. This name will + be used in debugging messages generated by + sd-event3 + for this event source, and may be queried using + sd_event_source_get_description() for + debugging purposes. The description parameter shall + point to a NUL-terminated string or be + NULL. In the latter case, the descriptive + name will be unset. The string is copied internally, hence the + description argument is not referenced + after the function returns. + + sd_event_source_get_description() may + be used to query the current descriptive name assigned to the + event source object source. It returns a + pointer to the current name in description, + stored in memory internal to the event source. The memory is + invalidated when the event source is destroyed or the descriptive + name is changed. + + Event source objects generally have no description set when + they are created, except for UNIX signal event sources created + with + sd_event_add_signal3, + whose descriptive name is initialized to the signal's C constant + name (e.g. SIGINT or + SIGTERM). + + + + Return Value + + On success, sd_event_source_set_description() and + sd_event_source_get_description() return a + non-negative integer. On failure, they return a negative + errno-style error code. + + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + source is not a valid + pointer to an sd_event_source + object or the description argument for + sd_event_source_get_description() is + NULL. + + + + -ENOMEM + + Not enough memory to copy the + name. + + + + -ECHILD + + The event loop has been created in a different process. + + + + + -ENXIO + + No name was set for the event + source. + + + + + + + + + See Also + + + sd-event3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_child3, + sd_event_add_signal3, + sd_event_add_defer3, + sd_event_source_set_userdata3 + + + + diff --git a/man/sd_event_source_set_enabled.xml b/man/sd_event_source_set_enabled.xml new file mode 100644 index 000000000..6844f29a4 --- /dev/null +++ b/man/sd_event_source_set_enabled.xml @@ -0,0 +1,179 @@ + + + + + + + + + sd_event_source_set_enabled + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_source_set_enabled + 3 + + + + sd_event_source_set_enabled + sd_event_source_get_enabled + SD_EVENT_ON + SD_EVENT_OFF + SD_EVENT_ONESHOT + + Enable or disable event sources + + + + + #include <systemd/sd-event.h> + + enum { + SD_EVENT_OFF = 0, + SD_EVENT_ON = 1, + SD_EVENT_ONESHOT = -1, +}; + + + int sd_event_source_set_enabled + sd_event_source *source + int enabled + + + + int sd_event_source_get_enabled + sd_event_source *source + int *enabled + + + + + + + Description + + sd_event_source_set_enabled() may be + used to enable or disable the event source object specified as + source. The enabled + parameter takes one of SD_EVENT_ON (to + enable), SD_EVENT_OFF (to disable) or + SD_EVENT_ONESHOT. If invoked with + SD_EVENT_ONESHOT the event source will be + enabled but automatically reset to + SD_EVENT_OFF after the event source was + dispatched once. + + Event sources that are disabled will not result in event + loop wakeups and will not be dispatched, until they are enabled + again. + + sd_event_source_get_enabled() may be + used to query whether the event source object + source is currently enabled or not. It + returns the enablement state in + enabled. + + Event source objects are enabled when they are first created + with calls such as + sd_event_add_io3, + sd_event_add_time3. However, + depending on the event source type they are enabled continuously + (SD_EVENT_ON) or only for a single invocation + of the event source handler + (SD_EVENT_ONESHOT). For details see the + respective manual pages. + + As event source objects stay active and may be dispatched as + long as there is at least one reference to them, in many cases it + is a good idea to combine a call to + sd_event_source_unref3 + with a prior call to + sd_event_source_set_enabled() with + SD_EVENT_OFF, to ensure the event source is + not dispatched again until all other remaining references are dropped. + + + + Return Value + + On success, sd_event_source_set_enabled() and + sd_event_source_get_enabled() return a + non-negative integer. On failure, they return a negative + errno-style error code. + + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + source is not a valid + pointer to an sd_event_source + object. + + + + -ENOMEM + + Not enough memory. + + + + -ECHILD + + The event loop has been created in a different process. + + + + + + + + + + See Also + + + sd-event3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_child3, + sd_event_add_signal3, + sd_event_add_defer3, + sd_event_source_unref3 + + + + diff --git a/man/sd_event_source_set_prepare.xml b/man/sd_event_source_set_prepare.xml new file mode 100644 index 000000000..24861d01d --- /dev/null +++ b/man/sd_event_source_set_prepare.xml @@ -0,0 +1,171 @@ + + + + + + + + + sd_event_source_set_prepare + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_source_set_prepare + 3 + + + + sd_event_source_set_prepare + + Set a preparation callback for event sources + + + + + #include <systemd/sd-event.h> + + + int sd_event_source_set_prepare + sd_event_source *source + sd_event_handler_t callback + + + + typedef int (*sd_event_handler_t) + sd_event_source *s + void *userdata + + + + + + + Description + + sd_event_source_set_prepare() may be + used to set a preparation callback for the event source object + specified as source. The callback function + specified as callback will be invoked + immediately before the event loop goes to sleep to wait for + incoming events. It is invoked with the user data pointer passed + when the event source was created. The callback function may be + used to reconfigure the precise events to wait for. If the + callback parameter is passed as NULL the + callback function is reset. + + Event source objects have no preparation callback associated + when they are first created with calls such as + sd_event_add_io3, + sd_event_add_time3. Preparation + callback functions are supported for all event source types with + the exception of those created with + sd_event_add_exit3. Preparation + callback functions are dispatched in the order indicated by the + event source's priority field, as set with + sd_event_source_set_priority3. Preparation + callbacks of disabled event sources (see + sd_event_source_set_enabled3) + are not invoked. + + + + Return Value + + On success, + sd_event_source_set_prepare() returns a + non-negative integer. On failure, it returns a negative + errno-style error code. + + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + source is not a valid + pointer to an sd_event_source + object. + + + + -ESTALE + + The event loop is already terminated. + + + + -ENOMEM + + Not enough memory. + + + + -ECHILD + + The event loop has been created in a different process. + + + + + -EDOM + + The specified event source has been created + with + sd_event_add_exit3. + + + + + + + + + + See Also + + + sd-event3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_child3, + sd_event_add_signal3, + sd_event_add_defer3, + sd_event_source_set_enabled3, + sd_event_source_set_priority3, + sd_event_source_set_userdata3 + + + + diff --git a/man/sd_event_source_set_priority.xml b/man/sd_event_source_set_priority.xml new file mode 100644 index 000000000..9234f4233 --- /dev/null +++ b/man/sd_event_source_set_priority.xml @@ -0,0 +1,189 @@ + + + + + + + + + sd_event_source_set_priority + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_source_set_priority + 3 + + + + sd_event_source_set_priority + sd_event_source_get_priority + SD_EVENT_PRIORITY_IMPORTANT + SD_EVENT_PRIORITY_NORMAL + SD_EVENT_PRIORITY_IDLE + + Set or retrieve the priority of event sources + + + + + #include <systemd/sd-event.h> + + enum { + SD_EVENT_SOURCE_IMPORTANT = -100, + SD_EVENT_SOURCE_NORMAL = 0, + SD_EVENT_SOURCE_IDLE = 100, +}; + + + int sd_event_source_set_priority + sd_event_source *source + int64_t priority + + + + int sd_event_source_get_priority + sd_event_source *source + int64_t *priority + + + + + + + Description + + sd_event_source_set_priority() may be + used to set the priority for the event source object specified as + source. The priority is specified as an + arbitrary signed 64bit integer. The priority is initialized to + SD_EVENT_PRIORITY_NORMAL (0) when the event + source is allocated with a call such as + sd_event_add_io3 + or + sd_event_add_time3, + and may be changed with this call. If multiple event sources have seen events at the same time, they are dispatched in the order indicated by the + event sources' priorities. Event sources with smaller priority + values are dispatched first. As well-known points of reference, + the constants SD_EVENT_PRIORITY_IMPORTANT + (-100), SD_EVENT_PRIORITY_NORMAL (0) and + SD_EVENT_PRIORITY_IDLE (100) may be used to + indicate event sources that shall be dispatched early, normally or + late. It is recommended to specify priorities based on these + definitions, and relative to them -- however, the full 64bit + signed integer range is available for ordering event + sources. + + Priorities define the order in which event sources that have + seen events are dispatched. Care should be taken to ensure that + high-priority event sources (those with negative priority values + assigned) do not cause starvation of low-priority event sources + (those with positive priority values assigned). + + The order in which event sources with the same priority are + dispatched is undefined, but the event loop generally tries to + dispatch them in the order it learnt about events on them. As the + backing kernel primitives do not provide accurate information + about the order in which events occurred this is not necessarily + reliable. However, it is guaranteed that if events are seen on + multiple same-priority event sources at the same time, each one is + not dispatched again until all others have been dispatched + once. This behaviour guarantees that within each priority + particular event sources do not starve or dominate the event + loop. + + sd_event_source_get_priority() may be + used to query the current priority assigned to the event source + object source. + + + + Return Value + + On success, + sd_event_source_set_priority() and + sd_event_source_get_priority() return a + non-negative integer. On failure, they return a negative + errno-style error code. + + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + source is not a valid + pointer to an sd_event_source + object. + + + + -ENOMEM + + Not enough memory. + + + + -ESTALE + + The event loop is already terminated. + + + + + -ECHILD + + The event loop has been created in a different process. + + + + + + + + + + See Also + + + sd-event3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_child3, + sd_event_add_signal3, + sd_event_add_defer3 + + + + diff --git a/man/sd_event_source_set_userdata.xml b/man/sd_event_source_set_userdata.xml new file mode 100644 index 000000000..533d491b1 --- /dev/null +++ b/man/sd_event_source_set_userdata.xml @@ -0,0 +1,119 @@ + + + + + + + + + sd_event_source_set_userdata + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_source_set_userdata + 3 + + + + sd_event_source_set_userdata + sd_event_source_get_userdata + + Set or retrieve user data pointer of event sources + + + + + #include <systemd/sd-event.h> + + + void* sd_event_source_set_userdata + sd_event_source *source + void *userdata + + + + void* sd_event_source_get_userdata + sd_event_source *source + + + + + + + Description + + sd_event_source_set_userdata() may be + used to set an arbitrary user data pointer for the event source + object specified as source. The user data + pointer is usually specified when creating an event source object + with calls such as + sd_event_add_io3 + or + sd_event_add_time3, + and may be updated with this call. The user data pointer is also + passed to all handler callback functions associated with the event + source. The userdata parameter specifies + the new user data pointer to set, the function returns the + previous user data pointer. Note that NULL is + a valid user data pointer. + + sd_event_source_get_userdata() may be + used to query the current user data pointer assigned to the event + source object source. + + + + Return Value + + On success, + sd_event_source_set_userdata() and + sd_event_source_get_userdata() return the + previously set user data pointer. On failure, they return + NULL. + + + + + + See Also + + + sd-event3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_child3, + sd_event_add_signal3, + sd_event_add_defer3, + sd_event_source_set_description3 + + + + diff --git a/man/sd_event_source_unref.xml b/man/sd_event_source_unref.xml new file mode 100644 index 000000000..2c4d45076 --- /dev/null +++ b/man/sd_event_source_unref.xml @@ -0,0 +1,142 @@ + + + + + + + + + sd_event_source_unref + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_event_source_unref + 3 + + + + sd_event_source_unref + sd_event_source_unrefp + sd_event_source_ref + + Increase or decrease event source reference counters + + + + + #include <systemd/sd-event.h> + + + sd_event_source* sd_event_source_unref + sd_event_source *source + + + + void sd_event_source_unrefp + sd_event_source **source + + + + sd_event_source* sd_event_source_ref + sd_event_source *source + + + + + + + Description + + sd_event_source_unref() may be used to + decrement by one the reference counter of the event source object + specified as source. The reference counter + is initially set to one, when the event source is created with calls + such as + sd_event_add_io3 + or + sd_event_add_time3. When + the reference counter reaches zero it is removed from its event loop + object and destroyed. + + sd_event_source_unrefp() is similar to + sd_event_source_unref() but takes a pointer to a + pointer to an sd_event_source object. This call is useful in + conjunction with GCC's and LLVM's Clean-up + Variable Attribute. Note that this function is defined as + inline function. + + sd_event_source_ref() may be used + to increase by one the reference counter of the event source object + specified as source. + + sd_event_source_unref(), + sd_bus_creds_unrefp() and + sd_bus_creds_ref() execute no operation if + the passed event source object is + NULL. + + Note that event source objects stay alive and may be + dispatched as long as they have a reference counter greater than + zero. In order to drop a reference of an event source and make + sure the associated event source handler function is not called + anymore it is recommended to combine a call of + sd_event_source_unref() with a prior call to + sd_event_source_set_enabled() with + SD_EVENT_OFF. + + + + Return Value + + sd_event_source_unref() always returns + NULL. + sd_event_source_ref() always returns the + event source object passed in. + + + + + + See Also + + + sd-event3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_child3, + sd_event_add_signal3, + sd_event_add_defer3, + sd_event_source_set_enabled3 + + + + diff --git a/man/sd_event_wait.xml b/man/sd_event_wait.xml index 7ca50aedf..f2aea00e9 100644 --- a/man/sd_event_wait.xml +++ b/man/sd_event_wait.xml @@ -21,7 +21,7 @@ along with systemd; If not, see . --> - + sd_event_wait @@ -46,14 +46,32 @@ sd_event_wait sd_event_prepare sd_event_dispatch + sd_event_get_state + SD_EVENT_INITIAL + SD_EVENT_PREPARING + SD_EVENT_ARMED + SD_EVENT_PENDING + SD_EVENT_RUNNING + SD_EVENT_EXITING + SD_EVENT_FINISHED - Run parts of the libsystemd event loop + Low-level event loop operations #include <systemd/sd-event.h> + enum { + SD_EVENT_INITIAL, + SD_EVENT_PREPARING, + SD_EVENT_ARMED, + SD_EVENT_PENDING, + SD_EVENT_RUNNING, + SD_EVENT_EXITING, + SD_EVENT_FINISHED, +}; + int sd_event_prepare sd_event *event @@ -62,7 +80,7 @@ int sd_event_wait sd_event *event - uint64_t timeout + uint64_t usec @@ -70,66 +88,184 @@ sd_event *event + + int sd_event_get_state + sd_event *event + + Description - Functions described here form parts of an event loop. + The low-level sd_event_prepare(), + sd_event_wait() and + sd_event_dispatch() functions may be used to + execute specific phases of an event loop. See + sd_event_run3 + and + sd_event_loop3 + for higher-level functions that execute individual but complete + iterations of an event loop or run it continuously. - sd_event_prepare checks for pending + sd_event_prepare() checks for pending events and arms necessary timers. If any events are ready to be - processed, it returns a positive value, and the events should be - processed with sd_event_dispatch. - sd_event_dispatch runs a handler for one of - the events from the sources with the highest priority. On success, - sd_event_dispatch returns either 0, which - means that the loop is finished, or a positive value, which means - that the loop is again in the initial state and - sd_event_prepare should be called again. - + processed ("pending"), it returns a positive, non-zero value, and the caller + should process these events with + sd_event_dispatch(). - In case sd_event_prepare returned 0, - sd_event_wait should be called to wait for - events or a timeout. If any events are ready to be processed, it - returns a positive value, and the events should be processed with - sd_event_dispatch. Otherwise, the loop is - back in the initial state and sd_event_prepare - should be called again. + sd_event_dispatch() dispatches the + highest priority event source that has a pending event. On + success, sd_event_dispatch() returns either + zero, which indicates that no further event sources may be + dispatched and exiting of the event loop was requested via + sd_event_exit3; + or a positive non-zero value, which means that an event source was + dispatched and the loop returned to its initial state, and the + caller should initiate the next event loop iteration by invoking + sd_event_prepare() again. + + In case sd_event_prepare() returned + zero, sd_event_wait() should be called to + wait for further events or a timeout. If any events are ready to + be processed, it returns a positive, non-zero value, and the + events should be dispatched with + sd_event_dispatch(). Otherwise, the event + loop returned to its initial state and the next event loop + iteration should be initiated by invoking + sd_event_prepare() again. + + sd_event_get_state() may be used to + determine the state the event loop is currently in. It returns one + of the states described below. + + All four functions take, as the first argument, the event + loop object event that has been created + with sd_event_new(). The timeout for + sd_event_wait() is specified in + usec in milliseconds. (uint64_t) + -1 may be used to specify an infinite timeout. + + + + State Machine + + The event loop knows the following states, that may be + queried with sd_event_get_state(). + + + + SD_EVENT_INITIAL + + The initial state the event loop is in, + before each event loop iteration. Use + sd_event_prepare() to transition the + event loop into the SD_EVENT_ARMED or + SD_EVENT_PENDING states. + + + + SD_EVENT_PREPARING + + An event source is currently being prepared, + i.e. the preparation handler is currently being executed, as + set with + sd_event_set_prepare3. This + state is only seen in the event source preparation handler + that is invoked from the + sd_event_prepare() call and is + immediately followed by SD_EVENT_ARMED or + SD_EVENT_PENDING. + + + + SD_EVENT_ARMED + + sd_event_prepare() has + been called and no event sources were ready to be + dispatched. Use sd_event_wait() to wait + for new events, and transition into + SD_EVENT_PENDING or back into + SD_EVENT_INITIAL. + + + + SD_EVENT_PENDING + + sd_event_prepare() or + sd_event_wait() have been called and + there were event sources with events pending. Use + sd_event_dispatch() to dispatch the + highest priority event source and transition back to + SD_EVENT_INITIAL, or + SD_EVENT_FINISHED. + + + + SD_EVENT_RUNNING + + A regular event source is currently being + dispatched. This state is only seen in the event source + handler that is invoked from the + sd_event_dispatch() call, and is + immediately followed by SD_EVENT_INITIAL + or SD_EVENT_FINISHED as soon the event + source handler returns. Note that during dispatching of exit + event sources the SD_EVENT_EXITING state + is seen instead. + + + + SD_EVENT_EXITING + + Similar to + SD_EVENT_RUNNING but is the state in + effect while dispatching exit event sources. It is followed by + SD_EVENT_INITIAL or + SD_EVENT_FINISHED as soon as the event + handler returns. + + + + SD_EVENT_FINISHED + + The event loop has exited. All exit event + sources have run. If the event loop is in this state it serves + no purpose anymore, and should be freed. + + + + + A simplified flow chart of the states and the calls to + transition between them is shown below. Note that + SD_EVENT_PREPARING, + SD_EVENT_RUNNING and + SD_EVENT_EXITING are not shown here. - ┌──────────┐ - │ initial ├──←←←←←←←←←←←←←←←←←←←─┐ - └───┬──────┘ ↑ - │ ↑ - sd_event_prepare ┌─────────┐ ↑ - ├ 0 →→→→→→→──┤ armed │ ↑ - 1 └───┬─────┘ ↑ - ↓ │ ↑ - ↓ sd_event_wait ↑ - ├───←←←←←←←─── 1 ┴─ 0 →→→→→→→─┘ - ┌───┴──────┐ ↑ - │ pending │ ↑ - └───┬──────┘ ↑ - │ ↑ - sd_event_dispatch ↑ - ↓ ↑ - ├ 1 ──────────→→→→→→→─────────┘ - 0 - ↓ - ┌───┴──────┐ - │ finished │ - └──────────┘ + INITIAL -<---<---<---<---<---<---<---<---<---<---<---<---\ + | | + | ^ + | | + v ret == 0 | + sd_event_prepare() >--->--->--->--->- ARMED | + | | ^ + | ret > 0 | | + | | | + v v ret == 0 | + PENDING <---<---<---<---<---< sd_event_wait() >--->--->--+ + | ret > 0 ^ + | | + | | + v | + sd_event_dispatch() >--->--->--->--->--->--->--->--->--->--->/ + | ret > 0 + | ret == 0 + | + v + FINISHED - - All three functions take, as the first argument, the event - loop object event that is created with - sd_event_new. The timeout for - sd_event_wait is specified with - timeout in milliseconds. - (uint64_t) -1 may be used to specify an - infinite timeout. @@ -137,13 +273,15 @@ On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style error code. In case - of sd_event_prepare and - sd_event_wait, a positive value means that - events are ready to be processed and 0 means that no events are - ready. In case of sd_event_dispatch, a - positive value means that the loop is again in the initial state - and 0 means the loop is finished. For any of these functions, a - negative return value means the loop must be aborted. + of sd_event_prepare() and + sd_event_wait(), a positive, non-zero return + code indicates that events are ready to be processed and zero + indicates that no events are ready. In case of + sd_event_dispatch(), a positive, non-zero + return code indicates that the event loop returned to its initial + state and zero indicates the event loop has + exited. sd_event_get_state() returns a + positive or zero state on success. @@ -156,7 +294,7 @@ -EINVAL The event parameter is - NULL. + invalid or NULL. @@ -185,14 +323,7 @@ Other errors are possible, too. - - Notes - - Functions described here are available - as a shared library, which can be compiled and linked to with the - libsystemd pkg-config1 - file. - + See Also @@ -200,13 +331,15 @@ systemd1, sd_event_new3, - sd_event_run3, sd_event_add_io3, sd_event_add_time3, sd_event_add_signal3, sd_event_add_defer3, sd_event_add_exit3, - sd_event_add_post3. + sd_event_add_post3, + sd_event_run3, + sd_event_get_fd3, + sd_event_source_set_prepare3 diff --git a/man/sd_journal_enumerate_fields.xml b/man/sd_journal_enumerate_fields.xml new file mode 100644 index 000000000..fa5884106 --- /dev/null +++ b/man/sd_journal_enumerate_fields.xml @@ -0,0 +1,161 @@ + + + + + + + + + sd_journal_enumerate_fields + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + sd_journal_enumerate_fields + 3 + + + + sd_journal_enumerate_fields + sd_journal_restart_fields + SD_JOURNAL_FOREACH_FIELD + Read used field names from the journal + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_enumerate_fields + sd_journal *j + const char **field + + + + void sd_journal_restart_fields + sd_journal *j + + + + SD_JOURNAL_FOREACH_FIELD + sd_journal *j + const char *field + + + + + + + Description + + sd_journal_enumerate_fields() may be used to iterate through all field names used in the + opened journal files. On each invocation the next field name is returned. The order of the returned field names is + not defined. It takes two arguments: the journal context object, plus a pointer to a constant string pointer where + the field name is stored in. The returned data is in a read-only memory map and is only valid until the next + invocation of sd_journal_enumerate_fields(). Note that this call is subject to the data field + size threshold as controlled by sd_journal_set_data_threshold(). + + sd_journal_restart_fields() resets the field name enumeration index to the beginning of + the list. The next invocation of sd_journal_enumerate_fields() will return the first field + name again. + + The SD_JOURNAL_FOREACH_FIELD() macro may be used as a handy wrapper around + sd_journal_restart_fields() and sd_journal_enumerate_fields(). + + These functions currently are not influenced by matches set with sd_journal_add_match() + but this might change in a later version of this software. + + To retrieve the possible values a specific field can take use + sd_journal_query_unique3. + + + + Return Value + + sd_journal_enumerate_fields() returns a + positive integer if the next field name has been read, 0 when no + more field names are known, or a negative errno-style error code. + sd_journal_restart_fields() returns + nothing. + + + + Notes + + The sd_journal_enumerate_fields() and sd_journal_restart_fields() + interfaces are available as a shared library, which can be compiled and linked to with the + libsystemd pkg-config1 file. + + + + Examples + + Use the SD_JOURNAL_FOREACH_FIELD macro to iterate through all field names in use in the + current journal. + + #include <stdio.h> +#include <string.h> +#include <systemd/sd-journal.h> + +int main(int argc, char *argv[]) { + sd_journal *j; + const char *field; + int r; + + r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); + if (r < 0) { + fprintf(stderr, "Failed to open journal: %s\n", strerror(-r)); + return 1; + } + SD_JOURNAL_FOREACH_FIELD(j, field) + printf("%s\n", field); + sd_journal_close(j); + return 0; +} + + + + + See Also + + + systemd1, + systemd.journal-fields7, + sd-journal3, + sd_journal_open3, + sd_journal_query_unique3, + sd_journal_get_data3, + sd_journal_add_match3 + + + + diff --git a/man/sd_journal_has_runtime_files.xml b/man/sd_journal_has_runtime_files.xml new file mode 100644 index 000000000..237e64920 --- /dev/null +++ b/man/sd_journal_has_runtime_files.xml @@ -0,0 +1,95 @@ + + + + + + + + + sd_journal_has_runtime_files + systemd + + + + Developer + Jan + Synáček + jan.synacek@gmail.com + + + + + + sd_journal_has_runtime_files + 3 + + + + sd_journal_has_runtime_files + sd_journal_has_persistent_files + Query availability of runtime or persistent journal files. + + + + + #include <systemd/sd-journal.h> + + + int sd_journal_has_runtime_files + sd_journal *j + + + + int sd_journal_has_persistent_files + sd_journal *j + + + + + + + Description + + sd_journal_has_runtime_files() returns a positive value + if runtime journal files (present in /run/systemd/journal/) have been found. + Otherwise returns 0. + + sd_journal_has_persistent_files() returns a positive value + if persistent journal files (present in /var/log/journal/) have been found. + Otherwise returns 0. + + + + Return value + Both sd_journal_has_runtime_files() + and sd_journal_has_persistent_files() return -EINVAL + if their argument is NULL. + + + + + See Also + + sd-journal3 + + + + diff --git a/man/sd_journal_query_unique.xml b/man/sd_journal_query_unique.xml index ac0e5f633..dbff55c10 100644 --- a/man/sd_journal_query_unique.xml +++ b/man/sd_journal_query_unique.xml @@ -128,6 +128,11 @@ Note that these functions currently are not influenced by matches set with sd_journal_add_match() but this might change in a later version of this software. + + To enumerate all field names currently in use (and thus all suitable field parameters for + sd_journal_query_unique()), use the + sd_journal_enumerate_fields3 + call. @@ -167,25 +172,25 @@ #include <systemd/sd-journal.h> int main(int argc, char *argv[]) { - sd_journal *j; - const void *d; - size_t l; - int r; + sd_journal *j; + const void *d; + size_t l; + int r; - r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); - if (r < 0) { - fprintf(stderr, "Failed to open journal: %s\n", strerror(-r)); - return 1; - } - r = sd_journal_query_unique(j, "_SYSTEMD_UNIT"); - if (r < 0) { - fprintf(stderr, "Failed to query journal: %s\n", strerror(-r)); - return 1; - } - SD_JOURNAL_FOREACH_UNIQUE(j, d, l) - printf("%.*s\n", (int) l, (const char*) d); - sd_journal_close(j); - return 0; + r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY); + if (r < 0) { + fprintf(stderr, "Failed to open journal: %s\n", strerror(-r)); + return 1; + } + r = sd_journal_query_unique(j, "_SYSTEMD_UNIT"); + if (r < 0) { + fprintf(stderr, "Failed to query journal: %s\n", strerror(-r)); + return 1; + } + SD_JOURNAL_FOREACH_UNIQUE(j, d, l) + printf("%.*s\n", (int) l, (const char*) d); + sd_journal_close(j); + return 0; } @@ -198,6 +203,7 @@ int main(int argc, char *argv[]) { systemd.journal-fields7, sd-journal3, sd_journal_open3, + sd_journal_enumerate_fields3, sd_journal_get_data3, sd_journal_add_match3 diff --git a/man/sd_login_monitor_new.xml b/man/sd_login_monitor_new.xml index db21d7025..5625ab920 100644 --- a/man/sd_login_monitor_new.xml +++ b/man/sd_login_monitor_new.xml @@ -45,6 +45,7 @@ sd_login_monitor_new sd_login_monitor_unref + sd_login_monitor_unrefp sd_login_monitor_flush sd_login_monitor_get_fd sd_login_monitor_get_events @@ -68,6 +69,11 @@ sd_login_monitor *m + + void sd_login_monitor_unrefp + sd_login_monitor **m + + int sd_login_monitor_flush sd_login_monitor *m @@ -121,6 +127,26 @@ descriptor returned by sd_login_monitor_get_fd(). + sd_login_monitor_unrefp() is similar to + sd_login_monitor_unref() but takes a pointer + to a pointer to an sd_login_monitor object. This call + is useful in conjunction with GCC's and LLVM's Clean-up + Variable Attribute. Note that this function is defined as + inline function. Use a declaration like the following, in order to + allocate a login monitor object that is freed automatically as the + code block is left: + + { + __attribute__((cleanup(sd_login_monitor_unrefp)) sd_login_monitor *m = NULL; + int r; + … + r = sd_login_monitor_default(&m); + if (r < 0) + fprintf(stderr, "Failed to allocate login monitor object: %s\n", strerror(-r)); + … +} + sd_login_monitor_flush() may be used to reset the wakeup state of the monitor object. Whenever an event causes the monitor to wake up the event loop via the file @@ -128,6 +154,11 @@ state. If this call is not invoked, the file descriptor will immediately wake up the event loop again. + sd_login_monitor_unref() and + sd_login_monitor_unrefp() execute no + operation if the passed in monitor object is + NULL. + sd_login_monitor_get_fd() may be used to retrieve the file descriptor of the monitor object that may be integrated in an application defined event loop, based around diff --git a/man/sd_notify.xml b/man/sd_notify.xml index dbf633045..bd6cfdcd2 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -242,7 +242,7 @@ multiple file descriptors are submitted at once, the specified name will be assigned to all of them. In order to assign different names to submitted file descriptors, submit them in - seperate invocations of + separate invocations of sd_pid_notify_with_fds(). The name may consist of any ASCII character, but must not contain control characters or :. It may not be longer than diff --git a/man/sd_seat_get_active.xml b/man/sd_seat_get_active.xml index 6e1d505dc..c5e6ddab0 100644 --- a/man/sd_seat_get_active.xml +++ b/man/sd_seat_get_active.xml @@ -192,7 +192,7 @@ sd_seat_get_sessions(), sd_seat_can_multi_session(), sd_seat_can_tty() and - sd_seat_can_grapical() interfaces are + sd_seat_can_graphical() interfaces are available as a shared library, which can be compiled and linked to with the libsystemd pkg-config1 diff --git a/man/sd_watchdog_enabled.xml b/man/sd_watchdog_enabled.xml index 144ab1db6..6e27528a7 100644 --- a/man/sd_watchdog_enabled.xml +++ b/man/sd_watchdog_enabled.xml @@ -98,6 +98,11 @@ WatchdogSec= in service files. See systemd.service5 for details. + + Use + sd_event_set_watchdog3 + to enable automatic watchdog support in + sd-event3-based event loops. @@ -168,7 +173,8 @@ sd-daemon3, daemon7, systemd.service5, - sd_notify3 + sd_notify3, + sd_event_set_watchdog3 diff --git a/man/systemctl.xml b/man/systemctl.xml index 755a74f98..1480bf838 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -683,14 +683,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service Start (activate) one or more units specified on the command line. - Note that glob patterns operate on a list of currently - loaded units. Units which are not active and are not in a - failed state usually are not loaded, and would not be - matched by any pattern. In addition, in case of - instantiated units, systemd is often unaware of the - instance name until the instance has been started. Therefore, - using glob patterns with start - has limited usefulness. + Note that glob patterns operate on the set of primary names of currently loaded units. Units which + are not active and are not in a failed state usually are not loaded, and will not be matched by any + pattern. In addition, in case of instantiated units, systemd is often unaware of the instance name until + the instance has been started. Therefore, using glob patterns with start has limited + usefulness. Also, secondary alias names of units are not considered. @@ -736,9 +733,9 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service Restart one or more units specified on the command line if the units are running. This does nothing if units are not - running. Note that, for compatibility with Red Hat init - scripts, condrestart is equivalent to this - command. + running. + @@ -751,14 +748,14 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service - reload-or-try-restart PATTERN... + try-reload-or-restart PATTERN... Reload one or more units if they support it. If not, restart them instead. This does nothing if the units are not - running. Note that, for compatibility with SysV init scripts, - force-reload is equivalent to this - command. + running. + @@ -832,7 +829,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service output. If you are looking for computer-parsable output, use show instead. By default, this function only shows 10 lines of output and ellipsizes - lines to fit in the terminal window. This can be changes + lines to fit in the terminal window. This can be changed with and , see above. In addition, journalctl --unit=NAME or @@ -888,6 +885,11 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service Example: systemctl set-property foobar.service CPUShares=777 + If the specified unit appears to be inactive, the + changes will be only stored on disk as described + previously hence they will be effective when the unit will + be started. + Note that this command allows changing multiple properties at the same time, which is preferable over setting them individually. Like unit file configuration @@ -1132,7 +1134,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service enabled - Enabled through a symlink in a .wants/ or .requires/ subdirectory of /etc/systemd/system/ (persistently) or /run/systemd/system/ (transiently). + Enabled via .wants/, .requires/ or alias symlinks (permanently in /etc/systemd/system/, or transiently in /run/systemd/system/). 0 @@ -1171,7 +1173,7 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service bad - Unit file is invalid or another error occured. Note that is-enabled will not actually return this state, but print an error message instead. However the unit file listing printed by list-unit-files might show it. + Unit file is invalid or another error occurred. Note that is-enabled will not actually return this state, but print an error message instead. However the unit file listing printed by list-unit-files might show it. > 0 @@ -1696,34 +1698,28 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service Parameter Syntax - Unit commands listed above take either a single unit name - (designated as NAME), or multiple - unit specifications (designated as - PATTERN...). In the first case, the - unit name with or without a suffix must be given. If the suffix - is not specified, systemctl will append a suitable suffix, - .service by default, and a type-specific - suffix in case of commands which operate only on specific unit - types. For example, + Unit commands listed above take either a single unit name (designated as NAME), + or multiple unit specifications (designated as PATTERN...). In the first case, the + unit name with or without a suffix must be given. If the suffix is not specified (unit name is "abbreviated"), + systemctl will append a suitable suffix, .service by default, and a type-specific suffix in + case of commands which operate only on specific unit types. For example, # systemctl start sshd and # systemctl start sshd.service are equivalent, as are # systemctl isolate default and # systemctl isolate default.target - Note that (absolute) paths to device nodes are automatically - converted to device unit names, and other (absolute) paths to - mount unit names. + Note that (absolute) paths to device nodes are automatically converted to device unit names, and other (absolute) + paths to mount unit names. # systemctl status /dev/sda # systemctl status /home are equivalent to: # systemctl status dev-sda.device # systemctl status home.mount - In the second case, shell-style globs will be matched against - currently loaded units; literal unit names, with or without - a suffix, will be treated as in the first case. This means that - literal unit names always refer to exactly one unit, but globs - may match zero units and this is not considered an error. + In the second case, shell-style globs will be matched against the primary names of all currently loaded units; + literal unit names, with or without a suffix, will be treated as in the first case. This means that literal unit + names always refer to exactly one unit, but globs may match zero units and this is not considered an + error. Glob patterns use fnmatch3, @@ -1731,16 +1727,16 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service *, ?, [] may be used. See glob7 - for more details. The patterns are matched against the names of + for more details. The patterns are matched against the primary names of currently loaded units, and patterns which do not match anything are silently skipped. For example: # systemctl stop sshd@*.service - will stop all sshd@.service instances. + will stop all sshd@.service instances. Note that alias names of units, and units that aren't + loaded are not considered for glob expansion. - For unit file commands, the specified - NAME should be the full name of the - unit file, or the absolute path to the unit file: + For unit file commands, the specified NAME should be the name of the unit file + (possibly abbreviated, see above), or the absolute path to the unit file: # systemctl enable foo.service or # systemctl link /path/to/foo.service diff --git a/man/systemd-activate.xml b/man/systemd-activate.xml index 5fe1a3905..995e6eecc 100644 --- a/man/systemd-activate.xml +++ b/man/systemd-activate.xml @@ -60,24 +60,21 @@ Description - systemd-activate can be used to - launch a socket-activated daemon from the command line for - testing purposes. It can also be used to launch single instances - of the daemon per connection (inetd-style). + systemd-activate may be used to launch a socket-activated service binary from the command + line for testing purposes. It may also be used to launch individual instances of the service binary per connection. The daemon to launch and its options should be specified after options intended for systemd-activate. - If the option is given, file descriptor - of the connection will be used as the standard input and output of - the launched process. Otherwise, standard input and output will be - inherited, and sockets will be passed through file descriptors 3 - and higher. Sockets passed through $LISTEN_FDS - to systemd-activate will be passed through to - the daemon, in the original positions. Other sockets specified - with will use consecutive descriptors. + If the option is given, the socket file descriptor will be used as the standard + input and output of the launched process. Otherwise, standard input and output will be inherited, and sockets will + be passed through file descriptors 3 and higher. Sockets passed through $LISTEN_FDS to + systemd-activate will be passed through to the daemon, in the original positions. Other sockets + specified with will use consecutive descriptors. By default, + systemd-activate listens on a stream socket, use and + to listen on datagram or sequential packet sockets instead (see below). @@ -98,9 +95,32 @@ - Launch a separate instance of daemon per - connection and pass the connection socket as standard input - and standard output. + Launch an instance of the service binary for each connection and pass the connection + socket. + + + + + + + Listen on a datagram socket (SOCK_DGRAM), instead of a stream socket + (SOCK_STREAM). May not be combined with . + + + + + + Listen on a sequential packet socket (SOCK_SEQPACKET), instead of a stream + socket (SOCK_STREAM). May not be combined with + . + + + + + + Use the inetd protocol for passing file descriptors, i.e. as standard input and standard + output, instead of the new-style protocol for passing file descriptors using $LISTEN_FDS + (see above). @@ -160,7 +180,7 @@ Run an echo server on port 2000 - $ /usr/lib/systemd/systemd-activate -l 2000 -a cat + $ /usr/lib/systemd/systemd-activate -l 2000 --inetd -a cat diff --git a/man/systemd-ask-password.xml b/man/systemd-ask-password.xml index 6fb322e84..2a4d24349 100644 --- a/man/systemd-ask-password.xml +++ b/man/systemd-ask-password.xml @@ -149,7 +149,7 @@ possible to cache multiple passwords under the same keyname, in which case they will be stored as NUL-separated list of passwords. Use - keyctl1 + keyctl1 to access the cached key via the kernel keyring directly. Example: --keyname=cryptsetup @@ -209,7 +209,7 @@ systemd1, systemctl1, - keyctl1, + keyctl1, plymouth8, wall1 diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml index 5d19322cd..2b7f4e69a 100644 --- a/man/systemd-detect-virt.xml +++ b/man/systemd-detect-virt.xml @@ -59,7 +59,7 @@ systemd-detect-virt detects execution in a virtualized environment. It identifies the virtualization - technology and can distinguish full VM virtualization from + technology and can distinguish full machine virtualization from container virtualization. systemd-detect-virt exits with a return value of 0 (success) if a virtualization technology is detected, and non-zero (error) otherwise. By default, @@ -88,7 +88,7 @@ - VM + VM qemu QEMU software virtualization @@ -139,7 +139,7 @@ - Container + Container openvz OpenVZ/Virtuozzo @@ -173,8 +173,8 @@ If multiple virtualization solutions are used, only the - "innermost" is detected and identified. That means if both VM - virtualization and container virtualization are used in + "innermost" is detected and identified. That means if both + machine and container virtualization are used in conjunction, only the latter will be identified (unless is passed). @@ -197,8 +197,7 @@ - Only detects VM virtualization (i.e. full - hardware virtualization). + Only detects hardware virtualization). diff --git a/man/systemd-escape.xml b/man/systemd-escape.xml index 5407773f2..dbb3869a2 100644 --- a/man/systemd-escape.xml +++ b/man/systemd-escape.xml @@ -64,7 +64,7 @@ used to escape and to undo escaping of strings. The command takes any number of strings on the command line, - and will process them individually, one after the other. It will + and will process them individually, one after another. It will output them separated by spaces to stdout. By default, this command will escape the strings passed, diff --git a/man/systemd-journal-gatewayd.service.xml b/man/systemd-journal-gatewayd.service.xml index 6df224857..e32ac2685 100644 --- a/man/systemd-journal-gatewayd.service.xml +++ b/man/systemd-journal-gatewayd.service.xml @@ -193,7 +193,7 @@ - application/event-stream + text/event-stream Entries are formatted as JSON data structures, wrapped in a format suitable for - Retrieve events from a remote + Retrieve all available events from a remote systemd-journal-gatewayd8 instance and store them in - /var/log/journal/some.host/remote-some~host.journal: + /var/log/journal/remote/remote-some.host.journal: systemd-journal-remote --url http://some.host:19531/ - + + Retrieve current boot events and wait for new events from a remote + systemd-journal-gatewayd8 + instance, and store them in + /var/log/journal/remote/remote-some.host.journal: + +systemd-journal-remote --url http://some.host:19531/entries?boot&follow + + + See Also diff --git a/man/systemd-journald.service.xml b/man/systemd-journald.service.xml index f1054b03b..2810638bc 100644 --- a/man/systemd-journald.service.xml +++ b/man/systemd-journald.service.xml @@ -106,13 +106,6 @@ mkdir -p /var/log/journal systemd-tmpfiles --create --prefix /var/log/journal - systemd-journald will forward all - received log messages to the - AF_UNIX/SOCK_DGRAM - socket /run/systemd/journal/syslog, if it - exists, which may be used by Unix syslog daemons to process the - data further. - See journald.conf5 for information about the configuration of this service. diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index a97b7c44e..86cdb4e12 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -248,16 +248,76 @@ . + + + + + Invoke the shell or specified program as process ID (PID) 2 instead of PID 1 (init). By + default, if neither this option nor is used, the selected binary is run as process with + PID 1, a mode only suitable for programs that are aware of the special semantics that the process with PID 1 + has on UNIX. For example, it needs to reap all processes reparented to it, and should implement + sysvinit compatible signal handling (specifically: it needs to reboot on SIGINT, reexecute + on SIGTERM, reload configuration on SIGHUP, and so on). With a minimal stub init + process is run as PID 1 and the selected binary is executed as PID 2 (and hence does not need to implement any + special semantics). The stub init process will reap processes as necessary and react appropriately to + signals. It is recommended to use this mode to invoke arbitrary commands in containers, unless they have been + modified to run correctly as PID 1. Or in other words: this switch should be used for pretty much all commands, + except when the command refers to an init or shell implementation, as these are generally capable of running + correctly as PID 1). This option may not be combined with or + . + + + - Automatically search for an init binary and - invoke it instead of a shell or a user supplied program. If - this option is used, arguments specified on the command line - are used as arguments for the init binary. This option may not - be combined with . - + Automatically search for an init binary and invoke it as PID 1, instead of a shell or a user + supplied program. If this option is used, arguments specified on the command line are used as arguments for the + init binary. This option may not be combined with or + . + + The following table explains the different modes of invocation and relationship to + (see above): + + + Invocation Mode + + + + + + Switch + Explanation + + + + + Neither nor specified + The passed parameters are interpreted as command line, which is executed as PID 1 in the container. + + + + specified + The passed parameters are interpreted as command line, which are executed as PID 2 in the container. A stub init process is run as PID 1. + + + + specified + An init binary as automatically searched and run as PID 1 in the container. The passed parameters are used as invocation parameters for this process. + + + + +
+
+
+ + + + + Change to the specified working directory before invoking the process in the container. Expects + an absolute path in the container's file system namespace. @@ -770,8 +830,8 @@ , full volatile mode is enabled. This means the root directory is mounted as a mostly unpopulated tmpfs instance, and - /usr from the OS tree is mounted into it, - read-only (the system thus starts up with read-only OS + /usr from the OS tree is mounted into it + in read-only mode (the system thus starts up with read-only OS resources, but pristine state and configuration, any changes to the either are lost on shutdown). When the mode parameter is specified as , the OS tree is diff --git a/man/systemd-path.xml b/man/systemd-path.xml index da6026e3b..e2b23eec5 100644 --- a/man/systemd-path.xml +++ b/man/systemd-path.xml @@ -60,7 +60,7 @@ systemd-path may be used to query system and user paths. The tool makes many of the paths described in file-hierarchy7 - queriable. + available for querying.
When invoked without arguments, a list of known paths and their current values is shown. When at least one argument is diff --git a/man/systemd-resolve.xml b/man/systemd-resolve.xml new file mode 100644 index 000000000..f1e663c5b --- /dev/null +++ b/man/systemd-resolve.xml @@ -0,0 +1,277 @@ + + + + + + + + + systemd-resolve + systemd + + + + Developer + Lennart + Poettering + lennart@poettering.net + + + + + + systemd-resolve + 1 + + + + systemd-resolve + Resolve domain names, IPV4 and IPv6 addresses, DNS resource records, and services + + + + + systemd-resolve + OPTIONS + HOSTNAME + + + + systemd-resolve + OPTIONS + ADDRESS + + + + systemd-resolve + OPTIONS + --type=TYPE + RRDOMAIN + + + + systemd-resolve + OPTIONS + --service + NAME + TYPE DOMAIN + + + + systemd-resolve + OPTIONS + --statistics + + + + systemd-resolve + OPTIONS + --reset-statistics + + + + + + Description + + systemd-resolve may be used to resolve domain names, IPv4 and IPv6 addresses, DNS resource + records and services with the + systemd-resolved.service8 + resolver service. By default, the specified list of parameters will be resolved as hostnames, retrieving their IPv4 + and IPv6 addresses. If the parameters specified are formatted as IPv4 or IPv6 operation the reverse operation is + done, and a hostname is retrieved for the specified addresses. + + The switch may be used to specify a DNS resource record type (A, AAAA, SOA, MX, ...) in + order to request a specific DNS resource record, instead of the address or reverse address lookups. + The special value help may be used to list known values. + + The switch may be used to resolve SRV and DNS-SD services (see below). In this mode, between one and three + arguments are required. If three parameters are passed the first is assumed to be the DNS-SD service name, the + second the SRV service type, and the third the domain to search in. In this case a full DNS-SD style SRV and TXT + lookup is executed. If only two parameters are specified, the first is assumed to be the SRV service type, and the + second the domain to look in. In this case no TXT RR is requested. Finally, if only one parameter is specified, it + is assumed to be a domain name, that is already prefixed with an SRV type, and an SRV lookup is done (no + TXT). + + The switch may be used to show resolver statistics, including information about + the number of succesful and failed DNSSEC validations. + + The may be used to reset various statistics counters maintained the + resolver, including those shown in the output. This operation requires root + privileges. + + + + Options + + + + + + By default, when resolving a hostname, both IPv4 and IPv6 + addresses are acquired. By specifying only IPv4 addresses are requested, by specifying + only IPv6 addresses are requested. + + + + + INTERFACE + INTERFACE + + Specifies the network interface to execute the query on. This may either be specified as numeric + interface index or as network interface string (e.g. en0). Note that this option has no + effect if system-wide DNS configuration (as configured in /etc/resolv.conf or + /etc/systemd/resolve.conf) in place of per-link configuration is used. + + + + PROTOCOL + PROTOCOL + + Specifies the network protocol for the query. May be one of dns + (i.e. classic unicast DNS), llmnr (Link-Local Multicast Name Resolution), + llmr-ipv4, llmnr-ipv6 (LLMNR via the indicated underlying IP + protocols). By default the lookup is done via all protocols suitable for the lookup. If used, limits the set of + protocols that may be used. Use this option multiple times to enable resolving via multiple protocols at the + same time. The setting llmnr is identical to specifying this switch once with + llmnr-ipv4 and once via llmnr-ipv6. Note that this option does not force + the service to resolve the operation with the specified protocol, as that might require a suitable network + interface and configuration. + The special value help may be used to list known values. + + + + + TYPE + TYPE + CLASS + CLASS + + Specifies the DNS resource record type (e.g. A, AAAA, MX, …) and class (e.g. IN, ANY, …) to + look up. If these options are used a DNS resource record set matching the specified class and type is + requested. The class defaults to IN if only a type is specified. + The special value help may be used to list known values. + + + + + + + Enables service resolution. This enables DNS-SD and simple SRV service resolution, depending + on the specified list of parameters (see above). + + + + BOOL + + Takes a boolean parameter. If true (the default), when doing a service lookup with + the hostnames contained in the SRV resource records are resolved as well. + + + + BOOL + + Takes a boolean parameter. If true (the default), when doing a DNS-SD service lookup with + the TXT service metadata record is resolved as well. + + + + BOOL + + Takes a boolean parameter. If true (the default), DNS CNAME or DNAME redirections are + followed. Otherwise, if a CNAME or DNAME record is encountered while resolving, an error is + returned. + + + + BOOL + + Takes a boolean parameter. If true (the default), any specified single-label hostnames will be + searched in the domains configured in the search domain list, if it is non-empty. Otherwise, the search domain + logic is disabled. + + + + BOOL + + Takes a boolean parameter. If true (the default), column headers and meta information about the + query response are shown. Otherwise, this output is suppressed. + + + + + + If specified general resolver statistics are shown, including information whether DNSSEC is + enabled and available, as well as resolution and validation statistics. + + + + + + Resets the statistics counters shown in to zero. + + + + + + + + + Examples + + + Retrieve the addresses of the <literal>www.0pointer.net</literal> domain + + $ systemd-resolve www.0pointer.net + + + + Retrieve the domain of the <literal>85.214.157.71</literal> IP address + + $ systemd-resolve 85.214.157.71 + + + + Retrieve the MX record of the <literal>0pointer.net</literal> domain + + $ systemd-resolve -t MX 0pointer.net + + + + Resolve an SRV service + + $ systemd-resolve --service _xmpp-server._tcp gmail.com + + + + + + See Also + + systemd1, + systemd-resolved.service8 + + + diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 43d568c6f..7a9e23a2c 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -56,15 +56,15 @@ Description - systemd-resolved is a system service that - manages network name resolution. It implements a caching DNS stub - resolver and an LLMNR resolver and responder. It also generates - /run/systemd/resolve/resolv.conf for - compatibility which may be symlinked from - /etc/resolv.conf. The glibc NSS module - nss-resolve8 - is necessary to allow libc's NSS resolver functions to resolve - host names via systemd-resolved. + systemd-resolved is a system service that provides network name resolution to local + applications. It implements a caching and validating DNS/DNSSEC stub resolver, as well as an LLMNR resolver and + responder. In addition it maintains the /run/systemd/resolve/resolv.conf file for + compatibility with traditional Linux programs. This file may be symlinked from + /etc/resolv.conf. + + The glibc NSS module + nss-resolve8 is required to + permit glibc's NSS resolver functions to resolve host names via systemd-resolved. The DNS servers contacted are determined from the global settings in /etc/systemd/resolved.conf, the @@ -87,15 +87,18 @@ is on the local loopback) and the IPv6 address ::1 (which is the local host). - The hostname localhost is - resolved to the IP addresses 127.0.0.1 and - ::1. + The hostname localhost (as well as any hostname ending in + .localhost, .localdomain or equal to localdomain) is + resolved to the IP addresses 127.0.0.1 and ::1. The hostname gateway is resolved to all current default routing gateway addresses, ordered by their metric. This assigns a stable hostname to the current gateway, useful for referencing it independently of the current network configuration state. + + The mappings defined in /etc/hosts are resolved to their configured + addresses and back. Lookup requests are routed to the available DNS servers @@ -104,7 +107,7 @@ Lookups for the special hostname localhost are never routed to the - network. + network. (A few other, special domains are handled the same way.) Single-label names are routed to all local interfaces capable of IP multicasting, using the LLMNR @@ -117,7 +120,7 @@ Multi-label names are routed to all local interfaces that have a DNS sever configured, plus the globally configured DNS server if there is one. Address lookups from the - link-local addres range are never routed to + link-local address range are never routed to DNS. @@ -133,10 +136,12 @@ per-interface domains are exclusively routed to the matching interfaces. - Note that - /run/systemd/resolve/resolv.conf should not - be used directly, but only through a symlink from - /etc/resolv.conf. + Note that /run/systemd/resolve/resolv.conf should not be used directly by applications, + but only through a symlink from /etc/resolv.conf. + + See the resolved D-Bus API + Documentation for information about the APIs systemd-resolved provides. + @@ -144,7 +149,11 @@ systemd1, resolved.conf5, + dnssec-trust-anchors.d5, nss-resolve8, + systemd-resolve1, + resolv.conf5, + hosts5, systemd.network5, systemd-networkd.service8 diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index ead52951d..edc6df914 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -354,13 +354,26 @@ These settings control various default resource limits for units. See setrlimit2 - for details. Use the string infinity to - configure no limit on a specific resource. The multiplicative suffixes - K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for - resource limits measured in bytes (e.g. DefaultLimitAS=16G). These - settings may be overridden in individual units using the corresponding - LimitXXX= directives. Note that these resource limits are only - defaults for units, they are not applied to PID 1 + for details. The resource limit is possible to specify in two formats, + to set soft and hard limits to the same value, + or to set both limits individually (e.g. DefaultLimitAS=4G:16G). + Use the string infinity to + configure no limit on a specific resource. The multiplicative + suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E + may be used for resource limits measured in bytes + (e.g. DefaultLimitAS=16G). For the limits referring to time values, + the usual time units ms, s, min, h and so on may be used (see + systemd.time7 + for details). Note that if no time unit is specified for + DefaultLimitCPU= the default unit of seconds is + implied, while for DefaultLimitRTTIME= the default + unit of microseconds is implied. Also, note that the effective + granularity of the limits might influence their + enforcement. For example, time limits specified for + DefaultLimitCPU= will be rounded up implicitly to + multiples of 1s. These settings may be overridden in individual units + using the corresponding LimitXXX= directives. Note that these resource + limits are only defaults for units, they are not applied to PID 1 itself. diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index 6dda6c5e6..f0f77c509 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -630,7 +630,10 @@ These settings set both soft and hard limits of various resources for executed processes. See setrlimit2 - for details. Use the string infinity to + for details. The resource limit is possible to specify in two formats, + to set soft and hard limits to the same value, + or to set both limits individually (e.g. LimitAS=4G:16G). + Use the string infinity to configure no limit on a specific resource. The multiplicative suffixes K (=1024), M (=1024*1024) and so on for G, T, P and E may be used for resource limits measured in bytes @@ -803,6 +806,35 @@ settings. + + AmbientCapabilities= + + Controls which capabilities to include in the + ambient capability set for the executed process. Takes a + whitespace-separated list of capability names as read by + cap_from_name3, + e.g. CAP_SYS_ADMIN, + CAP_DAC_OVERRIDE, + CAP_SYS_PTRACE. This option may appear more than + once in which case the ambient capability sets are merged. + If the list of capabilities is prefixed with ~, all + but the listed capabilities will be included, the effect of the + assignment inverted. If the empty string is + assigned to this option, the ambient capability set is reset to + the empty capability set, and all prior settings have no effect. + If set to ~ (without any further argument), the + ambient capability set is reset to the full set of available + capabilities, also undoing any previous settings. Note that adding + capabilities to ambient capability set adds them to the process's + inherited capability set. + + Ambient capability sets are useful if you want to execute a process + as a non-privileged user but still want to give it some capabilities. + Note that in this case option keep-caps is + automatically added to SecureBits= to retain the + capabilities over the user change. + + SecureBits= Controls the secure bits set for the executed @@ -1381,6 +1413,7 @@ $LISTEN_FDS $LISTEN_PID + $LISTEN_FDNAMES Information about file descriptors passed to a service for socket activation. See @@ -1388,6 +1421,24 @@ + + $NOTIFY_SOCKET + + The socket + sd_notify() talks to. See + sd_notify3. + + + + + $WATCHDOG_PID + $WATCHDOG_USEC + + Information about watchdog keep-alive notifications. See + sd_watchdog_enabled3. + + + $TERM @@ -1402,8 +1453,8 @@ Additional variables may be configured by the following means: for processes spawned in specific units, use the - Environment= and - EnvironmentFile= options above; to specify + Environment=, EnvironmentFile= + and PassEnvironment= options above; to specify variables globally, use DefaultEnvironment= (see systemd-system.conf5) diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml index b36aab325..4b80dab10 100644 --- a/man/systemd.generator.xml +++ b/man/systemd.generator.xml @@ -164,13 +164,16 @@ Generators are run very early at boot and cannot rely on any external services. They may not talk to any other process. That includes simple things such as logging to - syslog3, + syslog3, or systemd itself (this means: no - systemctl1!). They - can however rely on the most basic kernel functionality to - be available, including a mounted /sys, - /proc, /dev. + systemctl1)!. + Non-essential file systems like + /var and /home + are mounted after generators have run. Generators + can however rely on the most basic kernel functionality to be + available, including a mounted /sys, + /proc, /dev, + /usr. @@ -315,7 +318,7 @@
- Debuging a generator + Debugging a generator dir=$(mktemp -d) SYSTEMD_LOG_LEVEL=debug &systemgeneratordir;/systemd-fstab-generator \ diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml index a724d8858..4a8d265fe 100644 --- a/man/systemd.mount.xml +++ b/man/systemd.mount.xml @@ -88,7 +88,8 @@ configured in a unit file home-lennart.mount. For details about the escaping logic used to convert a file system path to a unit name, see - systemd.unit5. + systemd.unit5. + Note that mount units cannot be templated. Optionally, a mount unit may be accompanied by an automount unit, to allow on-demand or parallelized mounting. See diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 16e41e05b..b697d0c9a 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -493,6 +493,25 @@ VXLAN Group Policy document. Defaults to false. + + DestinationPort= + + Configures the default destination UDP port on a per-device basis. + If destination port is not specified then Linux kernel default will be used. + Set destination port 4789 to get the IANA assigned value, + and destination port 0 to get default values. + + + + PortRange= + + Configures VXLAN port range. VXLAN bases source + UDP port based on flow to help the receiver to be able + to load balance based on outer header flow. It + restricts the port range to the normal UDP local + ports, and allows overriding via configuration. + + diff --git a/man/systemd.network.xml b/man/systemd.network.xml index e6dedb027..f88751b67 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -228,7 +228,7 @@ ipv4, or ipv6. Note that DHCPv6 will by default be triggered by Router - Advertisment, if that is enabled, regardless of this parameter. + Advertisement, if that is enabled, regardless of this parameter. By enabling DHCPv6 support explicitly, the DHCPv6 client will be started regardless of the presence of routers on the link, or what flags the routers pass. See @@ -277,10 +277,59 @@ LLMNR= - A boolean or resolve. When true, enables - Link-Local Multicast Name Resolution on the link. When set to - resolve, only resolution is enabled, but not - announcement. Defaults to true. + A boolean or resolve. When true, + enables Link-Local + Multicast Name Resolution on the link. When set to + resolve, only resolution is enabled, + but not host registration and announcement. Defaults to + true. This setting is read by + systemd-resolved.service8. + + + + MulticastDNS= + + A boolean or resolve. When true, + enables Multicast + DNS support on the link. When set to + resolve, only resolution is enabled, + but not host or service registration and + announcement. Defaults to false. This setting is read by + systemd-resolved.service8. + + + + DNSSEC= + + A boolean or + allow-downgrade. When true, enables + DNSSEC + DNS validation support on the link. When set to + allow-downgrade, compatibility with + non-DNSSEC capable networks is increased, by automatically + turning off DNSEC in this case. This option defines a + per-interface setting for + resolved.conf5's + global DNSSEC= option. Defaults to + false. This setting is read by + systemd-resolved.service8. + + + + DNSSECNegativeTrustAnchors= + A space-separated list of DNSSEC negative + trust anchor domains. If specified and DNSSEC is enabled, + look-ups done via the interface's DNS server will be subject + to the list of negative trust anchors, and not require + authentication for the specified domains, or anything below + it. Use this to disable DNSSEC authentication for specific + private domains, that cannot be proven valid using the + Internet DNS hierarchy. Defaults to the empty list. This + setting is read by + systemd-resolved.service8. @@ -346,19 +395,38 @@ A DNS server address, which must be in the format described in inet_pton3. - This option may be specified more than once. + This option may be specified more than once. This setting is read by + systemd-resolved.service8. Domains= - The domains used for DNS resolution over this link. + The domains used for DNS host name resolution on this link. Takes a list of DNS domain names which + are used as search suffixes for extending single-label host names (host names containing no dots) to become + fully qualified domain names (FQDNs). If a single-label host name is resolved on this interface, each of + the specified search domains are appended to it in turn, converting it into a fully qualified domain name, + until one of them may be successfully resolved. + + The specified domains are also used for routing of DNS queries: look-ups for host names ending in the + domains specified here are preferably routed to the DNS servers configured for this interface. If a domain + name is prefixed with ~, the domain name becomes a pure "routing" domain, is used for + DNS query routing purposes only and is not used in the described domain search logic. By specifying a + routing domain of ~. (the tilda indicating definition of a routing domain, the dot + referring to the DNS root domain which is the implied suffix of all valid DNS names) it is possible to + route all DNS traffic preferably to the DNS server specified for this interface. The route domain logic is + particularly useful on multi-homed hosts with DNS servers serving particular private DNS zones on each + interface. + + This setting is read by + systemd-resolved.service8. NTP= - An NTP server address. This option may be specified more than once. + An NTP server address. This option may be specified more than once. This setting is read by + systemd-timesyncd.service8. @@ -649,15 +717,20 @@ UseDomains= - When true (not the default), the domain name - received from the DHCP server will be used for DNS - resolution over this link. When a name cannot be resolved - as specified, the domain name will be used a suffix and - name resolution of that will be attempted. + Takes a boolean argument, or a the special value route. When true, the domain name + received from the DHCP server will be used as DNS search domain over this link, similar to the effect of + the setting. If set to route, the domain name received from + the DHCP server will be used for routing DNS queries only, but not for searching, similar to the effect of + the setting when the argument is prefixed with ~. Defaults to + false. - This corresponds to the - option in resolv.conf5 - and should not be enabled on untrusted networks. + It is recommended to enable this option only on trusted networks, as setting this affects resolution + of all host names, in particular to single-label names. It is generally safer to use the supplied domain + only as routing domain, rather than as search domain, in order to not have it affect local resolution of + single-label names. + + When set to true, this setting corresponds to the option in resolv.conf5. @@ -673,7 +746,7 @@ UseTimezone= When true, the timezone received from the - DHCP server will be set as as timezone of the local + DHCP server will be set as timezone of the local system. Defaults to no. @@ -1011,9 +1084,10 @@ DHCP=yes See Also systemd1, - systemd-networkd8, + systemd-networkd.service8, systemd.link5, - systemd.netdev5 + systemd.netdev5, + systemd-resolved.service8 diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index e95268833..c07a4b024 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -141,15 +141,21 @@ Boot= - Takes a boolean argument, which defaults to off. If - enabled, systemd-nspawn will automatically - search for an init executable and invoke - it. In this case, the specified parameters using - Parameters= are passed as additional - arguments to the init process. This - setting corresponds to the switch on - the systemd-nspawn command - line. + Takes a boolean argument, which defaults to off. If enabled, systemd-nspawn + will automatically search for an init executable and invoke it. In this case, the + specified parameters using Parameters= are passed as additional arguments to the + init process. This setting corresponds to the switch on the + systemd-nspawn command line. This option may not be combined with + ProcessTwo=yes. + + + + ProcessTwo= + + Takes a boolean argument, which defaults to off. If enabled, the specified program is run as + PID 2. A stub init process is run as PID 1. This setting corresponds to the switch + on the systemd-nspawn command line. This option may not be combined with + Boot=yes. @@ -186,13 +192,21 @@ switch. + + WorkingDirectory= + + Selects the working directory for the process invoked in the container. Expects an absolute + path in the container's file system namespace. This corresponds to the command line + switch. + + Capability= DropCapability= Takes a space-separated list of Linux process capabilities (see - capabilities7 + capabilities7 for details). The Capability= setting specifies additional capabilities to pass on top of the default set of capabilities. The diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index b1106c759..08cdf06e2 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -423,23 +423,6 @@ - - NetClass= - Configures a network class number to assign to the - unit. This value will be set to the - net_cls.class_id property of the - net_cls cgroup of the unit. The directive - accepts a numerical value (for fixed number assignment) and the keyword - auto (for dynamic allocation). Network traffic of - all processes inside the unit will have the network class ID assigned - by the kernel. Also see - the kernel docs for - net_cls controller - and - systemd.resource-control5. - - - Slice= @@ -459,6 +442,12 @@ this setting is the parent slice. Since the name of a slice unit implies the parent slice, it is hence redundant to ever set this parameter directly for slice units. + + Special care should be taken when relying on the default slice assignment in templated service units + that have DefaultDependencies=no set, see + systemd.service5, section + "Automatic Dependencies" for details. + diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 20a71afe5..d7760d4f2 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -113,6 +113,16 @@ involved with early boot or late system shutdown should disable this option. + Instanced service units (i.e. service units with an @ in their name) are assigned by + default a per-template slice unit (see + systemd.slice5), named after the + template unit, containing all instances of the specific template. This slice is normally stopped at shutdown, + together with all template instances. If that is not desired, set DefaultDependencies=no in the + template unit, and either define your own per-template slice unit file that also sets + DefaultDependencies=no, or set Slice=system.slice (or another suitable slice) + in the template unit. Also see + systemd.resource-control5. + Additional implicit dependencies may be added as result of execution and resource control parameters as documented in systemd.exec5 @@ -361,7 +371,7 @@ with a - exit successfully. ExecStartPost= commands are only run after - the service has started, as determined by Type= + the service has started successfully, as determined by Type= (i.e. the process has been started for Type=simple or Type=idle, the process exits successfully for Type=oneshot, the initial process exits successfully @@ -373,6 +383,11 @@ used to start long-running processes. All processes forked off by processes invoked via ExecStartPre= will be killed before the next service process is run. + + Note that if any of the commands specified in ExecStartPre=, + ExecStart=, or ExecStartPost= fail (and are not prefixed with + -, see above) or time out before the service is fully up, execution continues with commands + specified in ExecStopPost=, the commands in ExecStop= are skipped. @@ -428,21 +443,36 @@ SIGKILL immediately after the command exited, this would not result in a clean stop. The specified command should hence be a synchronous operation, not an - asynchronous one. + asynchronous one. + + Note that the commands specified in ExecStop= are only executed when the service + started successfuly first. They are not invoked if the service was never started at all, or in case its + start-up failed, for example because any of the commands specified in ExecStart=, + ExecStartPre= or ExecStartPost= failed (and weren't prefixed with + -, see above) or timed out. Use ExecStopPost= to invoke commands when a + service failed to start up correctly and is shut down again. + + It is recommended to use this setting for commands that communicate with the service requesting clean + termination. When the commands specified with this option are executed it should be assumed that the service is + still fully up and is able to react correctly to all commands. For post-mortem clean-up steps use + ExecStopPost= instead. ExecStopPost= - Additional commands that are executed after - the service was stopped. This includes cases where the - commands configured in ExecStop= were used, - where the service does not have any - ExecStop= defined, or where the service - exited unexpectedly. This argument takes multiple command - lines, following the same scheme as described for - ExecStart=. Use of these settings is - optional. Specifier and environment variable substitution is - supported. + Additional commands that are executed after the service is stopped. This includes cases where + the commands configured in ExecStop= were used, where the service does not have any + ExecStop= defined, or where the service exited unexpectedly. This argument takes multiple + command lines, following the same scheme as described for ExecStart=. Use of these settings + is optional. Specifier and environment variable substitution is supported. Note that – unlike + ExecStop= – commands specified with this setting are invoked when a service failed to start + up correctly and is shut down again. + + It is recommended to use this setting for clean-up operations that shall be executed even when the + service failed to start up correctly. Commands configured with this setting need to be able to operate even if + the service failed starting up half-way and left incompletely initialized data around. As the service's + processes have been terminated already when the commands specified with this setting are executed they should + not attempt to communicate with them. @@ -460,7 +490,7 @@ configured time, the service will be considered failed and will be shut down again. Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass - 0 to disable the timeout logic. Defaults to + infinity to disable the timeout logic. Defaults to DefaultTimeoutStartSec= from the manager configuration file, except when Type=oneshot is used, in which case the @@ -479,7 +509,7 @@ KillMode= in systemd.kill5). Takes a unit-less value in seconds, or a time span value such - as "5min 20s". Pass 0 to disable the + as "5min 20s". Pass infinity to disable the timeout logic. Defaults to DefaultTimeoutStopSec= from the manager configuration file (see @@ -495,6 +525,16 @@ + + RuntimeMaxSec= + + Configures a maximum time for the service to run. If this is used and the service has been + active for longer than the specified time it is terminated and put into a failure state. Note that this setting + does not have any effect on Type=oneshot services, as they terminate immediately after + activation completed. Pass infinity (the default) to configure no runtime + limit. + + WatchdogSec= Configures the watchdog timeout for a service. @@ -506,7 +546,8 @@ larger than the configured time, then the service is placed in a failed state and it will be terminated with SIGABRT. By setting - Restart= to or + Restart= to , + , or , the service will be automatically restarted. The time configured here will be passed to the executed service process in the @@ -521,7 +562,9 @@ check whether the service manager expects watchdog keep-alive notifications. See sd_watchdog_enabled3 - for details. + for details. + sd_event_set_watchdog3 + may be used to enable automatic watchdog notification support. @@ -678,8 +721,10 @@ SIGPIPE. Exit status definitions can either be numeric exit codes or termination signal names, separated by spaces. For example: - SuccessExitStatus=1 2 8 - SIGKILL ensures that exit codes 1, 2, 8 and + + SuccessExitStatus=1 2 8 SIGKILL + + ensures that exit codes 1, 2, 8 and the termination signal SIGKILL are considered clean service terminations. @@ -711,14 +756,16 @@ signal names, and are separated by spaces. Defaults to the empty list, so that, by default, no exit status is excluded from the configured restart logic. For example: - RestartPreventExitStatus=1 6 - SIGABRT ensures that exit codes 1 and 6 and - the termination signal SIGABRT will not - result in automatic service restarting. This option may appear - more than once, in which case the list of restart-preventing - statuses is merged. If the empty string is assigned to this - option, the list is reset and all prior assignments of this - option will have no effect. + + RestartPreventExitStatus=1 6 SIGABRT + + ensures that exit codes 1 and 6 and the termination signal + SIGABRT will not result in automatic + service restarting. This option may appear more than once, in + which case the list of restart-preventing statuses is + merged. If the empty string is assigned to this option, the + list is reset and all prior assignments of this option will + have no effect. @@ -826,86 +873,12 @@ effect. - - StartLimitInterval= - StartLimitBurst= - - Configure service start rate limiting. By - default, services which are started more than 5 times within - 10 seconds are not permitted to start any more times until the - 10 second interval ends. With these two options, this rate - limiting may be modified. Use - StartLimitInterval= to configure the - checking interval (defaults to - DefaultStartLimitInterval= in manager - configuration file, set to 0 to disable any kind of rate - limiting). Use StartLimitBurst= to - configure how many starts per interval are allowed (defaults - to DefaultStartLimitBurst= in manager - configuration file). These configuration options are - particularly useful in conjunction with - Restart=; however, they apply to all kinds - of starts (including manual), not just those triggered by the - Restart= logic. Note that units which are - configured for Restart= and which reach the - start limit are not attempted to be restarted anymore; - however, they may still be restarted manually at a later - point, from which point on, the restart logic is again - activated. Note that systemctl reset-failed - will cause the restart rate counter for a service to be - flushed, which is useful if the administrator wants to - manually start a service and the start limit interferes with - that. - - - - StartLimitAction= - - Configure the action to take if the rate limit - configured with StartLimitInterval= and - StartLimitBurst= is hit. Takes one of - , - , - , - , - , - or - . If - is set, hitting the rate limit will - trigger no action besides that the start will not be - permitted. causes a reboot following - the normal shutdown procedure (i.e. equivalent to - systemctl reboot). - causes a forced reboot which - will terminate all processes forcibly but should cause no - dirty file systems on reboot (i.e. equivalent to - systemctl reboot -f) and - causes immediate execution - of the - reboot2 - system call, which might result in data loss. Similarly, - , , - have the effect of - powering down the system with similar semantics. Defaults to - . - - FailureAction= - Configure the action to take when the service - enters a failed state. Takes the same values as - StartLimitAction= and executes the same - actions. Defaults to . - - - - RebootArgument= - Configure the optional argument for the - reboot2 - system call if StartLimitAction= or - FailureAction= is a reboot action. This - works just like the optional argument to systemctl - reboot command. + Configure the action to take when the service enters a failed state. Takes the same values as + the unit setting StartLimitAction= and executes the same actions (see + systemd.unit5). Defaults to + . diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml index beac053bf..43841c239 100644 --- a/man/systemd.socket.xml +++ b/man/systemd.socket.xml @@ -310,6 +310,15 @@ + + SocketProtocol= + Takes a one of + or . Specifies a socket protocol + (IPPROTO_UDPLITE) UDP-Lite + (IPPROTO_SCTP) SCTP socket respectively. + + + BindIPv6Only= Takes a one of , diff --git a/man/systemd.special.xml b/man/systemd.special.xml index 54e7c49a9..055d85455 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -92,6 +92,7 @@ shutdown.target, sigpwr.target, sleep.target, + slices.target, smartcard.target, sockets.target, sound.target, @@ -203,12 +204,22 @@ emergency.target - A special target unit that starts an emergency shell - on the main console. This unit is supposed to be used with - the kernel command line option - systemd.unit= and has otherwise little - use. - + A special target unit that starts an emergency shell on the main console. This target does not pull in + any serices or mounts. It is the most minimal version of starting the system in order to acquire an + interactive shell; the only processes running are usually just the system manager (PID 1) and the shell + process. This unit is supposed to be used with the kernel command line option + systemd.unit=; it is also used when a file system check on a required file system fails, + and boot-up cannot continue. Compare with rescue.target, which serves a similar purpose, + but also starts the most basic services and mounts all file systems. + + Use the systemd.unit=emergency.target kernel command line option to boot into this + mode. A short alias for this kernel command line option is emergency, for compatibility + with SysV. + + In many ways booting into emergency.target is similar to the effect of booting + with init=/bin/sh on the kernel command line, except that emergency mode provides you with + the full system and service manager, and allows starting individual units in order to continue the boot + process in steps. @@ -439,11 +450,18 @@ rescue.target - A special target unit for setting up the base system - and a rescue shell. + A special target unit that pulls in the base system (including system mounts) and spawns a rescue + shell. Isolate to this target in order to administer the system in single-user mode with all file systems + mounted but with no services running, except for the most basic. Compare with + emergency.target, which is much more reduced and does not provide the file systems or + most basic services. - runlevel1.target is an alias for - this target unit, for compatibility with SysV. + runlevel1.target is an alias for this target unit, for compatibility with + SysV. + + Use the systemd.unit=rescue.target kernel command line option to boot into this + mode. A short alias for this kernel command line option is 1, for compatibility with + SysV. @@ -502,11 +520,24 @@ hook units into the sleep state logic. + + slices.target + + A special target unit that sets up all slice units (see + systemd.slice5 for + details) that shall be active after boot. By default the generic user.slice, + system.slice, machines.slice slice units, as well as the the root + slice unit -.slice are pulled in and ordered before this unit (see below). + + It's a good idea to add WantedBy=slices.target lines to the [Install] + section of all slices units that may be installed dynamically. + + sockets.target A special target unit that sets up all socket - units.(see + units (see systemd.socket5 for details) that shall be active after boot. @@ -587,7 +618,7 @@ umount.target - A special target unit that umounts all mount and + A special target unit that unmounts all mount and automount points on system shutdown. Mounts that shall be unmounted on system shutdown diff --git a/man/systemd.time.xml b/man/systemd.time.xml index a6fcc95e4..ffcac8226 100644 --- a/man/systemd.time.xml +++ b/man/systemd.time.xml @@ -229,6 +229,10 @@ the value and all values plus multiples of the repetition value are matched. + The seconds component may contain decimal fractions both in + the value and the repetition. All fractions are rounded to 6 + decimal places. + Either time or date specification may be omitted, in which case the current day and 00:00:00 is implied, respectively. If the second component is not specified, :00 is @@ -276,6 +280,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03 Sat,Sun 12-05 08:05:40 → Sat,Sun *-12-05 08:05:40 Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40 2003-03-05 05:40 → 2003-03-05 05:40:00 +05:40:23.4200004/3.1700005 → 05:40:23.420000/3.170001 2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC 2003-03-05 → 2003-03-05 00:00:00 03-05 → *-03-05 00:00:00 diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml index 384158882..29e235e2d 100644 --- a/man/systemd.timer.xml +++ b/man/systemd.timer.xml @@ -190,13 +190,12 @@ OnUnitInactiveSec= and ending the time configured with AccuracySec= later. Within this time window, the expiry time will be placed at a - host-specific, randomized but stable position that is + host-specific, randomized, but stable position that is synchronized between all local timer units. This is done in - order to distribute the wake-up time in networked - installations, as well as optimizing power consumption to - suppress unnecessary CPU wake-ups. To get best accuracy, set - this option to 1us. Note that the timer is still subject to - the timer slack configured via + order to optimize power consumption to suppress unnecessary + CPU wake-ups. To get best accuracy, set this option to + 1us. Note that the timer is still subject to the timer slack + configured via systemd-system.conf5's TimerSlackNSec= setting. See prctl2 @@ -204,6 +203,38 @@ this value as high as possible and as low as necessary. + + + RandomizedDelaySec= + + Delay the timer by a randomly selected, evenly + distributed amount of time between 0 and the specified time + value. Defaults to 0, indicating that no randomized delay + shall be applied. Each timer unit will determine this delay + randomly each time it is started, and the delay will simply be + added on top of the next determined elapsing time. This is + useful to stretch dispatching of similarly configured timer + events over a certain amount time, to avoid that they all fire + at the same time, possibly resulting in resource + congestion. Note the relation to + AccuracySec= above: the latter allows the + service manager to coalesce timer events within a specified + time range in order to minimize wakeups, the former does the + opposite: it stretches timer events over a time range, to make + it unlikely that they fire simultaneously. If + RandomizedDelaySec= and + AccuracySec= are used in conjunction, first + the randomized delay is added, and then the result is + possibly further shifted to coalesce it with other timer + events happening on the system. As mentioned above + AccuracySec= defaults to 1min and + RandomizedDelaySec= to 0, thus encouraging + coalescing of timer events. In order to optimally stretch + timer events over a certain range of time, make sure to set + RandomizedDelaySec= to a higher value, and + AccuracySec=1us. + + Unit= @@ -245,11 +276,20 @@ - RemainAfterExit= + RemainAfterElapse= Takes a boolean argument. If true, an elapsed - timer will stay loaded, and its state remains - queriable. Defaults to + timer will stay loaded, and its state remains queriable. If + false, an elapsed timer unit that cannot elapse anymore is + unloaded. Turning this off is particularly useful for + transient timer units that shall disappear after they first + elapse. Note that this setting has an effect on repeatedly + starting a timer unit that only elapses once: if + RemainAfterElapse= is on, it will not be + started again, and is guaranteed to elapse only once. However, + if RemainAfterLeapse= is off, it might be + started again if it is already elapsed, and thus be triggered + multiple times. Defaults to yes. diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 5b12378ed..579468196 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -178,19 +178,26 @@ directory suffix is .requires/ in this case. - Along with a unit file foo.service, a - directory foo.service.d/ may exist. All files - with the suffix .conf from this directory will - be parsed after the file itself is parsed. This is useful to alter - or add configuration settings to a unit, without having to modify - their unit files. Make sure that the file that is included has the - appropriate section headers before any directive. Note that, for - instanced units, this logic will first look for the instance - .d/ subdirectory and read its - .conf files, followed by the template - .d/ subdirectory and reads its - .conf files. + Along with a unit file foo.service, a "drop-in" directory + foo.service.d/ may exist. All files with the suffix .conf from this + directory will be parsed after the file itself is parsed. This is useful to alter or add configuration settings for + a unit, without having to modify unit files. Each drop-in file must have appropriate section headers. Note that for + instantiated units, this logic will first look for the instance .d/ subdirectory and read its + .conf files, followed by the template .d/ subdirectory and the + .conf files there. Also note that settings from the [Install] section are not + honoured in drop-in unit files, and have no effect. + In addition to /etc/systemd/system, + the drop-in .conf files for system services + can be placed in /usr/lib/systemd/system or + /run/systemd/system directories. Drop-in + files in /etc take precedence over those in + /run which in turn take precedence over + those in /usr/lib. Drop-in files under any of + these directories take precedence over unit files wherever located. + (Of course, since /run is temporary and + /usr/lib is for vendors, it is unlikely + drop-ins should be used in either of those places.) @@ -717,20 +724,14 @@ JobTimeoutAction= JobTimeoutRebootArgument= - When a job for this unit is queued, a time-out - may be configured. If this time limit is reached, the job will - be cancelled, the unit however will not change state or even - enter the failed mode. This value defaults - to 0 (job timeouts disabled), except for device units. NB: - this timeout is independent from any unit-specific timeout - (for example, the timeout set with - TimeoutStartSec= in service units) as the - job timeout has no effect on the unit itself, only on the job - that might be pending for it. Or in other words: unit-specific - timeouts are useful to abort unit state changes, and revert - them. The job timeout set with this option however is useful - to abort only the job waiting for the unit state to - change. + When a job for this unit is queued, a time-out may be configured. If this time limit is + reached, the job will be cancelled, the unit however will not change state or even enter the + failed mode. This value defaults to infinity (job timeouts disabled), + except for device units. NB: this timeout is independent from any unit-specific timeout (for example, the + timeout set with TimeoutStartSec= in service units) as the job timeout has no effect on the + unit itself, only on the job that might be pending for it. Or in other words: unit-specific timeouts are useful + to abort unit state changes, and revert them. The job timeout set with this option however is useful to abort + only the job waiting for the unit state to change. JobTimeoutAction= optionally configures an additional @@ -748,6 +749,55 @@ system call. + + StartLimitInterval= + StartLimitBurst= + + Configure unit start rate limiting. By default, units which are started more than 5 times + within 10 seconds are not permitted to start any more times until the 10 second interval ends. With these two + options, this rate limiting may be modified. Use StartLimitInterval= to configure the + checking interval (defaults to DefaultStartLimitInterval= in manager configuration file, set + to 0 to disable any kind of rate limiting). Use StartLimitBurst= to configure how many + starts per interval are allowed (defaults to DefaultStartLimitBurst= in manager + configuration file). These configuration options are particularly useful in conjunction with the service + setting Restart= (see + systemd.service5); however, + they apply to all kinds of starts (including manual), not just those triggered by the + Restart= logic. Note that units which are configured for Restart= and + which reach the start limit are not attempted to be restarted anymore; however, they may still be restarted + manually at a later point, from which point on, the restart logic is again activated. Note that + systemctl reset-failed will cause the restart rate counter for a service to be flushed, + which is useful if the administrator wants to manually start a unit and the start limit interferes with + that. + + + + StartLimitAction= + + Configure the action to take if the rate limit configured with + StartLimitInterval= and StartLimitBurst= is hit. Takes one of + , , , + , , or + . If is set, hitting the rate limit will trigger no + action besides that the start will not be permitted. causes a reboot following the + normal shutdown procedure (i.e. equivalent to systemctl reboot). + causes a forced reboot which will terminate all processes forcibly but should + cause no dirty file systems on reboot (i.e. equivalent to systemctl reboot -f) and + causes immediate execution of the + reboot2 system call, which + might result in data loss. Similarly, , , + have the effect of powering down the system with similar + semantics. Defaults to . + + + + RebootArgument= + Configure the optional argument for the + reboot2 system call if + StartLimitAction= or a service's FailureAction= is a reboot action. This + works just like the optional argument to systemctl reboot command. + + ConditionArchitecture= ConditionVirtualization= @@ -773,13 +823,14 @@ useful and probably just confusing. --> - Before starting a unit verify that the - specified condition is true. If it is not true, the starting - of the unit will be skipped, however all ordering dependencies - of it are still respected. A failing condition will not result - in the unit being moved into a failure state. The condition is - checked at the time the queued start job is to be - executed. + Before starting a unit, verify that the specified condition is true. If it is not true, the + starting of the unit will be (mostly silently) skipped, however all ordering dependencies of it are still + respected. A failing condition will not result in the unit being moved into a failure state. The condition is + checked at the time the queued start job is to be executed. Use condition expressions in order to silently skip + units that do not apply to the local running system, for example because the kernel or runtime environment + doesn't require its functionality. Use the various AssertArchitecture=, + AssertVirtualization=, … options for a similar mechanism that puts the unit in a failure + state and logs about the failed check (see below). ConditionArchitecture= may be used to check whether the system is running on a specific @@ -875,7 +926,7 @@ ConditionSecurity= may be used to check whether the given security module is enabled on the - system. Currently, the recognized values values are + system. Currently, the recognized values are selinux, apparmor, ima, @@ -918,7 +969,7 @@ /var on the next following boot. Units making use of this condition should order themselves before systemd-update-done.service8, - to make sure they run before the stamp files's modification + to make sure they run before the stamp file's modification time gets reset indicating a completed update. ConditionFirstBoot= takes a boolean @@ -1013,14 +1064,12 @@ AssertFileNotEmpty= AssertFileIsExecutable= - Similar to the - ConditionArchitecture=, - ConditionVirtualization=, etc., condition - settings described above, these settings add assertion checks - to the start-up of the unit. However, unlike the conditions - settings, any assertion setting that is not met results in - failure of the start job it was triggered - by. + Similar to the ConditionArchitecture=, + ConditionVirtualization=, …, condition settings described above, these settings add + assertion checks to the start-up of the unit. However, unlike the conditions settings, any assertion setting + that is not met results in failure of the start job (which means this is logged loudly). Use assertion + expressions for units that cannot operate when specific requirements are not met, and when this is something + the administrator or user should look into. @@ -1040,15 +1089,13 @@ [Install] Section Options - Unit file may include an [Install] - section, which carries installation information for the unit. This - section is not interpreted by - systemd1 - during runtime. It is used exclusively by the - enable and disable commands - of the - systemctl1 - tool during installation of a unit: + Unit files may include an [Install] section, which carries installation information for + the unit. This section is not interpreted by + systemd1 during runtime; it is + used by the enable and disable commands of the + systemctl1 tool during + installation of a unit. Note that settings in the [Install] section may not appear in + .d/*.conf unit file drop-ins (see above). @@ -1402,6 +1449,7 @@ PrivateTmp=yes cannot be reset to an empty list, so dependencies can only be added in drop-ins. If you want to remove dependencies, you have to override the entire unit. + diff --git a/man/systemd.xml b/man/systemd.xml index 6de18f829..b8d91b894 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -255,6 +255,14 @@ . + + + + Override the machine-id set on the hard drive, + useful for network booting or for containers. May not be set + to all zeros. + + @@ -826,6 +834,13 @@ script runlevel link farms. + + $SYSTEMD_COLORS + + Controls whether colorized output should be generated. + + + $LISTEN_PID $LISTEN_FDS @@ -976,6 +991,15 @@ than once to set multiple variables. + + systemd.machine_id= + + Takes a 32 character hex value to be + used for setting the machine-id. Intended mostly for + network booting where the same machine-id is desired + for every boot. + + quiet diff --git a/man/sysusers.d.xml b/man/sysusers.d.xml index 42b53b275..18ee3800d 100644 --- a/man/sysusers.d.xml +++ b/man/sysusers.d.xml @@ -113,7 +113,7 @@ u root 0 "Superuser" /root m Add a user to a group. If the user or group - are not existing yet, they will be implicitly + do not exist yet, they will be implicitly created. diff --git a/man/timesyncd.conf.xml b/man/timesyncd.conf.xml index 10c2de89f..8c86fd007 100644 --- a/man/timesyncd.conf.xml +++ b/man/timesyncd.conf.xml @@ -68,6 +68,8 @@ Options + The following settings are configured in the [Time] section: + diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index 5bf1f2956..3b6b1e3f1 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -264,7 +264,8 @@ be removed and be replaced by the symlink. If the argument is omitted, symlinks to files with the same name residing in the directory /usr/share/factory/ are - created. + created. Note that permissions and ownership on symlinks + are ignored. @@ -421,7 +422,7 @@ systemd-tmpfiles will automatically add the required base entries for user and group based on the access mode of the file, unless base entries already exist - or are explictly specified. The mask will be added if not + or are explicitly specified. The mask will be added if not specified explicitly or already present. Lines of this type accept shell-style globs in place of normal path names. This can be useful for allowing additional access to certain diff --git a/man/udev_device_new_from_syspath.xml b/man/udev_device_new_from_syspath.xml index 11db1a0fa..0bb71c8e9 100644 --- a/man/udev_device_new_from_syspath.xml +++ b/man/udev_device_new_from_syspath.xml @@ -134,7 +134,7 @@ a uevent file. udev_device_new_from_devnum takes a device type, which can be b for block devices or c for character devices, as well as a devnum (see - makedev3). + makedev3). udev_device_new_from_subsystem_sysname looks up devices based on the provided subsystem and sysname (see udev_device_get_subsystem3 @@ -171,7 +171,7 @@ udev_device_new_from_environment creates a device from the current environment (see - environ7). + environ7). Each key-value pair is interpreted in the same way as if it was received in an uevent (see udev_monitor_receive_device3). @@ -189,7 +189,8 @@ udev_device_new_from_device_id() and udev_device_new_from_environment() return a pointer to the allocated udev device. On failure, - NULL is returned. + NULL is returned, + and errno is set appropriately. udev_device_ref() returns the argument that it was passed, unmodified. udev_device_unref() always returns diff --git a/po/el.po b/po/el.po index 95cde045b..94c9986d6 100644 --- a/po/el.po +++ b/po/el.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2014-04-29 09:17+0300\n" "Last-Translator: Dimitris Spingos (Δημήτρης Σπίγγος) \n" "Language-Team: team@lists.gnome.gr\n" @@ -451,6 +451,15 @@ msgid "" "interface." msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +#, fuzzy +msgid "Authentication is required to set a wall message" +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "" @@ -461,20 +470,68 @@ msgid "Authentication is required to log into a local container." msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 -msgid "Manage local virtual machines and containers" +msgid "Log into the local host" msgstr "" #: ../src/machine/org.freedesktop.machine1.policy.in.h:4 #, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +#, fuzzy +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 +msgid "Manage local virtual machines and containers" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 +#, fuzzy msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "Απαιτείται πιστοποίηση για να ορίσετε πληροφορίες τοπικής μηχανής." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 #, fuzzy msgid "" "Authentication is required to manage local virtual machine and container " @@ -520,3 +577,38 @@ msgid "" msgstr "" "Απαιτείται πιστοποίηση για να ελέγξετε αν ο συγχρονισμός ώρας δικτύου θα " "ενεργοποιηθεί." + +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." diff --git a/po/es.po b/po/es.po index ceca42386..681b30d5b 100644 --- a/po/es.po +++ b/po/es.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-04-24 13:26+0200\n" "Last-Translator: Álex Puchades \n" "Language-Team: Español; Castellano \n" @@ -446,6 +446,15 @@ msgstr "" "Se requiere autenticación para indicar al firmware que arranque la interfaz " "de configuración." +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +#, fuzzy +msgid "Authentication is required to set a wall message" +msgstr "Se requiere autenticación para establecer el nombre de equipo local." + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Conectarse a un contenedor local" @@ -455,21 +464,70 @@ msgid "Authentication is required to log into a local container." msgstr "Se requiere autenticación para conectarse a un contenedor local." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "Conectarse a un contenedor local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "Se requiere autenticación para conectarse a un contenedor local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Conectarse a un contenedor local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Se requiere autenticación para conectarse a un contenedor local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Se requiere autenticación para establecer el nombre de equipo local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Conectarse a un contenedor local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "Se requiere autenticación para conectarse a un contenedor local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +#, fuzzy +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Se requiere autenticación para establecer el nombre de equipo local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 msgid "Manage local virtual machines and containers" msgstr "Administrar máquinas virtuales y contenedores locales" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "" "Se requiere autenticación para administrar las máquinas virtuales y los " "contenedores locales." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "Administrar imágenes de máquina virtual y de contenedor locales" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -517,6 +575,41 @@ msgstr "" "Se requiere autenticación para activar/desactivar la sincronización de hora " "por red." +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "Se requiere autenticación para recargar el estado de systemd." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "Se requiere autenticación para conectarse a un contenedor local." + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Se requiere autenticación para establecer el nombre de equipo local." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Se requiere autenticación para establecer la fecha y hora del sistema." + #~ msgid "Press Ctrl+C to cancel all filesystem checks in progress" #~ msgstr "" #~ "Presione Ctrl+C para cancelar todas las comprobaciones del sistema de " diff --git a/po/hu.po b/po/hu.po index c5dee2505..88fecbc50 100644 --- a/po/hu.po +++ b/po/hu.po @@ -1,14 +1,14 @@ # Hungarian translation of systemd -# Copyright (C) 2015. Free Software Foundation, Inc. +# Copyright (C) 2015, 2016. Free Software Foundation, Inc. # This file is distributed under the same license as the systemd package. # -# Gabor Kelemen , 2015. +# Gabor Kelemen , 2015, 2016. msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" -"PO-Revision-Date: 2015-01-02 22:58+0100\n" +"POT-Creation-Date: 2016-01-02 13:41+0100\n" +"PO-Revision-Date: 2016-01-02 13:45+0100\n" "Last-Translator: Gabor Kelemen \n" "Language-Team: Hungarian \n" "Language: hu\n" @@ -29,15 +29,13 @@ msgstr "" "Hitelesítés szükséges a bevitt jelmondat visszaküldéséhez a rendszernek." #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3 -#, fuzzy msgid "Manage system services or other units" -msgstr "Rendszerszolgáltatások vagy -egységek kezelése" +msgstr "Rendszerszolgáltatások vagy más egységek kezelése" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 -#, fuzzy msgid "Authentication is required to manage system services or other units." msgstr "" -"Hitelesítés szükséges a rendszerszolgáltatások vagy -egységek kezeléséhez." +"Hitelesítés szükséges a rendszerszolgáltatások vagy más egységek kezeléséhez." #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5 msgid "Manage system service or unit files" @@ -51,14 +49,16 @@ msgstr "" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7 msgid "Set or unset system and service manager environment variables" msgstr "" +"Rendszer- és szolgáltatáskezelő környezeti változóinak beállítása vagy " +"törlése" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8 -#, fuzzy msgid "" "Authentication is required to set or unset system and service manager " "environment variables." msgstr "" -"Hitelesítés szükséges a rendszerszolgáltatás- vagy egységfájlok kezeléséhez." +"Hitelesítés szükséges a rendszer- és szolgáltatáskezelő környezeti " +"változóinak beállításához vagy törléséhez." #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9 msgid "Reload the systemd state" @@ -98,30 +98,27 @@ msgstr "Hitelesítés szükséges a helyi gép információinak beállításáho #: ../src/import/org.freedesktop.import1.policy.in.h:1 msgid "Import a VM or container image" -msgstr "" +msgstr "VM vagy konténer lemezkép importálása" #: ../src/import/org.freedesktop.import1.policy.in.h:2 -#, fuzzy msgid "Authentication is required to import a VM or container image" -msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." +msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép importálásához." #: ../src/import/org.freedesktop.import1.policy.in.h:3 msgid "Export a VM or container image" -msgstr "" +msgstr "VM vagy konténer lemezkép exportálása" #: ../src/import/org.freedesktop.import1.policy.in.h:4 -#, fuzzy msgid "Authentication is required to export a VM or container image" -msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." +msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép exportálásához." #: ../src/import/org.freedesktop.import1.policy.in.h:5 msgid "Download a VM or container image" -msgstr "" +msgstr "VM vagy konténer lemezkép letöltése" #: ../src/import/org.freedesktop.import1.policy.in.h:6 -#, fuzzy msgid "Authentication is required to download a VM or container image" -msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." +msgstr "Hitelesítés szükséges a VM vagy konténer lemezkép letöltéséhez." #: ../src/locale/org.freedesktop.locale1.policy.in.h:1 msgid "Set system locale" @@ -409,65 +406,113 @@ msgstr "" #: ../src/login/org.freedesktop.login1.policy.in.h:49 msgid "Manage active sessions, users and seats" -msgstr "" +msgstr "Aktív munkamenetek, felhasználók és munkaállomások kezelése" #: ../src/login/org.freedesktop.login1.policy.in.h:50 -#, fuzzy msgid "" "Authentication is required for managing active sessions, users and seats." msgstr "" -"Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy " -"munkaállomáshoz" +"Hitelesítés szükséges az aktív munkamenetek, felhasználók és munkaállomások " +"kezeléséhez." #: ../src/login/org.freedesktop.login1.policy.in.h:51 msgid "Lock or unlock active sessions" -msgstr "" +msgstr "Aktív munkamenetek zárolása vagy feloldása" #: ../src/login/org.freedesktop.login1.policy.in.h:52 -#, fuzzy msgid "Authentication is required to lock or unlock active sessions." -msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." +msgstr "" +"Hitelesítés szükséges az aktív munkamenetek zárolásához vagy feloldásához." #: ../src/login/org.freedesktop.login1.policy.in.h:53 msgid "Allow indication to the firmware to boot to setup interface" -msgstr "" +msgstr "A firmware-nek jelezhető, hogy a beállítófelületet bootolja" #: ../src/login/org.freedesktop.login1.policy.in.h:54 -#, fuzzy msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." -msgstr "Hitelesítés szükséges a helyi gépnév beállításához." +msgstr "" +"Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet " +"bootolja" + +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "Falüzenet beállítása" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +msgid "Authentication is required to set a wall message" +msgstr "Hitelesítés szükséges a falüzenet beállításához" #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Bejelentkezés helyi konténerbe" #: ../src/machine/org.freedesktop.machine1.policy.in.h:2 -#, fuzzy msgid "Authentication is required to log into a local container." msgstr "Hitelesítés szükséges a bejelentkezéshez egy helyi konténerbe." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 -msgid "Manage local virtual machines and containers" -msgstr "" +msgid "Log into the local host" +msgstr "Bejelentkezés a helyi gépre" #: ../src/machine/org.freedesktop.machine1.policy.in.h:4 -#, fuzzy -msgid "" -"Authentication is required to manage local virtual machines and containers." -msgstr "Hitelesítés szükséges a helyi gép információinak beállításához." +msgid "Authentication is required to log into the local host." +msgstr "Hitelesítés szükséges a bejelentkezéshez a helyi gépre." #: ../src/machine/org.freedesktop.machine1.policy.in.h:5 -msgid "Manage local virtual machine and container images" -msgstr "" +msgid "Acquire a shell in a local container" +msgstr "Parancsértelmező elérése helyi konténerben" #: ../src/machine/org.freedesktop.machine1.policy.in.h:6 -#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Hitelesítés szükséges a parancsértelmező eléréséhez helyi konténerben." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "Parancsértelmező elérése a helyi gépen" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Hitelesítés szükséges a parancsértelmező eléréséhez a helyi gépen." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +msgid "Acquire a pseudo TTY in a local container" +msgstr "Pszeudoterminál elérése helyi konténerben" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "Hitelesítés szükséges a pszeudoterminál eléréséhez helyi konténerben." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "Pszeudoterminál elérése helyi gépen" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Hitelesítés szükséges a pszeudoterminál eléréséhez a helyi gépen." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 +msgid "Manage local virtual machines and containers" +msgstr "Virtuális gépek és konténerek kezelése" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 +msgid "" +"Authentication is required to manage local virtual machines and containers." +msgstr "Hitelesítés szükséges helyi virtuális gépek és konténerek kezeléséhez." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 +msgid "Manage local virtual machine and container images" +msgstr "Helyi virtuális gép és konténer lemezképek kezelése" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." -msgstr "Hitelesítés szükséges a helyi gép információinak beállításához." +msgstr "" +"Hitelesítés szükséges a helyi virtuális gép és konténer lemezképek " +"kezeléséhez." #: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1 msgid "Set system time" @@ -506,3 +551,34 @@ msgid "" "Authentication is required to control whether network time synchronization " "shall be enabled." msgstr "Hitelesítés szükséges a hálózati időszinkronizáció engedélyezéséhez." + +#: ../src/core/dbus-unit.c:449 +msgid "Authentication is required to start '$(unit)'." +msgstr "Hitelesítés szükséges a következő elindításához: „$(unit)”." + +#: ../src/core/dbus-unit.c:450 +msgid "Authentication is required to stop '$(unit)'." +msgstr "Hitelesítés szükséges a következő leállításához: „$(unit)”." + +#: ../src/core/dbus-unit.c:451 +msgid "Authentication is required to reload '$(unit)'." +msgstr "Hitelesítés szükséges a következő újratöltéséhez: „$(unit)”." + +#: ../src/core/dbus-unit.c:452 ../src/core/dbus-unit.c:453 +msgid "Authentication is required to restart '$(unit)'." +msgstr "Hitelesítés szükséges a következő újraindításához: „$(unit)”." + +#: ../src/core/dbus-unit.c:556 +msgid "Authentication is required to kill '$(unit)'." +msgstr "Hitelesítés szükséges a következő kilövéséhez: „$(unit)”." + +#: ../src/core/dbus-unit.c:586 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" +"Hitelesítés szükséges a következő „sikertelen” állapotának törléséhez: " +"„$(unit)”." + +#: ../src/core/dbus-unit.c:618 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "" +"Hitelesítés szükséges a következő tulajdonságainak beállításához: „$(unit)”." diff --git a/po/it.po b/po/it.po index e11e7e3fa..a8547b939 100644 --- a/po/it.po +++ b/po/it.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" -"PO-Revision-Date: 2015-06-10 23:10+0100\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" +"PO-Revision-Date: 2015-11-22 16:54+0100\n" "Last-Translator: Daniele Medri \n" "Language-Team: Italian\n" "Language: it\n" @@ -16,7 +16,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 1.7.6\n" +"X-Generator: Poedit 1.8.5\n" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1 msgid "Send passphrase back to system" @@ -443,6 +443,14 @@ msgstr "" "Autenticazione richiesta per indicare al firmware di avviare l'interfaccia " "di configurazione." +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "Configura un messaggio per gli utenti" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +msgid "Authentication is required to set a wall message" +msgstr "Autenticazione richiesta per configurare un messaggio per gli utenti" + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Accedi in un container locale" @@ -452,20 +460,62 @@ msgid "Authentication is required to log into a local container." msgstr "Autenticazione richiesta per accedere in un container locale." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +msgid "Log into the local host" +msgstr "Accedi in un host locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +msgid "Authentication is required to log into the local host." +msgstr "Autenticazione richiesta per accedere in un host locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +msgid "Acquire a shell in a local container" +msgstr "Apri una shell in un container locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Autenticazione richiesta per aprire una shell in un container locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "Apri una shell in un host locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Autenticazione richiesta per aprire una shell in un host locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +msgid "Acquire a pseudo TTY in a local container" +msgstr "Apri un pseudo TTY in un container locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "" +"Autenticazione richiesta per aprire un pseudo TTY in un container locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "Apri un pseudo TTY in un host locale" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Autenticazione richiesta per aprire un pseudo TTY in un host locale." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 msgid "Manage local virtual machines and containers" msgstr "Gestisci le virtual machine e i container locali" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "" "Autenticazione richiesta per gestire le virtual machine e i container locali." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "Gestisci le immagini locali delle virtual machine e dei container" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -514,3 +564,32 @@ msgid "" msgstr "" "Autenticazione richiesta per verificare se la sincronizzazione dell'orario " "in rete possa essere attivata." + +#: ../src/core/dbus-unit.c:428 +msgid "Authentication is required to start '$(unit)'." +msgstr "Autenticazione richiesta per avviare '$(unit)'." + +#: ../src/core/dbus-unit.c:429 +msgid "Authentication is required to stop '$(unit)'." +msgstr "Autenticazione richiesta per fermare '$(unit)'." + +#: ../src/core/dbus-unit.c:430 +msgid "Authentication is required to reload '$(unit)'." +msgstr "Autenticazione richiesta per ricaricare '$(unit)'." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +msgid "Authentication is required to restart '$(unit)'." +msgstr "Autenticazione richiesta per riavviare '$(unit)'." + +#: ../src/core/dbus-unit.c:535 +msgid "Authentication is required to kill '$(unit)'." +msgstr "Autenticazione richiesta per terminare '$(unit)'." + +#: ../src/core/dbus-unit.c:565 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" +"Autenticazione richiesta per riconfigurare lo stato \"fallito\" di '$(unit)'." + +#: ../src/core/dbus-unit.c:597 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Autenticazione richiesta per configurare le proprietà di '$(unit)'." diff --git a/po/pt_BR.po b/po/pt_BR.po index 1dd5900e2..2a11371f9 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-01-10 12:23-0300\n" "Last-Translator: Rafael Ferreira \n" "Language-Team: Brazilian Portuguese \n" @@ -441,6 +441,15 @@ msgid "" "interface." msgstr "É necessária autenticação para definir nome de máquina local." +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +#, fuzzy +msgid "Authentication is required to set a wall message" +msgstr "É necessária autenticação para definir nome de máquina local." + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Conectar a um contêiner local" @@ -451,20 +460,69 @@ msgid "Authentication is required to log into a local container." msgstr "É necessária autenticação para se conectar a um contêiner local." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "Conectar a um contêiner local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "É necessária autenticação para se conectar a um contêiner local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Conectar a um contêiner local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "É necessária autenticação para se conectar a um contêiner local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "É necessária autenticação para definir nome de máquina local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Conectar a um contêiner local" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "É necessária autenticação para se conectar a um contêiner local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +#, fuzzy +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "É necessária autenticação para definir nome de máquina local." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 msgid "Manage local virtual machines and containers" msgstr "" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 #, fuzzy msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "É necessária autenticação para definir informações de máquina local." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 #, fuzzy msgid "" "Authentication is required to manage local virtual machine and container " @@ -510,3 +568,38 @@ msgid "" msgstr "" "É necessária autenticação para controlar se deve ser habilitada, ou não, a " "sincronização de horário através de rede." + +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "É necessária autenticação para definir o horário do sistema." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "É necessária autenticação para definir o horário do sistema." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "É necessária autenticação para recarregar o estado do sistema." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "É necessária autenticação para definir o horário do sistema." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "É necessária autenticação para se conectar a um contêiner local." + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "É necessária autenticação para definir nome de máquina local." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "É necessária autenticação para definir o horário do sistema." diff --git a/po/ru.po b/po/ru.po index efb6f7b41..0c0fab780 100644 --- a/po/ru.po +++ b/po/ru.po @@ -1,13 +1,13 @@ # translation of ru.po to Rissian # Julia Dronova , 2013. -# Sergey Ptashnick <0comffdiz@inbox.ru>, 2013-2015. +# Sergey Ptashnick <0comffdiz@inbox.ru>, 2013-2016. # msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" -"PO-Revision-Date: 2015-03-22 21:53+0300\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" +"PO-Revision-Date: 2016-02-02 20:22+0300\n" "Last-Translator: Sergey Ptashnick <0comffdiz@inbox.ru>\n" "Language: ru\n" "MIME-Version: 1.0\n" @@ -26,12 +26,10 @@ msgid "" msgstr "Чтобы отправить пароль системе, необходимо пройти аутентификацию." #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3 -#, fuzzy msgid "Manage system services or other units" msgstr "Управление системными службами и юнитами" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 -#, fuzzy msgid "Authentication is required to manage system services or other units." msgstr "" "Для управления системными службами и юнитами, необходимо пройти " @@ -456,14 +454,24 @@ msgstr "" #: ../src/login/org.freedesktop.login1.policy.in.h:53 msgid "Allow indication to the firmware to boot to setup interface" -msgstr "" +msgstr "Разрешить загрузку в режиме настройки прошивки материнской платы" #: ../src/login/org.freedesktop.login1.policy.in.h:54 -#, fuzzy msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." -msgstr "Чтобы настроить имя компьютера, необходимо пройти аутентификацию." +msgstr "" +"Чтобы разрешить загрузку в режиме настройки прошивки материнской платы, " +"необходимо пройти аутентификацию." + +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "Отправить сообщение на все терминалы" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +msgid "Authentication is required to set a wall message" +msgstr "" +"Чтобы отправить сообщение на все терминалы, необходимо пройти аутентификацию." #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" @@ -474,21 +482,70 @@ msgid "Authentication is required to log into a local container." msgstr "Чтобы зайти в локальный контейнер, необходимо пройти аутентификацию." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +msgid "Log into the local host" +msgstr "Зайти на этот компьютер" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +msgid "Authentication is required to log into the local host." +msgstr "Чтобы зайти на этот компьютер, необходимо пройти аутентификацию." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +msgid "Acquire a shell in a local container" +msgstr "Получить командную оболочку в локальном контейнере" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "" +"Чтобы получить командную оболочку в локальном контейнере, необходимо пройти " +"аутентификацию." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "Запустить командную оболочку на этом компьютере" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "" +"Чтобы запустить командную оболочку на этом компьютере, необходимо пройти " +"аутентификацию." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +msgid "Acquire a pseudo TTY in a local container" +msgstr "Получить псевдо-терминал в локальном контейнере" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "" +"Чтобы получить псевдо-терминал в локальном контейнере, необходимо пройти " +"аутентификацию." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "Получить псевдо-терминал на этом компьютере" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "" +"Чтобы получить псевдо-терминал на этом компьютере, необходимо пройти " +"аутентификацию." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 msgid "Manage local virtual machines and containers" msgstr "Управление виртуальными машинами и контейнерами" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "" "Для управления виртуальными машинами и контейнерами, необходимо пройти " "аутентификацию." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "Управление образами виртуальных машин и контейнеров" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -536,6 +593,39 @@ msgstr "" "Чтобы включить или выключить синхронизацию времени по сети, необходимо " "пройти аутентификацию." +#: ../src/core/dbus-unit.c:428 +msgid "Authentication is required to start '$(unit)'." +msgstr "Чтобы запустить «$(unit)», необходимо пройти аутентификацию." + +#: ../src/core/dbus-unit.c:429 +msgid "Authentication is required to stop '$(unit)'." +msgstr "Чтобы остановить «$(unit)», необходимо пройти аутентификацию." + +#: ../src/core/dbus-unit.c:430 +msgid "Authentication is required to reload '$(unit)'." +msgstr "" +"Чтобы заставить «$(unit)» перечитать конфигурацию, необходимо пройти " +"аутентификацию." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +msgid "Authentication is required to restart '$(unit)'." +msgstr "Чтобы перезапустить «$(unit)», необходимо пройти аутентификацию." + +#: ../src/core/dbus-unit.c:535 +msgid "Authentication is required to kill '$(unit)'." +msgstr "Чтобы убить юнит «$(unit)», необходимо пройти аутентификацию." + +#: ../src/core/dbus-unit.c:565 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" +"Чтобы сбросить состояние «failed» у юнита «$(unit)», необходимо пройти " +"аутентификацию." + +#: ../src/core/dbus-unit.c:597 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Чтобы изменить параметры юнита «$(unit)», необходимо пройти " +"аутентификацию." + #~ msgid "Press Ctrl+C to cancel all filesystem checks in progress" #~ msgstr "" #~ "Чтобы прервать все запущенные проверки файловых систем, нажмите Ctrl+C" diff --git a/po/sv.po b/po/sv.po index af8f421ab..283074130 100644 --- a/po/sv.po +++ b/po/sv.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-03-14 11:09+0100\n" "Last-Translator: Sebastian Rasmussen \n" "Language-Team: Swedish\n" @@ -418,6 +418,15 @@ msgid "" "interface." msgstr "Autentisering krävs för att ange lokalt värdnamn." +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +#, fuzzy +msgid "Authentication is required to set a wall message" +msgstr "Autentisering krävs för att ange lokalt värdnamn." + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "Logga till en lokal behållare" @@ -427,20 +436,69 @@ msgid "Authentication is required to log into a local container." msgstr "Autentisering krävs för att logga till en lokal behållare" #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "Logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "Autentisering krävs för att logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "Logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Autentisering krävs för att logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Autentisering krävs för att ange lokalt värdnamn." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "Logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "Autentisering krävs för att logga till en lokal behållare" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +#, fuzzy +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Autentisering krävs för att ange lokalt värdnamn." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 msgid "Manage local virtual machines and containers" msgstr "Hantera lokala virtuella maskiner och behållare" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "" "Autentisering krävs för att hantera lokala virtuella maskiner och behållare." -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "Hantera lokala virtuella maskin- och behållaravbildningar" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -490,6 +548,41 @@ msgstr "" "Autentisering krävs för att kontrollera huruvida synkronisering av " "nätverkstid ska vara aktiverat." +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "Autentisering krävs för ange systemtiden." + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "Autentisering krävs för ange systemtiden." + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "Autentisering krävs för att läsa om tillståndet för systemd." + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "Autentisering krävs för ange systemtiden." + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "Autentisering krävs för att logga till en lokal behållare" + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Autentisering krävs för att ange lokalt värdnamn." + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Autentisering krävs för ange systemtiden." + #~ msgid "Press Ctrl+C to cancel all filesystem checks in progress" #~ msgstr "Tryck Ctrl+C för att avbryta alla pågående filsystemskontroller." diff --git a/po/uk.po b/po/uk.po index 656d59c79..66044b868 100644 --- a/po/uk.po +++ b/po/uk.po @@ -2,21 +2,21 @@ # Copyright (C) 2014 systemd's COPYRIGHT HOLDER # This file is distributed under the same license as the systemd package. # Eugene Melnik , 2014. -# Daniel Korostil , 2014. +# Daniel Korostil , 2014, 2016. msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" -"PO-Revision-Date: 2014-07-16 19:13+0300\n" +"POT-Creation-Date: 2016-01-11 09:21+0200\n" +"PO-Revision-Date: 2016-01-11 11:00+0300\n" "Last-Translator: Daniel Korostil \n" "Language-Team: linux.org.ua\n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Virtaal 0.7.1\n" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:1 @@ -30,43 +30,42 @@ msgstr "Засвідчення потрібно, щоб надіслати вв #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:3 msgid "Manage system services or other units" -msgstr "" +msgstr "Керувати системними службами й іншими одиницями" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:4 -#, fuzzy msgid "Authentication is required to manage system services or other units." -msgstr "Засвідчення потрібно, щоб доступитись до менеджера системи і служб." +msgstr "" +"Засвідчення потрібно, щоб керувати системними службами й іншими одиницями." #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:5 msgid "Manage system service or unit files" -msgstr "" +msgstr "Керувати системними службами й файлами одиниць" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:6 -#, fuzzy msgid "Authentication is required to manage system service or unit files." -msgstr "Засвідчення потрібно, щоб доступитись до менеджера системи і служб." +msgstr "" +"Засвідчення потрібно, щоб керувати системними службами й файлами одиниць." #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:7 -#, fuzzy msgid "Set or unset system and service manager environment variables" -msgstr "Привілейований доступ до менеджера системи і служб" +msgstr "" +"Встановити або забрати змінну середовища з керування службами і системою" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:8 -#, fuzzy msgid "" "Authentication is required to set or unset system and service manager " "environment variables." -msgstr "Засвідчення потрібно, щоб доступитись до менеджера системи і служб." +msgstr "" +"Засвідчення потрібно, щоб установити або забрати змінні середовища з " +"керування службами і системою." #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:9 -#, fuzzy msgid "Reload the systemd state" -msgstr "Перезавантажити систему" +msgstr "Перезапустити стан системи" #: ../src/core/org.freedesktop.systemd1.policy.in.in.h:10 -#, fuzzy msgid "Authentication is required to reload the systemd state." -msgstr "Засвідчення потрібно, щоб вказати системний час." +msgstr "Засвідчення потрібно, щоб перезапустити стан системи." #: ../src/hostname/org.freedesktop.hostname1.policy.in.h:1 msgid "Set host name" @@ -98,30 +97,31 @@ msgstr "Засвідчення потрібно, щоб вказати лока #: ../src/import/org.freedesktop.import1.policy.in.h:1 msgid "Import a VM or container image" -msgstr "" +msgstr "Імпортувати образ контейнера або віртуальної машини" #: ../src/import/org.freedesktop.import1.policy.in.h:2 -#, fuzzy msgid "Authentication is required to import a VM or container image" -msgstr "Засвідчення потрібно, щоб вказати системний час." +msgstr "" +"Засвідчення потрібно, щоб імпортувати образ контейнера або віртуальної машини" #: ../src/import/org.freedesktop.import1.policy.in.h:3 msgid "Export a VM or container image" -msgstr "" +msgstr "Експортувати образ контейнера або віртуальної машини" #: ../src/import/org.freedesktop.import1.policy.in.h:4 -#, fuzzy msgid "Authentication is required to export a VM or container image" -msgstr "Засвідчення потрібно, щоб вказати системний час." +msgstr "" +"Засвідчення потрібно, щоб експортувати образ контейнера або віртуальної " +"машини" #: ../src/import/org.freedesktop.import1.policy.in.h:5 msgid "Download a VM or container image" -msgstr "" +msgstr "Звантажити образ контейнера або віртуальної машини" #: ../src/import/org.freedesktop.import1.policy.in.h:6 -#, fuzzy msgid "Authentication is required to download a VM or container image" -msgstr "Засвідчення потрібно, щоб вказати локальну інформацію про машини." +msgstr "" +"Засвідчення потрібно, щоб звантажити образ контейнера або віртуальної машини" #: ../src/locale/org.freedesktop.locale1.policy.in.h:1 msgid "Set system locale" @@ -277,7 +277,7 @@ msgstr "Засвідчення потрібно, щоб вимкнути сис #: ../src/login/org.freedesktop.login1.policy.in.h:27 msgid "Power off the system while other users are logged in" -msgstr "Вимикнути систему, коли інші користувачі ще в ній" +msgstr "Вимкнути систему, коли інші користувачі ще в ній" #: ../src/login/org.freedesktop.login1.policy.in.h:28 msgid "" @@ -288,7 +288,7 @@ msgstr "" #: ../src/login/org.freedesktop.login1.policy.in.h:29 msgid "Power off the system while an application asked to inhibit it" -msgstr "Вимкнути систему, коли програми намагаються першкодити цьому" +msgstr "Вимкнути систему, коли програми намагаються перешкодити цьому" #: ../src/login/org.freedesktop.login1.policy.in.h:30 msgid "" @@ -296,7 +296,7 @@ msgid "" "asked to inhibit it." msgstr "" "Засвідчення потрібно, щоб вимкнути систему, коли програми намагаються " -"першкодити цьому." +"перешкодити цьому." #: ../src/login/org.freedesktop.login1.policy.in.h:31 msgid "Reboot the system" @@ -308,7 +308,7 @@ msgstr "Для перезавантаження системи необхідн #: ../src/login/org.freedesktop.login1.policy.in.h:33 msgid "Reboot the system while other users are logged in" -msgstr "Перезавантажити, якщо інщі користувачі в системі" +msgstr "Перезавантажити, якщо інші користувачі в системі" #: ../src/login/org.freedesktop.login1.policy.in.h:34 msgid "" @@ -319,7 +319,7 @@ msgstr "" #: ../src/login/org.freedesktop.login1.policy.in.h:35 msgid "Reboot the system while an application asked to inhibit it" -msgstr "Перезапустити систему, коли програми намагаються першкодити цьому" +msgstr "Перезапустити систему, коли програми намагаються перешкодити цьому" #: ../src/login/org.freedesktop.login1.policy.in.h:36 msgid "" @@ -327,7 +327,7 @@ msgid "" "asked to inhibit it." msgstr "" "Засвідчення потрібно, щоб перезапустити систему, коли програми намагаються " -"першкодити цьому." +"перешкодити цьому." #: ../src/login/org.freedesktop.login1.policy.in.h:37 msgid "Suspend the system" @@ -350,15 +350,15 @@ msgstr "" #: ../src/login/org.freedesktop.login1.policy.in.h:41 msgid "Suspend the system while an application asked to inhibit it" -msgstr "Призупинити систему, коли програми намагаються першкодити цьому" +msgstr "Призупинити систему, коли програми намагаються перешкодити цьому" #: ../src/login/org.freedesktop.login1.policy.in.h:42 msgid "" "Authentication is required for suspending the system while an application " "asked to inhibit it." msgstr "" -"Засвідчення потрібно, щоб призупнити систему, коли програми намагаються " -"першкодити цьому." +"Засвідчення потрібно, щоб призупинити систему, коли програми намагаються " +"перешкодити цьому." #: ../src/login/org.freedesktop.login1.policy.in.h:43 msgid "Hibernate the system" @@ -381,7 +381,7 @@ msgstr "" #: ../src/login/org.freedesktop.login1.policy.in.h:47 msgid "Hibernate the system while an application asked to inhibit it" -msgstr "Приспати систему, коли програми намагаються першкодити цьому" +msgstr "Приспати систему, коли програми намагаються перешкодити цьому" #: ../src/login/org.freedesktop.login1.policy.in.h:48 msgid "" @@ -389,67 +389,118 @@ msgid "" "asked to inhibit it." msgstr "" "Засвідчення потрібно, щоб приспати систему, коли програми намагаються " -"першкодити цьому." +"перешкодити цьому." #: ../src/login/org.freedesktop.login1.policy.in.h:49 msgid "Manage active sessions, users and seats" -msgstr "" +msgstr "Керувати сеансами, користувачами і робочими місцями" #: ../src/login/org.freedesktop.login1.policy.in.h:50 -#, fuzzy msgid "" "Authentication is required for managing active sessions, users and seats." -msgstr "Засвідчення потрібно, щоб під'єднувати пристрої до місць." +msgstr "" +"Засвідчення потрібно, щоб керувати сеансами, користувачами і робочими " +"місцями." #: ../src/login/org.freedesktop.login1.policy.in.h:51 msgid "Lock or unlock active sessions" -msgstr "" +msgstr "Заблокувати або розблокувати сеанси" #: ../src/login/org.freedesktop.login1.policy.in.h:52 -#, fuzzy msgid "Authentication is required to lock or unlock active sessions." -msgstr "Засвідчення потрібно, щоб вказати локальну інформацію про машини." +msgstr "Засвідчення потрібно, щоб заблокувати або розблокувати сеанси." #: ../src/login/org.freedesktop.login1.policy.in.h:53 msgid "Allow indication to the firmware to boot to setup interface" -msgstr "" +msgstr "Дозволити мікрокоду визначати, чи завантажувати інтерфейс встановлення" #: ../src/login/org.freedesktop.login1.policy.in.h:54 -#, fuzzy msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." -msgstr "Засвідчення потрібне, щоб встановити назву локального вузла." +msgstr "" +"Засвідчення потрібне, щоб дозволити мікрокоду визначати, чи завантажувати " +"інтерфейс встановлення." + +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "Вказати повідомлення на стіні" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +msgid "Authentication is required to set a wall message" +msgstr "Засвідчення потрібне, щоб вказати повідомлення на стіні" #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" -msgstr "" +msgstr "Увійти в локальний контейнер" #: ../src/machine/org.freedesktop.machine1.policy.in.h:2 -#, fuzzy msgid "Authentication is required to log into a local container." -msgstr "Засвідчення потрібне, щоб встановити назву локального вузла." +msgstr "Засвідчення потрібне, щоб увійти в локальний контейнер." #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 -msgid "Manage local virtual machines and containers" -msgstr "" +msgid "Log into the local host" +msgstr "Увійти в локальний вузол" #: ../src/machine/org.freedesktop.machine1.policy.in.h:4 -#, fuzzy -msgid "" -"Authentication is required to manage local virtual machines and containers." -msgstr "Засвідчення потрібно, щоб вказати локальну інформацію про машини." +msgid "Authentication is required to log into the local host." +msgstr "Засвідчення потрібне, щоб увійти в локальний вузол." #: ../src/machine/org.freedesktop.machine1.policy.in.h:5 -msgid "Manage local virtual machine and container images" -msgstr "" +msgid "Acquire a shell in a local container" +msgstr "Перейняти оболонку в локальному контейнері" #: ../src/machine/org.freedesktop.machine1.policy.in.h:6 -#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "Засвідчення потрібне, щоб перейняти оболонку в локальному контейнері." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "Перейняти оболонку на локальному вузлі" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "Засвідчення потрібне, щоб перейняти оболонку на локальному вузлі." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +msgid "Acquire a pseudo TTY in a local container" +msgstr "Перейняти псевдо TTY в локальному контейнері" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "Засвідчення потрібне, щоб перейняти псевдо TTY в локальному контейнері." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "Перейняти псевдо TTY на локальному вузлі" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "Засвідчення потрібне, щоб перейняти псевдо TTY на локальному вузлі." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 +msgid "Manage local virtual machines and containers" +msgstr "Керувати локальними віртуальними машинами і контейнерами" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 +msgid "" +"Authentication is required to manage local virtual machines and containers." +msgstr "" +"Засвідчення потрібно, щоб керувати локальними віртуальними машинами і " +"контейнерами." + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 +msgid "Manage local virtual machine and container images" +msgstr "Керувати локальними образами віртуальних машин і контейнерів" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." -msgstr "Засвідчення потрібно, щоб вказати локальну інформацію про машини." +msgstr "" +"Засвідчення потрібно, щоб керувати локальними образами віртуальних машин і " +"контейнерів." #: ../src/timedate/org.freedesktop.timedate1.policy.in.h:1 msgid "Set system time" @@ -488,3 +539,31 @@ msgid "" msgstr "" "Засвідчення потрібно, щоб контролювати, чи синхронізування часу через мережу " "запущено." + +#: ../src/core/dbus-unit.c:449 +msgid "Authentication is required to start '$(unit)'." +msgstr "Засвідчення потрібно, щоб запустити «$(unit)»." + +#: ../src/core/dbus-unit.c:450 +msgid "Authentication is required to stop '$(unit)'." +msgstr "Засвідчення потрібно, щоб зупинити «$(unit)»." + +#: ../src/core/dbus-unit.c:451 +msgid "Authentication is required to reload '$(unit)'." +msgstr "Засвідчення потрібно, щоб перезавантажити «$(unit)»." + +#: ../src/core/dbus-unit.c:452 ../src/core/dbus-unit.c:453 +msgid "Authentication is required to restart '$(unit)'." +msgstr "Засвідчення потрібно, щоб перезапустити «$(unit)»." + +#: ../src/core/dbus-unit.c:556 +msgid "Authentication is required to kill '$(unit)'." +msgstr "Засвідчення потрібне, щоб вбити «$(unit)»." + +#: ../src/core/dbus-unit.c:586 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "Засвідчення потрібне, щоб скинути «пошкоджений» стан з «$(unit)»." + +#: ../src/core/dbus-unit.c:618 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "Засвідчення потрібно, щоб вказати властивості на «$(unit)»." diff --git a/po/zh_TW.po b/po/zh_TW.po index fb276a157..5a214a3c4 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-06-18 00:53+0200\n" +"POT-Creation-Date: 2015-11-22 16:37+0100\n" "PO-Revision-Date: 2015-06-11 12:44+0800\n" "Last-Translator: Jeff Huang \n" "Language-Team: chinese-l10n \n" @@ -373,6 +373,15 @@ msgid "" "interface." msgstr "對韌體的指示以開始設定介面需要驗證。" +#: ../src/login/org.freedesktop.login1.policy.in.h:55 +msgid "Set a wall message" +msgstr "" + +#: ../src/login/org.freedesktop.login1.policy.in.h:56 +#, fuzzy +msgid "Authentication is required to set a wall message" +msgstr "設定主機名稱需要驗證。" + #: ../src/machine/org.freedesktop.machine1.policy.in.h:1 msgid "Log into a local container" msgstr "登入到本機容器" @@ -382,19 +391,68 @@ msgid "Authentication is required to log into a local container." msgstr "登入到本機容器需要驗證。" #: ../src/machine/org.freedesktop.machine1.policy.in.h:3 +#, fuzzy +msgid "Log into the local host" +msgstr "登入到本機容器" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#, fuzzy +msgid "Authentication is required to log into the local host." +msgstr "登入到本機容器需要驗證。" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#, fuzzy +msgid "Acquire a shell in a local container" +msgstr "登入到本機容器" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#, fuzzy +msgid "Authentication is required to acquire a shell in a local container." +msgstr "登入到本機容器需要驗證。" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:7 +msgid "Acquire a shell on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:8 +#, fuzzy +msgid "Authentication is required to acquire a shell on the local host." +msgstr "設定主機名稱需要驗證。" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:9 +#, fuzzy +msgid "Acquire a pseudo TTY in a local container" +msgstr "登入到本機容器" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:10 +#, fuzzy +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "登入到本機容器需要驗證。" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:11 +msgid "Acquire a pseudo TTY on the local host" +msgstr "" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:12 +#, fuzzy +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "設定主機名稱需要驗證。" + +#: ../src/machine/org.freedesktop.machine1.policy.in.h:13 msgid "Manage local virtual machines and containers" msgstr "管理本機虛擬機器及容器" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:4 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:14 msgid "" "Authentication is required to manage local virtual machines and containers." msgstr "管理本機虛擬機器及容器需要驗證。" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:5 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:15 msgid "Manage local virtual machine and container images" msgstr "管理本機虛擬機器及容器映像" -#: ../src/machine/org.freedesktop.machine1.policy.in.h:6 +#: ../src/machine/org.freedesktop.machine1.policy.in.h:16 msgid "" "Authentication is required to manage local virtual machine and container " "images." @@ -435,3 +493,38 @@ msgid "" "Authentication is required to control whether network time synchronization " "shall be enabled." msgstr "控制網路時間同步是否啟用需要驗證。" + +#: ../src/core/dbus-unit.c:428 +#, fuzzy +msgid "Authentication is required to start '$(unit)'." +msgstr "設定系統時間需要驗證。" + +#: ../src/core/dbus-unit.c:429 +#, fuzzy +msgid "Authentication is required to stop '$(unit)'." +msgstr "設定系統時間需要驗證。" + +#: ../src/core/dbus-unit.c:430 +#, fuzzy +msgid "Authentication is required to reload '$(unit)'." +msgstr "重新載入 systemd 狀態需要驗證。" + +#: ../src/core/dbus-unit.c:431 ../src/core/dbus-unit.c:432 +#, fuzzy +msgid "Authentication is required to restart '$(unit)'." +msgstr "設定系統時間需要驗證。" + +#: ../src/core/dbus-unit.c:535 +#, fuzzy +msgid "Authentication is required to kill '$(unit)'." +msgstr "登入到本機容器需要驗證。" + +#: ../src/core/dbus-unit.c:565 +#, fuzzy +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "設定主機名稱需要驗證。" + +#: ../src/core/dbus-unit.c:597 +#, fuzzy +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "設定系統時間需要驗證。" diff --git a/shell-completion/bash/journalctl b/shell-completion/bash/journalctl index 321d439f0..7c8a9ce36 100644 --- a/shell-completion/bash/journalctl +++ b/shell-completion/bash/journalctl @@ -24,6 +24,12 @@ __contains_word () { done } +__get_machines() { + local a b + (machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager; echo ".host") | \ + { while read a b; do echo " $a"; done; } | sort -u; +} + __journal_fields=(MESSAGE{,_ID} PRIORITY CODE_{FILE,LINE,FUNC} ERRNO SYSLOG_{FACILITY,IDENTIFIER,PID} COREDUMP_EXE _{P,U,G}ID _COMM _EXE _CMDLINE @@ -49,11 +55,11 @@ _journalctl() { --utc -x --catalog --no-full --force --dump-catalog --flush --rotate --sync' [ARG]='-b --boot --this-boot -D --directory --file -F --field - -o --output -u --unit --user-unit -p --priority + -M --machine -o --output -u --unit --user-unit -p --priority --vacuum-size --vacuum-time' [ARGUNKNOWN]='-c --cursor --interval -n --lines -S --since -U --until --after-cursor --verify-key -t --identifier - --root -M --machine' + --root' ) if __contains_word "$prev" ${OPTS[ARG]} ${OPTS[ARGUNKNOWN]}; then @@ -74,6 +80,9 @@ _journalctl() { ;; --field|-F) comps=${__journal_fields[*]} + ;; + --machine|-M) + comps=$( __get_machines ) ;; --priority|-p) comps=${__syslog_priorities[*]} diff --git a/shell-completion/bash/loginctl b/shell-completion/bash/loginctl index 7a083d287..776eca4e6 100644 --- a/shell-completion/bash/loginctl +++ b/shell-completion/bash/loginctl @@ -41,7 +41,8 @@ _loginctl () { if __contains_word "$prev" ${OPTS[ARG]}; then case $prev in --signal|-s) - comps=$(compgen -A signal) + _signals + return ;; --kill-who) comps='all leader' diff --git a/shell-completion/bash/machinectl b/shell-completion/bash/machinectl index 140465d31..e7829ca96 100644 --- a/shell-completion/bash/machinectl +++ b/shell-completion/bash/machinectl @@ -40,7 +40,7 @@ _machinectl() { ) local -A VERBS=( - [STANDALONE]='list list-images pull-tar pull-raw pull-dkr import-tar import-raw export-tar export-raw list-transfers cancel-transfer' + [STANDALONE]='list list-images pull-tar pull-raw import-tar import-raw export-tar export-raw list-transfers cancel-transfer' [MACHINES]='status show start login shell enable disable poweroff reboot terminate kill copy-to copy-from image-status show-image clone rename read-only remove set-limit' ) @@ -57,7 +57,8 @@ _machinectl() { if __contains_word "$prev" ${OPTS[ARG]}; then case $prev in --signal|-s) - comps=$(compgen -A signal) + _signals + return ;; --kill-who) comps='all leader' diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in index d80d8f02a..ef7dc6285 100644 --- a/shell-completion/bash/systemctl.in +++ b/shell-completion/bash/systemctl.in @@ -115,7 +115,8 @@ _systemctl () { if __contains_word "$prev" ${OPTS[ARG]}; then case $prev in --signal|-s) - comps=$(compgen -A signal) + _signals + return ;; --type|-t) comps=$(__systemctl $mode -t help) @@ -169,7 +170,7 @@ _systemctl () { [STARTABLE_UNITS]='start' [STOPPABLE_UNITS]='stop condstop kill try-restart condrestart' [ISOLATABLE_UNITS]='isolate' - [RELOADABLE_UNITS]='reload condreload reload-or-try-restart force-reload' + [RELOADABLE_UNITS]='reload condreload try-reload-or-restart force-reload' [RESTARTABLE_UNITS]='restart reload-or-restart' [TARGET_AND_UNITS]='add-wants add-requires' [MASKED_UNITS]='unmask' diff --git a/shell-completion/bash/systemd-nspawn b/shell-completion/bash/systemd-nspawn index f9b740380..429e712eb 100644 --- a/shell-completion/bash/systemd-nspawn +++ b/shell-completion/bash/systemd-nspawn @@ -57,7 +57,7 @@ _systemd_nspawn() { [ARG]='-D --directory -u --user --uuid --capability --drop-capability --link-journal --bind --bind-ro -M --machine -S --slice --setenv -Z --selinux-context -L --selinux-apifs-context --register --network-interface --network-bridge --personality -i --image --tmpfs --volatile - --network-macvlan' + --network-macvlan --kill-signal' ) _init_completion || return @@ -132,6 +132,10 @@ _systemd_nspawn() { compopt -o nospace comps=$( compgen -A file -- "$cur" ) ;; + --kill-signal) + _signals + return + ;; esac COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 diff --git a/shell-completion/zsh/_busctl b/shell-completion/zsh/_busctl index ef790e558..a425b8c70 100644 --- a/shell-completion/zsh/_busctl +++ b/shell-completion/zsh/_busctl @@ -1,6 +1,6 @@ #compdef busctl -# hostnamectl(1) completion -*- shell-script -*- +# busctl(1) completion -*- shell-script -*- # # This file is part of systemd. # diff --git a/shell-completion/zsh/_journalctl b/shell-completion/zsh/_journalctl index b50f0cafc..2bee23b6d 100644 --- a/shell-completion/zsh/_journalctl +++ b/shell-completion/zsh/_journalctl @@ -34,7 +34,10 @@ _journal_none() { _journal_fields() { local -a _fields cmd cmd=("journalctl" "-F ${@[-1]}" "2>/dev/null" ) - _fields=( ${(f)"$(_call_program fields $cmd[@])"} ) + _fields=$(_call_program fields $cmd[@]) + _fields=${_fields//'\'/'\\'} + _fields=${_fields//':'/'\:'} + _fields=( ${(f)_fields} ) typeset -U _fields _describe 'possible values' _fields } diff --git a/shell-completion/zsh/_machinectl b/shell-completion/zsh/_machinectl index 7898d7c05..198fa28f7 100644 --- a/shell-completion/zsh/_machinectl +++ b/shell-completion/zsh/_machinectl @@ -44,7 +44,6 @@ _available_machines() { "pull-tar:Download a TAR container image" "pull-raw:Download a RAW container or VM image" - "pull-dkr:Download a DKR container image" "list-transfers:Show list of downloads in progress" "cancel-transfer:Cancel a download" ) @@ -57,7 +56,7 @@ _available_machines() { if (( $#cmd )); then if (( CURRENT == 2 )); then case $cmd in - list*|cancel-transfer|pull-tar|pull-raw|pull-dkr) + list*|cancel-transfer|pull-tar|pull-raw) msg="no options" ;; start) _available_machines ;; @@ -97,5 +96,4 @@ _arguments \ {-o+,--output=}'[Change journal output mode.]:output modes:_sd_outputmodes' \ '--verify=[Verification mode for downloaded images.]:verify:(no checksum signature)' \ '--force[Download image even if already exists.]' \ - '--dkr-index-url=[Specify the index URL to use for DKR image downloads.]' \ '*::machinectl command:_machinectl_command' diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 58c88c9d9..667243eb5 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -17,7 +17,7 @@ "force-reload:Reload one or more units if possible, otherwise restart if active" "hibernate:Hibernate the system" "hybrid-sleep:Hibernate and suspend the system" - "reload-or-try-restart:Reload one or more units if possible, otherwise restart if active" + "try-reload-or-restart:Reload one or more units if possible, otherwise restart if active" "isolate:Start one unit and stop all others" "kill:Send signal to processes of a unit" "is-active:Check whether units are active" @@ -69,7 +69,7 @@ # Deal with any aliases case $cmd in condrestart) cmd="try-restart";; - force-reload) cmd="reload-or-try-restart";; + force-reload) cmd="try-reload-or-restart";; esac if (( $#cmd )); then @@ -230,7 +230,7 @@ done } # Completion functions for RELOADABLE_UNITS -for fun in reload reload-or-try-restart force-reload ; do +for fun in reload try-reload-or-restart force-reload ; do (( $+functions[_systemctl_$fun] )) || _systemctl_$fun() { local _sys_active_units; _systemctl_active_units diff --git a/shell-completion/zsh/_systemd b/shell-completion/zsh/_systemd index 05459dc5f..62114ff09 100644 --- a/shell-completion/zsh/_systemd +++ b/shell-completion/zsh/_systemd @@ -27,7 +27,7 @@ case "$service" in '--no-pager[Do not pipe output into a pager]' \ {-a,--all}'[Show all groups, including empty]' \ '-k[Include kernel threads in output]' \ - ':cgroups:(cpuset cpu cpuacct memory devices freezer net_cls blkio)' + ':cgroups:(cpuset cpu cpuacct memory devices freezer blkio)' ;; systemd-cgtop) _arguments \ diff --git a/src/ac-power/ac-power.c b/src/ac-power/ac-power.c index 2f2573461..c5277884a 100644 --- a/src/ac-power/ac-power.c +++ b/src/ac-power/ac-power.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/activate/activate.c b/src/activate/activate.c index b7e6255f4..0db4967ed 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -39,9 +37,11 @@ static char** arg_listen = NULL; static bool arg_accept = false; +static int arg_socket_type = SOCK_STREAM; static char** arg_args = NULL; static char** arg_setenv = NULL; static const char *arg_fdname = NULL; +static bool arg_inetd = false; static int add_epoll(int epoll_fd, int fd) { struct epoll_event ev = { @@ -97,8 +97,7 @@ static int open_sockets(int *epoll_fd, bool accept) { */ STRV_FOREACH(address, arg_listen) { - - fd = make_socket_fd(LOG_DEBUG, *address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC)); + fd = make_socket_fd(LOG_DEBUG, *address, arg_socket_type, (arg_accept*SOCK_CLOEXEC)); if (fd < 0) { log_open(); return log_error_errno(fd, "Failed to open '%s': %m", *address); @@ -129,14 +128,20 @@ static int open_sockets(int *epoll_fd, bool accept) { return count; } -static int launch(char* name, char **argv, char **env, int fds) { +static int exec_process(const char* name, char **argv, char **env, int start_fd, int n_fds) { - static const char* tocopy[] = {"TERM=", "PATH=", "USER=", "HOME="}; _cleanup_strv_free_ char **envp = NULL; - _cleanup_free_ char *tmp = NULL; + _cleanup_free_ char *joined = NULL; unsigned n_env = 0, length; - char **s; + const char *tocopy; unsigned i; + char **s; + int r; + + if (arg_inetd && n_fds != 1) { + log_error("--inetd only supported for single file descriptors."); + return -EINVAL; + } length = strv_length(arg_setenv); @@ -146,70 +151,119 @@ static int launch(char* name, char **argv, char **env, int fds) { return log_oom(); STRV_FOREACH(s, arg_setenv) { - if (strchr(*s, '=')) - envp[n_env++] = *s; - else { + + if (strchr(*s, '=')) { + char *k; + + k = strdup(*s); + if (!k) + return log_oom(); + + envp[n_env++] = k; + } else { _cleanup_free_ char *p; + const char *n; p = strappend(*s, "="); if (!p) return log_oom(); - envp[n_env] = strv_find_prefix(env, p); - if (envp[n_env]) - n_env ++; + + n = strv_find_prefix(env, p); + if (!n) + continue; + + envp[n_env] = strdup(n); + if (!envp[n_env]) + return log_oom(); + + n_env ++; } } - for (i = 0; i < ELEMENTSOF(tocopy); i++) { - envp[n_env] = strv_find_prefix(env, tocopy[i]); - if (envp[n_env]) - n_env ++; - } + FOREACH_STRING(tocopy, "TERM=", "PATH=", "USER=", "HOME=") { + const char *n; - if ((asprintf((char**)(envp + n_env++), "LISTEN_FDS=%d", fds) < 0) || - (asprintf((char**)(envp + n_env++), "LISTEN_PID=%d", getpid()) < 0)) - return log_oom(); + n = strv_find_prefix(env, tocopy); + if (!n) + continue; - if (arg_fdname) { - char *e; - - e = strappend("LISTEN_FDNAMES=", arg_fdname); - if (!e) + envp[n_env] = strdup(n); + if (!envp[n_env]) return log_oom(); - for (i = 1; i < (unsigned) fds; i++) { - char *c; - - c = strjoin(e, ":", arg_fdname, NULL); - if (!c) { - free(e); - return log_oom(); - } - - free(e); - e = c; - } - - envp[n_env++] = e; + n_env ++; } - tmp = strv_join(argv, " "); - if (!tmp) + if (arg_inetd) { + assert(n_fds == 1); + + r = dup2(start_fd, STDIN_FILENO); + if (r < 0) + return log_error_errno(errno, "Failed to dup connection to stdin: %m"); + + r = dup2(start_fd, STDOUT_FILENO); + if (r < 0) + return log_error_errno(errno, "Failed to dup connection to stdout: %m"); + + start_fd = safe_close(start_fd); + } else { + if (start_fd != SD_LISTEN_FDS_START) { + assert(n_fds == 1); + + r = dup2(start_fd, SD_LISTEN_FDS_START); + if (r < 0) + return log_error_errno(errno, "Failed to dup connection: %m"); + + safe_close(start_fd); + start_fd = SD_LISTEN_FDS_START; + } + + if (asprintf((char**)(envp + n_env++), "LISTEN_FDS=%i", n_fds) < 0) + return log_oom(); + + if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid()) < 0) + return log_oom(); + + if (arg_fdname) { + char *e; + + e = strappend("LISTEN_FDNAMES=", arg_fdname); + if (!e) + return log_oom(); + + for (i = 1; i < (unsigned) n_fds; i++) { + char *c; + + c = strjoin(e, ":", arg_fdname, NULL); + if (!c) { + free(e); + return log_oom(); + } + + free(e); + e = c; + } + + envp[n_env++] = e; + } + } + + joined = strv_join(argv, " "); + if (!joined) return log_oom(); - log_info("Execing %s (%s)", name, tmp); + log_info("Execing %s (%s)", name, joined); execvpe(name, argv, envp); - return log_error_errno(errno, "Failed to execp %s (%s): %m", name, tmp); + return log_error_errno(errno, "Failed to execp %s (%s): %m", name, joined); } -static int launch1(const char* child, char** argv, char **env, int fd) { - _cleanup_free_ char *tmp = NULL; +static int fork_and_exec_process(const char* child, char** argv, char **env, int fd) { + _cleanup_free_ char *joined = NULL; pid_t parent_pid, child_pid; - int r; - tmp = strv_join(argv, " "); - if (!tmp) + joined = strv_join(argv, " "); + if (!joined) return log_oom(); parent_pid = getpid(); @@ -224,24 +278,6 @@ static int launch1(const char* child, char** argv, char **env, int fd) { (void) reset_all_signal_handlers(); (void) reset_signal_mask(); - r = dup2(fd, STDIN_FILENO); - if (r < 0) { - log_error_errno(errno, "Failed to dup connection to stdin: %m"); - _exit(EXIT_FAILURE); - } - - r = dup2(fd, STDOUT_FILENO); - if (r < 0) { - log_error_errno(errno, "Failed to dup connection to stdout: %m"); - _exit(EXIT_FAILURE); - } - - r = close(fd); - if (r < 0) { - log_error_errno(errno, "Failed to close dupped connection: %m"); - _exit(EXIT_FAILURE); - } - /* Make sure the child goes away when the parent dies */ if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) _exit(EXIT_FAILURE); @@ -251,31 +287,27 @@ static int launch1(const char* child, char** argv, char **env, int fd) { if (getppid() != parent_pid) _exit(EXIT_SUCCESS); - execvp(child, argv); - log_error_errno(errno, "Failed to exec child %s: %m", child); + exec_process(child, argv, env, fd, 1); _exit(EXIT_FAILURE); } - log_info("Spawned %s (%s) as PID %d", child, tmp, child_pid); - + log_info("Spawned %s (%s) as PID %d", child, joined, child_pid); return 0; } static int do_accept(const char* name, char **argv, char **envp, int fd) { _cleanup_free_ char *local = NULL, *peer = NULL; - _cleanup_close_ int fd2 = -1; + _cleanup_close_ int fd_accepted = -1; - fd2 = accept(fd, NULL, NULL); - if (fd2 < 0) { - log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd); - return fd2; - } + fd_accepted = accept4(fd, NULL, NULL, 0); + if (fd_accepted < 0) + return log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd); - getsockname_pretty(fd2, &local); - getpeername_pretty(fd2, &peer); + getsockname_pretty(fd_accepted, &local); + getpeername_pretty(fd_accepted, true, &peer); log_info("Connection from %s to %s", strna(peer), strna(local)); - return launch1(name, argv, envp, fd2); + return fork_and_exec_process(name, argv, envp, fd_accepted); } /* SIGCHLD handler. */ @@ -283,32 +315,38 @@ static void sigchld_hdl(int sig, siginfo_t *t, void *data) { PROTECT_ERRNO; log_info("Child %d died with code %d", t->si_pid, t->si_status); + /* Wait for a dead child. */ - waitpid(t->si_pid, NULL, 0); + (void) waitpid(t->si_pid, NULL, 0); } static int install_chld_handler(void) { - int r; - struct sigaction act = { + static const struct sigaction act = { .sa_flags = SA_SIGINFO, .sa_sigaction = sigchld_hdl, }; + int r; + r = sigaction(SIGCHLD, &act, 0); if (r < 0) - log_error_errno(errno, "Failed to install SIGCHLD handler: %m"); - return r; + return log_error_errno(errno, "Failed to install SIGCHLD handler: %m"); + + return 0; } static void help(void) { printf("%s [OPTIONS...]\n\n" "Listen on sockets and launch child on connection.\n\n" "Options:\n" - " -l --listen=ADDR Listen for raw connections at ADDR\n" - " -a --accept Spawn separate child for each connection\n" " -h --help Show this help and exit\n" + " --version Print version string and exit\n" + " -l --listen=ADDR Listen for raw connections at ADDR\n" + " -d --datagram Listen on datagram instead of stream socket\n" + " --seqpacket Listen on SOCK_SEQPACKET instead of stream socket\n" + " -a --accept Spawn separate child for each connection\n" " -E --setenv=NAME[=VALUE] Pass an environment variable to children\n" - " --version Print version string and exit\n" + " --inetd Enable inetd file descriptor passing protocol\n" "\n" "Note: file descriptors from sd_listen_fds() will be passed through.\n" , program_invocation_short_name); @@ -318,16 +356,21 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_FDNAME, + ARG_SEQPACKET, + ARG_INETD, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, + { "datagram", no_argument, NULL, 'd' }, + { "seqpacket", no_argument, NULL, ARG_SEQPACKET }, { "listen", required_argument, NULL, 'l' }, { "accept", no_argument, NULL, 'a' }, { "setenv", required_argument, NULL, 'E' }, { "environment", required_argument, NULL, 'E' }, /* legacy alias */ { "fdname", required_argument, NULL, ARG_FDNAME }, + { "inetd", no_argument, NULL, ARG_INETD }, {} }; @@ -336,7 +379,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hl:aE:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "+hl:aEd", options, NULL)) >= 0) switch(c) { case 'h': help(); @@ -352,6 +395,24 @@ static int parse_argv(int argc, char *argv[]) { break; + case 'd': + if (arg_socket_type == SOCK_SEQPACKET) { + log_error("--datagram may not be combined with --seqpacket."); + return -EINVAL; + } + + arg_socket_type = SOCK_DGRAM; + break; + + case ARG_SEQPACKET: + if (arg_socket_type == SOCK_DGRAM) { + log_error("--seqpacket may not be combined with --datagram."); + return -EINVAL; + } + + arg_socket_type = SOCK_SEQPACKET; + break; + case 'a': arg_accept = true; break; @@ -372,6 +433,10 @@ static int parse_argv(int argc, char *argv[]) { arg_fdname = optarg; break; + case ARG_INETD: + arg_inetd = true; + break; + case '?': return -EINVAL; @@ -385,6 +450,12 @@ static int parse_argv(int argc, char *argv[]) { return -EINVAL; } + if (arg_socket_type == SOCK_DGRAM && arg_accept) { + log_error("Datagram sockets do not accept connections. " + "The --datagram and --accept options may not be combined."); + return -EINVAL; + } + arg_args = argv + optind; return 1 /* work to do */; @@ -427,15 +498,14 @@ int main(int argc, char **argv, char **envp) { log_info("Communication attempt on fd %i.", event.data.fd); if (arg_accept) { - r = do_accept(argv[optind], argv + optind, envp, - event.data.fd); + r = do_accept(argv[optind], argv + optind, envp, event.data.fd); if (r < 0) return EXIT_FAILURE; } else break; } - launch(argv[optind], argv + optind, envp, n); + exec_process(argv[optind], argv + optind, envp, SD_LISTEN_FDS_START, n); return EXIT_SUCCESS; } diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c index deb102c22..d36c8db3d 100644 --- a/src/analyze/analyze-verify.c +++ b/src/analyze/analyze-verify.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -30,6 +28,47 @@ #include "pager.h" #include "path-util.h" #include "strv.h" +#include "unit-name.h" + +static int prepare_filename(const char *filename, char **ret) { + int r; + const char *name; + _cleanup_free_ char *abspath = NULL; + _cleanup_free_ char *dir = NULL; + _cleanup_free_ char *with_instance = NULL; + char *c; + + assert(filename); + assert(ret); + + r = path_make_absolute_cwd(filename, &abspath); + if (r < 0) + return r; + + name = basename(abspath); + if (!unit_name_is_valid(name, UNIT_NAME_ANY)) + return -EINVAL; + + if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) { + r = unit_name_replace_instance(name, "i", &with_instance); + if (r < 0) + return r; + } + + dir = dirname_malloc(abspath); + if (!dir) + return -ENOMEM; + + if (with_instance) + c = path_join(NULL, dir, with_instance); + else + c = path_join(NULL, dir, name); + if (!c) + return -ENOMEM; + + *ret = c; + return 0; +} static int generate_path(char **var, char **filenames) { char **filename; @@ -164,7 +203,7 @@ static int verify_documentation(Unit *u, bool check_man) { } static int verify_unit(Unit *u, bool check_man) { - _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL; int r, k; assert(u); @@ -193,7 +232,7 @@ static int verify_unit(Unit *u, bool check_man) { } int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) { - _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL; Manager *m = NULL; FILE *serial = NULL; FDSet *fdset = NULL; @@ -233,18 +272,19 @@ int verify_units(char **filenames, ManagerRunningAs running_as, bool check_man) log_debug("Loading remaining units from the command line..."); STRV_FOREACH(filename, filenames) { - char fname[UNIT_NAME_MAX + 2 + 1] = "./"; + _cleanup_free_ char *prepared = NULL; log_debug("Handling %s...", *filename); - /* manager_load_unit does not like pure basenames, so prepend - * the local directory, but only for valid names. manager_load_unit - * will print the error for other ones. */ - if (!strchr(*filename, '/') && strlen(*filename) <= UNIT_NAME_MAX) { - strncat(fname + 2, *filename, UNIT_NAME_MAX); - k = manager_load_unit(m, NULL, fname, &err, &units[count]); - } else - k = manager_load_unit(m, NULL, *filename, &err, &units[count]); + k = prepare_filename(*filename, &prepared); + if (k < 0) { + log_error_errno(k, "Failed to prepare filename %s: %m", *filename); + if (r == 0) + r = k; + continue; + } + + k = manager_load_unit(m, NULL, prepared, &err, &units[count]); if (k < 0) { log_error_errno(k, "Failed to load %s: %m", *filename); if (r == 0) diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h index d2d4a7f19..54adad93e 100644 --- a/src/analyze/analyze-verify.h +++ b/src/analyze/analyze-verify.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index e922d6fb3..a84708478 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -134,7 +132,7 @@ static void pager_open_if_enabled(void) { } static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *interface, const char *property, uint64_t *val) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -161,7 +159,7 @@ static int bus_get_uint64_property(sd_bus *bus, const char *path, const char *in } static int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *property, char ***strv) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -339,8 +337,8 @@ static void free_host_info(struct host_info *hi) { DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info*, free_host_info); static int acquire_time_data(sd_bus *bus, struct unit_times **out) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r, c = 0; struct boot_times *boot_times = NULL; struct unit_times *unit_times = NULL; @@ -455,7 +453,7 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) { {} }; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(free_host_infop) struct host_info *host; int r; @@ -899,8 +897,8 @@ static int list_dependencies(sd_bus *bus, const char *name) { int r; const char *id; _cleanup_free_ char *path = NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; struct boot_times *boot; assert(bus); @@ -1096,7 +1094,7 @@ static int expand_patterns(sd_bus *bus, char **patterns, char ***ret) { int r; STRV_FOREACH(pattern, patterns) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *unit = NULL, *unit_id = NULL; if (strv_extend(&expanded_patterns, *pattern) < 0) @@ -1133,8 +1131,8 @@ static int expand_patterns(sd_bus *bus, char **patterns, char ***ret) { } static int dot(sd_bus *bus, char* patterns[]) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_strv_free_ char **expanded_patterns = NULL; _cleanup_strv_free_ char **expanded_from_patterns = NULL; _cleanup_strv_free_ char **expanded_to_patterns = NULL; @@ -1198,8 +1196,8 @@ static int dot(sd_bus *bus, char* patterns[]) { } static int dump(sd_bus *bus, char **args) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *text = NULL; int r; @@ -1231,7 +1229,7 @@ static int dump(sd_bus *bus, char **args) { } static int set_log_level(sd_bus *bus, char **args) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -1258,7 +1256,7 @@ static int set_log_level(sd_bus *bus, char **args) { } static int set_log_target(sd_bus *bus, char **args) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -1456,7 +1454,7 @@ int main(int argc, char *argv[]) { arg_user ? MANAGER_USER : MANAGER_SYSTEM, arg_man); else { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; r = bus_connect_transport_systemd(arg_transport, arg_host, arg_user, &bus); if (r < 0) { diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index a54486600..adc928661 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c index b0fa079fe..45be135a2 100644 --- a/src/backlight/backlight.c +++ b/src/backlight/backlight.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -323,7 +321,7 @@ int main(int argc, char *argv[]) { errno = 0; device = udev_device_new_from_subsystem_sysname(udev, ss, sysname); if (!device) { - if (errno != 0) + if (errno > 0) log_error_errno(errno, "Failed to get backlight or LED device '%s:%s': %m", ss, sysname); else log_oom(); diff --git a/src/basic/af-list.c b/src/basic/af-list.c index 07dfff6ad..3fac9c508 100644 --- a/src/basic/af-list.c +++ b/src/basic/af-list.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,7 +21,7 @@ #include #include "af-list.h" -#include "util.h" +#include "macro.h" static const struct af_name* lookup_af(register const char *str, register unsigned int len); diff --git a/src/basic/af-list.h b/src/basic/af-list.h index e346ab87f..135248dc6 100644 --- a/src/basic/af-list.h +++ b/src/basic/af-list.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c index 48183e381..b540dcddf 100644 --- a/src/basic/alloc-util.c +++ b/src/basic/alloc-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,11 @@ along with systemd; If not, see . ***/ +#include +#include + #include "alloc-util.h" +#include "macro.h" #include "util.h" void* memdup(const void *p, size_t l) { diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index 12b602e18..679ba7f39 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include +#include #include #include diff --git a/src/basic/arphrd-list.c b/src/basic/arphrd-list.c index 03d8ad740..6792d1ee3 100644 --- a/src/basic/arphrd-list.c +++ b/src/basic/arphrd-list.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,7 +21,7 @@ #include #include "arphrd-list.h" -#include "util.h" +#include "macro.h" static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len); diff --git a/src/basic/arphrd-list.h b/src/basic/arphrd-list.h index 5ca182c9e..c0f8758db 100644 --- a/src/basic/arphrd-list.h +++ b/src/basic/arphrd-list.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/async.c b/src/basic/async.c index cfc5d224e..a1f163f27 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,15 @@ along with systemd; If not, see . ***/ +#include #include +#include #include #include "async.h" #include "fd-util.h" #include "log.h" +#include "macro.h" #include "util.h" int asynchronous_job(void* (*func)(void *p), void *arg) { diff --git a/src/basic/async.h b/src/basic/async.h index 7f1ef7953..9bd13ff6e 100644 --- a/src/basic/async.h +++ b/src/basic/async.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c index 461229733..5741fecdd 100644 --- a/src/basic/audit-util.c +++ b/src/basic/audit-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,7 +18,9 @@ ***/ #include +#include #include +#include #include "alloc-util.h" #include "audit-util.h" @@ -30,7 +30,6 @@ #include "parse-util.h" #include "process-util.h" #include "user-util.h" -#include "util.h" int audit_session_from_pid(pid_t pid, uint32_t *id) { _cleanup_free_ char *s = NULL; diff --git a/src/basic/audit-util.h b/src/basic/audit-util.h index 6de331c73..e04850399 100644 --- a/src/basic/audit-util.h +++ b/src/basic/audit-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#include #include +#include #include #define AUDIT_SESSION_INVALID ((uint32_t) -1) diff --git a/src/basic/barrier.c b/src/basic/barrier.c index 2d55bab4a..2da633b31 100644 --- a/src/basic/barrier.c +++ b/src/basic/barrier.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -32,7 +30,6 @@ #include "barrier.h" #include "fd-util.h" #include "macro.h" -#include "util.h" /** * Barriers @@ -198,6 +195,7 @@ static bool barrier_write(Barrier *b, uint64_t buf) { if (barrier_i_aborted(b)) return false; + assert(b->me >= 0); do { len = write(b->me, &buf, sizeof(buf)); } while (len < 0 && IN_SET(errno, EAGAIN, EINTR)); diff --git a/src/basic/barrier.h b/src/basic/barrier.h index b8954694d..6347fddc4 100644 --- a/src/basic/barrier.h +++ b/src/basic/barrier.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,8 @@ along with systemd; If not, see . ***/ +#include +#include #include #include "macro.h" diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c index 1449e2ea8..ad1fda019 100644 --- a/src/basic/bitmap.c +++ b/src/basic/bitmap.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,16 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include + #include "alloc-util.h" #include "bitmap.h" -#include "util.h" +#include "hashmap.h" +#include "macro.h" struct Bitmap { uint64_t *bitmaps; @@ -133,7 +138,8 @@ bool bitmap_isset(Bitmap *b, unsigned n) { bool bitmap_isclear(Bitmap *b) { unsigned i; - assert(b); + if (!b) + return true; for (i = 0; i < b->n_bitmaps; i++) if (b->bitmaps[i] != 0) @@ -143,7 +149,9 @@ bool bitmap_isclear(Bitmap *b) { } void bitmap_clear(Bitmap *b) { - assert(b); + + if (!b) + return; b->bitmaps = mfree(b->bitmaps); b->n_bitmaps = 0; @@ -190,7 +198,10 @@ bool bitmap_equal(Bitmap *a, Bitmap *b) { Bitmap *c; unsigned i; - if (!a ^ !b) + if (a == b) + return true; + + if (!a != !b) return false; if (!a) diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h index 2874bc99f..f5f8f2f01 100644 --- a/src/basic/bitmap.h +++ b/src/basic/bitmap.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,10 @@ along with systemd; If not, see . ***/ -#include "macro.h" +#include + #include "hashmap.h" +#include "macro.h" typedef struct Bitmap Bitmap; diff --git a/src/basic/blkid-util.h b/src/basic/blkid-util.h index c68931032..7aa75eb09 100644 --- a/src/basic/blkid-util.h +++ b/src/basic/blkid-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/btrfs-ctree.h b/src/basic/btrfs-ctree.h index d3ae57331..66bdf9736 100644 --- a/src/basic/btrfs-ctree.h +++ b/src/basic/btrfs-ctree.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once #include "macro.h" diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index be40dc570..359d85f2e 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,20 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include #include +#include +#include #include -#include +#include +#include +#include + #ifdef HAVE_LINUX_BTRFS_H #include #endif @@ -32,13 +41,16 @@ #include "copy.h" #include "fd-util.h" #include "fileio.h" +#include "io-util.h" #include "macro.h" #include "missing.h" #include "path-util.h" #include "selinux-util.h" #include "smack-util.h" +#include "sparse-endian.h" #include "stat-util.h" #include "string-util.h" +#include "time-util.h" #include "util.h" /* WARNING: Be careful with file system ioctls! When we get an fd, we @@ -900,6 +912,10 @@ int btrfs_resize_loopback_fd(int fd, uint64_t new_size, bool grow_only) { dev_t dev = 0; int r; + /* In contrast to btrfs quota ioctls ftruncate() cannot make sense of "infinity" or file sizes > 2^31 */ + if (!FILE_SIZE_VALID(new_size)) + return -EINVAL; + /* btrfs cannot handle file systems < 16M, hence use this as minimum */ if (new_size < 16*1024*1024) new_size = 16*1024*1024; @@ -2038,7 +2054,7 @@ int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) { args.key.nr_items = 256; if (ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args) < 0) - return -errno; + return negative_errno(); if (args.key.nr_items <= 0) break; diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 8c11ce35d..37802c256 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,8 +20,11 @@ #pragma once #include +#include #include +#include "sd-id128.h" + #include "time-util.h" typedef struct BtrfsSubvolInfo { diff --git a/src/basic/build.h b/src/basic/build.h index 24873ab9d..633c2aacc 100644 --- a/src/basic/build.h +++ b/src/basic/build.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/bus-label.c b/src/basic/bus-label.c index c1534657a..d4531c794 100644 --- a/src/basic/bus-label.c +++ b/src/basic/bus-label.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -25,7 +23,6 @@ #include "bus-label.h" #include "hexdecoct.h" #include "macro.h" -#include "util.h" char *bus_label_escape(const char *s) { char *r, *t; diff --git a/src/basic/bus-label.h b/src/basic/bus-label.h index ed1dc4e0a..62fb2c450 100644 --- a/src/basic/bus-label.h +++ b/src/basic/bus-label.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include #include diff --git a/src/basic/c-rbtree.c b/src/basic/c-rbtree.c new file mode 100644 index 000000000..914d7e522 --- /dev/null +++ b/src/basic/c-rbtree.c @@ -0,0 +1,679 @@ +/*** + This file is part of systemd. See COPYING for details. + + 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 . +***/ + +/* + * RB-Tree Implementation + * This implements the insertion/removal of elements in RB-Trees. You're highly + * recommended to have an RB-Tree documentation at hand when reading this. Both + * insertion and removal can be split into a handful of situations that can + * occur. Those situations are enumerated as "Case 1" to "Case n" here, and + * follow closely the cases described in most RB-Tree documentations. This file + * does not explain why it is enough to handle just those cases, nor does it + * provide a proof of correctness. Dig out your algorithm 101 handbook if + * you're interested. + * + * This implementation is *not* straightforward. Usually, a handful of + * rotation, reparent, swap and link helpers can be used to implement the + * rebalance operations. However, those often perform unnecessary writes. + * Therefore, this implementation hard-codes all the operations. You're highly + * recommended to look at the two basic helpers before reading the code: + * c_rbtree_swap_child() + * c_rbtree_set_parent_and_color() + * Those are the only helpers used, hence, you should really know what they do + * before digging into the code. + * + * For a highlevel documentation of the API, see the header file and docbook + * comments. + */ + +#include +#include +#include "c-rbtree.h" + +enum { + C_RBNODE_RED = 0, + C_RBNODE_BLACK = 1, +}; + +static inline unsigned long c_rbnode_color(CRBNode *n) { + return (unsigned long)n->__parent_and_color & 1UL; +} + +static inline _Bool c_rbnode_is_red(CRBNode *n) { + return c_rbnode_color(n) == C_RBNODE_RED; +} + +static inline _Bool c_rbnode_is_black(CRBNode *n) { + return c_rbnode_color(n) == C_RBNODE_BLACK; +} + +/** + * c_rbnode_leftmost() - return leftmost child + * @n: current node, or NULL + * + * This returns the leftmost child of @n. If @n is NULL, this will return NULL. + * In all other cases, this function returns a valid pointer. That is, if @n + * does not have any left children, this returns @n. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to leftmost child, or NULL. + */ +CRBNode *c_rbnode_leftmost(CRBNode *n) { + if (n) + while (n->left) + n = n->left; + return n; +} + +/** + * c_rbnode_rightmost() - return rightmost child + * @n: current node, or NULL + * + * This returns the rightmost child of @n. If @n is NULL, this will return + * NULL. In all other cases, this function returns a valid pointer. That is, if + * @n does not have any right children, this returns @n. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to rightmost child, or NULL. + */ +CRBNode *c_rbnode_rightmost(CRBNode *n) { + if (n) + while (n->right) + n = n->right; + return n; +} + +/** + * c_rbnode_next() - return next node + * @n: current node, or NULL + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically next node to @n. If @n is NULL, the last node or + * unlinked, this returns NULL. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to next node, or NULL. + */ +CRBNode *c_rbnode_next(CRBNode *n) { + CRBNode *p; + + if (!c_rbnode_is_linked(n)) + return NULL; + if (n->right) + return c_rbnode_leftmost(n->right); + + while ((p = c_rbnode_parent(n)) && n == p->right) + n = p; + + return p; +} + +/** + * c_rbnode_prev() - return previous node + * @n: current node, or NULL + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically previous node to @n. If @n is NULL, the first node or + * unlinked, this returns NULL. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to previous node, or NULL. + */ +CRBNode *c_rbnode_prev(CRBNode *n) { + CRBNode *p; + + if (!c_rbnode_is_linked(n)) + return NULL; + if (n->left) + return c_rbnode_rightmost(n->left); + + while ((p = c_rbnode_parent(n)) && n == p->left) + n = p; + + return p; +} + +/** + * c_rbtree_first() - return first node + * @t: tree to operate on + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically first node in @t. If @t is empty, NULL is returned. + * + * Fixed runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to first node, or NULL. + */ +CRBNode *c_rbtree_first(CRBTree *t) { + assert(t); + return c_rbnode_leftmost(t->root); +} + +/** + * c_rbtree_last() - return last node + * @t: tree to operate on + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically last node in @t. If @t is empty, NULL is returned. + * + * Fixed runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to last node, or NULL. + */ +CRBNode *c_rbtree_last(CRBTree *t) { + assert(t); + return c_rbnode_rightmost(t->root); +} + +/* + * Set the color and parent of a node. This should be treated as a simple + * assignment of the 'color' and 'parent' fields of the node. No other magic is + * applied. But since both fields share its backing memory, this helper + * function is provided. + */ +static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigned long c) { + assert(!((unsigned long)p & 1)); + assert(c < 2); + n->__parent_and_color = (CRBNode*)((unsigned long)p | c); +} + +/* same as c_rbnode_set_parent_and_color(), but keeps the current parent */ +static inline void c_rbnode_set_color(CRBNode *n, unsigned long c) { + c_rbnode_set_parent_and_color(n, c_rbnode_parent(n), c); +} + +/* same as c_rbnode_set_parent_and_color(), but keeps the current color */ +static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) { + c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n)); +} + +/* + * This function partially replaces an existing child pointer to a new one. The + * existing child must be given as @old, the new child as @new. @p must be the + * parent of @old (or NULL if it has no parent). + * This function ensures that the parent of @old now points to @new. However, + * it does *NOT* change the parent pointer of @new. The caller must ensure + * this. + * If @p is NULL, this function ensures that the root-pointer is adjusted + * instead (given as @t). + */ +static inline void c_rbtree_swap_child(CRBTree *t, CRBNode *p, CRBNode *old, CRBNode *new) { + if (p) { + if (p->left == old) + p->left = new; + else + p->right = new; + } else { + t->root = new; + } +} + +static inline CRBNode *c_rbtree_paint_one(CRBTree *t, CRBNode *n) { + CRBNode *p, *g, *gg, *u, *x; + + /* + * Paint a single node according to RB-Tree rules. The node must + * already be linked into the tree and painted red. + * We repaint the node or rotate the tree, if required. In case a + * recursive repaint is required, the next node to be re-painted + * is returned. + * p: parent + * g: grandparent + * gg: grandgrandparent + * u: uncle + * x: temporary + */ + + /* node is red, so we can access the parent directly */ + p = n->__parent_and_color; + + if (!p) { + /* Case 1: + * We reached the root. Mark it black and be done. As all + * leaf-paths share the root, the ratio of black nodes on each + * path stays the same. */ + c_rbnode_set_parent_and_color(n, p, C_RBNODE_BLACK); + n = NULL; + } else if (c_rbnode_is_black(p)) { + /* Case 2: + * The parent is already black. As our node is red, we did not + * change the number of black nodes on any path, nor do we have + * multiple consecutive red nodes. */ + n = NULL; + } else if (p == p->__parent_and_color->left) { /* parent is red, so grandparent exists */ + g = p->__parent_and_color; + gg = c_rbnode_parent(g); + u = g->right; + + if (u && c_rbnode_is_red(u)) { + /* Case 3: + * Parent and uncle are both red. We know the + * grandparent must be black then. Repaint parent and + * uncle black, the grandparent red and recurse into + * the grandparent. */ + c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED); + n = g; + } else { + /* parent is red, uncle is black */ + + if (n == p->right) { + /* Case 4: + * We're the right child. Rotate on parent to + * become left child, so we can handle it the + * same as case 5. */ + x = n->left; + p->right = n->left; + n->left = p; + if (x) + c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED); + p = n; + } + + /* 'n' is invalid from here on! */ + n = NULL; + + /* Case 5: + * We're the red left child or a red parent, black + * grandparent and uncle. Rotate on grandparent and + * switch color with parent. Number of black nodes on + * each path stays the same, but we got rid of the + * double red path. As the grandparent is still black, + * we're done. */ + x = p->right; + g->left = x; + p->right = g; + if (x) + c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED); + c_rbtree_swap_child(t, gg, g, p); + } + } else /* if (p == p->__parent_and_color->left) */ { /* same as above, but mirrored */ + g = p->__parent_and_color; + gg = c_rbnode_parent(g); + u = g->left; + + if (u && c_rbnode_is_red(u)) { + c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED); + n = g; + } else { + if (n == p->left) { + x = n->right; + p->left = n->right; + n->right = p; + if (x) + c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED); + p = n; + } + + n = NULL; + + x = p->left; + g->right = x; + p->left = g; + if (x) + c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED); + c_rbtree_swap_child(t, gg, g, p); + } + } + + return n; +} + +static inline void c_rbtree_paint(CRBTree *t, CRBNode *n) { + assert(t); + assert(n); + + while (n) + n = c_rbtree_paint_one(t, n); +} + +/** + * c_rbtree_add() - add node to tree + * @t: tree to operate one + * @p: parent node to link under, or NULL + * @l: left/right slot of @p (or root) to link at + * @n: node to add + * + * This links @n into the tree given as @t. The caller must provide the exact + * spot where to link the node. That is, the caller must traverse the tree + * based on their search order. Once they hit a leaf where to insert the node, + * call this function to link it and rebalance the tree. + * + * A typical insertion would look like this (@t is your tree, @n is your node): + * + * CRBNode **i, *p; + * + * i = &t->root; + * p = NULL; + * while (*i) { + * p = *i; + * if (compare(n, *i) < 0) + * i = &(*i)->left; + * else + * i = &(*i)->right; + * } + * + * c_rbtree_add(t, p, i, n); + * + * Once the node is linked into the tree, a simple lookup on the same tree can + * be coded like this: + * + * CRBNode *i; + * + * i = t->root; + * while (i) { + * int v = compare(n, i); + * if (v < 0) + * i = (*i)->left; + * else if (v > 0) + * i = (*i)->right; + * else + * break; + * } + * + * When you add nodes to a tree, the memory contents of the node do not matter. + * That is, there is no need to initialize the node via c_rbnode_init(). + * However, if you relink nodes multiple times during their lifetime, it is + * usually very convenient to use c_rbnode_init() and c_rbtree_remove_init(). + * In those cases, you should validate that a node is unlinked before you call + * c_rbtree_add(). + */ +void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n) { + assert(t); + assert(l); + assert(n); + assert(!p || l == &p->left || l == &p->right); + assert(p || l == &t->root); + + c_rbnode_set_parent_and_color(n, p, C_RBNODE_RED); + n->left = n->right = NULL; + *l = n; + + c_rbtree_paint(t, n); +} + +static inline CRBNode *c_rbtree_rebalance_one(CRBTree *t, CRBNode *p, CRBNode *n) { + CRBNode *s, *x, *y, *g; + + /* + * Rebalance tree after a node was removed. This happens only if you + * remove a black node and one path is now left with an unbalanced + * number or black nodes. + * This function assumes all paths through p and n have one black node + * less than all other paths. If recursive fixup is required, the + * current node is returned. + */ + + if (n == p->left) { + s = p->right; + if (c_rbnode_is_red(s)) { + /* Case 3: + * We have a red node as sibling. Rotate it onto our + * side so we can later on turn it black. This way, we + * gain the additional black node in our path. */ + g = c_rbnode_parent(p); + x = s->left; + p->right = x; + s->left = p; + c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); + c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED); + c_rbtree_swap_child(t, g, p, s); + s = x; + } + + x = s->right; + if (!x || c_rbnode_is_black(x)) { + y = s->left; + if (!y || c_rbnode_is_black(y)) { + /* Case 4: + * Our sibling is black and has only black + * children. Flip it red and turn parent black. + * This way we gained a black node in our path, + * or we fix it recursively one layer up, which + * will rotate the red sibling as parent. */ + c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED); + if (c_rbnode_is_black(p)) + return p; + + c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK); + return NULL; + } + + /* Case 5: + * Left child of our sibling is red, right one is black. + * Rotate on parent so the right child of our sibling is + * now red, and we can fall through to case 6. */ + x = y->right; + s->left = y->right; + y->right = s; + p->right = y; + if (x) + c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); + x = s; + s = y; + } + + /* Case 6: + * The right child of our sibling is red. Rotate left and flip + * colors, which gains us an additional black node in our path, + * that was previously on our sibling. */ + g = c_rbnode_parent(p); + y = s->left; + p->right = y; + s->left = p; + c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); + if (y) + c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y)); + c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); + c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK); + c_rbtree_swap_child(t, g, p, s); + } else /* if (!n || n == p->right) */ { /* same as above, but mirrored */ + s = p->left; + if (c_rbnode_is_red(s)) { + g = c_rbnode_parent(p); + x = s->right; + p->left = x; + s->right = p; + c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(s, g, C_RBNODE_BLACK); + c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED); + c_rbtree_swap_child(t, g, p, s); + s = x; + } + + x = s->left; + if (!x || c_rbnode_is_black(x)) { + y = s->right; + if (!y || c_rbnode_is_black(y)) { + c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED); + if (c_rbnode_is_black(p)) + return p; + + c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK); + return NULL; + } + + x = y->left; + s->right = y->left; + y->left = s; + p->left = y; + if (x) + c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); + x = s; + s = y; + } + + g = c_rbnode_parent(p); + y = s->right; + p->left = y; + s->right = p; + c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); + if (y) + c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y)); + c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); + c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK); + c_rbtree_swap_child(t, g, p, s); + } + + return NULL; +} + +static inline void c_rbtree_rebalance(CRBTree *t, CRBNode *p) { + CRBNode *n = NULL; + + assert(t); + assert(p); + + do { + n = c_rbtree_rebalance_one(t, p, n); + p = n ? c_rbnode_parent(n) : NULL; + } while (p); +} + +/** + * c_rbtree_remove() - remove node from tree + * @t: tree to operate one + * @n: node to remove + * + * This removes the given node from its tree. Once unlinked, the tree is + * rebalanced. + * The caller *must* ensure that the given tree is actually the tree it is + * linked on. Otherwise, behavior is undefined. + * + * This does *NOT* reset @n to being unlinked (for performance reason, this + * function *never* modifies @n at all). If you need this, use + * c_rbtree_remove_init(). + */ +void c_rbtree_remove(CRBTree *t, CRBNode *n) { + CRBNode *p, *s, *gc, *x, *next = NULL; + unsigned long c; + + assert(t); + assert(n); + assert(c_rbnode_is_linked(n)); + + /* + * There are three distinct cases during node removal of a tree: + * * The node has no children, in which case it can simply be removed. + * * The node has exactly one child, in which case the child displaces + * its parent. + * * The node has two children, in which case there is guaranteed to + * be a successor to the node (successor being the node ordered + * directly after it). This successor cannot have two children by + * itself (two interior nodes can never be successive). Therefore, + * we can simply swap the node with its successor (including color) + * and have reduced this case to either of the first two. + * + * Whenever the node we removed was black, we have to rebalance the + * tree. Note that this affects the actual node we _remove_, not @n (in + * case we swap it). + * + * p: parent + * s: successor + * gc: grand-...-child + * x: temporary + * next: next node to rebalance on + */ + + if (!n->left) { + /* + * Case 1: + * The node has no left child. If it neither has a right child, + * it is a leaf-node and we can simply unlink it. If it also + * was black, we have to rebalance, as always if we remove a + * black node. + * But if the node has a right child, the child *must* be red + * (otherwise, the right path has more black nodes as the + * non-existing left path), and the node to be removed must + * hence be black. We simply replace the node with its child, + * turning the red child black, and thus no rebalancing is + * required. + */ + p = c_rbnode_parent(n); + c = c_rbnode_color(n); + c_rbtree_swap_child(t, p, n, n->right); + if (n->right) + c_rbnode_set_parent_and_color(n->right, p, c); + else + next = (c == C_RBNODE_BLACK) ? p : NULL; + } else if (!n->right) { + /* + * Case 1.1: + * The node has exactly one child, and it is on the left. Treat + * it as mirrored case of Case 1 (i.e., replace the node by its + * child). + */ + p = c_rbnode_parent(n); + c = c_rbnode_color(n); + c_rbtree_swap_child(t, p, n, n->left); + c_rbnode_set_parent_and_color(n->left, p, c); + } else { + /* + * Case 2: + * We are dealing with a full interior node with a child not on + * both sides. Find its successor and swap it. Then remove the + * node similar to Case 1. For performance reasons we don't + * perform the full swap, but skip links that are about to be + * removed, anyway. + */ + s = n->right; + if (!s->left) { + /* right child is next, no need to touch grandchild */ + p = s; + gc = s->right; + } else { + /* find successor and swap partially */ + s = c_rbnode_leftmost(s); + p = c_rbnode_parent(s); + + gc = s->right; + p->left = s->right; + s->right = n->right; + c_rbnode_set_parent(n->right, s); + } + + /* node is partially swapped, now remove as in Case 1 */ + s->left = n->left; + c_rbnode_set_parent(n->left, s); + + x = c_rbnode_parent(n); + c = c_rbnode_color(n); + c_rbtree_swap_child(t, x, n, s); + if (gc) + c_rbnode_set_parent_and_color(gc, p, C_RBNODE_BLACK); + else + next = c_rbnode_is_black(s) ? p : NULL; + c_rbnode_set_parent_and_color(s, x, c); + } + + if (next) + c_rbtree_rebalance(t, next); +} diff --git a/src/basic/c-rbtree.h b/src/basic/c-rbtree.h new file mode 100644 index 000000000..20c5515ca --- /dev/null +++ b/src/basic/c-rbtree.h @@ -0,0 +1,297 @@ +#pragma once + +/*** + This file is part of systemd. See COPYING for details. + + 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 . +***/ + +/* + * Standalone Red-Black-Tree Implementation in Standard ISO-C11 + * + * This header provides an RB-Tree API, that is fully implemented in ISO-C11 + * and has no external dependencies. Furthermore, tree traversal, memory + * allocations, and key comparisons a fully in control of the API user. The + * implementation only provides the RB-Tree specific rebalancing and coloring. + * + * A tree is represented by the "CRBTree" structure. It contains a *singly* + * field, which is a pointer to the root node. If NULL, the tree is empty. If + * non-NULL, there is at least a single element in the tree. + * + * Each node of the tree is represented by the "CRBNode" structure. It has + * three fields. The @left and @right members can be accessed by the API user + * directly to traverse the tree. The third member is an implementation detail + * and encodes the parent pointer and color of the node. + * API users are required to embed the CRBNode object into their own objects + * and then use offsetof() (i.e., container_of() and friends) to turn CRBNode + * pointers into pointers to their own structure. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CRBNode CRBNode; +typedef struct CRBTree CRBTree; + +/** + * struct CRBNode - Node of a Red-Black Tree + * @__parent_and_color: internal state + * @left: left child, or NULL + * @right: right child, or NULL + * + * Each node in an RB-Tree must embed an CRBNode object. This object contains + * pointers to its left and right child, which can be freely accessed by the + * API user at any time. They are NULL, if the node does not have a left/right + * child. + * + * The @__parent_and_color field must never be accessed directly. It encodes + * the pointer to the parent node, and the color of the node. Use the accessor + * functions instead. + * + * There is no reason to initialize a CRBNode object before linking it. + * However, if you need a boolean state that tells you whether the node is + * linked or not, you should initialize the node via c_rbnode_init() or + * C_RBNODE_INIT. + */ +struct CRBNode { + CRBNode *__parent_and_color; + CRBNode *left; + CRBNode *right; +}; + +#define C_RBNODE_INIT(_var) { .__parent_and_color = &(_var) } + +CRBNode *c_rbnode_leftmost(CRBNode *n); +CRBNode *c_rbnode_rightmost(CRBNode *n); +CRBNode *c_rbnode_next(CRBNode *n); +CRBNode *c_rbnode_prev(CRBNode *n); + +/** + * struct CRBTree - Red-Black Tree + * @root: pointer to the root node, or NULL + * + * Each Red-Black Tree is rooted in an CRBTree object. This object contains a + * pointer to the root node of the tree. The API user is free to access the + * @root member at any time, and use it to traverse the tree. + * + * To initialize an RB-Tree, set it to NULL / all zero. + */ +struct CRBTree { + CRBNode *root; +}; + +CRBNode *c_rbtree_first(CRBTree *t); +CRBNode *c_rbtree_last(CRBTree *t); + +void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n); +void c_rbtree_remove(CRBTree *t, CRBNode *n); + +/** + * c_rbnode_init() - mark a node as unlinked + * @n: node to operate on + * + * This marks the node @n as unlinked. The node will be set to a valid state + * that can never happen if the node is linked in a tree. Furthermore, this + * state is fully known to the implementation, and as such handled gracefully + * in all cases. + * + * You are *NOT* required to call this on your node. c_rbtree_add() can handle + * uninitialized nodes just fine. However, calling this allows to use + * c_rbnode_is_linked() to check for the state of a node. Furthermore, + * iterators and accessors can be called on initialized (yet unlinked) nodes. + * + * Use the C_RBNODE_INIT macro if you want to initialize static variables. + */ +static inline void c_rbnode_init(CRBNode *n) { + *n = (CRBNode)C_RBNODE_INIT(*n); +} + +/** + * c_rbnode_is_linked() - check whether a node is linked + * @n: node to check, or NULL + * + * This checks whether the passed node is linked. If you pass NULL, or if the + * node is not linked into a tree, this will return false. Otherwise, this + * returns true. + * + * Note that you must have either linked the node or initialized it, before + * calling this function. Never call this function on uninitialized nodes. + * Furthermore, removing a node via c_rbtree_remove() does *NOT* mark the node + * as unlinked. You have to call c_rbnode_init() yourself after removal, or use + * the c_rbtree_remove_init() helper. + * + * Return: true if the node is linked, false if not. + */ +static inline _Bool c_rbnode_is_linked(CRBNode *n) { + return n && n->__parent_and_color != n; +} + +/** + * c_rbnode_parent() - return parent pointer + * @n node to access + * + * This returns a pointer to the parent of the given node @n. If @n does not + * have a parent, NULL is returned. If @n is not linked, @n itself is returned. + * + * You should not call this on unlinked or uninitialized nodes! If you do, you + * better know how its semantics. + * + * Return: Pointer to parent. + */ +static inline CRBNode *c_rbnode_parent(CRBNode *n) { + return (CRBNode*)((unsigned long)n->__parent_and_color & ~1UL); +} + +/** + * c_rbtree_remove_init() - safely remove node from tree and reinitialize it + * @t: tree to operate on + * @n: node to remove, or NULL + * + * This is almost the same as c_rbtree_remove(), but extends it slightly, to be + * more convenient to use in many cases: + * - if @n is unlinked or NULL, this is a no-op + * - @n is reinitialized after being removed + */ +static inline void c_rbtree_remove_init(CRBTree *t, CRBNode *n) { + if (c_rbnode_is_linked(n)) { + c_rbtree_remove(t, n); + c_rbnode_init(n); + } +} + +/** + * CRBCompareFunc - compare a node to a key + * @t: tree where the node is linked to + * @k: key to compare + * @n: node to compare + * + * If you use the tree-traversal helpers (which are optional), you need to + * provide this callback so they can compare nodes in a tree to the key you + * look for. + * + * The tree @t is provided as optional context to this callback. The key you + * look for is provided as @k, the current node that should be compared to is + * provided as @n. This function should work like strcmp(), that is, return -1 + * if @key orders before @n, 0 if both compare equal, and 1 if it orders after + * @n. + */ +typedef int (*CRBCompareFunc) (CRBTree *t, void *k, CRBNode *n); + +/** + * c_rbtree_find_node() - find node + * @t: tree to search through + * @f: comparison function + * @k: key to search for + * + * This searches through @t for a node that compares equal to @k. The function + * @f must be provided by the caller, which is used to compare nodes to @k. See + * the documentation of CRBCompareFunc for details. + * + * If there are multiple entries that compare equal to @k, this will return a + * pseudo-randomly picked node. If you need stable lookup functions for trees + * where duplicate entries are allowed, you better code your own lookup. + * + * Return: Pointer to matching node, or NULL. + */ +static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const void *k) { + CRBNode *i; + + assert(t); + assert(f); + + i = t->root; + while (i) { + int v = f(t, (void *)k, i); + if (v < 0) + i = i->left; + else if (v > 0) + i = i->right; + else + return i; + } + + return NULL; +} + +/** + * c_rbtree_find_entry() - find entry + * @_t: tree to search through + * @_f: comparison function + * @_k: key to search for + * @_t: type of the structure that embeds the nodes + * @_o: name of the node-member in type @_t + * + * This is very similar to c_rbtree_find_node(), but instead of returning a + * pointer to the CRBNode, it returns a pointer to the surrounding object. This + * object must embed the CRBNode object. The type of the surrounding object + * must be given as @_t, and the name of the embedded CRBNode member as @_o. + * + * See c_rbtree_find_node() for more details. + * + * Return: Pointer to found entry, NULL if not found. + */ +#define c_rbtree_find_entry(_m, _f, _k, _t, _o) \ + ((_t *)(((char *)c_rbtree_find_node((_m), (_f), (_k)) ?: \ + (char *)NULL + offsetof(_t, _o)) - offsetof(_t, _o))) + +/** + * c_rbtree_find_slot() - find slot to insert new node + * @t: tree to search through + * @f: comparison function + * @k: key to search for + * @p: output storage for parent pointer + * + * This searches through @t just like c_rbtree_find_node() does. However, + * instead of returning a pointer to a node that compares equal to @k, this + * searches for a slot to insert a node with key @k. A pointer to the slot is + * returned, and a pointer to the parent of the slot is stored in @p. Both + * can be passed directly to c_rbtree_add(), together with your node to insert. + * + * If there already is a node in the tree, that compares equal to @k, this will + * return NULL and store the conflicting node in @p. In all other cases, + * this will return a pointer (non-NULL) to the empty slot to insert the node + * at. @p will point to the parent node of that slot. + * + * If you want trees that allow duplicate nodes, you better code your own + * insertion function. + * + * Return: Pointer to slot to insert node, or NULL on conflicts. + */ +static inline CRBNode **c_rbtree_find_slot(CRBTree *t, CRBCompareFunc f, const void *k, CRBNode **p) { + CRBNode **i; + + assert(t); + assert(f); + assert(p); + + i = &t->root; + *p = NULL; + while (*i) { + int v = f(t, (void *)k, *i); + *p = *i; + if (v < 0) + i = &(*i)->left; + else if (v > 0) + i = &(*i)->right; + else + return NULL; + } + + return i; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 157ae1fb7..775879076 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,19 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include #include #include +#include #include "alloc-util.h" #include "calendarspec.h" #include "fileio.h" +#include "macro.h" +#include "parse-util.h" #include "string-util.h" #define BITS_WEEKDAYS 127 @@ -49,7 +54,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 +140,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 +182,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 +237,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 +246,25 @@ static void format_chain(FILE *f, int space, const CalendarComponent *c) { } assert(c->value >= 0); - fprintf(f, "%0*i", space, c->value); + 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) - fprintf(f, "/%i", c->repeat); + 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 +286,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 +407,70 @@ static int parse_weekdays(const char **p, CalendarSpec *c) { } } -static int prepend_component(const char **p, CalendarComponent **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, &ee, 10); + if (errno > 0) + return -errno; + if (ee == *p) + return -EINVAL; + if ((unsigned long) (int) value != value) + return -ERANGE; + e = ee; + + if (usec) { + if (value * USEC_PER_SEC / USEC_PER_SEC != value) + return -ERANGE; + + 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; - char *e = NULL, *ee = NULL; CalendarComponent *cc; + int r; + const char *e; assert(p); assert(c); - errno = 0; - value = strtoul(*p, &e, 10); - if (errno > 0) - return -errno; - if (e == *p) - return -EINVAL; - if ((unsigned long) (int) value != value) - return -ERANGE; + e = *p; + + r = parse_component_decimal(&e, usec, &value); + if (r < 0) + return r; 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) - return -ERANGE; + e++; + r = parse_component_decimal(&e, usec, &repeat); + if (r < 0) + return r; - e = ee; + if (repeat == 0) + return -ERANGE; } if (*e != 0 && *e != ' ' && *e != ',' && *e != '-' && *e != ':') @@ -438,39 +489,12 @@ 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) { - const char *t; - CalendarComponent *cc = NULL; - int r; - - assert(p); - assert(c); - - t = *p; - - if (t[0] == '*') { - *p = t + 1; - *c = NULL; - return 0; - } - - r = prepend_component(&t, &cc); - if (r < 0) { - free_chain(cc); - return r; - } - - *p = t; - *c = cc; - return 0; -} - static int const_chain(int value, CalendarComponent **c) { CalendarComponent *cc = NULL; @@ -489,6 +513,40 @@ static int const_chain(int value, CalendarComponent **c) { return 0; } +static int parse_chain(const char **p, bool usec, CalendarComponent **c) { + const char *t; + CalendarComponent *cc = NULL; + int r; + + assert(p); + assert(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; + return 0; + } + + r = prepend_component(&t, usec, &cc); + if (r < 0) { + free_chain(cc); + return r; + } + + *p = t; + *c = cc; + return 0; +} + static int parse_date(const char **p, CalendarSpec *c) { const char *t; int r; @@ -503,7 +561,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 +577,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 +598,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 +640,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 +650,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 +668,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 +697,8 @@ finish: *p = t; c->hour = h; c->minute = m; - c->second = s; + c->microsecond = s; + return 0; fail: @@ -671,7 +730,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 +738,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 +749,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 +763,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 +783,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 +797,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 +824,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 +848,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 +965,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 +988,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 +999,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 +1030,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 +1039,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 +1064,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 +1082,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 56dc02f39..f6472c124 100644 --- a/src/basic/calendarspec.h +++ b/src/basic/calendarspec.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,6 +23,8 @@ * time, a la cron */ #include + +#include "time-util.h" #include "util.h" typedef struct CalendarComponent { @@ -44,7 +44,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 f0974900c..3e773a06f 100644 --- a/src/basic/cap-list.c +++ b/src/basic/cap-list.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,11 @@ along with systemd; If not, see . ***/ +#include #include #include "cap-list.h" +#include "macro.h" #include "missing.h" #include "parse-util.h" #include "util.h" diff --git a/src/basic/cap-list.h b/src/basic/cap-list.h index 9824fad70..c1f6b94ad 100644 --- a/src/basic/cap-list.h +++ b/src/basic/cap-list.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index 0eb5c03d6..d4c5bd693 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -95,7 +94,62 @@ unsigned long cap_last_cap(void) { return p; } -int capability_bounding_set_drop(uint64_t drop, bool right_now) { +int capability_update_inherited_set(cap_t caps, uint64_t set) { + unsigned long i; + + /* Add capabilities in the set to the inherited caps. Do not apply + * them yet. */ + + for (i = 0; i < cap_last_cap(); i++) { + + if (set & (UINT64_C(1) << i)) { + cap_value_t v; + + v = (cap_value_t) i; + + /* Make the capability inheritable. */ + if (cap_set_flag(caps, CAP_INHERITABLE, 1, &v, CAP_SET) < 0) + return -errno; + } + } + + return 0; +} + +int capability_ambient_set_apply(uint64_t set, bool also_inherit) { + unsigned long i; + _cleanup_cap_free_ cap_t caps = NULL; + + /* Add the capabilities to the ambient set. */ + + if (also_inherit) { + int r; + caps = cap_get_proc(); + if (!caps) + return -errno; + + r = capability_update_inherited_set(caps, set); + if (r < 0) + return -errno; + + if (cap_set_proc(caps) < 0) + return -errno; + } + + for (i = 0; i < cap_last_cap(); i++) { + + if (set & (UINT64_C(1) << i)) { + + /* Add the capability to the ambient set. */ + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, i, 0, 0) < 0) + return -errno; + } + } + + return 0; +} + +int capability_bounding_set_drop(uint64_t keep, bool right_now) { _cleanup_cap_free_ cap_t after_cap = NULL; cap_flag_value_t fv; unsigned long i; @@ -136,7 +190,7 @@ int capability_bounding_set_drop(uint64_t drop, bool right_now) { for (i = 0; i <= cap_last_cap(); i++) { - if (drop & ((uint64_t) 1ULL << (uint64_t) i)) { + if (!(keep & (UINT64_C(1) << i))) { cap_value_t v; /* Drop it from the bounding set */ @@ -175,7 +229,7 @@ finish: return r; } -static int drop_from_file(const char *fn, uint64_t drop) { +static int drop_from_file(const char *fn, uint64_t keep) { int r, k; uint32_t hi, lo; uint64_t current, after; @@ -195,7 +249,7 @@ static int drop_from_file(const char *fn, uint64_t drop) { return -EIO; current = (uint64_t) lo | ((uint64_t) hi << 32ULL); - after = current & ~drop; + after = current & keep; if (current == after) return 0; @@ -212,14 +266,14 @@ static int drop_from_file(const char *fn, uint64_t drop) { return r; } -int capability_bounding_set_drop_usermode(uint64_t drop) { +int capability_bounding_set_drop_usermode(uint64_t keep) { int r; - r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", drop); + r = drop_from_file("/proc/sys/kernel/usermodehelper/inheritable", keep); if (r < 0) return r; - r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", drop); + r = drop_from_file("/proc/sys/kernel/usermodehelper/bset", keep); if (r < 0) return r; @@ -256,7 +310,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) { return log_error_errno(errno, "Failed to disable keep capabilities flag: %m"); /* Drop all caps from the bounding set, except the ones we want */ - r = capability_bounding_set_drop(~keep_capabilities, true); + r = capability_bounding_set_drop(keep_capabilities, true); if (r < 0) return log_error_errno(r, "Failed to drop capabilities: %m"); diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h index 4eb5c2a83..35a896e22 100644 --- a/src/basic/capability-util.h +++ b/src/basic/capability-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,14 +20,22 @@ ***/ #include +#include #include +#include +#include "macro.h" #include "util.h" +#define CAP_ALL (uint64_t) -1 + unsigned long cap_last_cap(void); int have_effective_cap(int value); -int capability_bounding_set_drop(uint64_t drop, bool right_now); -int capability_bounding_set_drop_usermode(uint64_t drop); +int capability_bounding_set_drop(uint64_t keep, bool right_now); +int capability_bounding_set_drop_usermode(uint64_t keep); + +int capability_ambient_set_apply(uint64_t set, bool also_inherit); +int capability_update_inherited_set(cap_t caps, uint64_t ambient_set); int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities); @@ -43,3 +49,9 @@ static inline void cap_free_charpp(char **p) { cap_free(*p); } #define _cleanup_cap_free_charp_ _cleanup_(cap_free_charpp) + +static inline bool cap_test_all(uint64_t caps) { + uint64_t m; + m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1; + return (caps & m) == m; +} diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index f7fc2c2c9..6ef00d51d 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,23 +20,29 @@ #include #include #include +#include #include +#include #include #include #include +#include #include #include #include "alloc-util.h" #include "cgroup-util.h" +#include "def.h" #include "dirent-util.h" #include "extract-word.h" #include "fd-util.h" #include "fileio.h" #include "formats-util.h" #include "fs-util.h" +#include "log.h" #include "login-util.h" #include "macro.h" +#include "missing.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" @@ -47,11 +51,11 @@ #include "set.h" #include "special.h" #include "stat-util.h" +#include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "unit-name.h" #include "user-util.h" -#include "util.h" int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) { _cleanup_free_ char *fs = NULL; @@ -87,7 +91,7 @@ int cg_read_pid(FILE *f, pid_t *_pid) { if (feof(f)) return 0; - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; } if (ul <= 0) @@ -642,7 +646,7 @@ int cg_trim(const char *controller, const char *path, bool delete_root) { if (nftw(fs, trim_cb, 64, FTW_DEPTH|FTW_MOUNT|FTW_PHYS) != 0) { if (errno == ENOENT) r = 0; - else if (errno != 0) + else if (errno > 0) r = -errno; else r = -EIO; @@ -711,7 +715,7 @@ int cg_attach(const char *controller, const char *path, pid_t pid) { if (pid == 0) pid = getpid(); - snprintf(c, sizeof(c), PID_FMT"\n", pid); + xsprintf(c, PID_FMT "\n", pid); return write_string_file(fs, c, 0); } @@ -2085,7 +2089,7 @@ int cg_kernel_controllers(Set *controllers) { if (feof(f)) break; - if (ferror(f) && errno != 0) + if (ferror(f) && errno > 0) return -errno; return -EBADMSG; @@ -2130,7 +2134,7 @@ int cg_unified(void) { else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC)) unified_cache = false; else - return -ENOEXEC; + return -ENOMEDIUM; return unified_cache; } @@ -2265,7 +2269,6 @@ static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = { [CGROUP_CONTROLLER_MEMORY] = "memory", [CGROUP_CONTROLLER_DEVICES] = "devices", [CGROUP_CONTROLLER_PIDS] = "pids", - [CGROUP_CONTROLLER_NET_CLS] = "net_cls", }; DEFINE_STRING_TABLE_LOOKUP(cgroup_controller, CGroupController); diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index 01359fa7c..ad1edd9cd 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,12 +19,16 @@ along with systemd; If not, see . ***/ -#include -#include #include +#include +#include +#include +#include -#include "set.h" #include "def.h" +#include "hashmap.h" +#include "macro.h" +#include "set.h" /* An enum of well known cgroup controllers */ typedef enum CGroupController { @@ -36,7 +38,6 @@ typedef enum CGroupController { CGROUP_CONTROLLER_MEMORY, CGROUP_CONTROLLER_DEVICES, CGROUP_CONTROLLER_PIDS, - CGROUP_CONTROLLER_NET_CLS, _CGROUP_CONTROLLER_MAX, _CGROUP_CONTROLLER_INVALID = -1, } CGroupController; @@ -51,7 +52,6 @@ typedef enum CGroupMask { CGROUP_MASK_MEMORY = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_MEMORY), CGROUP_MASK_DEVICES = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_DEVICES), CGROUP_MASK_PIDS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_PIDS), - CGROUP_MASK_NET_CLS = CGROUP_CONTROLLER_TO_MASK(CGROUP_CONTROLLER_NET_CLS), _CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1 } CGroupMask; diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c index d49ca0537..2896a729a 100644 --- a/src/basic/chattr-util.c +++ b/src/basic/chattr-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,13 +17,15 @@ along with systemd; If not, see . ***/ +#include +#include #include #include #include #include "chattr-util.h" #include "fd-util.h" -#include "util.h" +#include "macro.h" int chattr_fd(int fd, unsigned value, unsigned mask) { unsigned old_attr, new_attr; diff --git a/src/basic/chattr-util.h b/src/basic/chattr-util.h index ba6b8eb5c..960cf6d5b 100644 --- a/src/basic/chattr-util.h +++ b/src/basic/chattr-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index 00ee4c279..507e757ff 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,6 +19,9 @@ #include #include +#include +#include +#include #include #include #include @@ -119,7 +120,8 @@ int clock_set_timezone(int *min) { * have read from the RTC. */ if (settimeofday(tv_null, &tz) < 0) - return -errno; + return negative_errno(); + if (min) *min = minutesdelta; return 0; @@ -142,3 +144,17 @@ int clock_reset_timewarp(void) { return 0; } + +#define TIME_EPOCH_USEC ((usec_t) TIME_EPOCH * USEC_PER_SEC) + +int clock_apply_epoch(void) { + struct timespec ts; + + if (now(CLOCK_REALTIME) >= TIME_EPOCH_USEC) + return 0; + + if (clock_settime(CLOCK_REALTIME, timespec_store(&ts, TIME_EPOCH_USEC)) < 0) + return -errno; + + return 1; +} diff --git a/src/basic/clock-util.h b/src/basic/clock-util.h index fef2d471a..f471f2abc 100644 --- a/src/basic/clock-util.h +++ b/src/basic/clock-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -28,3 +26,4 @@ int clock_set_timezone(int *min); int clock_reset_timewarp(void); int clock_get_hwclock(struct tm *tm); int clock_set_hwclock(const struct tm *tm); +int clock_apply_epoch(void); diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index be9972fff..c781610e1 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,6 +19,7 @@ #include #include +#include #include #include #include @@ -40,6 +39,7 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char *suffix) { _cleanup_closedir_ DIR *dir = NULL; const char *dirpath; + struct dirent *de; int r; assert(path); @@ -54,18 +54,9 @@ static int files_add(Hashmap *h, const char *root, const char *path, const char return -errno; } - for (;;) { - struct dirent *de; + FOREACH_DIRENT(de, dir, return -errno) { char *p; - errno = 0; - de = readdir(dir); - if (!de && errno != 0) - return -errno; - - if (!de) - break; - if (!dirent_is_file_with_suffix(de, suffix)) continue; @@ -115,17 +106,15 @@ static int conf_files_list_strv_internal(char ***strv, const char *suffix, const STRV_FOREACH(p, dirs) { r = files_add(fh, root, *p, suffix); - if (r == -ENOMEM) { + if (r == -ENOMEM) return r; - } else if (r < 0) - log_debug_errno(r, "Failed to search for files in %s: %m", - *p); + if (r < 0) + log_debug_errno(r, "Failed to search for files in %s, ignoring: %m", *p); } files = hashmap_get_strv(fh); - if (files == NULL) { + if (!files) return -ENOMEM; - } qsort_safe(files, hashmap_size(fh), sizeof(char *), base_cmp); *strv = files; diff --git a/src/basic/conf-files.h b/src/basic/conf-files.h index d8aebc5e5..e00e0e81f 100644 --- a/src/basic/conf-files.h +++ b/src/basic/conf-files.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/copy.c b/src/basic/copy.c index a187ae08f..519b41294 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,8 +17,18 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include +#include #include +#include #include +#include +#include #include "alloc-util.h" #include "btrfs-util.h" @@ -31,10 +39,11 @@ #include "fileio.h" #include "fs-util.h" #include "io-util.h" +#include "macro.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "umask-util.h" -#include "util.h" #include "xattr-util.h" #define COPY_BUFFER_SIZE (16*1024) diff --git a/src/basic/copy.h b/src/basic/copy.h index ba0890b44..3e5eb5250 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,6 +21,7 @@ #include #include +#include #include int copy_file_fd(const char *from, int to, bool try_reflink); diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c index e2ec4ca83..95ed6928f 100644 --- a/src/basic/cpu-set-util.c +++ b/src/basic/cpu-set-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,12 +18,17 @@ along with systemd; If not, see . ***/ +#include +#include +#include + #include "alloc-util.h" #include "cpu-set-util.h" #include "extract-word.h" +#include "log.h" +#include "macro.h" #include "parse-util.h" #include "string-util.h" -#include "util.h" cpu_set_t* cpu_set_malloc(unsigned *ncpus) { cpu_set_t *c; diff --git a/src/basic/cpu-set-util.h b/src/basic/cpu-set-util.h index 19b457a68..6f49d9afb 100644 --- a/src/basic/cpu-set-util.h +++ b/src/basic/cpu-set-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/def.h b/src/basic/def.h index 0657ac736..963343eb7 100644 --- a/src/basic/def.h +++ b/src/basic/def.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/device-nodes.c b/src/basic/device-nodes.c index 9d5af72d2..38c0628a9 100644 --- a/src/basic/device-nodes.c +++ b/src/basic/device-nodes.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,9 @@ along with systemd; If not, see . ***/ +#include #include +#include #include "device-nodes.h" #include "utf8.h" diff --git a/src/basic/device-nodes.h b/src/basic/device-nodes.h index 7db81f3d5..94f385abc 100644 --- a/src/basic/device-nodes.h +++ b/src/basic/device-nodes.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include int encode_devnode_name(const char *str, char *str_enc, size_t len); diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index c433d5844..5fb535cb1 100644 --- a/src/basic/dirent-util.c +++ b/src/basic/dirent-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,10 +19,9 @@ #include #include -#include -#include #include "dirent-util.h" +#include "path-util.h" #include "string-util.h" int dirent_ensure_type(DIR *d, struct dirent *de) { diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h index 5866a755f..6bf099b46 100644 --- a/src/basic/dirent-util.h +++ b/src/basic/dirent-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,7 +20,10 @@ ***/ #include +#include +#include +#include "macro.h" #include "path-util.h" int dirent_ensure_type(DIR *d, struct dirent *de); diff --git a/src/basic/env-util.c b/src/basic/env-util.c index 441169db3..7f5fddb70 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,17 +17,21 @@ along with systemd; If not, see . ***/ +#include #include +#include +#include +#include #include #include "alloc-util.h" -#include "def.h" #include "env-util.h" +#include "extract-word.h" +#include "macro.h" #include "parse-util.h" #include "string-util.h" #include "strv.h" #include "utf8.h" -#include "util.h" #define VALID_CHARS_ENV_NAME \ DIGITS LETTERS \ diff --git a/src/basic/env-util.h b/src/basic/env-util.h index 5efffa3dc..b1fef704c 100644 --- a/src/basic/env-util.h +++ b/src/basic/env-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include +#include #include "macro.h" diff --git a/src/basic/errno-list.c b/src/basic/errno-list.c index 22869e413..31b66bad5 100644 --- a/src/basic/errno-list.c +++ b/src/basic/errno-list.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,10 +20,10 @@ #include #include "errno-list.h" -#include "util.h" +#include "macro.h" static const struct errno_name* lookup_errno(register const char *str, - register unsigned int len); + register unsigned int len); #include "errno-from-name.h" #include "errno-to-name.h" @@ -48,8 +46,9 @@ int errno_from_name(const char *name) { sc = lookup_errno(name, strlen(name)); if (!sc) - return 0; + return -EINVAL; + assert(sc->id > 0); return sc->id; } diff --git a/src/basic/errno-list.h b/src/basic/errno-list.h index ba533294e..4eec0cc78 100644 --- a/src/basic/errno-list.h +++ b/src/basic/errno-list.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/escape.c b/src/basic/escape.c index 4815161b0..2e483880c 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,15 @@ along with systemd; If not, see . ***/ +#include +#include +#include + #include "alloc-util.h" #include "escape.h" #include "hexdecoct.h" -#include "string-util.h" +#include "macro.h" #include "utf8.h" -#include "util.h" size_t cescape_char(char c, char *buf) { char * buf_old = buf; @@ -89,20 +90,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,16 +111,24 @@ char *cescape(const char *s) { return r; } -int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode) { +char *cescape(const char *s) { + assert(s); + + return cescape_length(s, strlen(s)); +} + +int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit) { int r = 1; assert(p); assert(*p); assert(ret); - /* Unescapes C style. Returns the unescaped character in ret, - * unless we encountered a \u sequence in which case the full - * unicode character is returned in ret_unicode, instead. */ + /* Unescapes C style. Returns the unescaped character in ret. + * Sets *eight_bit to true if the escaped sequence either fits in + * one byte in UTF-8 or is a non-unicode literal byte and should + * instead be copied directly. + */ if (length != (size_t) -1 && length < 1) return -EINVAL; @@ -181,7 +190,8 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode if (a == 0 && b == 0) return -EINVAL; - *ret = (char) ((a << 4U) | b); + *ret = (a << 4U) | b; + *eight_bit = true; r = 3; break; } @@ -208,16 +218,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode if (c == 0) return -EINVAL; - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - + *ret = c; r = 5; break; } @@ -227,7 +228,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode int a[8]; unsigned i; - uint32_t c; + char32_t c; if (length != (size_t) -1 && length < 9) return -EINVAL; @@ -249,16 +250,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode if (!unichar_is_valid(c)) return -EINVAL; - if (c < 128) - *ret = c; - else { - if (!ret_unicode) - return -EINVAL; - - *ret = 0; - *ret_unicode = c; - } - + *ret = c; r = 9; break; } @@ -273,7 +265,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode case '7': { /* octal encoding */ int a, b, c; - uint32_t m; + char32_t m; if (length != (size_t) -1 && length < 3) return -EINVAL; @@ -300,6 +292,7 @@ int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode return -EINVAL; *ret = m; + *eight_bit = true; r = 3; break; } @@ -332,8 +325,8 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi for (f = s, t = r + pl; f < s + length; f++) { size_t remaining; - uint32_t u; - char c; + bool eight_bit = false; + char32_t u; int k; remaining = s + length - f; @@ -356,7 +349,7 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi return -EINVAL; } - k = cunescape_one(f + 1, remaining - 1, &c, &u); + k = cunescape_one(f + 1, remaining - 1, &u, &eight_bit); if (k < 0) { if (flags & UNESCAPE_RELAX) { /* Invalid escape code, let's take it literal then */ @@ -368,14 +361,13 @@ int cunescape_length_with_prefix(const char *s, size_t length, const char *prefi return k; } - if (c != 0) - /* Non-Unicode? Let's encode this directly */ - *(t++) = c; - else - /* Unicode? Then let's encode this in UTF-8 */ - t += utf8_encode_unichar(t, u); - f += k; + if (eight_bit) + /* One byte? Set directly as specified */ + *(t++) = u; + else + /* Otherwise encode as multi-byte UTF-8 */ + t += utf8_encode_unichar(t, u); } *t = 0; diff --git a/src/basic/escape.h b/src/basic/escape.h index 85ba90908..1b28bd10a 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,14 @@ along with systemd; If not, see . ***/ -#include #include +#include +#include +#include +#include + +#include "string-util.h" +#include "missing.h" /* What characters are special in the shell? */ /* must be escaped outside and inside double-quotes */ @@ -35,12 +39,13 @@ 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); int cunescape_length(const char *s, size_t length, UnescapeFlags flags, char **ret); int cunescape_length_with_prefix(const char *s, size_t length, const char *prefix, UnescapeFlags flags, char **ret); -int cunescape_one(const char *p, size_t length, char *ret, uint32_t *ret_unicode); +int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit); char *xescape(const char *s, const char *bad); diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index 2bf3bfec1..ded6d31f4 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,9 @@ along with systemd; If not, see . ***/ +#include #include +#include #include "ether-addr-util.h" #include "macro.h" diff --git a/src/basic/ether-addr-util.h b/src/basic/ether-addr-util.h index 008f3b893..4487149ef 100644 --- a/src/basic/ether-addr-util.h +++ b/src/basic/ether-addr-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/exit-status.c b/src/basic/exit-status.c index 4c8373154..5e0bc415c 100644 --- a/src/basic/exit-status.c +++ b/src/basic/exit-status.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h index 7259cd1d1..79525d30e 100644 --- a/src/basic/exit-status.h +++ b/src/basic/exit-status.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,6 +21,8 @@ #include +#include "hashmap.h" +#include "macro.h" #include "set.h" typedef enum ExitStatus { diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index fd495692f..ee35d2a0e 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,22 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include +#include +#include + #include "alloc-util.h" #include "escape.h" #include "extract-word.h" +#include "log.h" +#include "macro.h" #include "string-util.h" #include "utf8.h" -#include "util.h" int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { _cleanup_free_ char *s = NULL; @@ -97,9 +105,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra } if (flags & EXTRACT_CUNESCAPE) { - uint32_t u; + bool eight_bit = false; + char32_t u; - r = cunescape_one(*p, (size_t) -1, &c, &u); + r = cunescape_one(*p, (size_t) -1, &u, &eight_bit); if (r < 0) { if (flags & EXTRACT_CUNESCAPE_RELAX) { s[sz++] = '\\'; @@ -109,10 +118,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra } else { (*p) += r - 1; - if (c != 0) - s[sz++] = c; /* normal explicit char */ + if (eight_bit) + s[sz++] = u; else - sz += utf8_encode_unichar(s + sz, u); /* unicode chars we'll encode as utf8 */ + sz += utf8_encode_unichar(s + sz, u); } } else s[sz++] = c; diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h index 9606ab64b..21db5ef33 100644 --- a/src/basic/extract-word.h +++ b/src/basic/extract-word.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index d1b1db3a4..ec9560cd0 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,18 @@ along with systemd; If not, see . ***/ -#include "dirent-util.h" +#include +#include +#include +#include +#include +#include + #include "fd-util.h" +#include "macro.h" +#include "missing.h" #include "parse-util.h" +#include "path-util.h" #include "socket-util.h" #include "util.h" diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index 0e9182d75..44528c6e3 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,9 +19,9 @@ along with systemd; If not, see . ***/ -#include #include #include +#include #include #include "macro.h" @@ -73,3 +71,7 @@ int same_fd(int a, int b); void cmsg_close_all(struct msghdr *mh); bool fdname_is_valid(const char *s); + +/* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */ +#define ERRNO_IS_DISCONNECT(r) \ + IN_SET(r, ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, ENETUNREACH) diff --git a/src/basic/fdset.c b/src/basic/fdset.c index e5452f3bb..3674d3ed9 100644 --- a/src/basic/fdset.c +++ b/src/basic/fdset.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,19 +17,21 @@ along with systemd; If not, see . ***/ +#include #include #include #include +#include #include "sd-daemon.h" -#include "dirent-util.h" #include "fd-util.h" #include "fdset.h" +#include "log.h" #include "macro.h" #include "parse-util.h" +#include "path-util.h" #include "set.h" -#include "util.h" #define MAKE_SET(s) ((Set*) s) #define MAKE_FDSET(s) ((FDSet*) s) diff --git a/src/basic/fdset.h b/src/basic/fdset.h index 70d8acbcf..12d0cef76 100644 --- a/src/basic/fdset.h +++ b/src/basic/fdset.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,10 @@ along with systemd; If not, see . ***/ +#include + +#include "hashmap.h" +#include "macro.h" #include "set.h" typedef struct FDSet FDSet; diff --git a/src/basic/fileio-label.c b/src/basic/fileio-label.c index 0405822ce..66dbc0fe1 100644 --- a/src/basic/fileio-label.c +++ b/src/basic/fileio-label.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,9 +18,11 @@ along with systemd; If not, see . ***/ +#include + #include "fileio-label.h" +#include "fileio.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 25fa351be..fe7543013 100644 --- a/src/basic/fileio-label.h +++ b/src/basic/fileio-label.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,6 +21,7 @@ ***/ #include + #include "fileio.h" int write_string_file_atomic_label(const char *fn, const char *line); diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 10aacdc56..e43ca6d29 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,6 +17,15 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include "alloc-util.h" @@ -28,15 +35,17 @@ #include "fileio.h" #include "fs-util.h" #include "hexdecoct.h" +#include "log.h" +#include "macro.h" #include "parse-util.h" #include "path-util.h" #include "random-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "umask-util.h" #include "utf8.h" -#include "util.h" int write_string_stream(FILE *f, const char *line, bool enforce_newline) { @@ -154,7 +163,7 @@ int read_one_line_file(const char *fn, char **line) { if (!fgets(t, sizeof(t), f)) { if (ferror(f)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; t[0] = 0; } @@ -1053,7 +1062,7 @@ int fflush_and_check(FILE *f) { fflush(f); if (ferror(f)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return 0; } @@ -1240,3 +1249,32 @@ int read_timestamp_file(const char *fn, usec_t *ret) { *ret = (usec_t) t; return 0; } + +int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) { + int r; + + assert(s); + + /* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter + * when specified shall initially point to a boolean variable initialized to false. It is set to true after the + * first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each + * element, but not before the first one. */ + + if (!f) + f = stdout; + + if (space) { + if (!separator) + separator = " "; + + if (*space) { + r = fputs(separator, f); + if (r < 0) + return r; + } + + *space = true; + } + + return fputs(s, f); +} diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 95e869894..8084895ff 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -82,3 +80,5 @@ int tempfn_random_child(const char *p, const char *extra, char **ret); int write_timestamp_file_atomic(const char *fn, usec_t n); int read_timestamp_file(const char *fn, usec_t *ret); + +int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space); diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 2b6189ad9..3ef1b90ed 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,16 +17,30 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "alloc-util.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "log.h" +#include "macro.h" +#include "missing.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "user-util.h" #include "util.h" @@ -327,7 +339,8 @@ int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gi if (parents) mkdir_parents(path, 0755); - fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644); + fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, + (mode == 0 || mode == MODE_INVALID) ? 0644 : mode); if (fd < 0) return -errno; @@ -467,7 +480,7 @@ int get_files_in_directory(const char *path, char ***list) { errno = 0; de = readdir(d); - if (!de && errno != 0) + if (!de && errno > 0) return -errno; if (!de) break; diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 902c7e295..0e2fcb21b 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,10 +20,12 @@ ***/ #include +#include +#include +#include #include #include #include -#include #include "time-util.h" diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c index 0bfbcb1d3..007198c26 100644 --- a/src/basic/glob-util.c +++ b/src/basic/glob-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,12 @@ along with systemd; If not, see . ***/ +#include #include #include "glob-util.h" -#include "string-util.h" +#include "macro.h" #include "strv.h" -#include "util.h" int glob_exists(const char *path) { _cleanup_globfree_ glob_t g = {}; @@ -40,7 +38,7 @@ int glob_exists(const char *path) { if (k == GLOB_NOSPACE) return -ENOMEM; if (k != 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return !strv_isempty(g.gl_pathv); } @@ -58,7 +56,7 @@ int glob_extend(char ***strv, const char *path) { if (k == GLOB_NOSPACE) return -ENOMEM; if (k != 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; if (strv_isempty(g.gl_pathv)) return -ENOENT; diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h index 793adf4a6..5d8fb47a2 100644 --- a/src/basic/glob-util.h +++ b/src/basic/glob-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include #include "macro.h" diff --git a/src/basic/gunicode.c b/src/basic/gunicode.c index d89a2f3ed..542110503 100644 --- a/src/basic/gunicode.c +++ b/src/basic/gunicode.c @@ -4,6 +4,8 @@ * Copyright 2000, 2005 Red Hat, Inc. */ +#include + #include "gunicode.h" #define unichar uint32_t diff --git a/src/basic/gunicode.h b/src/basic/gunicode.h index e70818fdd..b03aa4316 100644 --- a/src/basic/gunicode.h +++ b/src/basic/gunicode.h @@ -6,8 +6,8 @@ #pragma once -#include #include +#include #include char *utf8_prev_char (const char *p); diff --git a/src/basic/hash-funcs.c b/src/basic/hash-funcs.c new file mode 100644 index 000000000..c3a4a011b --- /dev/null +++ b/src/basic/hash-funcs.c @@ -0,0 +1,81 @@ +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2014 Michal Schmidt + + 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 . +***/ + +#include "hash-funcs.h" + +void string_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, strlen(p) + 1, state); +} + +int string_compare_func(const void *a, const void *b) { + return strcmp(a, b); +} + +const struct hash_ops string_hash_ops = { + .hash = string_hash_func, + .compare = string_compare_func +}; + +void trivial_hash_func(const void *p, struct siphash *state) { + siphash24_compress(&p, sizeof(p), state); +} + +int trivial_compare_func(const void *a, const void *b) { + return a < b ? -1 : (a > b ? 1 : 0); +} + +const struct hash_ops trivial_hash_ops = { + .hash = trivial_hash_func, + .compare = trivial_compare_func +}; + +void uint64_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(uint64_t), state); +} + +int uint64_compare_func(const void *_a, const void *_b) { + uint64_t a, b; + a = *(const uint64_t*) _a; + b = *(const uint64_t*) _b; + return a < b ? -1 : (a > b ? 1 : 0); +} + +const struct hash_ops uint64_hash_ops = { + .hash = uint64_hash_func, + .compare = uint64_compare_func +}; + +#if SIZEOF_DEV_T != 8 +void devt_hash_func(const void *p, struct siphash *state) { + siphash24_compress(p, sizeof(dev_t), state); +} + +int devt_compare_func(const void *_a, const void *_b) { + dev_t a, b; + a = *(const dev_t*) _a; + b = *(const dev_t*) _b; + return a < b ? -1 : (a > b ? 1 : 0); +} + +const struct hash_ops devt_hash_ops = { + .hash = devt_hash_func, + .compare = devt_compare_func +}; +#endif diff --git a/src/basic/hash-funcs.h b/src/basic/hash-funcs.h new file mode 100644 index 000000000..299189d14 --- /dev/null +++ b/src/basic/hash-funcs.h @@ -0,0 +1,65 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + Copyright 2014 Michal Schmidt + + 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 . +***/ + +#include "macro.h" +#include "siphash24.h" + +typedef void (*hash_func_t)(const void *p, struct siphash *state); +typedef int (*compare_func_t)(const void *a, const void *b); + +struct hash_ops { + hash_func_t hash; + compare_func_t compare; +}; + +void string_hash_func(const void *p, struct siphash *state); +int string_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops string_hash_ops; + +/* This will compare the passed pointers directly, and will not + * dereference them. This is hence not useful for strings or + * suchlike. */ +void trivial_hash_func(const void *p, struct siphash *state); +int trivial_compare_func(const void *a, const void *b) _const_; +extern const struct hash_ops trivial_hash_ops; + +/* 32bit values we can always just embed in the pointer itself, but + * in order to support 32bit archs we need store 64bit values + * indirectly, since they don't fit in a pointer. */ +void uint64_hash_func(const void *p, struct siphash *state); +int uint64_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops uint64_hash_ops; + +/* On some archs dev_t is 32bit, and on others 64bit. And sometimes + * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ +#if SIZEOF_DEV_T != 8 +void devt_hash_func(const void *p, struct siphash *state) _pure_; +int devt_compare_func(const void *a, const void *b) _pure_; +extern const struct hash_ops devt_hash_ops = { + .hash = devt_hash_func, + .compare = devt_compare_func +}; +#else +#define devt_hash_func uint64_hash_func +#define devt_compare_func uint64_compare_func +#define devt_hash_ops uint64_hash_ops +#endif diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 6e501ef6f..6f1a049d4 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,8 +19,9 @@ ***/ #include -#include +#include #include +#include #include "alloc-util.h" #include "hashmap.h" @@ -36,6 +35,7 @@ #include "util.h" #ifdef ENABLE_DEBUG_HASHMAP +#include #include "list.h" #endif @@ -278,66 +278,6 @@ static const struct hashmap_type_info hashmap_type_info[_HASHMAP_TYPE_MAX] = { }, }; -void string_hash_func(const void *p, struct siphash *state) { - siphash24_compress(p, strlen(p) + 1, state); -} - -int string_compare_func(const void *a, const void *b) { - return strcmp(a, b); -} - -const struct hash_ops string_hash_ops = { - .hash = string_hash_func, - .compare = string_compare_func -}; - -void trivial_hash_func(const void *p, struct siphash *state) { - siphash24_compress(&p, sizeof(p), state); -} - -int trivial_compare_func(const void *a, const void *b) { - return a < b ? -1 : (a > b ? 1 : 0); -} - -const struct hash_ops trivial_hash_ops = { - .hash = trivial_hash_func, - .compare = trivial_compare_func -}; - -void uint64_hash_func(const void *p, struct siphash *state) { - siphash24_compress(p, sizeof(uint64_t), state); -} - -int uint64_compare_func(const void *_a, const void *_b) { - uint64_t a, b; - a = *(const uint64_t*) _a; - b = *(const uint64_t*) _b; - return a < b ? -1 : (a > b ? 1 : 0); -} - -const struct hash_ops uint64_hash_ops = { - .hash = uint64_hash_func, - .compare = uint64_compare_func -}; - -#if SIZEOF_DEV_T != 8 -void devt_hash_func(const void *p, struct siphash *state) { - siphash24_compress(p, sizeof(dev_t), state); -} - -int devt_compare_func(const void *_a, const void *_b) { - dev_t a, b; - a = *(const dev_t*) _a; - b = *(const dev_t*) _b; - return a < b ? -1 : (a > b ? 1 : 0); -} - -const struct hash_ops devt_hash_ops = { - .hash = devt_hash_func, - .compare = devt_compare_func -}; -#endif - static unsigned n_buckets(HashmapBase *h) { return h->has_indirect ? h->indirect.n_buckets : hashmap_type_info[h->type].n_direct_buckets; diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index ed6a092d8..6d1ae48b2 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,10 +20,12 @@ along with systemd; If not, see . ***/ +#include #include +#include +#include "hash-funcs.h" #include "macro.h" -#include "siphash24.h" #include "util.h" /* @@ -68,47 +68,6 @@ typedef struct { #define _IDX_ITERATOR_FIRST (UINT_MAX - 1) #define ITERATOR_FIRST ((Iterator) { .idx = _IDX_ITERATOR_FIRST, .next_key = NULL }) -typedef void (*hash_func_t)(const void *p, struct siphash *state); -typedef int (*compare_func_t)(const void *a, const void *b); - -struct hash_ops { - hash_func_t hash; - compare_func_t compare; -}; - -void string_hash_func(const void *p, struct siphash *state); -int string_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops string_hash_ops; - -/* This will compare the passed pointers directly, and will not - * dereference them. This is hence not useful for strings or - * suchlike. */ -void trivial_hash_func(const void *p, struct siphash *state); -int trivial_compare_func(const void *a, const void *b) _const_; -extern const struct hash_ops trivial_hash_ops; - -/* 32bit values we can always just embedd in the pointer itself, but - * in order to support 32bit archs we need store 64bit values - * indirectly, since they don't fit in a pointer. */ -void uint64_hash_func(const void *p, struct siphash *state); -int uint64_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops uint64_hash_ops; - -/* On some archs dev_t is 32bit, and on others 64bit. And sometimes - * it's 64bit on 32bit archs, and sometimes 32bit on 64bit archs. Yuck! */ -#if SIZEOF_DEV_T != 8 -void devt_hash_func(const void *p, struct siphash *state) _pure_; -int devt_compare_func(const void *a, const void *b) _pure_; -extern const struct hash_ops devt_hash_ops = { - .hash = devt_hash_func, - .compare = devt_compare_func -}; -#else -#define devt_hash_func uint64_hash_func -#define devt_compare_func uint64_compare_func -#define devt_hash_ops uint64_hash_ops -#endif - /* Macros for type checking */ #define PTR_COMPATIBLE_WITH_HASHMAP_BASE(h) \ (__builtin_types_compatible_p(typeof(h), HashmapBase*) || \ diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index 4eb566b15..592df53cb 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,11 +18,13 @@ ***/ #include -#include +#include +#include +#include #include "alloc-util.h" #include "hexdecoct.h" -#include "util.h" +#include "macro.h" char octchar(int x) { return '0' + (x & 7); @@ -512,14 +512,14 @@ int unbase64char(char c) { return -EINVAL; } -char *base64mem(const void *p, size_t l) { +ssize_t base64mem(const void *p, size_t l, char **out) { char *r, *z; const uint8_t *x; /* three input bytes makes four output bytes, padding is added so we must round up */ z = r = malloc(4 * (l + 2) / 3 + 1); if (!r) - return NULL; + return -ENOMEM; for (x = p; x < (const uint8_t*) p + (l / 3) * 3; x += 3) { /* x[0] == XXXXXXXX; x[1] == YYYYYYYY; x[2] == ZZZZZZZZ */ @@ -547,9 +547,64 @@ char *base64mem(const void *p, size_t l) { } *z = 0; - return r; + *out = r; + return z - r; } +static int base64_append_width(char **prefix, int plen, + const char *sep, int indent, + const void *p, size_t l, + int width) { + + _cleanup_free_ char *x = NULL; + char *t, *s; + ssize_t slen, len, avail; + int line, lines; + + len = base64mem(p, l, &x); + if (len <= 0) + return len; + + lines = (len + width - 1) / width; + + slen = sep ? strlen(sep) : 0; + t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines); + if (!t) + return -ENOMEM; + + memcpy(t + plen, sep, slen); + + for (line = 0, s = t + plen + slen, avail = len; line < lines; line++) { + int act = MIN(width, avail); + + if (line > 0 || sep) { + memset(s, ' ', indent); + s += indent; + } + + memcpy(s, x + width * line, act); + s += act; + *(s++) = line < lines - 1 ? '\n' : '\0'; + avail -= act; + } + assert(avail == 0); + + *prefix = t; + return 0; +} + +int base64_append(char **prefix, int plen, + const void *p, size_t l, + int indent, int width) { + if (plen > width / 2 || plen + indent > width) + /* leave indent on the left, keep last column free */ + return base64_append_width(prefix, plen, "\n", indent, p, l, width - indent - 1); + else + /* leave plen on the left, keep last column free */ + return base64_append_width(prefix, plen, NULL, plen, p, l, width - plen - 1); +}; + + int unbase64mem(const char *p, size_t l, void **mem, size_t *_len) { _cleanup_free_ uint8_t *r = NULL; int a, b, c, d; diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h index 4aeb4c3bd..1ba2f69eb 100644 --- a/src/basic/hexdecoct.h +++ b/src/basic/hexdecoct.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include +#include #include #include @@ -48,7 +47,10 @@ int unbase64char(char c) _const_; char *base32hexmem(const void *p, size_t l, bool padding); int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *len); -char *base64mem(const void *p, size_t l); +ssize_t base64mem(const void *p, size_t l, char **out); +int base64_append(char **prefix, int plen, + const void *p, size_t l, + int margin, int width); int unbase64mem(const char *p, size_t l, void **mem, size_t *len); void hexdump(FILE *f, const void *p, size_t s); diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index ea0528c6f..7bb23448e 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,14 +17,19 @@ along with systemd; If not, see . ***/ -#include +#include +#include +#include +#include +#include #include +#include #include "fd-util.h" #include "fileio.h" #include "hostname-util.h" +#include "macro.h" #include "string-util.h" -#include "util.h" bool hostname_is_set(void) { struct utsname u; @@ -72,7 +75,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/hostname-util.h b/src/basic/hostname-util.h index d4f5bfe45..d062eddea 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index f4e24121e..245107ebb 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,9 +18,15 @@ ***/ #include +#include +#include +#include +#include #include "alloc-util.h" #include "in-addr-util.h" +#include "macro.h" +#include "util.h" int in_addr_is_null(int family, const union in_addr_union *u) { assert(u); @@ -44,7 +48,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 +56,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); @@ -200,7 +217,7 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { errno = 0; if (!inet_ntop(family, u, x, l)) { free(x); - return errno ? -errno : -EINVAL; + return errno > 0 ? -errno : -EINVAL; } *ret = x; @@ -217,7 +234,7 @@ int in_addr_from_string(int family, const char *s, union in_addr_union *ret) { errno = 0; if (inet_pton(family, s, ret) <= 0) - return errno ? -errno : -EINVAL; + return errno > 0 ? -errno : -EINVAL; return 0; } diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 51af08868..17798ce81 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,8 @@ ***/ #include +#include +#include #include "macro.h" #include "util.h" @@ -31,8 +31,14 @@ union in_addr_union { struct in6_addr in6; }; +struct in_addr_data { + int family; + union in_addr_union address; +}; + 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/io-util.c b/src/basic/io-util.c index ac8f93ff5..3ec8d6123 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,10 +17,15 @@ along with systemd; If not, see . ***/ +#include +#include #include +#include +#include #include #include "io-util.h" +#include "time-util.h" int flush_fd(int fd) { struct pollfd pollfd = { diff --git a/src/basic/io-util.h b/src/basic/io-util.h index cd2aa75ad..142c940d9 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,9 +20,12 @@ ***/ #include +#include +#include #include #include +#include "macro.h" #include "time-util.h" int flush_fd(int fd); @@ -74,3 +75,21 @@ static inline size_t IOVEC_INCREMENT(struct iovec *i, unsigned n, size_t k) { return k; } + +static inline bool FILE_SIZE_VALID(uint64_t l) { + /* ftruncate() and friends take an unsigned file size, but actually cannot deal with file sizes larger than + * 2^63 since the kernel internally handles it as signed value. This call allows checking for this early. */ + + return (l >> 63) == 0; +} + +static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { + + /* Same as above, but allows one extra value: -1 as indication for infinity. */ + + if (l == (uint64_t) -1) + return true; + + return FILE_SIZE_VALID(l); + +} diff --git a/src/basic/ioprio.h b/src/basic/ioprio.h index e5c71d004..d8bb6eb49 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 #include +#include /* * 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 9d5dedb93..daa98fc81 100644 --- a/src/basic/json.c +++ b/src/basic/json.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,10 @@ along with systemd; If not, see . ***/ +#include #include +#include +#include #include #include "alloc-util.h" @@ -319,7 +320,7 @@ static int json_parse_string(const char **p, char **ret) { else if (*c == 't') ch = '\t'; else if (*c == 'u') { - uint16_t x; + char16_t x; int r; r = unhex_ucs2(c + 1, &x); @@ -332,11 +333,11 @@ static int json_parse_string(const char **p, char **ret) { return -ENOMEM; if (!utf16_is_surrogate(x)) - n += utf8_encode_unichar(s + n, x); + n += utf8_encode_unichar(s + n, (char32_t) x); else if (utf16_is_trailing_surrogate(x)) return -EINVAL; else { - uint16_t y; + char16_t y; if (c[0] != '\\' || c[1] != 'u') return -EINVAL; diff --git a/src/basic/json.h b/src/basic/json.h index e0b4d810b..a4509f680 100644 --- a/src/basic/json.h +++ b/src/basic/json.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,10 @@ ***/ #include +#include +#include + +#include "macro.h" #include "util.h" enum { diff --git a/src/basic/label.c b/src/basic/label.c index f33502f90..f5ab855d3 100644 --- a/src/basic/label.c +++ b/src/basic/label.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,10 +17,14 @@ along with systemd; If not, see . ***/ +#include +#include +#include + #include "label.h" +#include "macro.h" #include "selinux-util.h" #include "smack-util.h" -#include "util.h" int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) { int r, q; diff --git a/src/basic/label.h b/src/basic/label.h index 8070bcb02..3e9251aa7 100644 --- a/src/basic/label.h +++ b/src/basic/label.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/list.h b/src/basic/list.h index 760abcdab..c68185f58 100644 --- a/src/basic/list.h +++ b/src/basic/list.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index b87fd7670..cda6b2895 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,22 @@ along with systemd; If not, see . ***/ +#include +#include +#include #include +#include #include +#include +#include +#include +#include #include +#include #include "dirent-util.h" #include "fd-util.h" +#include "hashmap.h" #include "locale-util.h" #include "path-util.h" #include "set.h" @@ -32,7 +40,6 @@ #include "string-util.h" #include "strv.h" #include "utf8.h" -#include "util.h" static int add_locales_from_archive(Set *locales) { /* Stolen from glibc... */ diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index c71d14513..b0f967928 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c index 0bdbae480..3ee4191e4 100644 --- a/src/basic/lockfile-util.c +++ b/src/basic/lockfile-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,20 +18,18 @@ ***/ #include -#include -#include +#include #include -#include #include #include +#include #include "alloc-util.h" #include "fd-util.h" -#include "fileio.h" #include "fs-util.h" #include "lockfile-util.h" +#include "macro.h" #include "path-util.h" -#include "util.h" int make_lock_file(const char *p, int operation, LockFile *ret) { _cleanup_close_ int fd = -1; diff --git a/src/basic/lockfile-util.h b/src/basic/lockfile-util.h index 38d47094b..22491ee8e 100644 --- a/src/basic/lockfile-util.h +++ b/src/basic/lockfile-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,8 @@ along with systemd; If not, see . ***/ +#include + #include "macro.h" #include "missing.h" diff --git a/src/basic/log.c b/src/basic/log.c index fe29cacd9..d89e6f727 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,12 +19,18 @@ #include #include -#include +#include +#include #include #include #include +#include +#include #include +#include +#include #include +#include #include #include "sd-messages.h" @@ -48,6 +52,7 @@ #include "string-util.h" #include "syslog-util.h" #include "terminal-util.h" +#include "time-util.h" #include "util.h" #define SNDBUF_SIZE (8*1024*1024) @@ -345,7 +350,7 @@ static int write_to_console( highlight = LOG_PRI(level) <= LOG_ERR && show_color; if (show_location) { - snprintf(location, sizeof(location), "(%s:%i) ", file, line); + xsprintf(location, "(%s:%i) ", file, line); IOVEC_SET_STRING(iovec[n++], location); } @@ -770,7 +775,7 @@ static void log_assert( return; DISABLE_WARNING_FORMAT_NONLITERAL; - snprintf(buffer, sizeof(buffer), format, text, file, line, func); + xsprintf(buffer, format, text, file, line, func); REENABLE_WARNING; log_abort_msg = buffer; @@ -798,6 +803,52 @@ int log_oom_internal(const char *file, int line, const char *func) { return -ENOMEM; } +int log_format_iovec( + struct iovec *iovec, + unsigned iovec_len, + unsigned *n, + bool newline_separator, + int error, + const char *format, + va_list ap) { + + static const char nl = '\n'; + + while (format && *n + 1 < iovec_len) { + va_list aq; + char *m; + int r; + + /* We need to copy the va_list structure, + * since vasprintf() leaves it afterwards at + * an undefined location */ + + if (error != 0) + errno = error; + + va_copy(aq, ap); + r = vasprintf(&m, format, aq); + va_end(aq); + if (r < 0) + return -EINVAL; + + /* Now, jump enough ahead, so that we point to + * the next format string */ + VA_FORMAT_ADVANCE(format, ap); + + IOVEC_SET_STRING(iovec[(*n)++], m); + + if (newline_separator) { + iovec[*n].iov_base = (char*) &nl; + iovec[*n].iov_len = 1; + (*n)++; + } + + format = va_arg(ap, char *); + } + return 0; +} + int log_struct_internal( int level, int error, @@ -830,10 +881,10 @@ int log_struct_internal( char header[LINE_MAX]; struct iovec iovec[17] = {}; unsigned n = 0, i; + int r; struct msghdr mh = { .msg_iov = iovec, }; - static const char nl = '\n'; bool fallback = false; /* If the journal is available do structured logging */ @@ -841,43 +892,14 @@ int log_struct_internal( IOVEC_SET_STRING(iovec[n++], header); va_start(ap, format); - while (format && n + 1 < ELEMENTSOF(iovec)) { - va_list aq; - char *m; - - /* We need to copy the va_list structure, - * since vasprintf() leaves it afterwards at - * an undefined location */ - - if (error != 0) - errno = error; - - va_copy(aq, ap); - if (vasprintf(&m, format, aq) < 0) { - va_end(aq); - fallback = true; - goto finish; - } - va_end(aq); - - /* Now, jump enough ahead, so that we point to - * the next format string */ - VA_FORMAT_ADVANCE(format, ap); - - IOVEC_SET_STRING(iovec[n++], m); - - iovec[n].iov_base = (char*) &nl; - iovec[n].iov_len = 1; - n++; - - format = va_arg(ap, char *); + r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, true, error, format, ap); + if (r < 0) + fallback = true; + else { + mh.msg_iovlen = n; + (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL); } - mh.msg_iovlen = n; - - (void) sendmsg(journal_fd, &mh, MSG_NOSIGNAL); - - finish: va_end(ap); for (i = 1; i < n; i += 2) free(iovec[i].iov_base); diff --git a/src/basic/log.h b/src/basic/log.h index cda1e45cc..60ddead74 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -26,6 +24,7 @@ #include #include #include +#include #include #include "sd-id128.h" @@ -127,6 +126,15 @@ int log_oom_internal( int line, const char *func); +int log_format_iovec( + struct iovec *iovec, + unsigned iovec_len, + unsigned *n, + bool newline_separator, + int error, + const char *format, + va_list ap); + /* This modifies the buffer passed! */ int log_dump_internal( int level, diff --git a/src/basic/login-util.c b/src/basic/login-util.c index 41cef14e7..339e94f12 100644 --- a/src/basic/login-util.c +++ b/src/basic/login-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,8 @@ along with systemd; If not, see . ***/ -#include "def.h" +#include + #include "login-util.h" #include "string-util.h" diff --git a/src/basic/login-util.h b/src/basic/login-util.h index be5bb6487..89a337d7c 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/basic/macro.h b/src/basic/macro.h index 5088e6720..2695d0edb 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -320,18 +318,47 @@ static inline unsigned long ALIGN_POWER2(unsigned long u) { #define SET_FLAG(v, flag, b) \ (v) = (b) ? ((v) | (flag)) : ((v) & ~(flag)) -#define IN_SET(x, y, ...) \ - ({ \ - static const typeof(y) _array[] = { (y), __VA_ARGS__ }; \ - const typeof(y) _x = (x); \ - unsigned _i; \ - bool _found = false; \ - for (_i = 0; _i < ELEMENTSOF(_array); _i++) \ - if (_array[_i] == _x) { \ - _found = true; \ - break; \ - } \ - _found; \ +#define CASE_F(X) case X: +#define CASE_F_1(CASE, X) CASE_F(X) +#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__) +#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__) +#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__) +#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__) +#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__) +#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__) +#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__) +#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__) +#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__) +#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__) +#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__) +#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__) +#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__) +#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__) +#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__) +#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__) +#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__) +#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__) +#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__) + +#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME +#define FOR_EACH_MAKE_CASE(...) \ + GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \ + CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ + (CASE_F,__VA_ARGS__) + +#define IN_SET(x, ...) \ + ({ \ + bool _found = false; \ + /* If the build breaks in the line below, you need to extend the case macros */ \ + static _unused_ char _static_assert__macros_need_to_be_extended[20 - sizeof((int[]){__VA_ARGS__})/sizeof(int)]; \ + switch(x) { \ + FOR_EACH_MAKE_CASE(__VA_ARGS__) \ + _found = true; \ + break; \ + default: \ + break; \ + } \ + _found; \ }) /* Define C11 thread_local attribute even on older gcc compiler diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index 92630f6b2..8c8cc78eb 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,10 @@ along with systemd; If not, see . ***/ +#include #include +#include +#include #ifdef HAVE_LINUX_MEMFD_H #include #endif @@ -29,11 +30,11 @@ #include "alloc-util.h" #include "fd-util.h" +#include "macro.h" #include "memfd-util.h" #include "missing.h" #include "string-util.h" #include "utf8.h" -#include "util.h" int memfd_new(const char *name) { _cleanup_free_ char *g = NULL; diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 2cb404ea8..46d4989e4 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,10 @@ along with systemd; If not, see . ***/ -#include #include +#include +#include +#include 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 9ee6e6a76..f95e2beb0 100644 --- a/src/basic/mempool.c +++ b/src/basic/mempool.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,6 +18,9 @@ along with systemd; If not, see . ***/ +#include +#include + #include "macro.h" #include "mempool.h" #include "util.h" diff --git a/src/basic/mempool.h b/src/basic/mempool.h index 42f473bee..fea7841bc 100644 --- a/src/basic/mempool.h +++ b/src/basic/mempool.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/missing.h b/src/basic/missing.h index d539ed00e..36b060496 100644 --- a/src/basic/missing.h +++ b/src/basic/missing.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -36,6 +34,7 @@ #include #include #include +#include #include #ifdef HAVE_AUDIT @@ -131,6 +130,10 @@ #define NETLINK_LIST_MEMBERSHIPS 9 #endif +#ifndef SOL_SCTP +#define SOL_SCTP 132 +#endif + #if !HAVE_DECL_PIVOT_ROOT static inline int pivot_root(const char *new_root, const char *put_old) { return syscall(SYS_pivot_root, new_root, put_old); @@ -970,6 +973,10 @@ static inline int setns(int fd, int nstype) { #define IFA_FLAGS 8 #endif +#ifndef IFA_F_MANAGETEMPADDR +#define IFA_F_MANAGETEMPADDR 0x100 +#endif + #ifndef IFA_F_NOPREFIXROUTE #define IFA_F_NOPREFIXROUTE 0x200 #endif @@ -1125,3 +1132,39 @@ static inline key_serial_t request_key(const char *type, const char *description #ifndef KEY_SPEC_USER_KEYRING #define KEY_SPEC_USER_KEYRING -4 #endif + +#ifndef PR_CAP_AMBIENT +#define PR_CAP_AMBIENT 47 +#endif + +#ifndef PR_CAP_AMBIENT_IS_SET +#define PR_CAP_AMBIENT_IS_SET 1 +#endif + +#ifndef PR_CAP_AMBIENT_RAISE +#define PR_CAP_AMBIENT_RAISE 2 +#endif + +#ifndef PR_CAP_AMBIENT_CLEAR_ALL +#define PR_CAP_AMBIENT_CLEAR_ALL 4 +#endif + +/* The following two defines are actually available in the kernel headers for longer, but we define them here anyway, + * since that makes it easier to use them in conjunction with the glibc net/if.h header which conflicts with + * linux/if.h. */ +#ifndef IF_OPER_UNKNOWN +#define IF_OPER_UNKNOWN 0 +#endif + +#ifndef IF_OPER_UP +#define IF_OPER_UP 6 + +#ifndef HAVE_DECL_CHAR32_T +#define char32_t uint32_t +#endif + +#ifndef HAVE_DECL_CHAR16_T +#define char16_t uint16_t +#endif + +#endif diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c index c241ef606..aa6878cdf 100644 --- a/src/basic/mkdir-label.c +++ b/src/basic/mkdir-label.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,6 +19,7 @@ ***/ #include +#include #include #include "label.h" diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 5d7fb9a12..6b1a98402 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,14 +18,16 @@ ***/ #include +#include #include +#include #include "fs-util.h" +#include "macro.h" #include "mkdir.h" #include "path-util.h" #include "stat-util.h" #include "user-util.h" -#include "util.h" int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) { struct stat st; diff --git a/src/basic/mkdir.h b/src/basic/mkdir.h index 2392d1fd1..d564a3547 100644 --- a/src/basic/mkdir.h +++ b/src/basic/mkdir.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 29997b1ce..33f2ee96d 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,21 +17,25 @@ along with systemd; If not, see . ***/ +#include +#include #include #include +#include #include +#include #include "alloc-util.h" #include "escape.h" #include "fd-util.h" #include "fileio.h" +#include "hashmap.h" #include "mount-util.h" #include "parse-util.h" #include "path-util.h" #include "set.h" #include "stdio-util.h" #include "string-util.h" -#include "util.h" static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) { char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index 48954c2d6..bdb525d6b 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,9 +22,11 @@ #include #include #include +#include #include #include +#include "macro.h" #include "missing.h" int fd_is_mount_point(int fd, const char *filename, int flags); diff --git a/src/shared/nss-util.h b/src/basic/nss-util.h similarity index 98% rename from src/shared/nss-util.h rename to src/basic/nss-util.h index 3657aa5d9..df565a359 100644 --- a/src/shared/nss-util.h +++ b/src/basic/nss-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,12 +19,13 @@ along with systemd; If not, see . ***/ -#include -#include -#include -#include #include +#include +#include +#include +#include +#define NSS_SIGNALS_BLOCK SIGALRM,SIGVTALRM,SIGPIPE,SIGCHLD,SIGTSTP,SIGIO,SIGHUP,SIGUSR1,SIGUSR2,SIGPROF,SIGURG,SIGWINCH #define NSS_GETHOSTBYNAME_PROTOTYPES(module) \ enum nss_status _nss_##module##_gethostbyname4_r( \ diff --git a/src/basic/ordered-set.c b/src/basic/ordered-set.c new file mode 100644 index 000000000..2e0bdf648 --- /dev/null +++ b/src/basic/ordered-set.c @@ -0,0 +1,64 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "ordered-set.h" +#include "strv.h" + +int ordered_set_consume(OrderedSet *s, void *p) { + int r; + + r = ordered_set_put(s, p); + if (r <= 0) + free(p); + + return r; +} + +int ordered_set_put_strdup(OrderedSet *s, const char *p) { + char *c; + int r; + + assert(s); + assert(p); + + c = strdup(p); + if (!c) + return -ENOMEM; + + r = ordered_set_consume(s, c); + if (r == -EEXIST) + return 0; + + return r; +} + +int ordered_set_put_strdupv(OrderedSet *s, char **l) { + int n = 0, r; + char **i; + + STRV_FOREACH(i, l) { + r = ordered_set_put_strdup(s, *i); + if (r < 0) + return r; + + n += r; + } + + return n; +} diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h index 6c617ab30..e1dfc8638 100644 --- a/src/basic/ordered-set.h +++ b/src/basic/ordered-set.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -29,6 +27,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; @@ -51,9 +60,15 @@ static inline bool ordered_set_iterate(OrderedSet *s, Iterator *i, void **value) return ordered_hashmap_iterate((OrderedHashmap*) s, i, value, NULL); } +int ordered_set_consume(OrderedSet *s, void *p); +int ordered_set_put_strdup(OrderedSet *s, const char *p); +int ordered_set_put_strdupv(OrderedSet *s, char **l); + #define ORDERED_SET_FOREACH(e, s, i) \ for ((i) = ITERATOR_FIRST; ordered_set_iterate((s), &(i), (void**)&(e)); ) DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedSet*, ordered_set_free_free); #define _cleanup_ordered_set_free_ _cleanup_(ordered_set_freep) +#define _cleanup_ordered_set_free_free_ _cleanup_(ordered_set_free_freep) diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 151067e91..a3cb81b04 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,11 +17,19 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include +#include + #include "alloc-util.h" #include "extract-word.h" +#include "macro.h" #include "parse-util.h" #include "string-util.h" -#include "util.h" int parse_boolean(const char *v) { assert(v); @@ -73,7 +79,7 @@ int parse_mode(const char *s, mode_t *ret) { errno = 0; l = strtol(s, &x, 8); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -168,7 +174,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { errno = 0; l = strtoull(p, &e, 10); - if (errno != 0) + if (errno > 0) return -errno; if (e == p) return -EINVAL; @@ -184,7 +190,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { char *e2; l2 = strtoull(e, &e2, 10); - if (errno != 0) + if (errno > 0) return -errno; /* Ignore failure. E.g. 10.M is valid */ @@ -322,7 +328,7 @@ int safe_atou(const char *s, unsigned *ret_u) { errno = 0; l = strtoul(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -344,7 +350,7 @@ int safe_atoi(const char *s, int *ret_i) { errno = 0; l = strtol(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -366,7 +372,7 @@ int safe_atollu(const char *s, long long unsigned *ret_llu) { errno = 0; l = strtoull(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -386,7 +392,7 @@ int safe_atolli(const char *s, long long int *ret_lli) { errno = 0; l = strtoll(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -406,7 +412,7 @@ int safe_atou8(const char *s, uint8_t *ret) { errno = 0; l = strtoul(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -430,7 +436,7 @@ int safe_atou16(const char *s, uint16_t *ret) { errno = 0; l = strtoul(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -452,7 +458,7 @@ int safe_atoi16(const char *s, int16_t *ret) { errno = 0; l = strtol(s, &x, 0); - if (errno != 0) + if (errno > 0) return -errno; if (!x || x == s || *x) return -EINVAL; @@ -477,7 +483,7 @@ int safe_atod(const char *s, double *ret_d) { errno = 0; d = strtod_l(s, &x, loc); - if (errno != 0) { + if (errno > 0) { freelocale(loc); return -errno; } @@ -490,3 +496,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 408690d0b..d8dc26a36 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,9 @@ ***/ #include +#include +#include +#include #include #include "macro.h" @@ -90,3 +91,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/path-util.c b/src/basic/path-util.c index ec90c432a..822c09bfb 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,11 +18,11 @@ ***/ #include -#include +#include #include #include #include -#include +#include #include /* When we include libgen.h because we need dirname() we immediately @@ -34,18 +32,16 @@ #undef basename #include "alloc-util.h" -#include "fd-util.h" -#include "fileio.h" +#include "extract-word.h" #include "fs-util.h" #include "log.h" #include "macro.h" #include "missing.h" -#include "parse-util.h" #include "path-util.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" -#include "util.h" +#include "time-util.h" bool path_is_absolute(const char *p) { return p[0] == '/'; @@ -104,7 +100,7 @@ int path_make_absolute_cwd(const char *p, char **ret) { cwd = get_current_dir_name(); if (!cwd) - return -errno; + return negative_errno(); c = strjoin(cwd, "/", p, NULL); } diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 989e0f900..2c2f87a9f 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,7 +19,9 @@ along with systemd; If not, see . ***/ +#include #include +#include #include "macro.h" #include "time-util.h" diff --git a/src/basic/prioq.c b/src/basic/prioq.c index 759069891..d2ec516d2 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -29,9 +27,12 @@ * The underlying algorithm used in this implementation is a Heap. */ +#include +#include + #include "alloc-util.h" +#include "hashmap.h" #include "prioq.h" -#include "util.h" struct prioq_item { void *data; diff --git a/src/basic/prioq.h b/src/basic/prioq.h index 1c044b135..113c73d04 100644 --- a/src/basic/prioq.h +++ b/src/basic/prioq.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,7 +19,10 @@ along with systemd; If not, see . ***/ +#include + #include "hashmap.h" +#include "macro.h" typedef struct Prioq Prioq; diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 4464573c5..3505fa9c9 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,6 +17,10 @@ along with systemd; If not, see . ***/ +#include +#include +#include + #include "alloc-util.h" #include "extract-word.h" #include "fileio.h" diff --git a/src/basic/proc-cmdline.h b/src/basic/proc-cmdline.h index ce6e84995..452642a2f 100644 --- a/src/basic/proc-cmdline.h +++ b/src/basic/proc-cmdline.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 7631928d5..189ef9ab6 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -17,19 +17,25 @@ along with systemd; If not, see . ***/ -#include #include #include +#include +#include #include #include #include #include +#include #include #include #include #include #include +#include #include +#ifdef HAVE_VALGRIND_VALGRIND_H +#include +#endif #include "alloc-util.h" #include "escape.h" @@ -38,8 +44,11 @@ #include "fs-util.h" #include "ioprio.h" #include "log.h" +#include "macro.h" +#include "missing.h" #include "process-util.h" #include "signal-util.h" +#include "stat-util.h" #include "string-table.h" #include "string-util.h" #include "user-util.h" @@ -629,6 +638,17 @@ bool pid_is_alive(pid_t pid) { return true; } +int pid_from_same_root_fs(pid_t pid) { + const char *root; + + if (pid < 0) + return 0; + + root = procfs_file_alloca(pid, "root"); + + return files_same(root, "/proc/1/root"); +} + bool is_main_thread(void) { static thread_local int cached = 0; @@ -725,6 +745,23 @@ const char* personality_to_string(unsigned long p) { return NULL; } +void valgrind_summary_hack(void) { +#ifdef HAVE_VALGRIND_VALGRIND_H + if (getpid() == 1 && RUNNING_ON_VALGRIND) { + pid_t pid; + pid = raw_clone(SIGCHLD, NULL); + if (pid < 0) + log_emergency_errno(errno, "Failed to fork off valgrind helper: %m"); + else if (pid == 0) + exit(EXIT_SUCCESS); + else { + log_info("Spawned valgrind helper as PID "PID_FMT".", pid); + (void) wait_for_terminate(pid, NULL); + } + } +#endif +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 72633ebf7..f5d193e76 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -19,12 +19,13 @@ along with systemd; If not, see . ***/ -#include -#include #include +#include +#include +#include #include #include -#include +#include #include "formats-util.h" #include "macro.h" @@ -69,6 +70,7 @@ int getenv_for_pid(pid_t pid, const char *field, char **_value); bool pid_is_alive(pid_t pid); bool pid_is_unwaited(pid_t pid); +int pid_from_same_root_fs(pid_t pid); bool is_main_thread(void); @@ -97,3 +99,5 @@ int sched_policy_from_string(const char *s); #define PTR_TO_PID(p) ((pid_t) ((uintptr_t) p)) #define PID_TO_PTR(p) ((void*) ((uintptr_t) p)) + +void valgrind_summary_hack(void); diff --git a/src/basic/random-util.c b/src/basic/random-util.c index 2f5c16e2a..2f468db77 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -17,23 +17,24 @@ along with systemd; If not, see . ***/ +#include #include #include +#include +#include +#include #include #include + #ifdef HAVE_SYS_AUXV_H #include #endif -#include -#include -#include #include "fd-util.h" #include "io-util.h" #include "missing.h" #include "random-util.h" #include "time-util.h" -#include "util.h" int dev_urandom(void *p, size_t n) { static int have_syscall = -1; @@ -94,17 +95,18 @@ void initialize_srand(void) { if (srand_called) return; - x = 0; - #ifdef HAVE_SYS_AUXV_H - /* The kernel provides us with a bit of entropy in auxv, so - * let's try to make use of that to seed the pseudo-random - * generator. It's better than nothing... */ + /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed the + * pseudo-random generator. It's better than nothing... */ auxv = (void*) getauxval(AT_RANDOM); - if (auxv) - x ^= *(unsigned*) auxv; + if (auxv) { + assert_cc(sizeof(x) < 16); + memcpy(&x, auxv, sizeof(x)); + } else #endif + x = 0; + x ^= (unsigned) now(CLOCK_REALTIME); x ^= (unsigned) gettid(); diff --git a/src/basic/random-util.h b/src/basic/random-util.h index f7862c8c8..3cee4c501 100644 --- a/src/basic/random-util.h +++ b/src/basic/random-util.h @@ -19,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include int dev_urandom(void *p, size_t n); diff --git a/src/basic/ratelimit.c b/src/basic/ratelimit.c index 81fc9c19f..3ca5625e4 100644 --- a/src/basic/ratelimit.c +++ b/src/basic/ratelimit.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,6 +18,9 @@ ***/ +#include + +#include "macro.h" #include "ratelimit.h" /* Modelled after Linux' lib/ratelimit.c by Dave Young diff --git a/src/basic/ratelimit.h b/src/basic/ratelimit.h index 58efca7df..9c8dddf5a 100644 --- a/src/basic/ratelimit.h +++ b/src/basic/ratelimit.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,9 @@ along with systemd; If not, see . ***/ +#include + +#include "time-util.h" #include "util.h" typedef struct RateLimit { diff --git a/src/basic/refcnt.h b/src/basic/refcnt.h index 8a39d69fe..1d77a6445 100644 --- a/src/basic/refcnt.h +++ b/src/basic/refcnt.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/replace-var.c b/src/basic/replace-var.c index bf757cbc4..6a204b9ec 100644 --- a/src/basic/replace-var.c +++ b/src/basic/replace-var.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,13 +17,15 @@ along with systemd; If not, see . ***/ +#include +#include +#include #include #include "alloc-util.h" #include "macro.h" #include "replace-var.h" #include "string-util.h" -#include "util.h" /* * Generic infrastructure for replacing @FOO@ style variables in diff --git a/src/basic/replace-var.h b/src/basic/replace-var.h index 7eaee93a3..78412910b 100644 --- a/src/basic/replace-var.h +++ b/src/basic/replace-var.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c index 2627c813f..7540b4321 100644 --- a/src/basic/rlimit-util.c +++ b/src/basic/rlimit-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,10 +17,17 @@ along with systemd; If not, see . ***/ +#include +#include + +#include "alloc-util.h" +#include "extract-word.h" +#include "formats-util.h" +#include "macro.h" #include "missing.h" #include "rlimit-util.h" #include "string-table.h" -#include "util.h" +#include "time-util.h" int setrlimit_closest(int resource, const struct rlimit *rlim) { struct rlimit highest, fixed; @@ -48,6 +53,202 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) { return 0; } +static int rlimit_parse_u64(const char *val, rlim_t *ret) { + uint64_t u; + int r; + + assert(val); + assert(ret); + + if (streq(val, "infinity")) { + *ret = RLIM_INFINITY; + return 0; + } + + /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */ + assert_cc(sizeof(rlim_t) == sizeof(uint64_t)); + + r = safe_atou64(val, &u); + if (r < 0) + return r; + if (u >= (uint64_t) RLIM_INFINITY) + return -ERANGE; + + *ret = (rlim_t) u; + return 0; +} + +static int rlimit_parse_size(const char *val, rlim_t *ret) { + uint64_t u; + int r; + + assert(val); + assert(ret); + + if (streq(val, "infinity")) { + *ret = RLIM_INFINITY; + return 0; + } + + r = parse_size(val, 1024, &u); + if (r < 0) + return r; + if (u >= (uint64_t) RLIM_INFINITY) + return -ERANGE; + + *ret = (rlim_t) u; + return 0; +} + +static int rlimit_parse_sec(const char *val, rlim_t *ret) { + uint64_t u; + usec_t t; + int r; + + assert(val); + assert(ret); + + if (streq(val, "infinity")) { + *ret = RLIM_INFINITY; + return 0; + } + + r = parse_sec(val, &t); + if (r < 0) + return r; + if (t == USEC_INFINITY) { + *ret = RLIM_INFINITY; + return 0; + } + + u = (uint64_t) DIV_ROUND_UP(t, USEC_PER_SEC); + if (u >= (uint64_t) RLIM_INFINITY) + return -ERANGE; + + *ret = (rlim_t) u; + return 0; +} + +static int rlimit_parse_usec(const char *val, rlim_t *ret) { + usec_t t; + int r; + + assert(val); + assert(ret); + + if (streq(val, "infinity")) { + *ret = RLIM_INFINITY; + return 0; + } + + r = parse_time(val, &t, 1); + if (r < 0) + return r; + if (t == USEC_INFINITY) { + *ret = RLIM_INFINITY; + return 0; + } + + *ret = (rlim_t) t; + return 0; +} + +static int (*const rlimit_parse_table[_RLIMIT_MAX])(const char *val, rlim_t *ret) = { + [RLIMIT_CPU] = rlimit_parse_sec, + [RLIMIT_FSIZE] = rlimit_parse_size, + [RLIMIT_DATA] = rlimit_parse_size, + [RLIMIT_STACK] = rlimit_parse_size, + [RLIMIT_CORE] = rlimit_parse_size, + [RLIMIT_RSS] = rlimit_parse_size, + [RLIMIT_NOFILE] = rlimit_parse_u64, + [RLIMIT_AS] = rlimit_parse_size, + [RLIMIT_NPROC] = rlimit_parse_u64, + [RLIMIT_MEMLOCK] = rlimit_parse_size, + [RLIMIT_LOCKS] = rlimit_parse_u64, + [RLIMIT_SIGPENDING] = rlimit_parse_u64, + [RLIMIT_MSGQUEUE] = rlimit_parse_size, + [RLIMIT_NICE] = rlimit_parse_u64, + [RLIMIT_RTPRIO] = rlimit_parse_u64, + [RLIMIT_RTTIME] = rlimit_parse_usec, +}; + +int rlimit_parse_one(int resource, const char *val, rlim_t *ret) { + assert(val); + assert(ret); + + if (resource < 0) + return -EINVAL; + if (resource >= _RLIMIT_MAX) + return -EINVAL; + + return rlimit_parse_table[resource](val, ret); +} + +int rlimit_parse(int resource, const char *val, struct rlimit *ret) { + _cleanup_free_ char *hard = NULL, *soft = NULL; + rlim_t hl, sl; + int r; + + assert(val); + assert(ret); + + r = extract_first_word(&val, &soft, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + r = rlimit_parse_one(resource, soft, &sl); + if (r < 0) + return r; + + r = extract_first_word(&val, &hard, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (!isempty(val)) + return -EINVAL; + if (r == 0) + hl = sl; + else { + r = rlimit_parse_one(resource, hard, &hl); + if (r < 0) + return r; + if (sl > hl) + return -EILSEQ; + } + + *ret = (struct rlimit) { + .rlim_cur = sl, + .rlim_max = hl, + }; + + return 0; +} + +int rlimit_format(const struct rlimit *rl, char **ret) { + char *s = NULL; + + assert(rl); + assert(ret); + + if (rl->rlim_cur >= RLIM_INFINITY && rl->rlim_max >= RLIM_INFINITY) + s = strdup("infinity"); + else if (rl->rlim_cur >= RLIM_INFINITY) + (void) asprintf(&s, "infinity:" RLIM_FMT, rl->rlim_max); + else if (rl->rlim_max >= RLIM_INFINITY) + (void) asprintf(&s, RLIM_FMT ":infinity", rl->rlim_cur); + else if (rl->rlim_cur == rl->rlim_max) + (void) asprintf(&s, RLIM_FMT, rl->rlim_cur); + else + (void) asprintf(&s, RLIM_FMT ":" RLIM_FMT, rl->rlim_cur, rl->rlim_max); + + if (!s) + return -ENOMEM; + + *ret = s; + return 0; +} + static const char* const rlimit_table[_RLIMIT_MAX] = { [RLIMIT_CPU] = "LimitCPU", [RLIMIT_FSIZE] = "LimitFSIZE", diff --git a/src/basic/rlimit-util.h b/src/basic/rlimit-util.h index 262f86dd0..d4594eccd 100644 --- a/src/basic/rlimit-util.h +++ b/src/basic/rlimit-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -30,4 +28,9 @@ int rlimit_from_string(const char *s) _pure_; int setrlimit_closest(int resource, const struct rlimit *rlim); +int rlimit_parse_one(int resource, const char *val, rlim_t *ret); +int rlimit_parse(int resource, const char *val, struct rlimit *ret); + +int rlimit_format(const struct rlimit *rl, char **ret); + #define RLIMIT_MAKE_CONST(lim) ((struct rlimit) { lim, lim }) diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index 8ec7dd75e..43816fd1b 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,14 +17,24 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include +#include +#include + #include "btrfs-util.h" #include "fd-util.h" +#include "log.h" +#include "macro.h" #include "mount-util.h" #include "path-util.h" #include "rm-rf.h" #include "stat-util.h" #include "string-util.h" -#include "util.h" int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { _cleanup_closedir_ DIR *d = NULL; @@ -72,7 +80,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { errno = 0; de = readdir(d); if (!de) { - if (errno != 0 && ret == 0) + if (errno > 0 && ret == 0) ret = -errno; return ret; } diff --git a/src/basic/rm-rf.h b/src/basic/rm-rf.h index 96579eb18..6d0326891 100644 --- a/src/basic/rm-rf.h +++ b/src/basic/rm-rf.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index e8ce5cfd9..6c63b9d65 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,7 +19,12 @@ #include #include +#include +#include +#include +#include #include +#include #ifdef HAVE_SELINUX #include @@ -30,9 +33,12 @@ #endif #include "alloc-util.h" +#include "log.h" +#include "macro.h" #include "path-util.h" #include "selinux-util.h" -#include "strv.h" +#include "time-util.h" +#include "util.h" #ifdef HAVE_SELINUX DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon); @@ -47,7 +53,7 @@ static struct selabel_handle *label_hnd = NULL; #define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__) #endif -bool mac_selinux_use(void) { +bool mac_selinux_have(void) { #ifdef HAVE_SELINUX if (cached_use < 0) cached_use = is_selinux_enabled() > 0; @@ -58,6 +64,16 @@ bool mac_selinux_use(void) { #endif } +bool mac_selinux_use(void) { + if (!mac_selinux_have()) + return false; + + /* Never try to configure SELinux features if we aren't + * root */ + + return getuid() == 0; +} + void mac_selinux_retest(void) { #ifdef HAVE_SELINUX cached_use = -1; @@ -197,7 +213,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) { assert(exe); assert(label); - if (!mac_selinux_use()) + if (!mac_selinux_have()) return -EOPNOTSUPP; r = getcon_raw(&mycon); @@ -223,7 +239,7 @@ int mac_selinux_get_our_label(char **label) { assert(label); #ifdef HAVE_SELINUX - if (!mac_selinux_use()) + if (!mac_selinux_have()) return -EOPNOTSUPP; r = getcon_raw(label); @@ -247,7 +263,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char * assert(exe); assert(label); - if (!mac_selinux_use()) + if (!mac_selinux_have()) return -EOPNOTSUPP; r = getcon_raw(&mycon); @@ -302,7 +318,7 @@ char* mac_selinux_free(char *label) { if (!label) return NULL; - if (!mac_selinux_use()) + if (!mac_selinux_have()) return NULL; diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 2afcaec18..27e8edb41 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,12 +19,14 @@ along with systemd; If not, see . ***/ -#include #include +#include +#include #include "macro.h" bool mac_selinux_use(void); +bool mac_selinux_have(void); void mac_selinux_retest(void); int mac_selinux_init(const char *prefix); diff --git a/src/basic/set.h b/src/basic/set.h index 4554ef2d4..2bff5062d 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -27,7 +25,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 c535c89d5..0ce4f7568 100644 --- a/src/basic/sigbus.c +++ b/src/basic/sigbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,9 @@ along with systemd; If not, see . ***/ +#include #include +#include #include #include "macro.h" diff --git a/src/basic/sigbus.h b/src/basic/sigbus.h index 23edc6d9c..cce9eb201 100644 --- a/src/basic/sigbus.h +++ b/src/basic/sigbus.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index 8038bc891..e3047b209 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,11 +17,16 @@ along with systemd; If not, see . ***/ +#include +#include +#include + +#include "macro.h" #include "parse-util.h" #include "signal-util.h" +#include "stdio-util.h" #include "string-table.h" #include "string-util.h" -#include "util.h" int reset_all_signal_handlers(void) { static const struct sigaction sa = { @@ -230,9 +233,9 @@ const char *signal_to_string(int signo) { return name; if (signo >= SIGRTMIN && signo <= SIGRTMAX) - snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN); + xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN); else - snprintf(buf, sizeof(buf), "%d", signo); + xsprintf(buf, "%d", signo); return buf; } diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index e7393e2da..72b10e871 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -41,3 +39,14 @@ int signal_from_string(const char *s) _pure_; int signal_from_string_try_harder(const char *s); void nop_signal_handler(int sig); + +static inline void block_signals_reset(sigset_t *ss) { + assert_se(sigprocmask(SIG_SETMASK, ss, NULL) >= 0); +} + +#define BLOCK_SIGNALS(...) \ + _cleanup_(block_signals_reset) sigset_t _saved_sigset = ({ \ + sigset_t t; \ + assert_se(sigprocmask_many(SIG_BLOCK, &t, __VA_ARGS__, -1) >= 0); \ + t; \ + }) diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index 10fc56da6..060e8ba38 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -17,10 +17,9 @@ coding style) */ +#include "macro.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) { assert(b < 64); diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index ba4f7d01b..54e2420cc 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #include struct siphash { @@ -14,6 +16,8 @@ struct siphash { void siphash24_init(struct siphash *state, const uint8_t k[16]); void siphash24_compress(const void *in, size_t inlen, struct siphash *state); +#define siphash24_compress_byte(byte, state) siphash24_compress((const uint8_t[]) { (byte) }, 1, (state)) + uint64_t siphash24_finalize(struct siphash *state); uint64_t siphash24(const void *in, size_t inlen, const uint8_t k[16]); diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index fcc046098..3a3df987d 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,15 +19,20 @@ along with systemd; If not, see . ***/ +#include +#include +#include #include +#include #include "alloc-util.h" #include "fileio.h" +#include "log.h" +#include "macro.h" #include "path-util.h" #include "process-util.h" #include "smack-util.h" #include "string-table.h" -#include "util.h" #include "xattr-util.h" #ifdef HAVE_SMACK diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h index e756dc8c2..f90ba0a02 100644 --- a/src/basic/smack-util.h +++ b/src/basic/smack-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,6 +22,7 @@ ***/ #include +#include #include "macro.h" diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index e5d4efc71..35e9573aa 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,19 +18,23 @@ ***/ #include +#include +#include #include #include +#include #include +#include #include #include "alloc-util.h" #include "fd-util.h" +#include "log.h" #include "macro.h" #include "missing.h" #include "mkdir.h" #include "selinux-util.h" #include "socket-util.h" -#include "util.h" int socket_address_listen( const SocketAddress *a, @@ -143,7 +145,7 @@ int socket_address_listen( return r; } -int make_socket_fd(int log_level, const char* address, int flags) { +int make_socket_fd(int log_level, const char* address, int type, int flags) { SocketAddress a; int fd, r; @@ -151,7 +153,9 @@ int make_socket_fd(int log_level, const char* address, int flags) { if (r < 0) return log_error_errno(r, "Failed to parse socket address \"%s\": %m", address); - fd = socket_address_listen(&a, flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT, + a.type = type; + + fd = socket_address_listen(&a, type | flags, SOMAXCONN, SOCKET_ADDRESS_DEFAULT, NULL, false, false, false, 0755, 0644, NULL); if (fd < 0 || log_get_max_level() >= log_level) { _cleanup_free_ char *p = NULL; diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 1acab1ef9..49e5f5b12 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,19 +19,22 @@ #include #include +#include #include #include #include #include +#include #include +#include #include -#include #include #include "alloc-util.h" #include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "log.h" #include "macro.h" #include "missing.h" #include "parse-util.h" @@ -437,17 +438,10 @@ const char* socket_address_get_path(const SocketAddress *a) { } bool socket_ipv6_is_supported(void) { - _cleanup_free_ char *l = NULL; - - if (access("/sys/module/ipv6", F_OK) != 0) + if (access("/proc/net/sockstat6", F_OK) != 0) return false; - /* If we can't check "disable" parameter, assume enabled */ - if (read_one_line_file("/sys/module/ipv6/parameters/disable", &l) < 0) - return true; - - /* If module was loaded with disable=1 no IPv6 available */ - return l[0] == '0'; + return true; } bool socket_address_matches_fd(const SocketAddress *a, int fd) { @@ -605,7 +599,7 @@ int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ return 0; } -int getpeername_pretty(int fd, char **ret) { +int getpeername_pretty(int fd, bool include_port, char **ret) { union sockaddr_union sa; socklen_t salen = sizeof(sa); int r; @@ -635,7 +629,7 @@ int getpeername_pretty(int fd, char **ret) { /* For remote sockets we translate IPv6 addresses back to IPv4 * if applicable, since that's nicer. */ - return sockaddr_pretty(&sa.sa, salen, true, true, ret); + return sockaddr_pretty(&sa.sa, salen, true, include_port, ret); } int getsockname_pretty(int fd, char **ret) { @@ -867,12 +861,19 @@ int getpeersec(int fd, char **ret) { return 0; } -int send_one_fd(int transport_fd, int fd, int flags) { +int send_one_fd_sa( + int transport_fd, + int fd, + const struct sockaddr *sa, socklen_t len, + int flags) { + union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(int))]; } control = {}; struct msghdr mh = { + .msg_name = (struct sockaddr*) sa, + .msg_namelen = len, .msg_control = &control, .msg_controllen = sizeof(control), }; diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index c60f2556a..92edc1dc2 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,9 +19,12 @@ along with systemd; If not, see . ***/ -#include -#include #include +#include +#include +#include +#include +#include #include #include #include @@ -86,7 +87,7 @@ int socket_address_listen( mode_t directory_mode, mode_t socket_mode, const char *label); -int make_socket_fd(int log_level, const char* address, int flags); +int make_socket_fd(int log_level, const char* address, int type, int flags); bool socket_address_is(const SocketAddress *a, const char *s, int type); bool socket_address_is_netlink(const SocketAddress *a, const char *s); @@ -102,7 +103,7 @@ bool socket_ipv6_is_supported(void); int sockaddr_port(const struct sockaddr *_sa) _pure_; int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret); -int getpeername_pretty(int fd, char **ret); +int getpeername_pretty(int fd, bool include_port, char **ret); int getsockname_pretty(int fd, char **ret); int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret); @@ -125,7 +126,11 @@ int ip_tos_from_string(const char *s); int getpeercred(int fd, struct ucred *ucred); int getpeersec(int fd, char **ret); -int send_one_fd(int transport_fd, int fd, int flags); +int send_one_fd_sa(int transport_fd, + int fd, + const struct sockaddr *sa, socklen_t len, + int flags); +#define send_one_fd(transport_fd, fd, flags) send_one_fd_sa(transport_fd, fd, NULL, 0, flags) int receive_one_fd(int transport_fd, int flags); #define CMSG_FOREACH(cmsg, mh) \ diff --git a/src/basic/special.h b/src/basic/special.h index f30458f25..2fd03d9f7 100644 --- a/src/basic/special.h +++ b/src/basic/special.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 3bc66b3be..309e84b93 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,11 @@ along with systemd; If not, see . ***/ +#include +#include #include +#include +#include #include #include #include diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index 909b220a2..56d28f791 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,7 +20,9 @@ ***/ #include +#include #include +#include #include #include @@ -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/stdio-util.h b/src/basic/stdio-util.h index b36e8a947..0a675571f 100644 --- a/src/basic/stdio-util.h +++ b/src/basic/stdio-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index f4f702a05..77220c025 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,12 +17,12 @@ along with systemd; If not, see . ***/ +#include #include #include #include "alloc-util.h" #include "strbuf.h" -#include "util.h" /* * Strbuf stores given strings in a single continuous allocated memory diff --git a/src/basic/strbuf.h b/src/basic/strbuf.h index fbc4e5f2a..a1632da0e 100644 --- a/src/basic/strbuf.h +++ b/src/basic/strbuf.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,7 +19,9 @@ along with systemd; If not, see . ***/ +#include #include +#include struct strbuf { char *buf; diff --git a/src/basic/string-table.c b/src/basic/string-table.c index a860324fc..a1499ab12 100644 --- a/src/basic/string-table.c +++ b/src/basic/string-table.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,6 +18,7 @@ ***/ #include "string-table.h" +#include "string-util.h" ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { size_t i; diff --git a/src/basic/string-table.h b/src/basic/string-table.h index 51b600721..b180488fe 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -1,6 +1,4 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ along with systemd; If not, see . ***/ +#include #include #include #include @@ -46,16 +45,34 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ } +#define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ + scope type name##_from_string(const char *s) { \ + int b; \ + b = parse_boolean(s); \ + if (b == 0) \ + return (type) 0; \ + else if (b > 0) \ + return yes; \ + return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ + } + #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,scope) \ struct __useless_struct_to_allow_trailing_semicolon__ +#define _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ + struct __useless_struct_to_allow_trailing_semicolon__ + #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) +#define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) + /* For string conversions where numbers are also acceptable */ #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ int name##_to_string_alloc(type i, char **str) { \ diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 6006767da..0bde55f9d 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,8 +17,15 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include + #include "alloc-util.h" #include "gunicode.h" +#include "macro.h" #include "string-util.h" #include "utf8.h" #include "util.h" @@ -310,18 +315,67 @@ char *truncate_nl(char *s) { return s; } +char ascii_tolower(char x) { + + if (x >= 'A' && x <= 'Z') + return x - 'A' + 'a'; + + return x; +} + char *ascii_strlower(char *t) { char *p; assert(t); for (p = t; *p; p++) - if (*p >= 'A' && *p <= 'Z') - *p = *p - 'A' + 'a'; + *p = ascii_tolower(*p); return t; } +char *ascii_strlower_n(char *t, size_t n) { + size_t i; + + if (n <= 0) + return t; + + for (i = 0; i < n; i++) + t[i] = ascii_tolower(t[i]); + + return t; +} + +int ascii_strcasecmp_n(const char *a, const char *b, size_t n) { + + for (; n > 0; a++, b++, n--) { + int x, y; + + x = (int) (uint8_t) ascii_tolower(*a); + y = (int) (uint8_t) ascii_tolower(*b); + + if (x != y) + return x - y; + } + + return 0; +} + +int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m) { + int r; + + r = ascii_strcasecmp_n(a, b, MIN(n, m)); + if (r != 0) + return r; + + if (n < m) + return -1; + else if (n > m) + return 1; + else + return 0; +} + bool chars_intersect(const char *a, const char *b) { const char *p; @@ -394,6 +448,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne char *e; const char *i, *j; unsigned k, len, len2; + int r; assert(s); assert(percent <= 100); @@ -413,10 +468,10 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne k = 0; for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) { - int c; + char32_t c; - c = utf8_encoded_to_unichar(i); - if (c < 0) + r = utf8_encoded_to_unichar(i, &c); + if (r < 0) return NULL; k += unichar_iswide(c) ? 2 : 1; } @@ -425,11 +480,11 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne x ++; for (j = s + old_length; k < new_length && j > i; ) { - int c; + char32_t c; j = utf8_prev_char(j); - c = utf8_encoded_to_unichar(j); - if (c < 0) + r = utf8_encoded_to_unichar(j, &c); + if (r < 0) return NULL; k += unichar_iswide(c) ? 2 : 1; } diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 54f9d3058..ad0c81376 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,7 +19,9 @@ along with systemd; If not, see . ***/ +#include #include +#include #include #include "macro.h" @@ -128,7 +128,12 @@ char *strstrip(char *s); char *delete_chars(char *s, const char *bad); char *truncate_nl(char *s); -char *ascii_strlower(char *path); +char ascii_tolower(char x); +char *ascii_strlower(char *s); +char *ascii_strlower_n(char *s, size_t n); + +int ascii_strcasecmp_n(const char *a, const char *b, size_t n); +int ascii_strcasecmp_nn(const char *a, size_t n, const char *b, size_t m); bool chars_intersect(const char *a, const char *b) _pure_; diff --git a/src/basic/strv.c b/src/basic/strv.c index 771781f9f..b5d4d8191 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,12 +18,16 @@ ***/ #include +#include #include +#include #include #include #include "alloc-util.h" #include "escape.h" +#include "extract-word.h" +#include "fileio.h" #include "string-util.h" #include "strv.h" #include "util.h" @@ -868,3 +870,22 @@ rollback: nl[k] = NULL; return -ENOMEM; } + +int fputstrv(FILE *f, char **l, const char *separator, bool *space) { + bool b = false; + char **s; + int r; + + /* Like fputs(), but for strv, and with a less stupid argument order */ + + if (!space) + space = &b; + + STRV_FOREACH(s, l) { + r = fputs_with_space(f, *s, separator, space); + if (r < 0) + return r; + } + + return 0; +} diff --git a/src/basic/strv.h b/src/basic/strv.h index e66794fc3..7bfa54408 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,8 +22,11 @@ #include #include #include +#include +#include "alloc-util.h" #include "extract-word.h" +#include "macro.h" #include "util.h" char *strv_find(char **l, const char *name) _pure_; @@ -166,3 +167,5 @@ char ***strv_free_free(char ***l); char **strv_skip(char **l, size_t n); int strv_extend_n(char ***l, const char *value, size_t n); + +int fputstrv(FILE *f, char **l, const char *separator, bool *space); diff --git a/src/basic/strxcpyx.c b/src/basic/strxcpyx.c index 088ba53c2..aaf11d21f 100644 --- a/src/basic/strxcpyx.c +++ b/src/basic/strxcpyx.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -25,6 +23,7 @@ * Returns the * remaining size, and 0 if the string was truncated. */ +#include #include #include diff --git a/src/basic/strxcpyx.h b/src/basic/strxcpyx.h index ccc7e52f3..80ff58726 100644 --- a/src/basic/strxcpyx.h +++ b/src/basic/strxcpyx.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,8 @@ ***/ +#include + #include "macro.h" size_t strpcpy(char **dest, size_t size, const char *src); diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c index 01577941a..db3405154 100644 --- a/src/basic/syslog-util.c +++ b/src/basic/syslog-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,10 +17,11 @@ along with systemd; If not, see . ***/ +#include #include -#include "assert.h" #include "hexdecoct.h" +#include "macro.h" #include "string-table.h" #include "syslog-util.h" diff --git a/src/basic/syslog-util.h b/src/basic/syslog-util.h index eb79c6dbd..5cb606a1b 100644 --- a/src/basic/syslog-util.h +++ b/src/basic/syslog-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 3931b03bc..0a9d2bbde 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -17,18 +17,25 @@ along with systemd; If not, see . ***/ -#include +#include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #include #include -#include #include #include -#include #include #include "alloc-util.h" @@ -36,8 +43,9 @@ #include "fileio.h" #include "fs-util.h" #include "io-util.h" +#include "log.h" +#include "macro.h" #include "parse-util.h" -#include "path-util.h" #include "process-util.h" #include "socket-util.h" #include "stat-util.h" @@ -120,7 +128,7 @@ int read_one_char(FILE *f, char *ret, usec_t t, bool *need_nl) { errno = 0; if (!fgets(line, sizeof(line), f)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; truncate_nl(line); @@ -204,7 +212,7 @@ int ask_string(char **ret, const char *text, ...) { errno = 0; if (!fgets(line, sizeof(line), stdin)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; if (!endswith(line, "\n")) putchar('\n'); @@ -718,9 +726,7 @@ bool tty_is_vc_resolve(const char *tty) { } const char *default_term_for_tty(const char *tty) { - assert(tty); - - return tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220"; + return tty && tty_is_vc_resolve(tty) ? "TERM=linux" : "TERM=vt220"; } int fd_columns(int fd) { @@ -1127,3 +1133,16 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { return receive_one_fd(pair[0], 0); } + +bool colors_enabled(void) { + const char *colors; + + colors = getenv("SYSTEMD_COLORS"); + if (!colors) { + if (streq_ptr(getenv("TERM"), "dumb")) + return false; + return on_tty(); + } + + return parse_boolean(colors) != 0; +} diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index f2185c1c1..a7c96a77c 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -19,9 +19,10 @@ along with systemd; If not, see . ***/ -#include #include +#include #include +#include #include "macro.h" #include "time-util.h" @@ -78,37 +79,38 @@ unsigned lines(void); void columns_lines_cache_reset(int _unused_ signum); bool on_tty(void); +bool colors_enabled(void); static inline const char *ansi_underline(void) { - return on_tty() ? ANSI_UNDERLINE : ""; + return colors_enabled() ? ANSI_UNDERLINE : ""; } static inline const char *ansi_highlight(void) { - return on_tty() ? ANSI_HIGHLIGHT : ""; + return colors_enabled() ? ANSI_HIGHLIGHT : ""; } static inline const char *ansi_highlight_underline(void) { - return on_tty() ? ANSI_HIGHLIGHT_UNDERLINE : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_UNDERLINE : ""; } static inline const char *ansi_highlight_red(void) { - return on_tty() ? ANSI_HIGHLIGHT_RED : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_RED : ""; } static inline const char *ansi_highlight_green(void) { - return on_tty() ? ANSI_HIGHLIGHT_GREEN : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_GREEN : ""; } static inline const char *ansi_highlight_yellow(void) { - return on_tty() ? ANSI_HIGHLIGHT_YELLOW : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_YELLOW : ""; } static inline const char *ansi_highlight_blue(void) { - return on_tty() ? ANSI_HIGHLIGHT_BLUE : ""; + return colors_enabled() ? ANSI_HIGHLIGHT_BLUE : ""; } static inline const char *ansi_normal(void) { - return on_tty() ? ANSI_NORMAL : ""; + return colors_enabled() ? ANSI_NORMAL : ""; } int get_ctty_devnr(pid_t pid, dev_t *d); diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 647763a23..3973850b4 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,19 +17,30 @@ along with systemd; If not, see . ***/ +#include +#include +#include #include +#include +#include #include #include +#include +#include #include "alloc-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "log.h" +#include "macro.h" +#include "parse-util.h" #include "path-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" -#include "util.h" + +static nsec_t timespec_load_nsec(const struct timespec *ts); usec_t now(clockid_t clock_id) { struct timespec ts; @@ -70,12 +79,7 @@ dual_timestamp* dual_timestamp_from_realtime(dual_timestamp *ts, usec_t u) { ts->realtime = u; delta = (int64_t) now(CLOCK_REALTIME) - (int64_t) u; - ts->monotonic = now(CLOCK_MONOTONIC); - - if ((int64_t) ts->monotonic > delta) - ts->monotonic -= delta; - else - ts->monotonic = 0; + ts->monotonic = usec_sub(now(CLOCK_MONOTONIC), delta); return ts; } @@ -91,12 +95,7 @@ dual_timestamp* dual_timestamp_from_monotonic(dual_timestamp *ts, usec_t u) { ts->monotonic = u; delta = (int64_t) now(CLOCK_MONOTONIC) - (int64_t) u; - - ts->realtime = now(CLOCK_REALTIME); - if ((int64_t) ts->realtime > delta) - ts->realtime -= delta; - else - ts->realtime = 0; + ts->realtime = usec_sub(now(CLOCK_REALTIME), delta); return ts; } @@ -108,25 +107,15 @@ dual_timestamp* dual_timestamp_from_boottime_or_monotonic(dual_timestamp *ts, us ts->realtime = ts->monotonic = USEC_INFINITY; return ts; } - ts->realtime = now(CLOCK_REALTIME); - ts->monotonic = now(CLOCK_MONOTONIC); + dual_timestamp_get(ts); delta = (int64_t) now(clock_boottime_or_monotonic()) - (int64_t) u; - - if ((int64_t) ts->realtime > delta) - ts->realtime -= delta; - else - ts->realtime = 0; - - if ((int64_t) ts->monotonic > delta) - ts->monotonic -= delta; - else - ts->monotonic = 0; + ts->realtime = usec_sub(ts->realtime, delta); + ts->monotonic = usec_sub(ts->monotonic, delta); return ts; } - usec_t timespec_load(const struct timespec *ts) { assert(ts); @@ -142,7 +131,7 @@ usec_t timespec_load(const struct timespec *ts) { (usec_t) ts->tv_nsec / NSEC_PER_USEC; } -nsec_t timespec_load_nsec(const struct timespec *ts) { +static nsec_t timespec_load_nsec(const struct timespec *ts) { assert(ts); if (ts->tv_sec == (time_t) -1 && @@ -198,9 +187,11 @@ struct timeval *timeval_store(struct timeval *tv, usec_t u) { return tv; } -static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) { +static char *format_timestamp_internal(char *buf, size_t l, usec_t t, + bool utc, bool us) { struct tm tm; time_t sec; + int k; assert(buf); assert(l > 0); @@ -211,48 +202,36 @@ static char *format_timestamp_internal(char *buf, size_t l, usec_t t, bool utc) sec = (time_t) (t / USEC_PER_SEC); localtime_or_gmtime_r(&sec, &tm, utc); - if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm) <= 0) + if (us) + k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm); + else + k = strftime(buf, l, "%a %Y-%m-%d %H:%M:%S %Z", &tm); + + if (k <= 0) return NULL; + if (us) { + snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC)); + if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0) + return NULL; + } return buf; } char *format_timestamp(char *buf, size_t l, usec_t t) { - return format_timestamp_internal(buf, l, t, false); + return format_timestamp_internal(buf, l, t, false, false); } char *format_timestamp_utc(char *buf, size_t l, usec_t t) { - return format_timestamp_internal(buf, l, t, true); -} - -static char *format_timestamp_internal_us(char *buf, size_t l, usec_t t, bool utc) { - struct tm tm; - time_t sec; - - assert(buf); - assert(l > 0); - - if (t <= 0 || t == USEC_INFINITY) - return NULL; - - sec = (time_t) (t / USEC_PER_SEC); - localtime_or_gmtime_r(&sec, &tm, utc); - - if (strftime(buf, l, "%a %Y-%m-%d %H:%M:%S", &tm) <= 0) - return NULL; - snprintf(buf + strlen(buf), l - strlen(buf), ".%06llu", (unsigned long long) (t % USEC_PER_SEC)); - if (strftime(buf + strlen(buf), l - strlen(buf), " %Z", &tm) <= 0) - return NULL; - - return buf; + return format_timestamp_internal(buf, l, t, true, false); } char *format_timestamp_us(char *buf, size_t l, usec_t t) { - return format_timestamp_internal_us(buf, l, t, false); + return format_timestamp_internal(buf, l, t, false, true); } char *format_timestamp_us_utc(char *buf, size_t l, usec_t t) { - return format_timestamp_internal_us(buf, l, t, true); + return format_timestamp_internal(buf, l, t, true, true); } char *format_timestamp_relative(char *buf, size_t l, usec_t t) { @@ -658,29 +637,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; + x_usec = add; - /* val has l digits, make them 6 */ - for (; l < 6; l++) - val *= 10; - for (; l > 6; l--) - val /= 10; - - x_usec = val; } from_tm: diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 0417c29cd..9894e626c 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,9 @@ ***/ #include +#include +#include +#include #include #include @@ -66,7 +67,7 @@ typedef struct dual_timestamp { #define FORMAT_TIMESTAMP_RELATIVE_MAX 256 #define FORMAT_TIMESPAN_MAX 64 -#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) +#define TIME_T_MAX (time_t)((UINTMAX_C(1) << ((sizeof(time_t) << 3) - 1)) - 1) #define DUAL_TIMESTAMP_NULL ((struct dual_timestamp) { 0ULL, 0ULL }) @@ -89,8 +90,6 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u); usec_t timeval_load(const struct timeval *tv) _pure_; struct timeval *timeval_store(struct timeval *tv, usec_t u); -nsec_t timespec_load_nsec(const struct timespec *ts) _pure_; - char *format_timestamp(char *buf, size_t l, usec_t t); char *format_timestamp_utc(char *buf, size_t l, usec_t t); char *format_timestamp_us(char *buf, size_t l, usec_t t); @@ -124,3 +123,29 @@ time_t mktime_or_timegm(struct tm *tm, bool utc); struct tm *localtime_or_gmtime_r(const time_t *t, struct tm *tm, bool utc); unsigned long usec_to_jiffies(usec_t usec); + +static inline usec_t usec_add(usec_t a, usec_t b) { + usec_t c; + + /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, and doesn't + * overflow. */ + + c = a + b; + if (c < a || c < b) /* overflow check */ + return USEC_INFINITY; + + return c; +} + +static inline usec_t usec_sub(usec_t timestamp, int64_t delta) { + if (delta < 0) + return usec_add(timestamp, (usec_t) (-delta)); + + if (timestamp == USEC_INFINITY) /* Make sure infinity doesn't degrade */ + return USEC_INFINITY; + + if (timestamp < (usec_t) delta) + return 0; + + return timestamp - delta; +} diff --git a/src/basic/umask-util.h b/src/basic/umask-util.h index 8ed34658b..359d87d27 100644 --- a/src/basic/umask-util.h +++ b/src/basic/umask-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/unaligned.h b/src/basic/unaligned.h index a8115eaa1..79be645be 100644 --- a/src/basic/unaligned.h +++ b/src/basic/unaligned.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index 9a55eacbf..fe883b95c 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,23 +18,38 @@ ***/ #include +#include +#include +#include #include #include "alloc-util.h" #include "bus-label.h" -#include "def.h" +#include "glob-util.h" #include "hexdecoct.h" +#include "macro.h" #include "path-util.h" #include "string-table.h" #include "string-util.h" #include "strv.h" #include "unit-name.h" -#include "util.h" +/* Characters valid in a unit name. */ #define VALID_CHARS \ - DIGITS LETTERS \ + DIGITS \ + LETTERS \ ":-_.\\" +/* The same, but also permits the single @ character that may appear */ +#define VALID_CHARS_WITH_AT \ + "@" \ + VALID_CHARS + +/* All chars valid in a unit name glob */ +#define VALID_CHARS_GLOB \ + VALID_CHARS_WITH_AT \ + "[]!-*?" + bool unit_name_is_valid(const char *n, UnitNameFlags flags) { const char *e, *i, *at; @@ -635,7 +648,7 @@ static char *do_escape_mangle(const char *f, UnitNameMangle allow_globs, char *t /* We'll only escape the obvious characters here, to play * safe. */ - valid_chars = allow_globs == UNIT_NAME_GLOB ? "@" VALID_CHARS "[]!-*?" : "@" VALID_CHARS; + valid_chars = allow_globs == UNIT_NAME_GLOB ? VALID_CHARS_GLOB : VALID_CHARS_WITH_AT; for (; *f; f++) { if (*f == '/') @@ -670,15 +683,15 @@ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, c if (!unit_suffix_is_valid(suffix)) return -EINVAL; - if (unit_name_is_valid(name, UNIT_NAME_ANY)) { - /* No mangling necessary... */ - s = strdup(name); - if (!s) - return -ENOMEM; + /* Already a fully valid unit name? If so, no mangling is necessary... */ + if (unit_name_is_valid(name, UNIT_NAME_ANY)) + goto good; - *ret = s; - return 0; - } + /* Already a fully valid globbing expression? If so, no mangling is necessary either... */ + if (allow_globs == UNIT_NAME_GLOB && + string_is_glob(name) && + in_charset(name, VALID_CHARS_GLOB)) + goto good; if (is_device_path(name)) { r = unit_name_from_path(name, ".device", ret); @@ -703,11 +716,21 @@ int unit_name_mangle_with_suffix(const char *name, UnitNameMangle allow_globs, c t = do_escape_mangle(name, allow_globs, s); *t = 0; - if (unit_name_to_type(s) < 0) + /* Append a suffix if it doesn't have any, but only if this is not a glob, so that we can allow "foo.*" as a + * valid glob. */ + if ((allow_globs != UNIT_NAME_GLOB || !string_is_glob(s)) && unit_name_to_type(s) < 0) strcpy(t, suffix); *ret = s; return 1; + +good: + s = strdup(name); + if (!s) + return -ENOMEM; + + *ret = s; + return 0; } int slice_build_parent_slice(const char *slice, char **ret) { diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index 03c1a6e4a..f209a8463 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 397880b0b..19155bce5 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,17 +17,27 @@ along with systemd; If not, see . ***/ +#include +#include +#include #include #include +#include +#include +#include +#include +#include +#include +#include #include "alloc-util.h" #include "fd-util.h" +#include "formats-util.h" #include "macro.h" #include "parse-util.h" #include "path-util.h" #include "string-util.h" #include "user-util.h" -#include "util.h" bool uid_is_valid(uid_t uid) { @@ -58,7 +66,7 @@ int parse_uid(const char *s, uid_t *ret) { if (!uid_is_valid(uid)) return -ENXIO; /* we return ENXIO instead of EINVAL * here, to make it easy to distuingish - * invalid numeric uids invalid + * invalid numeric uids from invalid * strings. */ if (ret) diff --git a/src/basic/user-util.h b/src/basic/user-util.h index 11ff6674c..c23f1d485 100644 --- a/src/basic/user-util.h +++ b/src/basic/user-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#include #include +#include bool uid_is_valid(uid_t uid); diff --git a/src/basic/utf8.c b/src/basic/utf8.c index b4063a4ce..629db123c 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -44,17 +42,16 @@ */ #include -#include #include #include #include #include "alloc-util.h" #include "hexdecoct.h" +#include "macro.h" #include "utf8.h" -#include "util.h" -bool unichar_is_valid(uint32_t ch) { +bool unichar_is_valid(char32_t ch) { if (ch >= 0x110000) /* End of unicode space */ return false; @@ -68,7 +65,7 @@ bool unichar_is_valid(uint32_t ch) { return true; } -static bool unichar_is_control(uint32_t ch) { +static bool unichar_is_control(char32_t ch) { /* 0 to ' '-1 is the C0 range. @@ -104,8 +101,9 @@ static int utf8_encoded_expected_len(const char *str) { } /* decode one unicode char */ -int utf8_encoded_to_unichar(const char *str) { - int unichar, len, i; +int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) { + char32_t unichar; + int len, i; assert(str); @@ -113,34 +111,37 @@ int utf8_encoded_to_unichar(const char *str) { switch (len) { case 1: - return (int)str[0]; + *ret_unichar = (char32_t)str[0]; + return 0; case 2: unichar = str[0] & 0x1f; break; case 3: - unichar = (int)str[0] & 0x0f; + unichar = (char32_t)str[0] & 0x0f; break; case 4: - unichar = (int)str[0] & 0x07; + unichar = (char32_t)str[0] & 0x07; break; case 5: - unichar = (int)str[0] & 0x03; + unichar = (char32_t)str[0] & 0x03; break; case 6: - unichar = (int)str[0] & 0x01; + unichar = (char32_t)str[0] & 0x01; break; default: return -EINVAL; } for (i = 1; i < len; i++) { - if (((int)str[i] & 0xc0) != 0x80) + if (((char32_t)str[i] & 0xc0) != 0x80) return -EINVAL; unichar <<= 6; - unichar |= (int)str[i] & 0x3f; + unichar |= (char32_t)str[i] & 0x3f; } - return unichar; + *ret_unichar = unichar; + + return 0; } bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { @@ -149,15 +150,16 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) { assert(str); for (p = str; length;) { - int encoded_len, val; + int encoded_len, r; + char32_t val; encoded_len = utf8_encoded_valid_unichar(p); if (encoded_len < 0 || (size_t) encoded_len > length) return false; - val = utf8_encoded_to_unichar(p); - if (val < 0 || + r = utf8_encoded_to_unichar(p, &val); + if (r < 0 || unichar_is_control(val) || (!newline && val == '\n')) return false; @@ -277,7 +279,7 @@ char *ascii_is_valid(const char *str) { * Returns: The length in bytes that the UTF-8 representation does or would * occupy. */ -size_t utf8_encode_unichar(char *out_utf8, uint32_t g) { +size_t utf8_encode_unichar(char *out_utf8, char32_t g) { if (g < (1 << 7)) { if (out_utf8) @@ -321,7 +323,7 @@ char *utf16_to_utf8(const void *s, size_t length) { t = r; while (f < (const uint8_t*) s + length) { - uint16_t w1, w2; + char16_t w1, w2; /* see RFC 2781 section 2.2 */ @@ -355,7 +357,7 @@ char *utf16_to_utf8(const void *s, size_t length) { } /* expected size used to encode one unicode char */ -static int utf8_unichar_to_encoded_len(int unichar) { +static int utf8_unichar_to_encoded_len(char32_t unichar) { if (unichar < 0x80) return 1; @@ -373,7 +375,8 @@ static int utf8_unichar_to_encoded_len(int unichar) { /* validate one encoded unicode char and return its length */ int utf8_encoded_valid_unichar(const char *str) { - int len, unichar, i; + int len, i, r; + char32_t unichar; assert(str); @@ -390,7 +393,9 @@ int utf8_encoded_valid_unichar(const char *str) { if ((str[i] & 0x80) != 0x80) return -EINVAL; - unichar = utf8_encoded_to_unichar(str); + r = utf8_encoded_to_unichar(str, &unichar); + if (r < 0) + return r; /* check if encoded length matches encoded value */ if (utf8_unichar_to_encoded_len(unichar) != len) diff --git a/src/basic/utf8.h b/src/basic/utf8.h index e745649f0..12c272d66 100644 --- a/src/basic/utf8.h +++ b/src/basic/utf8.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,12 +20,16 @@ ***/ #include +#include +#include +#include #include "macro.h" +#include "missing.h" #define UTF8_REPLACEMENT_CHARACTER "\xef\xbf\xbd" -bool unichar_is_valid(uint32_t c); +bool unichar_is_valid(char32_t c); const char *utf8_is_valid(const char *s) _pure_; char *ascii_is_valid(const char *s) _pure_; @@ -38,20 +40,20 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) _pu char *utf8_escape_invalid(const char *s); char *utf8_escape_non_printable(const char *str); -size_t utf8_encode_unichar(char *out_utf8, uint32_t g); +size_t utf8_encode_unichar(char *out_utf8, char32_t g); char *utf16_to_utf8(const void *s, size_t length); int utf8_encoded_valid_unichar(const char *str); -int utf8_encoded_to_unichar(const char *str); +int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar); -static inline bool utf16_is_surrogate(uint16_t c) { +static inline bool utf16_is_surrogate(char16_t c) { return (0xd800 <= c && c <= 0xdfff); } -static inline bool utf16_is_trailing_surrogate(uint16_t c) { +static inline bool utf16_is_trailing_surrogate(char16_t c) { return (0xdc00 <= c && c <= 0xdfff); } -static inline uint32_t utf16_surrogate_pair_to_unichar(uint16_t lead, uint16_t trail) { +static inline char32_t utf16_surrogate_pair_to_unichar(char16_t lead, char16_t trail) { return ((lead - 0xd800) << 10) + (trail - 0xdc00) + 0x10000; } diff --git a/src/basic/util.c b/src/basic/util.c index 58617b354..ea1bed7ce 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,91 +17,46 @@ along with systemd; If not, see . ***/ -#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include #include #include #include -#include -#include #include -#include -#include #include -#include -#include -#include +#include +#include #include -#include -#include -#include -#include #include -/* 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 -#undef basename - -#ifdef HAVE_SYS_AUXV_H -#include -#endif - -/* We include linux/fs.h as last of the system headers, as it - * otherwise conflicts with sys/mount.h. Yay, Linux is great! */ -#include - #include "alloc-util.h" #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" #include "fd-util.h" #include "fileio.h" #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 "parse-util.h" #include "path-util.h" #include "process-util.h" -#include "random-util.h" +#include "set.h" #include "signal-util.h" -#include "sparse-endian.h" #include "stat-util.h" -#include "string-table.h" #include "string-util.h" #include "strv.h" -#include "terminal-util.h" +#include "time-util.h" #include "user-util.h" -#include "utf8.h" #include "util.h" -#include "virt.h" /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); @@ -558,7 +511,7 @@ int on_ac_power(void) { errno = 0; de = readdir(d); - if (!de && errno != 0) + if (!de && errno > 0) return -errno; if (!de) diff --git a/src/basic/util.h b/src/basic/util.h index d9d2f72b7..6f42c85a3 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include +#include #include #include #include @@ -29,8 +28,10 @@ #include #include #include +#include #include #include +#include #include #include #include diff --git a/src/basic/verbs.c b/src/basic/verbs.c index d63062d39..d9cdb38d6 100644 --- a/src/basic/verbs.c +++ b/src/basic/verbs.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,16 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include + +#include "log.h" +#include "macro.h" #include "string-util.h" -#include "util.h" #include "verbs.h" +#include "virt.h" int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) { const Verb *verb; @@ -78,6 +83,11 @@ int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) { return -EINVAL; } + if ((verb->flags & VERB_NOCHROOT) && running_in_chroot() > 0) { + log_info("Running in chroot, ignoring request."); + return 0; + } + if (name) return verb->dispatch(left, argv + optind, userdata); else { diff --git a/src/basic/verbs.h b/src/basic/verbs.h index d59e4d59b..7b5e18510 100644 --- a/src/basic/verbs.h +++ b/src/basic/verbs.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,7 +20,8 @@ ***/ #define VERB_ANY ((unsigned) -1) -#define VERB_DEFAULT 1 +#define VERB_DEFAULT 1U +#define VERB_NOCHROOT 2U typedef struct { const char *verb; diff --git a/src/basic/virt.c b/src/basic/virt.c index 1e5d6eea6..19b6318e3 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,6 +18,8 @@ ***/ #include +#include +#include #include #include @@ -27,11 +27,11 @@ #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" +#include "macro.h" #include "process-util.h" #include "stat-util.h" #include "string-table.h" #include "string-util.h" -#include "util.h" #include "virt.h" static int detect_vm_cpuid(void) { @@ -269,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/basic/virt.h b/src/basic/virt.h index aca961867..a538f07f6 100644 --- a/src/basic/virt.h +++ b/src/basic/virt.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/web-util.c b/src/basic/web-util.c index 68ec04021..595688ed9 100644 --- a/src/basic/web-util.c +++ b/src/basic/web-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/basic/web-util.h b/src/basic/web-util.h index 40c1509eb..e6bb6b53f 100644 --- a/src/basic/web-util.h +++ b/src/basic/web-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index 6abdaedc3..8d7f14f38 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,13 +17,20 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include #include #include "alloc-util.h" #include "fd-util.h" +#include "macro.h" #include "sparse-endian.h" #include "stdio-util.h" -#include "util.h" +#include "time-util.h" #include "xattr-util.h" int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) { diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h index cf4cb12a2..6fa097bf7 100644 --- a/src/basic/xattr-util.h +++ b/src/basic/xattr-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include +#include #include #include "time-util.h" diff --git a/src/basic/xml.c b/src/basic/xml.c index 8126bce21..1dbeac732 100644 --- a/src/basic/xml.c +++ b/src/basic/xml.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,10 +17,12 @@ along with systemd; If not, see . ***/ +#include +#include #include +#include "macro.h" #include "string-util.h" -#include "util.h" #include "xml.h" enum { diff --git a/src/basic/xml.h b/src/basic/xml.h index b256b0ba1..41cb69f0d 100644 --- a/src/basic/xml.h +++ b/src/basic/xml.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index 03fb413fe..eeef04fb1 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 4cf42d17f..e9baf69f6 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -39,6 +37,7 @@ #include "alloc-util.h" #include "blkid-util.h" +#include "dirent-util.h" #include "efivars.h" #include "fd-util.h" #include "fileio.h" @@ -249,13 +248,10 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char return log_error_errno(errno, "Failed to read \"%s\": %m", p); } - while ((de = readdir(d))) { + FOREACH_DIRENT(de, d, break) { _cleanup_close_ int fd = -1; _cleanup_free_ char *v = NULL; - if (de->d_name[0] == '.') - continue; - if (!endswith_no_case(de->d_name, ".efi")) continue; @@ -270,9 +266,9 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char if (r < 0) return r; if (r > 0) - printf(" File: └─/%s/%s (%s)\n", path, de->d_name, v); + printf(" File: %s/%s/%s (%s)\n", draw_special_char(DRAW_TREE_RIGHT), path, de->d_name, v); else - printf(" File: └─/%s/%s\n", path, de->d_name); + printf(" File: %s/%s/%s\n", draw_special_char(DRAW_TREE_RIGHT), path, de->d_name); c++; } @@ -324,7 +320,7 @@ static int print_efi_option(uint16_t id, bool in_order) { printf(" ID: 0x%04X\n", id); printf(" Status: %sactive%s\n", active ? "" : "in", in_order ? ", boot-order" : ""); printf(" Partition: /dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", SD_ID128_FORMAT_VAL(partition)); - printf(" File: └─%s\n", path); + printf(" File: %s%s\n", draw_special_char(DRAW_TREE_RIGHT), path); printf("\n"); return 0; @@ -614,12 +610,9 @@ static int install_binaries(const char *esp_path, bool force) { if (!d) return log_error_errno(errno, "Failed to open \""BOOTLIBDIR"\": %m"); - while ((de = readdir(d))) { + FOREACH_DIRENT(de, d, break) { int k; - if (de->d_name[0] == '.') - continue; - if (!endswith_no_case(de->d_name, ".efi")) continue; @@ -797,13 +790,10 @@ static int remove_boot_efi(const char *esp_path) { return log_error_errno(errno, "Failed to open directory \"%s\": %m", p); } - while ((de = readdir(d))) { + FOREACH_DIRENT(de, d, break) { _cleanup_close_ int fd = -1; _cleanup_free_ char *v = NULL; - if (de->d_name[0] == '.') - continue; - if (!endswith_no_case(de->d_name, ".efi")) continue; diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 6d35adc0e..893980071 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c index 2151d3443..c436f8b47 100644 --- a/src/boot/efi/console.c +++ b/src/boot/efi/console.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/console.h b/src/boot/efi/console.h index 5c7808a06..3fe0ce5ec 100644 --- a/src/boot/efi/console.h +++ b/src/boot/efi/console.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/disk.c b/src/boot/efi/disk.c index 96063fbc2..3e3b5b224 100644 --- a/src/boot/efi/disk.c +++ b/src/boot/efi/disk.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/disk.h b/src/boot/efi/disk.h index 1b25343a0..af91a9c67 100644 --- a/src/boot/efi/disk.h +++ b/src/boot/efi/disk.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/graphics.c b/src/boot/efi/graphics.c index efa91fa7a..4854baf87 100644 --- a/src/boot/efi/graphics.c +++ b/src/boot/efi/graphics.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/graphics.h b/src/boot/efi/graphics.h index 3ee497279..cf48e647e 100644 --- a/src/boot/efi/graphics.h +++ b/src/boot/efi/graphics.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/linux.c b/src/boot/efi/linux.c index e9d097c13..0dc99a6c5 100644 --- a/src/boot/efi/linux.c +++ b/src/boot/efi/linux.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h index aff69a977..d9e6ed795 100644 --- a/src/boot/efi/linux.h +++ b/src/boot/efi/linux.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/pefile.c b/src/boot/efi/pefile.c index efb3271ee..77fff77b6 100644 --- a/src/boot/efi/pefile.c +++ b/src/boot/efi/pefile.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/pefile.h b/src/boot/efi/pefile.h index ca2f9a250..2e445ede1 100644 --- a/src/boot/efi/pefile.h +++ b/src/boot/efi/pefile.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c index b584b5e6a..b1cc2c0b7 100644 --- a/src/boot/efi/splash.c +++ b/src/boot/efi/splash.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/splash.h b/src/boot/efi/splash.h index 0183e79b1..09b543fb4 100644 --- a/src/boot/efi/splash.h +++ b/src/boot/efi/splash.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index 2cd5c33cb..9633bc179 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* This program 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 diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index 5e374edac..98c5be74c 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 4727a34d1..e673cdf9a 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by diff --git a/src/bootchart/bootchart.c b/src/bootchart/bootchart.c index 6a0e1d6b1..77d158f5f 100644 --- a/src/bootchart/bootchart.c +++ b/src/bootchart/bootchart.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/bootchart/bootchart.h b/src/bootchart/bootchart.h index bdb4b0019..1b445b954 100644 --- a/src/bootchart/bootchart.h +++ b/src/bootchart/bootchart.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,6 +23,7 @@ ***/ #include + #include "list.h" #define MAXCPUS 16 diff --git a/src/bootchart/store.c b/src/bootchart/store.c index c1b1e77e4..42cb8043c 100644 --- a/src/bootchart/store.c +++ b/src/bootchart/store.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/bootchart/store.h b/src/bootchart/store.h index bbb4796ef..6e9acf2a6 100644 --- a/src/bootchart/store.h +++ b/src/bootchart/store.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,6 +23,7 @@ ***/ #include + #include "bootchart.h" double gettime_ns(void); diff --git a/src/bootchart/svg.c b/src/bootchart/svg.c index 2bf473ffc..f2af53506 100644 --- a/src/bootchart/svg.c +++ b/src/bootchart/svg.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -37,6 +35,7 @@ #include "fileio.h" #include "list.h" #include "macro.h" +#include "stdio-util.h" #include "store.h" #include "svg.h" #include "utf8.h" @@ -171,7 +170,7 @@ static int svg_title(FILE *of, const char *build, int pscount, double log_start, strncpy(rootbdev, &c[10], sizeof(rootbdev) - 1); rootbdev[3] = '\0'; - snprintf(filename, sizeof(filename), "/sys/block/%s/device/model", rootbdev); + xsprintf(filename, "/sys/block/%s/device/model", rootbdev); r = read_one_line_file(filename, &model); if (r < 0) diff --git a/src/bootchart/svg.h b/src/bootchart/svg.h index 75efa2261..6e06b5ad9 100644 --- a/src/bootchart/svg.h +++ b/src/bootchart/svg.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c index 6a7134644..b6bd6eb39 100644 --- a/src/bus-proxyd/bus-proxyd.c +++ b/src/bus-proxyd/bus-proxyd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/bus-proxyd/bus-xml-policy.c b/src/bus-proxyd/bus-xml-policy.c index debd58ce8..8943e0dc1 100644 --- a/src/bus-proxyd/bus-xml-policy.c +++ b/src/bus-proxyd/bus-xml-policy.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/bus-proxyd/bus-xml-policy.h b/src/bus-proxyd/bus-xml-policy.h index 8f0ab8f17..3dcddaa04 100644 --- a/src/bus-proxyd/bus-xml-policy.h +++ b/src/bus-proxyd/bus-xml-policy.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,8 +21,8 @@ #include -#include "list.h" #include "hashmap.h" +#include "list.h" typedef enum PolicyItemType { _POLICY_ITEM_TYPE_UNSET = 0, diff --git a/src/bus-proxyd/driver.c b/src/bus-proxyd/driver.c index 2e8bd83ef..1af5c310e 100644 --- a/src/bus-proxyd/driver.c +++ b/src/bus-proxyd/driver.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -40,7 +38,7 @@ #include "util.h" static int get_creds_by_name(sd_bus *bus, const char *name, uint64_t mask, sd_bus_creds **_creds, sd_bus_error *error) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; int r; assert(bus); @@ -75,7 +73,7 @@ static int get_creds_by_message(sd_bus *bus, sd_bus_message *m, uint64_t mask, s } static int driver_activation(sd_bus_message *reply, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; ProxyActivation *activation = userdata; /* @@ -239,9 +237,9 @@ int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, return synthetic_reply_method_return(m, NULL); } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionCredentials")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (!sd_bus_message_has_signature(m, "s")) return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); @@ -305,9 +303,9 @@ int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, return synthetic_driver_send(m->bus, reply); } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionSELinuxSecurityContext")) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (!sd_bus_message_has_signature(m, "s")) return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); @@ -330,8 +328,8 @@ int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, return synthetic_driver_send(m->bus, reply); } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixProcessID")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (!sd_bus_message_has_signature(m, "s")) return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); @@ -346,8 +344,8 @@ int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, return synthetic_reply_method_return(m, "u", (uint32_t) creds->pid); } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetConnectionUnixUser")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (!sd_bus_message_has_signature(m, "s")) return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); @@ -376,8 +374,8 @@ int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "GetNameOwner")) { const char *name; - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (!sd_bus_message_has_signature(m, "s")) return synthetic_reply_method_error(m, &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_INVALID_ARGS, "Invalid parameters")); @@ -439,7 +437,7 @@ int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, }; struct kdbus_info *name_list, *name; _cleanup_strv_free_ char **owners = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *arg0; int err = 0; @@ -610,7 +608,7 @@ int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, return synthetic_reply_method_return(m, "u", BUS_NAME_PRIMARY_OWNER); } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "StartServiceByName")) { - _cleanup_bus_message_unref_ sd_bus_message *msg = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *msg = NULL; ProxyActivation *activation; const char *name; uint64_t cookie; @@ -674,7 +672,7 @@ int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, return 1; } else if (sd_bus_message_is_method_call(m, "org.freedesktop.DBus", "UpdateActivationEnvironment")) { - _cleanup_bus_message_unref_ sd_bus_message *msg = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *msg = NULL; _cleanup_strv_free_ char **args = NULL; if (!sd_bus_message_has_signature(m, "a{ss}")) @@ -738,7 +736,7 @@ int bus_proxy_process_driver(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m, return synthetic_reply_method_return(m, NULL); } else { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; r = sd_bus_error_setf(&error, SD_BUS_ERROR_UNKNOWN_METHOD, "Unknown method '%s'.", m->member); diff --git a/src/bus-proxyd/driver.h b/src/bus-proxyd/driver.h index da3834f8b..1630cdc7b 100644 --- a/src/bus-proxyd/driver.h +++ b/src/bus-proxyd/driver.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include "sd-bus.h" + #include "bus-xml-policy.h" #include "proxy.h" diff --git a/src/bus-proxyd/proxy.c b/src/bus-proxyd/proxy.c index db399b24f..907d93d4c 100644 --- a/src/bus-proxyd/proxy.c +++ b/src/bus-proxyd/proxy.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -49,7 +47,7 @@ #include "util.h" static int proxy_create_destination(Proxy *p, const char *destination, const char *local_sec, bool negotiate_fds) { - _cleanup_bus_flush_close_unref_ sd_bus *b = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *b = NULL; int r; r = sd_bus_new(&b); @@ -491,7 +489,7 @@ static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, (void) sd_bus_creds_get_egid(&m->creds, &sender_gid); if (sender_uid == UID_INVALID || sender_gid == GID_INVALID) { - _cleanup_bus_creds_unref_ sd_bus_creds *sender_creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *sender_creds = NULL; /* If the message came from another legacy * client, then the message creds will be @@ -522,7 +520,7 @@ static int process_policy_unlocked(sd_bus *from, sd_bus *to, sd_bus_message *m, } if (to->is_kernel) { - _cleanup_bus_creds_unref_ sd_bus_creds *destination_creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *destination_creds = NULL; uid_t destination_uid = UID_INVALID; gid_t destination_gid = GID_INVALID; const char *destination_unique = NULL; @@ -609,7 +607,7 @@ static int process_policy(sd_bus *from, sd_bus *to, sd_bus_message *m, SharedPol } static int process_hello(Proxy *p, sd_bus_message *m) { - _cleanup_bus_message_unref_ sd_bus_message *n = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL; bool is_hello; int r; @@ -723,7 +721,7 @@ static int patch_sender(sd_bus *a, sd_bus_message *m) { } static int proxy_process_destination_to_local(Proxy *p) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; bool matched, matched_synthetic; int r; @@ -832,7 +830,7 @@ static int proxy_process_destination_to_local(Proxy *p) { } static int proxy_process_local_to_destination(Proxy *p) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(p); diff --git a/src/bus-proxyd/proxy.h b/src/bus-proxyd/proxy.h index 7b2e5d422..d9e75cf73 100644 --- a/src/bus-proxyd/proxy.h +++ b/src/bus-proxyd/proxy.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/bus-proxyd/stdio-bridge.c b/src/bus-proxyd/stdio-bridge.c index 2dc5fe631..291c1b09e 100644 --- a/src/bus-proxyd/stdio-bridge.c +++ b/src/bus-proxyd/stdio-bridge.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -146,7 +144,7 @@ static int parse_argv(int argc, char *argv[]) { } static int rename_service(sd_bus *a, sd_bus *b) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; _cleanup_free_ char *p = NULL, *name = NULL; const char *comm; char **cmdline; diff --git a/src/bus-proxyd/synthesize.c b/src/bus-proxyd/synthesize.c index 7f1f9dc28..8eea7dc5b 100644 --- a/src/bus-proxyd/synthesize.c +++ b/src/bus-proxyd/synthesize.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -50,7 +48,7 @@ int synthetic_driver_send(sd_bus *b, sd_bus_message *m) { } int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(call); @@ -66,7 +64,7 @@ int synthetic_reply_method_error(sd_bus_message *call, const sd_bus_error *e) { } int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; va_list ap; va_start(ap, format); @@ -77,7 +75,7 @@ int synthetic_reply_method_errorf(sd_bus_message *call, const char *name, const } int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_error *p) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; assert(call); @@ -93,7 +91,7 @@ int synthetic_reply_method_errno(sd_bus_message *call, int error, const sd_bus_e } int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; va_list ap; assert(call); @@ -109,7 +107,7 @@ int synthetic_reply_method_errnof(sd_bus_message *call, int error, const char *f } int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(call); @@ -135,7 +133,7 @@ int synthetic_reply_method_return(sd_bus_message *call, const char *types, ...) } int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(call); @@ -155,7 +153,7 @@ int synthetic_reply_method_return_strv(sd_bus_message *call, char **l) { } int synthesize_name_acquired(Proxy *p, sd_bus *a, sd_bus *b, sd_bus_message *m) { - _cleanup_bus_message_unref_ sd_bus_message *n = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL; const char *name, *old_owner, *new_owner; int r; diff --git a/src/bus-proxyd/synthesize.h b/src/bus-proxyd/synthesize.h index ddfe2fd26..1b7197f8e 100644 --- a/src/bus-proxyd/synthesize.h +++ b/src/bus-proxyd/synthesize.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/bus-proxyd/test-bus-xml-policy.c b/src/bus-proxyd/test-bus-xml-policy.c index 1f465edd9..af7c9128a 100644 --- a/src/bus-proxyd/test-bus-xml-policy.c +++ b/src/bus-proxyd/test-bus-xml-policy.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index 22efc58ac..b839fadd0 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -123,15 +121,17 @@ static int parse_argv(int argc, char *argv[]) { } static int get_cgroup_root(char **ret) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *unit = NULL, *path = NULL; const char *m; int r; if (!arg_machine) { r = cg_get_root_path(ret); - if (r < 0) + if (r == -ENOMEDIUM) + return log_error_errno(r, "Failed to get root control group path: No cgroup filesystem mounted on /sys/fs/cgroup"); + else if (r < 0) return log_error_errno(r, "Failed to get root control group path: %m"); return 0; diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c index e48234f07..aadfba070 100644 --- a/src/cgroups-agent/cgroups-agent.c +++ b/src/cgroups-agent/cgroups-agent.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -27,7 +25,7 @@ #include "log.h" int main(int argc, char *argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; if (argc != 2) { diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index eea8aea76..60d6da324 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -40,6 +38,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "stdio-util.h" #include "terminal-util.h" #include "unit-name.h" #include "util.h" @@ -565,9 +564,9 @@ static void display(Hashmap *a) { } if (arg_cpu_type == CPU_PERCENT) - snprintf(buffer, sizeof(buffer), "%6s", "%CPU"); + xsprintf(buffer, "%6s", "%CPU"); else - snprintf(buffer, sizeof(buffer), "%*s", maxtcpu, "CPU Time"); + xsprintf(buffer, "%*s", maxtcpu, "CPU Time"); rows = lines(); if (rows <= 10) @@ -841,8 +840,8 @@ static const char* counting_what(void) { } static int get_cgroup_root(char **ret) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *unit = NULL, *path = NULL; const char *m; int r; diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c index 0a484d89f..76afe3fe1 100644 --- a/src/core/audit-fd.c +++ b/src/core/audit-fd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/audit-fd.h b/src/core/audit-fd.h index 8b58289dc..0eccb5921 100644 --- a/src/core/audit-fd.h +++ b/src/core/audit-fd.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/automount.c b/src/core/automount.c index 85b7b4e84..5dc6fd98e 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -702,7 +700,7 @@ static int automount_start_expire(Automount *a) { } static void automount_enter_runnning(Automount *a) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; struct stat st; int r; @@ -728,7 +726,15 @@ static void automount_enter_runnning(Automount *a) { if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id) log_unit_info(UNIT(a), "Automount point already active?"); else { - r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, &error, NULL); + Unit *trigger; + + trigger = UNIT_TRIGGER(UNIT(a)); + if (!trigger) { + log_unit_error(UNIT(a), "Unit to trigger vanished."); + goto fail; + } + + r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL); if (r < 0) { log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r)); goto fail; @@ -744,6 +750,7 @@ fail: static int automount_start(Unit *u) { Automount *a = AUTOMOUNT(u); + Unit *trigger; assert(a); assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED); @@ -753,8 +760,11 @@ static int automount_start(Unit *u) { return -EEXIST; } - if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED) + trigger = UNIT_TRIGGER(u); + if (!trigger || trigger->load_state != UNIT_LOADED) { + log_unit_error(u, "Refusing to start, unit to trigger not loaded."); return -ENOENT; + } a->result = AUTOMOUNT_SUCCESS; automount_enter_waiting(a); @@ -897,10 +907,11 @@ static bool automount_check_gc(Unit *u) { } static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; union autofs_v5_packet_union packet; Automount *a = AUTOMOUNT(userdata); struct stat st; + Unit *trigger; int r; assert(a); @@ -973,7 +984,13 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo break; } - r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, &error, NULL); + trigger = UNIT_TRIGGER(UNIT(a)); + if (!trigger) { + log_unit_error(UNIT(a), "Unit to trigger vanished."); + goto fail; + } + + r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, &error, NULL); if (r < 0) { log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r)); goto fail; diff --git a/src/core/automount.h b/src/core/automount.h index 43ea9f772..cf5b1cf99 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/bus-endpoint.h b/src/core/bus-endpoint.h index 4a31f4c4b..f2fbc4701 100644 --- a/src/core/bus-endpoint.h +++ b/src/core/bus-endpoint.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,8 +22,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 3b04f5457..5b2c4d595 100644 --- a/src/core/bus-policy.h +++ b/src/core/bus-policy.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,9 +19,9 @@ along with systemd; If not, see . ***/ +#include "kdbus.h" #include "list.h" #include "macro.h" -#include "kdbus.h" typedef struct BusNamePolicy BusNamePolicy; diff --git a/src/core/busname.c b/src/core/busname.c index 04fa12a4d..de2a21ccd 100644 --- a/src/core/busname.c +++ b/src/core/busname.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -112,29 +110,27 @@ static void busname_done(Unit *u) { n->timer_event_source = sd_event_source_unref(n->timer_event_source); } -static int busname_arm_timer(BusName *n) { +static int busname_arm_timer(BusName *n, usec_t usec) { int r; assert(n); - if (n->timeout_usec <= 0) { - n->timer_event_source = sd_event_source_unref(n->timer_event_source); - return 0; - } - if (n->timer_event_source) { - r = sd_event_source_set_time(n->timer_event_source, now(CLOCK_MONOTONIC) + n->timeout_usec); + r = sd_event_source_set_time(n->timer_event_source, usec); if (r < 0) return r; return sd_event_source_set_enabled(n->timer_event_source, SD_EVENT_ONESHOT); } + if (usec == USEC_INFINITY) + return 0; + r = sd_event_add_time( UNIT(n)->manager->event, &n->timer_event_source, CLOCK_MONOTONIC, - now(CLOCK_MONOTONIC) + n->timeout_usec, 0, + usec, 0, busname_dispatch_timer, n); if (r < 0) return r; @@ -372,7 +368,7 @@ static int busname_coldplug(Unit *u) { if (r < 0) return r; - r = busname_arm_timer(n); + r = busname_arm_timer(n, usec_add(u->state_change_timestamp.monotonic, n->timeout_usec)); if (r < 0) return r; } @@ -397,7 +393,7 @@ static int busname_make_starter(BusName *n, pid_t *_pid) { pid_t pid; int r; - r = busname_arm_timer(n); + r = busname_arm_timer(n, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec)); if (r < 0) goto fail; @@ -475,7 +471,7 @@ static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f } if (r > 0) { - r = busname_arm_timer(n); + r = busname_arm_timer(n, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec)); if (r < 0) { log_unit_warning_errno(UNIT(n), r, "Failed to arm timer: %m"); goto fail; @@ -557,7 +553,7 @@ fail: } static void busname_enter_running(BusName *n) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; bool pending = false; Unit *other; Iterator i; @@ -947,7 +943,6 @@ static void busname_reset_failed(Unit *u) { static void busname_trigger_notify(Unit *u, Unit *other) { BusName *n = BUSNAME(u); - Service *s; assert(n); assert(other); @@ -955,36 +950,43 @@ static void busname_trigger_notify(Unit *u, Unit *other) { if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING)) return; + if (other->start_limit_hit) { + busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT); + return; + } + if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE) return; - s = SERVICE(other); - - if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT) - busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT); - else if (IN_SET(s->state, - SERVICE_DEAD, SERVICE_FAILED, - SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, - SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, - SERVICE_AUTO_RESTART)) + if (IN_SET(SERVICE(other)->state, + SERVICE_DEAD, SERVICE_FAILED, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, + SERVICE_AUTO_RESTART)) busname_enter_listening(n); + + if (SERVICE(other)->state == SERVICE_RUNNING) + busname_set_state(n, BUSNAME_RUNNING); } static int busname_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, BUSNAME(u)->control_pid, error); } -static int busname_get_timeout(Unit *u, uint64_t *timeout) { +static int busname_get_timeout(Unit *u, usec_t *timeout) { BusName *n = BUSNAME(u); + usec_t t; int r; if (!n->timer_event_source) return 0; - r = sd_event_source_get_time(n->timer_event_source, timeout); + r = sd_event_source_get_time(n->timer_event_source, &t); if (r < 0) return r; + if (t == USEC_INFINITY) + return 0; + *timeout = t; return 1; } @@ -1004,7 +1006,7 @@ static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = { [BUSNAME_FAILURE_EXIT_CODE] = "exit-code", [BUSNAME_FAILURE_SIGNAL] = "signal", [BUSNAME_FAILURE_CORE_DUMP] = "core-dump", - [BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent", + [BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit", }; DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult); diff --git a/src/core/busname.h b/src/core/busname.h index 46f7b6f09..6b6f6c62d 100644 --- a/src/core/busname.h +++ b/src/core/busname.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -33,7 +31,7 @@ typedef enum BusNameResult { BUSNAME_FAILURE_EXIT_CODE, BUSNAME_FAILURE_SIGNAL, BUSNAME_FAILURE_CORE_DUMP, - BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT, + BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT, _BUSNAME_RESULT_MAX, _BUSNAME_RESULT_INVALID = -1 } BusNameResult; diff --git a/src/core/cgroup.c b/src/core/cgroup.c index d12217541..39235a95f 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -53,8 +51,6 @@ void cgroup_context_init(CGroupContext *c) { c->startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID; c->tasks_max = (uint64_t) -1; - - c->netclass_type = CGROUP_NETCLASS_TYPE_NONE; } void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) { @@ -299,7 +295,7 @@ fail: return -errno; } -void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, uint32_t netclass, ManagerState state) { +void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) { bool is_root; int r; @@ -497,17 +493,6 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, "Failed to set pids.max on %s: %m", path); } - - if (mask & CGROUP_MASK_NET_CLS) { - char buf[DECIMAL_STR_MAX(uint32_t)]; - - sprintf(buf, "%" PRIu32, netclass); - - r = cg_set_attribute("net_cls", path, "net_cls.classid", buf); - if (r < 0) - log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r, - "Failed to set net_cls.classid on %s: %m", path); - } } CGroupMask cgroup_context_get_mask(CGroupContext *c) { @@ -540,9 +525,6 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) { c->tasks_max != (uint64_t) -1) mask |= CGROUP_MASK_PIDS; - if (c->netclass_type != CGROUP_NETCLASS_TYPE_NONE) - mask |= CGROUP_MASK_NET_CLS; - return mask; } @@ -910,103 +892,6 @@ static bool unit_has_mask_realized(Unit *u, CGroupMask target_mask) { return u->cgroup_realized && u->cgroup_realized_mask == target_mask; } -static int unit_find_free_netclass_cgroup(Unit *u, uint32_t *ret) { - - uint32_t start, i; - Manager *m; - - assert(u); - - m = u->manager; - - i = start = m->cgroup_netclass_registry_last; - - do { - i++; - - if (!hashmap_get(m->cgroup_netclass_registry, UINT_TO_PTR(i))) { - m->cgroup_netclass_registry_last = i; - *ret = i; - return 0; - } - - if (i == UINT32_MAX) - i = CGROUP_NETCLASS_FIXED_MAX; - - } while (i != start); - - return -ENOBUFS; -} - -int unit_add_to_netclass_cgroup(Unit *u) { - - CGroupContext *cc; - Unit *first; - void *key; - int r; - - assert(u); - - cc = unit_get_cgroup_context(u); - if (!cc) - return 0; - - switch (cc->netclass_type) { - case CGROUP_NETCLASS_TYPE_NONE: - return 0; - - case CGROUP_NETCLASS_TYPE_FIXED: - u->cgroup_netclass_id = cc->netclass_id; - break; - - case CGROUP_NETCLASS_TYPE_AUTO: - /* Allocate a new ID in case it was requested and not done yet */ - if (u->cgroup_netclass_id == 0) { - r = unit_find_free_netclass_cgroup(u, &u->cgroup_netclass_id); - if (r < 0) - return r; - - log_debug("Dynamically assigned netclass cgroup id %" PRIu32 " to %s", u->cgroup_netclass_id, u->id); - } - - break; - } - - r = hashmap_ensure_allocated(&u->manager->cgroup_netclass_registry, &trivial_hash_ops); - if (r < 0) - return r; - - key = UINT32_TO_PTR(u->cgroup_netclass_id); - first = hashmap_get(u->manager->cgroup_netclass_registry, key); - - if (first) { - LIST_PREPEND(cgroup_netclass, first, u); - return hashmap_replace(u->manager->cgroup_netclass_registry, key, u); - } - - return hashmap_put(u->manager->cgroup_netclass_registry, key, u); -} - -int unit_remove_from_netclass_cgroup(Unit *u) { - - Unit *head; - void *key; - - assert(u); - - key = UINT32_TO_PTR(u->cgroup_netclass_id); - - LIST_FIND_HEAD(cgroup_netclass, u, head); - LIST_REMOVE(cgroup_netclass, head, u); - - if (head) - return hashmap_replace(u->manager->cgroup_netclass_registry, key, head); - - hashmap_remove(u->manager->cgroup_netclass_registry, key); - - return 0; -} - /* Check if necessary controllers and attributes for a unit are in place. * * If so, do nothing. @@ -1042,7 +927,7 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) { return r; /* Finally, apply the necessary attributes. */ - cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, u->cgroup_netclass_id, state); + cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, state); return 0; } diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 457544b49..360bbca30 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -26,11 +24,6 @@ #include "list.h" #include "time-util.h" -/* Maximum value for fixed (manual) net class ID assignment, - * and also the value at which the range of automatic assignments starts - */ -#define CGROUP_NETCLASS_FIXED_MAX UINT32_C(65535) - typedef struct CGroupContext CGroupContext; typedef struct CGroupDeviceAllow CGroupDeviceAllow; typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight; @@ -52,17 +45,6 @@ typedef enum CGroupDevicePolicy { _CGROUP_DEVICE_POLICY_INVALID = -1 } CGroupDevicePolicy; -typedef enum CGroupNetClassType { - /* Default - do not assign a net class */ - CGROUP_NETCLASS_TYPE_NONE, - - /* Automatically assign a net class */ - CGROUP_NETCLASS_TYPE_AUTO, - - /* Assign the net class that was provided by the user */ - CGROUP_NETCLASS_TYPE_FIXED, -} CGroupNetClassType; - struct CGroupDeviceAllow { LIST_FIELDS(CGroupDeviceAllow, device_allow); char *path; @@ -104,21 +86,18 @@ struct CGroupContext { CGroupDevicePolicy device_policy; LIST_HEAD(CGroupDeviceAllow, device_allow); - CGroupNetClassType netclass_type; - uint32_t netclass_id; - uint64_t tasks_max; bool delegate; }; -#include "unit.h" #include "cgroup-util.h" +#include "unit.h" void cgroup_context_init(CGroupContext *c); void cgroup_context_done(CGroupContext *c); void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix); -void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, uint32_t netclass_id, ManagerState state); +void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state); CGroupMask cgroup_context_get_mask(CGroupContext *c); @@ -146,9 +125,6 @@ int unit_watch_cgroup(Unit *u); int unit_attach_pids_to_cgroup(Unit *u); -int unit_add_to_netclass_cgroup(Unit *u); -int unit_remove_from_netclass_cgroup(Unit *u); - int manager_setup_cgroup(Manager *m); void manager_shutdown_cgroup(Manager *m, bool delete); diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c index 54830a515..b2806ad86 100644 --- a/src/core/dbus-automount.c +++ b/src/core/dbus-automount.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h index a2b124d75..7b51eb973 100644 --- a/src/core/dbus-automount.h +++ b/src/core/dbus-automount.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c index 445b23764..cf816ba15 100644 --- a/src/core/dbus-busname.c +++ b/src/core/dbus-busname.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-busname.h b/src/core/dbus-busname.h index ea55b6c8c..8643d1a40 100644 --- a/src/core/dbus-busname.h +++ b/src/core/dbus-busname.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 3fd295baa..859d155ec 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h index 9dc187c06..b2212fe44 100644 --- a/src/core/dbus-cgroup.h +++ b/src/core/dbus-cgroup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c index 97e4a4755..e1a12224d 100644 --- a/src/core/dbus-device.c +++ b/src/core/dbus-device.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-device.h b/src/core/dbus-device.h index 10e945e40..eb1d8c327 100644 --- a/src/core/dbus-device.h +++ b/src/core/dbus-device.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 093179c00..f2fc301f8 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -141,7 +139,7 @@ static int property_get_nice( else { errno = 0; n = getpriority(PRIO_PROCESS, 0); - if (errno != 0) + if (errno > 0) n = 0; } @@ -293,9 +291,25 @@ static int property_get_capability_bounding_set( assert(reply); assert(c); - /* We store this negated internally, to match the kernel, but - * we expose it normalized. */ - return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop); + return sd_bus_message_append(reply, "t", c->capability_bounding_set); +} + +static int property_get_ambient_capabilities( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + ExecContext *c = userdata; + + assert(bus); + assert(reply); + assert(c); + + return sd_bus_message_append(reply, "t", c->capability_ambient_set); } static int property_get_capabilities( @@ -632,21 +646,37 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitCPUSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitFSIZESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitDATASoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitSTACKSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitCORESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRSSSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNOFILESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitASSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNPROCSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitMEMLOCKSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitLOCKSSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitSIGPENDINGSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitMSGQUEUESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitNICESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRTPRIOSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("LimitRTTIMESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST), @@ -673,6 +703,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("AmbientCapabilities", "t", property_get_ambient_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("User", "s", NULL, offsetof(ExecContext, user), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST), @@ -802,7 +833,8 @@ int bus_exec_context_set_transient_property( UnitSetPropertiesMode mode, sd_bus_error *error) { - int r; + const char *soft = NULL; + int r, ri; assert(u); assert(c); @@ -1349,7 +1381,7 @@ int bus_exec_context_set_transient_property( dirs = &c->read_write_dirs; else if (streq(name, "ReadOnlyDirectories")) dirs = &c->read_only_dirs; - else if (streq(name, "InaccessibleDirectories")) + else /* "InaccessibleDirectories" */ dirs = &c->inaccessible_dirs; if (strv_length(l) == 0) { @@ -1459,7 +1491,23 @@ int bus_exec_context_set_transient_property( return 1; - } else if (rlimit_from_string(name) >= 0) { + } + + ri = rlimit_from_string(name); + if (ri < 0) { + soft = endswith(name, "Soft"); + if (soft) { + const char *n; + + n = strndupa(name, soft - name); + ri = rlimit_from_string(n); + if (ri >= 0) + name = n; + + } + } + + if (ri >= 0) { uint64_t rl; rlim_t x; @@ -1477,22 +1525,36 @@ int bus_exec_context_set_transient_property( } if (mode != UNIT_CHECK) { - int z; + _cleanup_free_ char *f = NULL; + struct rlimit nl; - z = rlimit_from_string(name); + if (c->rlimit[ri]) { + nl = *c->rlimit[ri]; - if (!c->rlimit[z]) { - c->rlimit[z] = new(struct rlimit, 1); - if (!c->rlimit[z]) + if (soft) + nl.rlim_cur = x; + else + nl.rlim_max = x; + } else + /* When the resource limit is not initialized yet, then assign the value to both fields */ + nl = (struct rlimit) { + .rlim_cur = x, + .rlim_max = x, + }; + + r = rlimit_format(&nl, &f); + if (r < 0) + return r; + + if (c->rlimit[ri]) + *c->rlimit[ri] = nl; + else { + c->rlimit[ri] = newdup(struct rlimit, &nl, 1); + if (!c->rlimit[ri]) return -ENOMEM; } - c->rlimit[z]->rlim_cur = c->rlimit[z]->rlim_max = x; - - if (x == RLIM_INFINITY) - unit_write_drop_in_private_format(u, mode, name, "%s=infinity\n", name); - else - unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, rl); + unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, f); } return 1; diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h index c44517ea2..d0aa8e1dd 100644 --- a/src/core/dbus-execute.h +++ b/src/core/dbus-execute.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c index 8c30d6625..97a93fb2f 100644 --- a/src/core/dbus-job.c +++ b/src/core/dbus-job.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -93,7 +91,7 @@ const sd_bus_vtable bus_job_vtable[] = { }; static int send_new_signal(sd_bus *bus, void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *p = NULL; Job *j = userdata; int r; @@ -153,7 +151,7 @@ void bus_job_send_change_signal(Job *j) { } static int send_removed_signal(sd_bus *bus, void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *p = NULL; Job *j = userdata; int r; diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h index 0f2fbe2ee..024d06719 100644 --- a/src/core/dbus-job.h +++ b/src/core/dbus-job.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c index c633eb1b7..fc50fafaa 100644 --- a/src/core/dbus-kill.c +++ b/src/core/dbus-kill.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h index 794c40204..b9b18811e 100644 --- a/src/core/dbus-kill.h +++ b/src/core/dbus-kill.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,8 +21,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 4d730290b..f93919639 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -229,7 +227,10 @@ static int property_set_log_level( if (r < 0) return r; - return log_set_max_level_from_string(t); + r = log_set_max_level_from_string(t); + if (r == 0) + log_info("Setting log level to %s.", t); + return r; } static int property_get_n_names( @@ -384,7 +385,7 @@ static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error return r; if (isempty(name)) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; pid_t pid; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); @@ -436,7 +437,7 @@ static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bu return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PID " PID_FMT, pid); if (pid == 0) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); if (r < 0) @@ -479,7 +480,7 @@ static int method_load_unit(sd_bus_message *message, void *userdata, sd_bus_erro return r; if (isempty(name)) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; pid_t pid; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); @@ -630,9 +631,13 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s if (r < 0) return r; - u = manager_get_unit(m, name); - if (!u) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name); + r = manager_load_unit(m, name, NULL, error, &u); + if (r < 0) + return r; + + r = bus_unit_check_load_state(u, error); + if (r < 0) + return r; return bus_unit_method_set_properties(message, u, error); } @@ -861,7 +866,7 @@ static int method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_e } static int list_units_filtered(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; const char *k; Iterator i; @@ -949,7 +954,7 @@ static int method_list_units_filtered(sd_bus_message *message, void *userdata, s } static int method_list_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; Iterator i; Job *j; @@ -1437,7 +1442,7 @@ static int method_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_ } static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; UnitFileList *item; Hashmap *h; @@ -1543,7 +1548,7 @@ static int method_get_default_target(sd_bus_message *message, void *userdata, sd } static int send_unit_files_changed(sd_bus *bus, void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *message = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; int r; assert(bus); @@ -1562,7 +1567,7 @@ static int reply_unit_file_changes_and_free( UnitFileChange *changes, unsigned n_changes) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; unsigned i; int r; @@ -1600,6 +1605,7 @@ static int reply_unit_file_changes_and_free( if (r < 0) goto fail; + unit_file_changes_free(changes, n_changes); return sd_bus_send(NULL, reply, NULL); fail: @@ -1836,8 +1842,10 @@ static int method_preset_all_unit_files(sd_bus_message *message, void *userdata, scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER; r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes); - if (r < 0) + if (r < 0) { + unit_file_changes_free(changes, n_changes); return r; + } return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes); } @@ -1935,21 +1943,37 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCPUSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitFSIZESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitDATASoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitSTACKSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitCORESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitRSSSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitNOFILESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitASSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitNPROCSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitMEMLOCKSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitLOCKSSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitSIGPENDINGSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitMSGQUEUESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultLimitNICESoft", "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("DefaultLimitRTPRIOSoft", "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("DefaultLimitRTTIMESoft", "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), @@ -2019,7 +2043,7 @@ const sd_bus_vtable bus_manager_vtable[] = { }; static int send_finished(sd_bus *bus, void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *message = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; usec_t *times = userdata; int r; @@ -2067,7 +2091,7 @@ void bus_manager_send_finished( } static int send_reloading(sd_bus *bus, void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *message = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *message = NULL; int r; assert(bus); diff --git a/src/core/dbus-manager.h b/src/core/dbus-manager.h index 5bdf6e17a..36a2e9481 100644 --- a/src/core/dbus-manager.h +++ b/src/core/dbus-manager.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c index bc5751a10..935db7c48 100644 --- a/src/core/dbus-mount.c +++ b/src/core/dbus-mount.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h index dd0bf51bb..ec16166d3 100644 --- a/src/core/dbus-mount.h +++ b/src/core/dbus-mount.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c index e0544e916..1e153e503 100644 --- a/src/core/dbus-path.c +++ b/src/core/dbus-path.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-path.h b/src/core/dbus-path.h index 389b0d7f9..d3c19e0c2 100644 --- a/src/core/dbus-path.h +++ b/src/core/dbus-path.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c index 16375b231..34ee9a8fa 100644 --- a/src/core/dbus-scope.c +++ b/src/core/dbus-scope.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -205,7 +203,7 @@ int bus_scope_commit_properties(Unit *u) { } int bus_scope_send_request_stop(Scope *s) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *p = NULL; int r; diff --git a/src/core/dbus-scope.h b/src/core/dbus-scope.h index 33beda47b..270306f50 100644 --- a/src/core/dbus-scope.h +++ b/src/core/dbus-scope.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_scope_vtable[]; diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 24f611a59..03eecca91 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -49,12 +47,14 @@ const sd_bus_vtable bus_service_vtable[] = { SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST), BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0), - SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Service, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), + /* The following four are obsolete, and thus marked hidden here. They moved into the Unit interface */ + SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), + SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), SD_BUS_PROPERTY("FailureAction", "s", property_get_failure_action, offsetof(Service, failure_action), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST), @@ -124,6 +124,19 @@ static int bus_service_set_transient_property( unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s\n", service_type_to_string(s->type)); } + return 1; + } else if (streq(name, "RuntimeMaxUSec")) { + usec_t u; + + r = sd_bus_message_read(message, "t", &u); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + s->runtime_max_usec = u; + unit_write_drop_in_private_format(UNIT(s), mode, name, "RuntimeMaxSec=" USEC_FMT "us\n", u); + } + return 1; } else if (STR_IN_SET(name, @@ -153,6 +166,8 @@ static int bus_service_set_transient_property( asynchronous_close(s->stderr_fd); s->stderr_fd = copy; } + + s->exec_context.stdio_as_fds = true; } return 1; diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h index aab9f7aa2..769a53769 100644 --- a/src/core/dbus-service.h +++ b/src/core/dbus-service.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,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 469e3e1c9..e37f50b28 100644 --- a/src/core/dbus-slice.c +++ b/src/core/dbus-slice.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-slice.h b/src/core/dbus-slice.h index eadc3b1a9..52ceebb13 100644 --- a/src/core/dbus-slice.h +++ b/src/core/dbus-slice.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,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 be5ef261a..d33e494f6 100644 --- a/src/core/dbus-socket.c +++ b/src/core/dbus-socket.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -150,6 +148,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 17164d987..7a792c7a8 100644 --- a/src/core/dbus-socket.h +++ b/src/core/dbus-socket.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,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 f2a0f1d17..292f8738c 100644 --- a/src/core/dbus-swap.c +++ b/src/core/dbus-swap.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h index 9469f68ab..5238471f9 100644 --- a/src/core/dbus-swap.h +++ b/src/core/dbus-swap.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,6 +21,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 654bcf1a2..6858b1ce7 100644 --- a/src/core/dbus-target.c +++ b/src/core/dbus-target.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h index 6be9c9f70..9be5ce06b 100644 --- a/src/core/dbus-target.h +++ b/src/core/dbus-target.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index 2e6c479c3..bc121b83a 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -180,6 +178,7 @@ 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), @@ -266,8 +265,24 @@ static int bus_timer_set_transient_property( return 1; - } else if (streq(name, "AccuracySec")) { + } else if (STR_IN_SET(name, "AccuracyUSec", "AccuracySec")) { + usec_t u = 0; + if (streq(name, "AccuracySec")) + log_notice("Client is using obsolete AccuracySec= transient property, please use AccuracyUSec= instead."); + + r = sd_bus_message_read(message, "t", &u); + if (r < 0) + return r; + + if (mode != UNIT_CHECK) { + t->accuracy_usec = u; + unit_write_drop_in_private_format(UNIT(t), mode, name, "AccuracySec=" USEC_FMT "us\n", u); + } + + return 1; + + } else if (streq(name, "RandomizedDelayUSec")) { usec_t u = 0; r = sd_bus_message_read(message, "t", &u); @@ -275,10 +290,8 @@ static int bus_timer_set_transient_property( return r; if (mode != UNIT_CHECK) { - char time[FORMAT_TIMESPAN_MAX]; - - t->accuracy_usec = u; - unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC)); + t->random_usec = u; + unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=" USEC_FMT "us\n", u); } return 1; diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h index 103172f05..39053dc4a 100644 --- a/src/core/dbus-timer.h +++ b/src/core/dbus-timer.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_timer_vtable[]; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index d9b7382c8..b351f6a2c 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -399,7 +397,7 @@ static int property_get_load_error( void *userdata, sd_bus_error *error) { - _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; Unit *u = userdata; assert(bus); @@ -458,7 +456,10 @@ int bus_unit_method_start_generic( assert(u); assert(job_type >= 0 && job_type < _JOB_TYPE_MAX); - r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error); + r = mac_selinux_unit_access_check( + u, message, + job_type_to_access_method(job_type), + error); if (r < 0) return r; @@ -671,6 +672,7 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0), SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0), + BUS_PROPERTY_DUAL_TIMESTAMP("StateChangeTimestamp", offsetof(Unit, state_change_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -699,7 +701,10 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0), SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("NetClass", "u", NULL, offsetof(Unit, cgroup_netclass_id), 0), + SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED), @@ -846,7 +851,7 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = { }; static int send_new_signal(sd_bus *bus, void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *p = NULL; Unit *u = userdata; int r; @@ -923,7 +928,7 @@ void bus_unit_send_change_signal(Unit *u) { } static int send_removed_signal(sd_bus *bus, void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *p = NULL; Unit *u = userdata; int r; @@ -983,19 +988,20 @@ int bus_unit_queue_job( assert(type >= 0 && type < _JOB_TYPE_MAX); assert(mode >= 0 && mode < _JOB_MODE_MAX); + r = mac_selinux_unit_access_check( + u, message, + job_type_to_access_method(type), + error); + if (r < 0) + return r; + if (reload_if_possible && unit_can_reload(u)) { if (type == JOB_RESTART) type = JOB_RELOAD_OR_START; else if (type == JOB_TRY_RESTART) - type = JOB_RELOAD; + type = JOB_TRY_RELOAD; } - r = mac_selinux_unit_access_check( - u, message, - (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" : - type == JOB_STOP ? "stop" : "reload", error); - if (r < 0) - return r; if (type == JOB_STOP && (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) && @@ -1251,3 +1257,20 @@ int bus_unit_set_properties( return n; } + +int bus_unit_check_load_state(Unit *u, sd_bus_error *error) { + + if (u->load_state == UNIT_LOADED) + return 0; + + /* Give a better description of the unit error when + * possible. Note that in the case of UNIT_MASKED, load_error + * is not set. */ + if (u->load_state == UNIT_MASKED) + return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id); + + if (u->load_state == UNIT_NOT_FOUND) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not found.", u->id); + + return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id); +} diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index b622e0ae8..07948b9cd 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include "sd-bus.h" + #include "unit.h" extern const sd_bus_vtable bus_unit_vtable[]; @@ -37,3 +36,5 @@ int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error); int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error); int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error); + +int bus_unit_check_load_state(Unit *u, sd_bus_error *error); diff --git a/src/core/dbus.c b/src/core/dbus.c index 793213003..413489373 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -74,7 +72,7 @@ int bus_send_queued_message(Manager *m) { } static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; const char *cgroup, *me; Manager *m = userdata; uid_t sender_uid; @@ -146,8 +144,8 @@ static int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_e } static int signal_activation_request(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; const char *name; Unit *u; @@ -245,7 +243,7 @@ static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_er } if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; pid_t pid; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); @@ -304,7 +302,7 @@ static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_ assert(path); if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_bus_message *message; pid_t pid; @@ -617,7 +615,7 @@ static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) { } static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; _cleanup_close_ int nfd = -1; Manager *m = userdata; sd_id128_t id; @@ -734,9 +732,11 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void return 0; } -static int bus_list_names(Manager *m, sd_bus *bus) { +int manager_sync_bus_names(Manager *m, sd_bus *bus) { _cleanup_strv_free_ char **names = NULL; - char **i; + const char *name; + Iterator i; + Unit *u; int r; assert(m); @@ -746,15 +746,55 @@ static int bus_list_names(Manager *m, sd_bus *bus) { if (r < 0) return log_error_errno(r, "Failed to get initial list of names: %m"); - /* This is a bit hacky, we say the owner of the name is the - * name itself, because we don't want the extra traffic to - * figure out the real owner. */ - STRV_FOREACH(i, names) { - Unit *u; + /* We have to synchronize the current bus names with the + * list of active services. To do this, walk the list of + * all units with bus names. */ + HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) { + Service *s = SERVICE(u); - u = hashmap_get(m->watch_bus, *i); - if (u) - UNIT_VTABLE(u)->bus_name_owner_change(u, *i, NULL, *i); + assert(s); + + if (!streq_ptr(s->bus_name, name)) { + log_unit_warning(u, "Bus name has changed from %s → %s, ignoring.", s->bus_name, name); + continue; + } + + /* Check if a service's bus name is in the list of currently + * active names */ + if (strv_contains(names, name)) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + const char *unique; + + /* If it is, determine its current owner */ + r = sd_bus_get_name_creds(bus, name, SD_BUS_CREDS_UNIQUE_NAME, &creds); + if (r < 0) { + log_error_errno(r, "Failed to get bus name owner %s: %m", name); + continue; + } + + r = sd_bus_creds_get_unique_name(creds, &unique); + if (r < 0) { + log_error_errno(r, "Failed to get unique name for %s: %m", name); + continue; + } + + /* Now, let's compare that to the previous bus owner, and + * if it's still the same, all is fine, so just don't + * bother the service. Otherwise, the name has apparently + * changed, so synthesize a name owner changed signal. */ + + if (!streq_ptr(unique, s->bus_name_owner)) + UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, unique); + } else { + /* So, the name we're watching is not on the bus. + * This either means it simply hasn't appeared yet, + * or it was lost during the daemon reload. + * Check if the service has a stored name owner, + * and synthesize a name loss signal in this case. */ + + if (s->bus_name_owner) + UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, NULL); + } } return 0; @@ -808,14 +848,16 @@ static int bus_setup_api(Manager *m, sd_bus *bus) { if (r < 0) return log_error_errno(r, "Failed to register name: %m"); - bus_list_names(m, bus); + r = manager_sync_bus_names(m, bus); + if (r < 0) + return r; log_debug("Successfully connected to API bus."); return 0; } static int bus_init_api(Manager *m) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; int r; if (m->api_bus) @@ -883,7 +925,7 @@ static int bus_setup_system(Manager *m, sd_bus *bus) { } static int bus_init_system(Manager *m) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; int r; if (m->system_bus) diff --git a/src/core/dbus.h b/src/core/dbus.h index 4f06ad11c..e16a84fbb 100644 --- a/src/core/dbus.h +++ b/src/core/dbus.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -34,6 +32,8 @@ void bus_track_serialize(sd_bus_track *t, FILE *f); int bus_track_deserialize_item(char ***l, const char *line); int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l); +int manager_sync_bus_names(Manager *m, sd_bus *bus); + int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata); int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error); diff --git a/src/core/device.c b/src/core/device.c index bcd4d1146..d201dc5e4 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -267,7 +265,7 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) { assert(u); assert(dev); - property = u->manager->running_as == MANAGER_USER ? "MANAGER_USER_WANTS" : "SYSTEMD_WANTS"; + property = u->manager->running_as == MANAGER_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS"; wants = udev_device_get_property_value(dev, property); if (!wants) return 0; @@ -315,12 +313,19 @@ static int device_setup_unit(Manager *m, struct udev_device *dev, const char *pa u = manager_get_unit(m, e); - if (u && - sysfs && - DEVICE(u)->sysfs && - !path_equal(DEVICE(u)->sysfs, sysfs)) { - log_unit_debug(u, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs); - return -EEXIST; + /* The device unit can still be present even if the device was + * unplugged: a mount unit can reference it hence preventing + * the GC to have garbaged it. That's desired since the device + * unit may have a dependency on the mount unit which was + * added during the loading of the later. */ + if (u && DEVICE(u)->state == DEVICE_PLUGGED) { + /* This unit is in plugged state: we're sure it's + * attached to a device. */ + if (!path_equal(DEVICE(u)->sysfs, sysfs)) { + log_unit_error(u, "Dev %s appeared twice with different sysfs paths %s and %s", + e, DEVICE(u)->sysfs, sysfs); + return -EEXIST; + } } if (!u) { diff --git a/src/core/device.h b/src/core/device.h index da8737870..184a1a349 100644 --- a/src/core/device.h +++ b/src/core/device.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/execute.c b/src/core/execute.c index 07979bf8b..1e4630182 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -183,26 +181,41 @@ static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) { return 0; } -_pure_ static const char *tty_path(const ExecContext *context) { +static const char *exec_context_tty_path(const ExecContext *context) { assert(context); + if (context->stdio_as_fds) + return NULL; + if (context->tty_path) return context->tty_path; return "/dev/console"; } -static void exec_context_tty_reset(const ExecContext *context) { +static void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p) { + const char *path; + assert(context); - if (context->tty_vhangup) - terminal_vhangup(tty_path(context)); + path = exec_context_tty_path(context); - if (context->tty_reset) - reset_terminal(tty_path(context)); + if (context->tty_vhangup) { + if (p && p->stdin_fd >= 0) + (void) terminal_vhangup_fd(p->stdin_fd); + else if (path) + (void) terminal_vhangup(path); + } - if (context->tty_vt_disallocate && context->tty_path) - vt_disallocate(context->tty_path); + if (context->tty_reset) { + if (p && p->stdin_fd >= 0) + (void) reset_terminal_fd(p->stdin_fd, true); + else if (path) + (void) reset_terminal(path); + } + + if (context->tty_vt_disallocate && path) + (void) vt_disallocate(path); } static bool is_terminal_output(ExecOutput o) { @@ -400,7 +413,7 @@ static int setup_input( case EXEC_INPUT_TTY_FAIL: { int fd, r; - fd = acquire_terminal(tty_path(context), + fd = acquire_terminal(exec_context_tty_path(context), i == EXEC_INPUT_TTY_FAIL, i == EXEC_INPUT_TTY_FORCE, false, @@ -485,7 +498,7 @@ static int setup_output( } else if (o == EXEC_OUTPUT_INHERIT) { /* If input got downgraded, inherit the original value */ if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input)) - return open_terminal_as(tty_path(context), O_WRONLY, fileno); + return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno); /* If the input is connected to anything that's not a /dev/null, inherit that... */ if (i != EXEC_INPUT_NULL) @@ -509,7 +522,7 @@ static int setup_output( return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno; /* We don't reset the terminal if this is just about output */ - return open_terminal_as(tty_path(context), O_WRONLY, fileno); + return open_terminal_as(exec_context_tty_path(context), O_WRONLY, fileno); case EXEC_OUTPUT_SYSLOG: case EXEC_OUTPUT_SYSLOG_AND_CONSOLE: @@ -737,12 +750,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) { /* Sets (but doesn't lookup) the uid and make sure we keep the * capabilities while doing so. */ - if (context->capabilities) { - _cleanup_cap_free_ cap_t d = NULL; - static const cap_value_t bits[] = { - CAP_SETUID, /* Necessary so that we can run setresuid() below */ - CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */ - }; + if (context->capabilities || context->capability_ambient_set != 0) { /* First step: If we need to keep capabilities but * drop privileges we need to make sure we keep our @@ -758,16 +766,24 @@ static int enforce_user(const ExecContext *context, uid_t uid) { /* Second step: set the capabilities. This will reduce * the capabilities to the minimum we need. */ - d = cap_dup(context->capabilities); - if (!d) - return -errno; + if (context->capabilities) { + _cleanup_cap_free_ cap_t d = NULL; + static const cap_value_t bits[] = { + CAP_SETUID, /* Necessary so that we can run setresuid() below */ + CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */ + }; - if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 || - cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) - return -errno; + d = cap_dup(context->capabilities); + if (!d) + return -errno; - if (cap_set_proc(d) < 0) - return -errno; + if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 || + cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0) + return -errno; + + if (cap_set_proc(d) < 0) + return -errno; + } } /* Third step: actually set the uids */ @@ -811,8 +827,7 @@ static int setup_pam( _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL; pam_handle_t *handle = NULL; sigset_t old_ss; - int pam_code = PAM_SUCCESS; - int err = 0; + int pam_code = PAM_SUCCESS, r; char **e = NULL; bool close_session = false; pid_t pam_pid = 0, parent_pid; @@ -829,8 +844,8 @@ static int setup_pam( * daemon. We do things this way to ensure that the main PID * of the daemon is the one we initially fork()ed. */ - err = barrier_create(&barrier); - if (err < 0) + r = barrier_create(&barrier); + if (r < 0) goto fail; if (log_get_max_level() < LOG_DEBUG) @@ -872,12 +887,13 @@ static int setup_pam( parent_pid = getpid(); pam_pid = fork(); - if (pam_pid < 0) + if (pam_pid < 0) { + r = -errno; goto fail; + } if (pam_pid == 0) { - int sig; - int r = EXIT_PAM; + int sig, ret = EXIT_PAM; /* The child's job is to reset the PAM session on * termination */ @@ -942,11 +958,11 @@ static int setup_pam( goto child_finish; } - r = 0; + ret = 0; child_finish: pam_end(handle, pam_code | flags); - _exit(r); + _exit(ret); } barrier_set_role(&barrier, BARRIER_PARENT); @@ -975,10 +991,9 @@ static int setup_pam( fail: if (pam_code != PAM_SUCCESS) { log_error("PAM failed: %s", pam_strerror(handle, pam_code)); - err = -EPERM; /* PAM errors do not map to errno */ - } else { - err = log_error_errno(err < 0 ? err : errno, "PAM failed: %m"); - } + r = -EPERM; /* PAM errors do not map to errno */ + } else + log_error_errno(r, "PAM failed: %m"); if (handle) { if (close_session) @@ -988,15 +1003,9 @@ fail: } strv_free(e); - closelog(); - if (pam_pid > 1) { - kill(pam_pid, SIGTERM); - kill(pam_pid, SIGCONT); - } - - return err; + return r; } #endif @@ -1236,9 +1245,8 @@ static void do_idle_pipe_dance(int idle_pipe[4]) { static int build_environment( const ExecContext *c, + const ExecParameters *p, unsigned n_fds, - char ** fd_names, - usec_t watchdog_usec, const char *home, const char *username, const char *shell, @@ -1266,7 +1274,7 @@ static int build_environment( return -ENOMEM; our_env[n_env++] = x; - joined = strv_join(fd_names, ":"); + joined = strv_join(p->fd_names, ":"); if (!joined) return -ENOMEM; @@ -1276,12 +1284,12 @@ static int build_environment( our_env[n_env++] = x; } - if (watchdog_usec > 0) { + if (p->watchdog_usec > 0) { if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0) return -ENOMEM; our_env[n_env++] = x; - if (asprintf(&x, "WATCHDOG_USEC="USEC_FMT, watchdog_usec) < 0) + if (asprintf(&x, "WATCHDOG_USEC="USEC_FMT, p->watchdog_usec) < 0) return -ENOMEM; our_env[n_env++] = x; } @@ -1317,7 +1325,7 @@ static int build_environment( c->std_error == EXEC_OUTPUT_TTY || c->tty_path) { - x = strdup(default_term_for_tty(tty_path(c))); + x = strdup(default_term_for_tty(exec_context_tty_path(c))); if (!x) return -ENOMEM; our_env[n_env++] = x; @@ -1494,7 +1502,7 @@ static int exec_child( return -errno; } - exec_context_tty_reset(context); + exec_context_tty_reset(context, params); if (params->confirm_spawn) { char response; @@ -1856,6 +1864,8 @@ static int exec_child( if (params->apply_permissions) { + int secure_bits = context->secure_bits; + for (i = 0; i < _RLIMIT_MAX; i++) { if (!context->rlimit[i]) continue; @@ -1866,28 +1876,71 @@ static int exec_child( } } - if (context->capability_bounding_set_drop) { - r = capability_bounding_set_drop(context->capability_bounding_set_drop, false); + if (!cap_test_all(context->capability_bounding_set)) { + r = capability_bounding_set_drop(context->capability_bounding_set, false); if (r < 0) { *exit_status = EXIT_CAPABILITIES; return r; } } + /* This is done before enforce_user, but ambient set + * does not survive over setresuid() if keep_caps is not set. */ + if (context->capability_ambient_set != 0) { + r = capability_ambient_set_apply(context->capability_ambient_set, true); + if (r < 0) { + *exit_status = EXIT_CAPABILITIES; + return r; + } + + if (context->capabilities) { + + /* The capabilities in ambient set need to be also in the inherited + * set. If they aren't, trying to get them will fail. Add the ambient + * set inherited capabilities to the capability set in the context. + * This is needed because if capabilities are set (using "Capabilities=" + * keyword), they will override whatever we set now. */ + + r = capability_update_inherited_set(context->capabilities, context->capability_ambient_set); + if (r < 0) { + *exit_status = EXIT_CAPABILITIES; + return r; + } + } + } + if (context->user) { r = enforce_user(context, uid); if (r < 0) { *exit_status = EXIT_USER; return r; } + if (context->capability_ambient_set != 0) { + + /* Fix the ambient capabilities after user change. */ + r = capability_ambient_set_apply(context->capability_ambient_set, false); + if (r < 0) { + *exit_status = EXIT_CAPABILITIES; + return r; + } + + /* If we were asked to change user and ambient capabilities + * were requested, we had to add keep-caps to the securebits + * so that we would maintain the inherited capability set + * through the setresuid(). Make sure that the bit is added + * also to the context secure_bits so that we don't try to + * drop the bit away next. */ + + secure_bits |= 1<secure_bits) - if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) { + if (prctl(PR_GET_SECUREBITS) != secure_bits) + if (prctl(PR_SET_SECUREBITS, secure_bits) < 0) { *exit_status = EXIT_SECUREBITS; return -errno; } @@ -1950,7 +2003,7 @@ static int exec_child( #endif } - r = build_environment(context, n_fds, params->fd_names, params->watchdog_usec, home, username, shell, &our_env); + r = build_environment(context, params, n_fds, home, username, shell, &our_env); if (r < 0) { *exit_status = EXIT_MEMORY; return r; @@ -2056,7 +2109,7 @@ int exec_spawn(Unit *unit, NULL); pid = fork(); if (pid < 0) - return log_unit_error_errno(unit, r, "Failed to fork: %m"); + return log_unit_error_errno(unit, errno, "Failed to fork: %m"); if (pid == 0) { int exit_status; @@ -2114,6 +2167,7 @@ void exec_context_init(ExecContext *c) { c->timer_slack_nsec = NSEC_INFINITY; c->personality = PERSONALITY_INVALID; c->runtime_directory_mode = 0755; + c->capability_bounding_set = CAP_ALL; } void exec_context_done(ExecContext *c) { @@ -2270,7 +2324,7 @@ int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l) { continue; strv_free(r); - return errno ? -errno : -EINVAL; + return errno > 0 ? -errno : -EINVAL; } count = pglob.gl_pathc; if (count == 0) { @@ -2324,6 +2378,9 @@ static bool tty_may_match_dev_console(const char *tty) { _cleanup_free_ char *active = NULL; char *console; + if (!tty) + return true; + if (startswith(tty, "/dev/")) tty += 5; @@ -2341,11 +2398,14 @@ static bool tty_may_match_dev_console(const char *tty) { } bool exec_context_may_touch_console(ExecContext *ec) { - return (ec->tty_reset || ec->tty_vhangup || ec->tty_vt_disallocate || + + return (ec->tty_reset || + ec->tty_vhangup || + ec->tty_vt_disallocate || is_terminal_input(ec->std_input) || is_terminal_output(ec->std_output) || is_terminal_output(ec->std_error)) && - tty_may_match_dev_console(tty_path(ec)); + tty_may_match_dev_console(exec_context_tty_path(ec)); } static void strv_fprintf(FILE *f, char **l) { @@ -2413,9 +2473,12 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { prefix, c->oom_score_adjust); for (i = 0; i < RLIM_NLIMITS; i++) - if (c->rlimit[i]) - fprintf(f, "%s%s: "RLIM_FMT"\n", + if (c->rlimit[i]) { + fprintf(f, "%s%s: " RLIM_FMT "\n", prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max); + fprintf(f, "%s%sSoft: " RLIM_FMT "\n", + prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur); + } if (c->ioprio_set) { _cleanup_free_ char *class_str = NULL; @@ -2514,12 +2577,23 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { (c->secure_bits & 1<secure_bits & 1<capability_bounding_set_drop) { + if (c->capability_bounding_set != CAP_ALL) { unsigned long l; fprintf(f, "%sCapabilityBoundingSet:", prefix); for (l = 0; l <= cap_last_cap(); l++) - if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) + if (c->capability_bounding_set & (UINT64_C(1) << l)) + fprintf(f, " %s", strna(capability_to_name(l))); + + fputs("\n", f); + } + + if (c->capability_ambient_set != 0) { + unsigned long l; + fprintf(f, "%sAmbientCapabilities:", prefix); + + for (l = 0; l <= cap_last_cap(); l++) + if (c->capability_ambient_set & (UINT64_C(1) << l)) fprintf(f, " %s", strna(capability_to_name(l))); fputs("\n", f); @@ -2620,7 +2694,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) { fputc('\n', f); } - if (c->syscall_errno != 0) + if (c->syscall_errno > 0) fprintf(f, "%sSystemCallErrorNumber: %s\n", prefix, strna(errno_to_name(c->syscall_errno))); @@ -2670,7 +2744,7 @@ void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, if (context->utmp_id) utmp_put_dead_process(context->utmp_id, pid, code, status); - exec_context_tty_reset(context); + exec_context_tty_reset(context, NULL); } } diff --git a/src/core/execute.h b/src/core/execute.h index 1faff160c..578f85b6b 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -27,16 +25,16 @@ typedef struct ExecContext ExecContext; typedef struct ExecRuntime ExecRuntime; typedef struct ExecParameters ExecParameters; -#include +#include #include #include -#include +#include -#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, @@ -122,6 +120,8 @@ struct ExecContext { nsec_t timer_slack_nsec; + bool stdio_as_fds; + char *tty_path; bool tty_reset; @@ -155,7 +155,9 @@ struct ExecContext { char **read_write_dirs, **read_only_dirs, **inaccessible_dirs; unsigned long mount_flags; - uint64_t capability_bounding_set_drop; + uint64_t capability_bounding_set; + + uint64_t capability_ambient_set; cap_t capabilities; int secure_bits; @@ -204,8 +206,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/failure-action.c b/src/core/failure-action.c index f67fb05af..39f5519ca 100644 --- a/src/core/failure-action.c +++ b/src/core/failure-action.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/failure-action.h b/src/core/failure-action.h index 1af4dd987..1adac4ad5 100644 --- a/src/core/failure-action.h +++ b/src/core/failure-action.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c index d92a9a764..68be52856 100644 --- a/src/core/hostname-setup.c +++ b/src/core/hostname-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/hostname-setup.h b/src/core/hostname-setup.h index 8dc3a9e1d..73e8c75c7 100644 --- a/src/core/hostname-setup.h +++ b/src/core/hostname-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c index 4f42ae6f3..ff7558d50 100644 --- a/src/core/ima-setup.c +++ b/src/core/ima-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/ima-setup.h b/src/core/ima-setup.h index 14b56d1fc..3bad74b24 100644 --- a/src/core/ima-setup.h +++ b/src/core/ima-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/job.c b/src/core/job.c index 965459063..97304c4d0 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -35,6 +33,7 @@ #include "parse-util.h" #include "set.h" #include "special.h" +#include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "strv.h" @@ -404,6 +403,13 @@ JobType job_type_collapse(JobType t, Unit *u) { return JOB_RESTART; + case JOB_TRY_RELOAD: + s = unit_active_state(u); + if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) + return JOB_NOP; + + return JOB_RELOAD; + case JOB_RELOAD_OR_START: s = unit_active_state(u); if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s)) @@ -754,7 +760,7 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) { return; DISABLE_WARNING_FORMAT_NONLITERAL; - snprintf(buf, sizeof(buf), format, unit_description(u)); + xsprintf(buf, format, unit_description(u)); REENABLE_WARNING; switch (t) { @@ -924,14 +930,14 @@ int job_start_timer(Job *j) { j->begin_usec = now(CLOCK_MONOTONIC); - if (j->unit->job_timeout <= 0) + if (j->unit->job_timeout == USEC_INFINITY) return 0; r = sd_event_add_time( j->manager->event, &j->timer_event_source, CLOCK_MONOTONIC, - j->begin_usec + j->unit->job_timeout, 0, + usec_add(j->begin_usec, j->unit->job_timeout), 0, job_dispatch_timer, j); if (r < 0) return r; @@ -1109,17 +1115,16 @@ int job_coldplug(Job *j) { if (j->state == JOB_WAITING) job_add_to_run_queue(j); - if (j->begin_usec == 0 || j->unit->job_timeout == 0) + if (j->begin_usec == 0 || j->unit->job_timeout == USEC_INFINITY) return 0; - if (j->timer_event_source) - j->timer_event_source = sd_event_source_unref(j->timer_event_source); + j->timer_event_source = sd_event_source_unref(j->timer_event_source); r = sd_event_add_time( j->manager->event, &j->timer_event_source, CLOCK_MONOTONIC, - j->begin_usec + j->unit->job_timeout, 0, + usec_add(j->begin_usec, j->unit->job_timeout), 0, job_dispatch_timer, j); if (r < 0) log_debug_errno(r, "Failed to restart timeout for job: %m"); @@ -1158,10 +1163,10 @@ void job_shutdown_magic(Job *j) { asynchronous_sync(); } -int job_get_timeout(Job *j, uint64_t *timeout) { +int job_get_timeout(Job *j, usec_t *timeout) { + usec_t x = USEC_INFINITY, y = USEC_INFINITY; Unit *u = j->unit; - uint64_t x = -1, y = -1; - int r = 0, q = 0; + int r; assert(u); @@ -1169,20 +1174,18 @@ int job_get_timeout(Job *j, uint64_t *timeout) { r = sd_event_source_get_time(j->timer_event_source, &x); if (r < 0) return r; - r = 1; } if (UNIT_VTABLE(u)->get_timeout) { - q = UNIT_VTABLE(u)->get_timeout(u, &y); - if (q < 0) - return q; + r = UNIT_VTABLE(u)->get_timeout(u, &y); + if (r < 0) + return r; } - if (r == 0 && q == 0) + if (x == USEC_INFINITY && y == USEC_INFINITY) return 0; *timeout = MIN(x, y); - return 1; } @@ -1201,6 +1204,7 @@ static const char* const job_type_table[_JOB_TYPE_MAX] = { [JOB_RELOAD_OR_START] = "reload-or-start", [JOB_RESTART] = "restart", [JOB_TRY_RESTART] = "try-restart", + [JOB_TRY_RELOAD] = "try-reload", [JOB_NOP] = "nop", }; @@ -1231,3 +1235,15 @@ static const char* const job_result_table[_JOB_RESULT_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult); + +const char* job_type_to_access_method(JobType t) { + assert(t >= 0); + assert(t < _JOB_TYPE_MAX); + + if (IN_SET(t, JOB_START, JOB_RESTART, JOB_TRY_RESTART)) + return "start"; + else if (t == JOB_STOP) + return "stop"; + else + return "reload"; +} diff --git a/src/core/job.h b/src/core/job.h index 60d8bd4f3..856b0ce82 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -26,6 +24,7 @@ #include "sd-event.h" #include "list.h" +#include "unit-name.h" typedef struct Job Job; typedef struct JobDependency JobDependency; @@ -65,6 +64,9 @@ enum JobType { * Thus we never need to merge it with anything. */ JOB_TRY_RESTART = _JOB_TYPE_MAX_IN_TRANSACTION, /* if running, stop and then start */ + /* Similar to JOB_TRY_RESTART but collapses to JOB_RELOAD or JOB_NOP */ + JOB_TRY_RELOAD, + /* JOB_RELOAD_OR_START won't enter into a transaction and cannot result * from transaction merging (there's no way for JOB_RELOAD and * JOB_START to meet in one transaction). It can result from a merge @@ -223,6 +225,8 @@ char *job_dbus_path(Job *j); void job_shutdown_magic(Job *j); +int job_get_timeout(Job *j, usec_t *timeout) _pure_; + const char* job_type_to_string(JobType t) _const_; JobType job_type_from_string(const char *s) _pure_; @@ -235,4 +239,4 @@ JobMode job_mode_from_string(const char *s) _pure_; const char* job_result_to_string(JobResult t) _const_; JobResult job_result_from_string(const char *s) _pure_; -int job_get_timeout(Job *j, uint64_t *timeout) _pure_; +const char* job_type_to_access_method(JobType t); diff --git a/src/core/kill.c b/src/core/kill.c index 1466d5ce6..6854587d5 100644 --- a/src/core/kill.c +++ b/src/core/kill.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/kill.h b/src/core/kill.h index 5d97abb10..b3d2056cb 100644 --- a/src/core/kill.h +++ b/src/core/kill.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/killall.c b/src/core/killall.c index 77f145b4d..09378f708 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -37,7 +35,7 @@ #define TIMEOUT_USEC (10 * USEC_PER_SEC) -static bool ignore_proc(pid_t pid) { +static bool ignore_proc(pid_t pid, bool warn_rootfs) { _cleanup_fclose_ FILE *f = NULL; char c; const char *p; @@ -72,7 +70,22 @@ static bool ignore_proc(pid_t pid) { * spree. * * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */ - if (count == 1 && c == '@') + if (c == '@' && warn_rootfs) { + _cleanup_free_ char *comm = NULL; + + r = pid_from_same_root_fs(pid); + if (r < 0) + return true; + + get_process_comm(pid, &comm); + + if (r) + log_notice("Process " PID_FMT " (%s) has been been marked to be excluded from killing. It is " + "running from the root file system, and thus likely to block re-mounting of the " + "root file system to read-only. Please consider moving it into an initrd file " + "system instead.", pid, strna(comm)); + return true; + } else if (c == '@') return true; return false; @@ -171,7 +184,7 @@ static int killall(int sig, Set *pids, bool send_sighup) { if (parse_pid(d->d_name, &pid) < 0) continue; - if (ignore_proc(pid)) + if (ignore_proc(pid, sig == SIGKILL && !in_initrd())) continue; if (sig == SIGKILL) { diff --git a/src/core/killall.h b/src/core/killall.h index 986cf432c..acc2439f0 100644 --- a/src/core/killall.h +++ b/src/core/killall.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c index a6ab8cf4b..3503db52e 100644 --- a/src/core/kmod-setup.c +++ b/src/core/kmod-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/kmod-setup.h b/src/core/kmod-setup.h index 24dcdddfa..685f4df30 100644 --- a/src/core/kmod-setup.h +++ b/src/core/kmod-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index 3fa66f91a..22b71b6f5 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -65,6 +63,7 @@ int unit_load_dropin(Unit *u) { } } + u->dropin_paths = strv_free(u->dropin_paths); r = unit_find_dropin_paths(u, &u->dropin_paths); if (r <= 0) return 0; diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h index 1e018c452..d8a4aefbb 100644 --- a/src/core/load-dropin.h +++ b/src/core/load-dropin.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#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 74ef72de8..5024fd19a 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -47,7 +47,8 @@ $1.SyslogLevel, config_parse_log_level, 0, $1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix) $1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context) $1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context) -$1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop) +$1.CapabilityBoundingSet, config_parse_capability_set, 0, offsetof($1, exec_context.capability_bounding_set) +$1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set) $1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec) $1.NoNewPrivileges, config_parse_no_new_privileges, 0, offsetof($1, exec_context) m4_ifdef(`HAVE_SECCOMP', @@ -59,22 +60,22 @@ $1.RestrictAddressFamilies, config_parse_address_families, 0, $1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0 $1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0') -$1.LimitCPU, config_parse_sec_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) -$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) -$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) -$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) -$1.LimitCORE, config_parse_bytes_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) -$1.LimitRSS, config_parse_bytes_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) +$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit) +$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit) +$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit) +$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit) +$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit) +$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit) $1.LimitNOFILE, config_parse_limit, RLIMIT_NOFILE, offsetof($1, exec_context.rlimit) -$1.LimitAS, config_parse_bytes_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) +$1.LimitAS, config_parse_limit, RLIMIT_AS, offsetof($1, exec_context.rlimit) $1.LimitNPROC, config_parse_limit, RLIMIT_NPROC, offsetof($1, exec_context.rlimit) -$1.LimitMEMLOCK, config_parse_bytes_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) +$1.LimitMEMLOCK, config_parse_limit, RLIMIT_MEMLOCK, offsetof($1, exec_context.rlimit) $1.LimitLOCKS, config_parse_limit, RLIMIT_LOCKS, offsetof($1, exec_context.rlimit) $1.LimitSIGPENDING, config_parse_limit, RLIMIT_SIGPENDING, offsetof($1, exec_context.rlimit) -$1.LimitMSGQUEUE, config_parse_bytes_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) +$1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQUEUE, offsetof($1, exec_context.rlimit) $1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit) $1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit) -$1.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) +$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit) $1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs) $1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs) $1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs) @@ -128,7 +129,7 @@ $1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, $1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting) $1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max) $1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate) -$1.NetClass, config_parse_netclass, 0, offsetof($1, cgroup_context)' +$1.NetClass, config_parse_warn_compat, DISABLED_LEGACY, 0' )m4_dnl Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation) @@ -160,9 +161,13 @@ Unit.OnFailureJobMode, config_parse_job_mode, 0, Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, offsetof(Unit, on_failure_job_mode) Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate) Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LEGACY, 0 -Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout) +Unit.JobTimeoutSec, config_parse_sec_fix_0, 0, offsetof(Unit, job_timeout) Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action) Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg) +Unit.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) +Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) +Unit.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action) +Unit.RebootArgument, config_parse_string, 0, offsetof(Unit, reboot_arg) Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions) Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions) Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, conditions) @@ -210,14 +215,15 @@ Service.ExecReload, config_parse_exec, SERVICE_EXE Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command) Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command) Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec) -Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec) -Service.TimeoutStartSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec) -Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec) +Service.TimeoutSec, config_parse_service_timeout, 0, 0 +Service.TimeoutStartSec, config_parse_service_timeout, 0, 0 +Service.TimeoutStopSec, config_parse_service_timeout, 0, 0 +Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec) Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec) -Service.StartLimitInterval, config_parse_sec, 0, offsetof(Service, start_limit.interval) -Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst) -Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Service, start_limit_action) -Service.RebootArgument, config_parse_string, 0, offsetof(Service, reboot_arg) +Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval) +Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst) +Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action) +Service.RebootArgument, config_parse_string, 0, offsetof(Unit, reboot_arg) Service.FailureAction, config_parse_failure_action, 0, offsetof(Service, failure_action) Service.Type, config_parse_service_type, 0, offsetof(Service, type) Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart) @@ -249,6 +255,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 @@ -346,6 +353,7 @@ Timer.Persistent, config_parse_bool, 0, 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 dda79267f..b3dec7b8c 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -38,6 +36,7 @@ #include "bus-internal.h" #include "bus-util.h" #include "cap-list.h" +#include "capability-util.h" #include "cgroup.h" #include "conf-parser.h" #include "cpu-set-util.h" @@ -53,6 +52,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "rlimit-util.h" #ifdef HAVE_SECCOMP #include "seccomp-util.h" #endif @@ -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, @@ -543,7 +574,9 @@ int config_parse_exec( void *data, void *userdata) { + _cleanup_free_ char *cmd = NULL; ExecCommand **e = data; + Unit *u = userdata; const char *p; bool semicolon; int r; @@ -552,6 +585,7 @@ int config_parse_exec( assert(lvalue); assert(rvalue); assert(e); + assert(u); e += ltype; rvalue += strspn(rvalue, WHITESPACE); @@ -562,7 +596,13 @@ int config_parse_exec( return 0; } - p = rvalue; + r = unit_full_printf(u, rvalue, &cmd); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue); + return 0; + } + + p = cmd; do { _cleanup_free_ char *path = NULL, *firstword = NULL; bool separate_argv0 = false, ignore = false; @@ -993,7 +1033,7 @@ int config_parse_exec_secure_bits(const char *unit, return 0; } -int config_parse_bounding_set( +int config_parse_capability_set( const char *unit, const char *filename, unsigned line, @@ -1005,8 +1045,8 @@ int config_parse_bounding_set( void *data, void *userdata) { - uint64_t *capability_bounding_set_drop = data; - uint64_t capability_bounding_set, sum = 0; + uint64_t *capability_set = data; + uint64_t sum = 0, initial = 0; bool invert = false; const char *p; @@ -1020,10 +1060,9 @@ int config_parse_bounding_set( rvalue++; } - /* Note that we store this inverted internally, since the - * kernel wants it like this. But we actually expose it - * non-inverted everywhere to have a fully normalized - * interface. */ + if (strcmp(lvalue, "CapabilityBoundingSet") == 0) + initial = CAP_ALL; /* initialized to all bits on */ + /* else "AmbientCapabilities" initialized to all bits off */ p = rvalue; for (;;) { @@ -1042,18 +1081,21 @@ int config_parse_bounding_set( cap = capability_from_name(word); if (cap < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word); + log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word); continue; } sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap; } - capability_bounding_set = invert ? ~sum : sum; - if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0) - *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set); + sum = invert ? ~sum : sum; + + if (sum == 0 || *capability_set == initial) + /* "" or uninitialized data -> replace */ + *capability_set = sum; else - *capability_bounding_set_drop = ~capability_bounding_set; + /* previous data -> merge */ + *capability_set |= sum; return 0; } @@ -1070,8 +1112,7 @@ int config_parse_limit( void *data, void *userdata) { - struct rlimit **rl = data; - rlim_t v; + struct rlimit **rl = data, d = {}; int r; assert(filename); @@ -1079,184 +1120,24 @@ int config_parse_limit( assert(rvalue); assert(data); - rl += ltype; - - if (streq(rvalue, "infinity")) - v = 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); - 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; - } - - v = (rlim_t) u; + r = rlimit_parse(ltype, rvalue, &d); + if (r == -EILSEQ) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue); + return 0; + } + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue); + return 0; } - if (!*rl) { - *rl = new(struct rlimit, 1); - if (!*rl) + if (rl[ltype]) + *rl[ltype] = d; + else { + rl[ltype] = newdup(struct rlimit, &d, 1); + if (!rl[ltype]) return log_oom(); } - (*rl)->rlim_cur = (*rl)->rlim_max = v; - 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) { - - struct rlimit **rl = data; - rlim_t bytes; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - rl += ltype; - - 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; - } - - bytes = (rlim_t) u; - } - - if (!*rl) { - *rl = new(struct rlimit, 1); - if (!*rl) - return log_oom(); - } - - (*rl)->rlim_cur = (*rl)->rlim_max = bytes; - return 0; -} - -int config_parse_sec_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) { - - struct rlimit **rl = data; - rlim_t seconds; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - 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; -} - - -int config_parse_usec_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) { - - struct rlimit **rl = data; - rlim_t useconds; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - rl += ltype; - - 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; } @@ -1305,38 +1186,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; } @@ -1670,7 +1541,7 @@ int config_parse_socket_service( void *data, void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *p = NULL; Socket *s = data; Unit *x; @@ -1840,18 +1711,20 @@ int config_parse_bus_name( return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, userdata); } -int config_parse_service_timeout(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_service_timeout( + 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) { Service *s = userdata; + usec_t usec; int r; assert(filename); @@ -1859,16 +1732,63 @@ int config_parse_service_timeout(const char *unit, assert(rvalue); assert(s); - r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype, - rvalue, data, userdata); - if (r < 0) - return r; + /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */ - if (streq(lvalue, "TimeoutSec")) { - s->start_timeout_defined = true; - s->timeout_stop_usec = s->timeout_start_usec; - } else if (streq(lvalue, "TimeoutStartSec")) + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue); + return 0; + } + + /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens + * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle + * all other timeouts. */ + if (usec <= 0) + usec = USEC_INFINITY; + + if (!streq(lvalue, "TimeoutStopSec")) { s->start_timeout_defined = true; + s->timeout_start_usec = usec; + } + + if (!streq(lvalue, "TimeoutStartSec")) + s->timeout_stop_usec = usec; + + return 0; +} + +int config_parse_sec_fix_0( + 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) { + + usec_t *usec = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(usec); + + /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for + * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a + * timeout. */ + + r = parse_sec(rvalue, usec); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue); + return 0; + } + + if (*usec <= 0) + *usec = USEC_INFINITY; return 0; } @@ -1885,7 +1805,7 @@ int config_parse_busname_service( void *data, void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; BusName *n = data; int r; Unit *x; @@ -3242,47 +3162,6 @@ int config_parse_blockio_bandwidth( return 0; } -int config_parse_netclass( - 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) { - - CGroupContext *c = data; - unsigned v; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - - if (streq(rvalue, "auto")) { - c->netclass_type = CGROUP_NETCLASS_TYPE_AUTO; - return 0; - } - - r = safe_atou32(rvalue, &v); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Netclass '%s' invalid. Ignoring.", rvalue); - return 0; - } - - if (v > CGROUP_NETCLASS_FIXED_MAX) - log_syntax(unit, LOG_ERR, filename, line, 0, - "Fixed netclass %" PRIu32 " out of allowed range (0-%d). Applying anyway.", v, (uint32_t) CGROUP_NETCLASS_FIXED_MAX); - - c->netclass_id = v; - c->netclass_type = CGROUP_NETCLASS_TYPE_FIXED; - - return 0; -} - DEFINE_CONFIG_PARSE_ENUM(config_parse_job_mode, job_mode, JobMode, "Failed to parse job mode"); int config_parse_job_mode_isolate( @@ -3973,7 +3852,7 @@ void unit_dump_config_items(FILE *f) { { config_parse_log_level, "LEVEL" }, { config_parse_exec_capabilities, "CAPABILITIES" }, { config_parse_exec_secure_bits, "SECUREBITS" }, - { config_parse_bounding_set, "BOUNDINGSET" }, + { config_parse_capability_set, "BOUNDINGSET" }, { config_parse_limit, "LIMIT" }, { config_parse_unit_deps, "UNIT [...]" }, { config_parse_exec, "PATH [ARGUMENT [...]]" }, diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 62300c10f..5fb591091 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -38,6 +36,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); @@ -55,11 +54,8 @@ int config_parse_exec_cpu_sched_prio(const char *unit, const char *filename, uns int config_parse_exec_cpu_affinity(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_capabilities(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_secure_bits(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_bounding_set(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_capability_set(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_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int 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); -int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_kill_signal(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_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); @@ -113,6 +109,7 @@ int config_parse_bus_name(const char* unit, const char *filename, unsigned line, int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_fdname(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_sec_fix_0(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length); diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c index 4c8d92038..ccf61d29f 100644 --- a/src/core/locale-setup.c +++ b/src/core/locale-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/locale-setup.h b/src/core/locale-setup.h index 62c654c37..3b97497af 100644 --- a/src/core/locale-setup.h +++ b/src/core/locale-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c index 4a5779310..04062a791 100644 --- a/src/core/loopback-setup.c +++ b/src/core/loopback-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -29,7 +27,7 @@ #include "netlink-util.h" static int start_loopback(sd_netlink *rtnl) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, LOOPBACK_IFINDEX); @@ -48,7 +46,7 @@ static int start_loopback(sd_netlink *rtnl) { } static bool check_loopback(sd_netlink *rtnl) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; unsigned flags; int r; @@ -68,7 +66,7 @@ static bool check_loopback(sd_netlink *rtnl) { } int loopback_setup(void) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int r; r = sd_netlink_open(&rtnl); diff --git a/src/core/loopback-setup.h b/src/core/loopback-setup.h index dd83cf13a..e7547b8a2 100644 --- a/src/core/loopback-setup.h +++ b/src/core/loopback-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c index 145ba2a28..9e6b3d329 100644 --- a/src/core/machine-id-setup.c +++ b/src/core/machine-id-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -198,7 +196,7 @@ static int generate_machine_id(char id[34], const char *root) { return 0; } -int machine_id_setup(const char *root) { +int machine_id_setup(const char *root, sd_id128_t machine_id) { const char *etc_machine_id, *run_machine_id; _cleanup_close_ int fd = -1; bool writable = true; @@ -248,15 +246,22 @@ int machine_id_setup(const char *root) { } } - if (read_machine_id(fd, id) >= 0) - return 0; + /* A machine id argument overrides all other machined-ids */ + if (!sd_id128_is_null(machine_id)) { + sd_id128_to_string(machine_id, id); + id[32] = '\n'; + id[33] = 0; + } else { + if (read_machine_id(fd, id) >= 0) + return 0; - /* Hmm, so, the id currently stored is not useful, then let's - * generate one */ + /* Hmm, so, the id currently stored is not useful, then let's + * generate one */ - r = generate_machine_id(id, root); - if (r < 0) - return r; + r = generate_machine_id(id, root); + if (r < 0) + return r; + } if (writable) if (write_machine_id(fd, id) >= 0) diff --git a/src/core/machine-id-setup.h b/src/core/machine-id-setup.h index f7707c3bf..a7e7678ed 100644 --- a/src/core/machine-id-setup.h +++ b/src/core/machine-id-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,4 +20,4 @@ ***/ int machine_id_commit(const char *root); -int machine_id_setup(const char *root); +int machine_id_setup(const char *root, sd_id128_t machine_id); diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in index 8a0e44b58..2cace3d3b 100644 --- a/src/core/macros.systemd.in +++ b/src/core/macros.systemd.in @@ -43,7 +43,7 @@ if [ $1 -eq 1 ] ; then \ fi \ %{nil} -%systemd_user_post() %systemd_post --user --global %{?*} +%systemd_user_post() %{expand:%systemd_post \\--user \\--global %%{?*}} %systemd_preun() \ if [ $1 -eq 0 ] ; then \ diff --git a/src/core/main.c b/src/core/main.c index 97f904b03..e2088574c 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -117,7 +115,7 @@ static usec_t arg_runtime_watchdog = 0; static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE; static char **arg_default_environment = NULL; static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {}; -static uint64_t arg_capability_bounding_set_drop = 0; +static uint64_t arg_capability_bounding_set = CAP_ALL; static nsec_t arg_timer_slack_nsec = NSEC_INFINITY; static usec_t arg_default_timer_accuracy_usec = 1 * USEC_PER_MINUTE; static Set* arg_syscall_archs = NULL; @@ -127,6 +125,7 @@ static bool arg_default_blockio_accounting = false; static bool arg_default_memory_accounting = false; static bool arg_default_tasks_accounting = true; static uint64_t arg_default_tasks_max = UINT64_C(512); +static sd_id128_t arg_machine_id = {}; static void pager_open_if_enabled(void) { @@ -173,19 +172,15 @@ noreturn static void crash(int sig) { if (pid < 0) log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig)); else if (pid == 0) { - struct rlimit rl = { - .rlim_cur = RLIM_INFINITY, - .rlim_max = RLIM_INFINITY, - }; - /* Enable default signal handler for core dump */ + sa = (struct sigaction) { .sa_handler = SIG_DFL, }; (void) sigaction(sig, &sa, NULL); - /* Don't limit the core dump size */ - (void) setrlimit(RLIMIT_CORE, &rl); + /* Don't limit the coredump size */ + (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY)); /* Just to be sure... */ (void) chdir("/"); @@ -300,6 +295,17 @@ static int parse_crash_chvt(const char *value) { return 0; } +static int set_machine_id(const char *m) { + + if (sd_id128_from_string(m, &arg_machine_id) < 0) + return -EINVAL; + + if (sd_id128_is_null(arg_machine_id)) + return -EINVAL; + + return 0; +} + static int parse_proc_cmdline_item(const char *key, const char *value) { int r; @@ -388,6 +394,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) { } else log_warning("Environment variable name '%s' is not valid. Ignoring.", value); + } else if (streq(key, "systemd.machine_id") && value) { + + r = set_machine_id(value); + if (r < 0) + log_warning("MachineID '%s' is not valid. Ignoring.", value); + } else if (streq(key, "quiet") && !value) { if (arg_show_status == _SHOW_STATUS_UNSET) @@ -644,7 +656,7 @@ static int parse_config_file(void) { { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers }, { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog }, { "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog }, - { "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop }, + { "Manager", "CapabilityBoundingSet", config_parse_capability_set, 0, &arg_capability_bounding_set }, #ifdef HAVE_SECCOMP { "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs }, #endif @@ -658,22 +670,22 @@ 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_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] }, - { "Manager", "DefaultLimitCORE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_CORE] }, - { "Manager", "DefaultLimitRSS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_RSS] }, - { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] }, - { "Manager", "DefaultLimitAS", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_AS] }, - { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] }, - { "Manager", "DefaultLimitMEMLOCK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] }, - { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] }, - { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] }, - { "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_usec_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] }, + { "Manager", "DefaultLimitCPU", config_parse_limit, RLIMIT_CPU, arg_default_rlimit }, + { "Manager", "DefaultLimitFSIZE", config_parse_limit, RLIMIT_FSIZE, arg_default_rlimit }, + { "Manager", "DefaultLimitDATA", config_parse_limit, RLIMIT_DATA, arg_default_rlimit }, + { "Manager", "DefaultLimitSTACK", config_parse_limit, RLIMIT_STACK, arg_default_rlimit }, + { "Manager", "DefaultLimitCORE", config_parse_limit, RLIMIT_CORE, arg_default_rlimit }, + { "Manager", "DefaultLimitRSS", config_parse_limit, RLIMIT_RSS, arg_default_rlimit }, + { "Manager", "DefaultLimitNOFILE", config_parse_limit, RLIMIT_NOFILE, arg_default_rlimit }, + { "Manager", "DefaultLimitAS", config_parse_limit, RLIMIT_AS, arg_default_rlimit }, + { "Manager", "DefaultLimitNPROC", config_parse_limit, RLIMIT_NPROC, arg_default_rlimit }, + { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, RLIMIT_MEMLOCK, arg_default_rlimit }, + { "Manager", "DefaultLimitLOCKS", config_parse_limit, RLIMIT_LOCKS, arg_default_rlimit }, + { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, RLIMIT_SIGPENDING, arg_default_rlimit }, + { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, RLIMIT_MSGQUEUE, arg_default_rlimit }, + { "Manager", "DefaultLimitNICE", config_parse_limit, RLIMIT_NICE, arg_default_rlimit }, + { "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit }, + { "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit }, { "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 }, @@ -692,8 +704,14 @@ static int parse_config_file(void) { CONF_PATHS_NULSTR("systemd/system.conf.d") : CONF_PATHS_NULSTR("systemd/user.conf.d"); - config_parse_many(fn, conf_dirs_nulstr, "Manager\0", - config_item_table_lookup, items, false, NULL); + config_parse_many(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL); + + /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY + * like everywhere else. */ + if (arg_default_timeout_start_usec <= 0) + arg_default_timeout_start_usec = USEC_INFINITY; + if (arg_default_timeout_stop_usec <= 0) + arg_default_timeout_stop_usec = USEC_INFINITY; return 0; } @@ -743,7 +761,8 @@ static int parse_argv(int argc, char *argv[]) { ARG_DESERIALIZE, ARG_SWITCHED_ROOT, ARG_DEFAULT_STD_OUTPUT, - ARG_DEFAULT_STD_ERROR + ARG_DEFAULT_STD_ERROR, + ARG_MACHINE_ID }; static const struct option options[] = { @@ -769,6 +788,7 @@ static int parse_argv(int argc, char *argv[]) { { "switched-root", no_argument, NULL, ARG_SWITCHED_ROOT }, { "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, }, { "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, }, + { "machine-id", required_argument, NULL, ARG_MACHINE_ID }, {} }; @@ -964,6 +984,14 @@ static int parse_argv(int argc, char *argv[]) { arg_switched_root = true; break; + case ARG_MACHINE_ID: + r = set_machine_id(optarg); + if (r < 0) { + log_error("MachineID '%s' is not valid.", optarg); + return r; + } + break; + case 'h': arg_action = ACTION_HELP; if (arg_no_pager < 0) @@ -1335,7 +1363,11 @@ int main(int argc, char *argv[]) { initrd_timestamp = userspace_timestamp; if (!skip_setup) { - mount_setup_early(); + r = mount_setup_early(); + if (r < 0) { + error_message = "Failed to early mount API filesystems"; + goto finish; + } dual_timestamp_get(&security_start_timestamp); if (mac_selinux_setup(&loaded_policy) < 0) { error_message = "Failed to load SELinux policy"; @@ -1386,8 +1418,14 @@ int main(int argc, char *argv[]) { * saving time change. All kernel local time concepts will be treated * as UTC that way. */ - clock_reset_timewarp(); + (void) clock_reset_timewarp(); } + + r = clock_apply_epoch(); + if (r < 0) + log_error_errno(r, "Current system time is before build time, but cannot correct: %m"); + else if (r > 0) + log_info("System time before build time, advancing clock."); } /* Set the default for later on, but don't actually @@ -1424,6 +1462,17 @@ int main(int argc, char *argv[]) { kernel_timestamp = DUAL_TIMESTAMP_NULL; } + if (getpid() == 1) { + /* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour the limit) + * will process core dumps for system services by default. */ + (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY)); + + /* But at the same time, turn off the core_pattern logic by default, so that no coredumps are stored + * until the systemd-coredump tool is enabled via sysctl. */ + if (!skip_setup) + (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0); + } + /* Initialize default unit */ r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET); if (r < 0) { @@ -1617,7 +1666,7 @@ int main(int argc, char *argv[]) { status_welcome(); hostname_setup(); - machine_id_setup(NULL); + machine_id_setup(NULL, arg_machine_id); loopback_setup(); bump_unix_max_dgram_qlen(); @@ -1631,14 +1680,14 @@ int main(int argc, char *argv[]) { if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0) log_error_errno(errno, "Failed to adjust timer slack: %m"); - if (arg_capability_bounding_set_drop) { - r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop); + if (!cap_test_all(arg_capability_bounding_set)) { + r = capability_bounding_set_drop_usermode(arg_capability_bounding_set); if (r < 0) { log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m"); error_message = "Failed to drop capability bounding set of usermode helpers"; goto finish; } - r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true); + r = capability_bounding_set_drop(arg_capability_bounding_set, true); if (r < 0) { log_emergency_errno(r, "Failed to drop capability bounding set: %m"); error_message = "Failed to drop capability bounding set"; @@ -1665,7 +1714,7 @@ int main(int argc, char *argv[]) { if (empty_etc) { r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, false, NULL, 0); if (r < 0) - log_warning_errno(r, "Failed to populate /etc with preset unit settings, ignoring: %m"); + log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r, "Failed to populate /etc with preset unit settings, ignoring: %m"); else log_info("Populated /etc with preset unit settings."); } @@ -1707,7 +1756,7 @@ int main(int argc, char *argv[]) { arg_serialization = safe_fclose(arg_serialization); if (queue_default_job) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; Unit *target = NULL; Job *default_unit_job; @@ -1940,6 +1989,15 @@ finish: (void) clearenv(); assert(i <= args_size); + + /* + * We want valgrind to print its memory usage summary before reexecution. + * Valgrind won't do this is on its own on exec(), but it will do it on exit(). + * Hence, to ensure we get a summary here, fork() off a child, let it exit() cleanly, + * so that it prints the summary, and wait() for it in the parent, before proceeding into the exec(). + */ + valgrind_summary_hack(); + (void) execv(args[0], (char* const*) args); } diff --git a/src/core/manager.c b/src/core/manager.c index edff6758c..f36cf5e32 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -233,7 +231,7 @@ static int have_ask_password(void) { errno = 0; de = readdir(dir); - if (!de && errno != 0) + if (!de && errno > 0) return -errno; if (!de) return false; @@ -380,6 +378,9 @@ static int enable_special_signals(Manager *m) { assert(m); + if (m->test_run) + return 0; + /* Enable that we get SIGINT on control-alt-del. In containers * this will fail with EPERM (older) or EINVAL (newer), so * ignore that. */ @@ -595,8 +596,6 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) { m->have_ask_password = -EINVAL; /* we don't know */ m->first_boot = -1; - m->cgroup_netclass_registry_last = CGROUP_NETCLASS_FIXED_MAX; - m->test_run = test_run; /* Reboot immediately if the user hits C-A-D more often than 7x per 2s */ @@ -980,13 +979,11 @@ Manager* manager_free(Manager *m) { hashmap_free(m->cgroup_unit); set_free_free(m->unit_path_cache); - hashmap_free(m->cgroup_netclass_registry); - free(m->switch_root); free(m->switch_root_init); for (i = 0; i < _RLIMIT_MAX; i++) - free(m->rlimit[i]); + m->rlimit[i] = mfree(m->rlimit[i]); assert(hashmap_isempty(m->units_requiring_mounts_for)); hashmap_free(m->units_requiring_mounts_for); @@ -1257,7 +1254,7 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode } int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(m); @@ -1700,7 +1697,7 @@ static int manager_dispatch_sigchld(Manager *m) { } static int manager_start_target(Manager *m, const char *name, JobMode mode) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; log_debug("Activating special unit %s", name); @@ -1885,23 +1882,21 @@ static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t switch (sfsi.ssi_signo - SIGRTMIN) { case 20: - log_debug("Enabling showing of status."); manager_set_show_status(m, SHOW_STATUS_YES); break; case 21: - log_debug("Disabling showing of status."); manager_set_show_status(m, SHOW_STATUS_NO); break; case 22: log_set_max_level(LOG_DEBUG); - log_notice("Setting log level to debug."); + log_info("Setting log level to debug."); break; case 23: log_set_max_level(LOG_INFO); - log_notice("Setting log level to info."); + log_info("Setting log level to info."); break; case 24: @@ -2576,6 +2571,10 @@ int manager_reload(Manager *m) { /* Third, fire things up! */ manager_coldplug(m); + /* Sync current state of bus names with our set of listening units */ + if (m->api_bus) + manager_sync_bus_names(m, m->api_bus); + assert(m->n_reloading > 0); m->n_reloading--; @@ -2918,6 +2917,8 @@ int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) { assert(m); for (i = 0; i < _RLIMIT_MAX; i++) { + m->rlimit[i] = mfree(m->rlimit[i]); + if (!default_rlimit[i]) continue; @@ -2961,6 +2962,9 @@ void manager_set_show_status(Manager *m, ShowStatus mode) { if (m->running_as != MANAGER_SYSTEM) return; + if (m->show_status != mode) + log_debug("%s showing of status.", + mode == SHOW_STATUS_NO ? "Disabling" : "Enabling"); m->show_status = mode; if (mode > 0) @@ -3087,18 +3091,18 @@ ManagerState manager_state(Manager *m) { /* Is the special shutdown target queued? If so, we are in shutdown state */ u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET); - if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START)) + if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_RELOAD_OR_START)) return MANAGER_STOPPING; /* Are the rescue or emergency targets active or queued? If so we are in maintenance state */ u = manager_get_unit(m, SPECIAL_RESCUE_TARGET); if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) || - (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START)))) + (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_RELOAD_OR_START)))) return MANAGER_MAINTENANCE; u = manager_get_unit(m, SPECIAL_EMERGENCY_TARGET); if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) || - (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START)))) + (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_RELOAD_OR_START)))) return MANAGER_MAINTENANCE; /* Are there any failed units? If so, we are in degraded mode */ diff --git a/src/core/manager.h b/src/core/manager.h index b5b258f90..9803f7312 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,12 +19,13 @@ along with systemd; If not, see . ***/ +#include #include #include -#include #include "sd-bus.h" #include "sd-event.h" + #include "cgroup-util.h" #include "fdset.h" #include "hashmap.h" @@ -306,10 +305,6 @@ struct Manager { const char *unit_log_format_string; int first_boot; - - /* Used for NetClass=auto units */ - Hashmap *cgroup_netclass_registry; - uint32_t cgroup_netclass_registry_last; }; int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m); diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c index 2b8d590ed..de1a361cc 100644 --- a/src/core/mount-setup.c +++ b/src/core/mount-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -158,11 +156,13 @@ static int mount_one(const MountPoint *p, bool relabel) { /* Relabel first, just in case */ if (relabel) - label_fix(p->where, true, true); + (void) label_fix(p->where, true, true); r = path_is_mount_point(p->where, AT_SYMLINK_FOLLOW); - if (r < 0 && r != -ENOENT) - return r; + if (r < 0 && r != -ENOENT) { + log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, r, "Failed to determine whether %s is a mount point: %m", p->where); + return (p->mode & MNT_FATAL) ? r : 0; + } if (r > 0) return 0; @@ -173,9 +173,9 @@ static int mount_one(const MountPoint *p, bool relabel) { /* The access mode here doesn't really matter too much, since * the mounted file system will take precedence anyway. */ if (relabel) - mkdir_p_label(p->where, 0755); + (void) mkdir_p_label(p->where, 0755); else - mkdir_p(p->where, 0755); + (void) mkdir_p(p->where, 0755); log_debug("Mounting %s to %s of type %s with options %s.", p->what, @@ -188,29 +188,25 @@ static int mount_one(const MountPoint *p, bool relabel) { p->type, p->flags, p->options) < 0) { - log_full((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, "Failed to mount %s at %s: %m", p->type, p->where); + log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, errno, "Failed to mount %s at %s: %m", p->type, p->where); return (p->mode & MNT_FATAL) ? -errno : 0; } /* Relabel again, since we now mounted something fresh here */ if (relabel) - label_fix(p->where, false, false); + (void) label_fix(p->where, false, false); return 1; } -int mount_setup_early(void) { +static int mount_points_setup(unsigned n, bool loaded_policy) { unsigned i; int r = 0; - assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table)); - - /* Do a minimal mount of /proc and friends to enable the most - * basic stuff, such as SELinux */ - for (i = 0; i < N_EARLY_MOUNT; i ++) { + for (i = 0; i < n; i ++) { int j; - j = mount_one(mount_table + i, false); + j = mount_one(mount_table + i, loaded_policy); if (j != 0 && r >= 0) r = j; } @@ -218,6 +214,14 @@ int mount_setup_early(void) { return r; } +int mount_setup_early(void) { + assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table)); + + /* Do a minimal mount of /proc and friends to enable the most + * basic stuff, such as SELinux */ + return mount_points_setup(N_EARLY_MOUNT, false); +} + int mount_cgroup_controllers(char ***join_controllers) { _cleanup_set_free_free_ Set *controllers = NULL; int r; @@ -304,13 +308,18 @@ int mount_cgroup_controllers(char ***join_controllers) { return log_oom(); r = symlink(options, t); - if (r < 0 && errno != EEXIST) - return log_error_errno(errno, "Failed to create symlink %s: %m", t); + if (r >= 0) { #ifdef SMACK_RUN_LABEL - r = mac_smack_copy(t, options); - if (r < 0 && r != -EOPNOTSUPP) - return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", options, t); + _cleanup_free_ char *src; + src = strappend("/sys/fs/cgroup/", options); + if (!src) + return log_oom(); + r = mac_smack_copy(t, src); + if (r < 0 && r != -EOPNOTSUPP) + return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", src, t); #endif + } else if (errno != EEXIST) + return log_error_errno(errno, "Failed to create symlink %s: %m", t); } } } @@ -347,16 +356,9 @@ static int nftw_cb( #endif int mount_setup(bool loaded_policy) { - unsigned i; int r = 0; - for (i = 0; i < ELEMENTSOF(mount_table); i ++) { - int j; - - j = mount_one(mount_table + i, loaded_policy); - if (j != 0 && r >= 0) - r = j; - } + r = mount_points_setup(ELEMENTSOF(mount_table), loaded_policy); if (r < 0) return r; diff --git a/src/core/mount-setup.h b/src/core/mount-setup.h index b32fbc5a5..647bd770a 100644 --- a/src/core/mount-setup.h +++ b/src/core/mount-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/mount.c b/src/core/mount.c index 9b44357e9..de1075d3a 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -152,29 +150,27 @@ static void mount_init(Unit *u) { u->ignore_on_isolate = true; } -static int mount_arm_timer(Mount *m) { +static int mount_arm_timer(Mount *m, usec_t usec) { int r; assert(m); - if (m->timeout_usec <= 0) { - m->timer_event_source = sd_event_source_unref(m->timer_event_source); - return 0; - } - if (m->timer_event_source) { - r = sd_event_source_set_time(m->timer_event_source, now(CLOCK_MONOTONIC) + m->timeout_usec); + r = sd_event_source_set_time(m->timer_event_source, usec); if (r < 0) return r; return sd_event_source_set_enabled(m->timer_event_source, SD_EVENT_ONESHOT); } + if (usec == USEC_INFINITY) + return 0; + r = sd_event_add_time( UNIT(m)->manager->event, &m->timer_event_source, CLOCK_MONOTONIC, - now(CLOCK_MONOTONIC) + m->timeout_usec, 0, + usec, 0, mount_dispatch_timer, m); if (r < 0) return r; @@ -335,7 +331,7 @@ static int mount_add_device_links(Mount *m) { if (mount_is_auto(p) && UNIT(m)->manager->running_as == MANAGER_SYSTEM) device_wants_mount = true; - r = unit_add_node_link(UNIT(m), p->what, device_wants_mount); + r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES); if (r < 0) return r; @@ -653,7 +649,7 @@ static int mount_coldplug(Unit *u) { if (r < 0) return r; - r = mount_arm_timer(m); + r = mount_arm_timer(m, usec_add(u->state_change_timestamp.monotonic, m->timeout_usec)); if (r < 0) return r; } @@ -725,11 +721,11 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { r = unit_setup_exec_runtime(UNIT(m)); if (r < 0) - goto fail; + return r; - r = mount_arm_timer(m); + r = mount_arm_timer(m, usec_add(now(CLOCK_MONOTONIC), m->timeout_usec)); if (r < 0) - goto fail; + return r; exec_params.environment = UNIT(m)->manager->environment; exec_params.confirm_spawn = UNIT(m)->manager->confirm_spawn; @@ -745,21 +741,16 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { m->exec_runtime, &pid); if (r < 0) - goto fail; + return r; r = unit_watch_pid(UNIT(m), pid); if (r < 0) /* FIXME: we need to do something here */ - goto fail; + return r; *_pid = pid; return 0; - -fail: - m->timer_event_source = sd_event_source_unref(m->timer_event_source); - - return r; } static void mount_enter_dead(Mount *m, MountResult f) { @@ -805,7 +796,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) { goto fail; if (r > 0) { - r = mount_arm_timer(m); + r = mount_arm_timer(m, usec_add(now(CLOCK_MONOTONIC), m->timeout_usec)); if (r < 0) goto fail; @@ -1563,17 +1554,21 @@ static void mount_shutdown(Manager *m) { m->mount_monitor = NULL; } -static int mount_get_timeout(Unit *u, uint64_t *timeout) { +static int mount_get_timeout(Unit *u, usec_t *timeout) { Mount *m = MOUNT(u); + usec_t t; int r; if (!m->timer_event_source) return 0; - r = sd_event_source_get_time(m->timer_event_source, timeout); + r = sd_event_source_get_time(m->timer_event_source, &t); if (r < 0) return r; + if (t == USEC_INFINITY) + return 0; + *timeout = t; return 1; } diff --git a/src/core/mount.h b/src/core/mount.h index 83d14ae71..3b343c6b1 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,8 +21,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/namespace.c b/src/core/namespace.c index 81ba09ea5..4fa381db5 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/namespace.h b/src/core/namespace.h index 00ab22bf2..40bee74e2 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/path.c b/src/core/path.c index 02fb134bb..460c1d3bf 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -465,7 +463,8 @@ static void path_enter_dead(Path *p, PathResult f) { } static void path_enter_running(Path *p) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + Unit *trigger; int r; assert(p); @@ -474,7 +473,14 @@ static void path_enter_running(Path *p) { if (unit_stop_pending(UNIT(p))) return; - r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)), JOB_REPLACE, &error, NULL); + trigger = UNIT_TRIGGER(UNIT(p)); + if (!trigger) { + log_unit_error(UNIT(p), "Unit to trigger vanished."); + path_enter_dead(p, TIMER_FAILURE_RESOURCES); + return; + } + + r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL); if (r < 0) goto fail; @@ -555,12 +561,16 @@ static void path_mkdir(Path *p) { static int path_start(Unit *u) { Path *p = PATH(u); + Unit *trigger; assert(p); assert(p->state == PATH_DEAD || p->state == PATH_FAILED); - if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED) + trigger = UNIT_TRIGGER(u); + if (!trigger || trigger->load_state != UNIT_LOADED) { + log_unit_error(u, "Refusing to start, unit to trigger not loaded."); return -ENOENT; + } path_mkdir(p); diff --git a/src/core/path.h b/src/core/path.h index deb9bab1e..bbbcebd78 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/scope.c b/src/core/scope.c index 1953af1f8..c5d0ecef0 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -66,29 +64,27 @@ static void scope_done(Unit *u) { s->timer_event_source = sd_event_source_unref(s->timer_event_source); } -static int scope_arm_timer(Scope *s) { +static int scope_arm_timer(Scope *s, usec_t usec) { int r; assert(s); - if (s->timeout_stop_usec <= 0) { - s->timer_event_source = sd_event_source_unref(s->timer_event_source); - return 0; - } - if (s->timer_event_source) { - r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec); + r = sd_event_source_set_time(s->timer_event_source, usec); if (r < 0) return r; return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); } + if (usec == USEC_INFINITY) + return 0; + r = sd_event_add_time( UNIT(s)->manager->event, &s->timer_event_source, CLOCK_MONOTONIC, - now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0, + usec, 0, scope_dispatch_timer, s); if (r < 0) return r; @@ -190,20 +186,19 @@ static int scope_coldplug(Unit *u) { assert(s); assert(s->state == SCOPE_DEAD); - if (s->deserialized_state != s->state) { + if (s->deserialized_state == s->state) + return 0; - if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) { - r = scope_arm_timer(s); - if (r < 0) - return r; - } - - if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED)) - unit_watch_all_pids(UNIT(s)); - - scope_set_state(s, s->deserialized_state); + if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) { + r = scope_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_stop_usec)); + if (r < 0) + return r; } + if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED)) + unit_watch_all_pids(UNIT(s)); + + scope_set_state(s, s->deserialized_state); return 0; } @@ -261,7 +256,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) { r = 1; if (r > 0) { - r = scope_arm_timer(s); + r = scope_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec)); if (r < 0) goto fail; @@ -348,17 +343,21 @@ static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, -1, error); } -static int scope_get_timeout(Unit *u, uint64_t *timeout) { +static int scope_get_timeout(Unit *u, usec_t *timeout) { Scope *s = SCOPE(u); + usec_t t; int r; if (!s->timer_event_source) return 0; - r = sd_event_source_get_time(s->timer_event_source, timeout); + r = sd_event_source_get_time(s->timer_event_source, &t); if (r < 0) return r; + if (t == USEC_INFINITY) + return 0; + *timeout = t; return 1; } diff --git a/src/core/scope.h b/src/core/scope.h index f838ee535..2dc86325c 100644 --- a/src/core/scope.h +++ b/src/core/scope.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index 8856927c8..2cdfcf7b5 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -134,52 +132,45 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) { #endif va_start(ap, fmt); - log_internalv(LOG_AUTH | callback_type_to_priority(type), - 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap); + log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap); va_end(ap); return 0; } -/* - Function must be called once to initialize the SELinux AVC environment. - Sets up callbacks. - If you want to cleanup memory you should need to call selinux_access_finish. -*/ -static int access_init(void) { - int r = 0; - - if (avc_open(NULL, 0)) - return log_error_errno(errno, "avc_open() failed: %m"); - - selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback); - selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback); - - if (security_getenforce() < 0){ - r = -errno; - avc_destroy(); - } - - return r; -} - -static int mac_selinux_access_init(sd_bus_error *error) { - int r; - - if (initialized) - return 0; +static int access_init(sd_bus_error *error) { if (!mac_selinux_use()) return 0; - r = access_init(); - if (r < 0) - return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux."); + if (initialized) + return 1; + + if (avc_open(NULL, 0) != 0) { + int enforce, saved_errno = errno; + + enforce = security_getenforce(); + log_full_errno(enforce != 0 ? LOG_ERR : LOG_WARNING, saved_errno, "Failed to open the SELinux AVC: %m"); + + /* If enforcement isn't on, then let's suppress this + * error, and just don't do any AVC checks. The + * warning we printed is hence all the admin will + * see. */ + if (enforce == 0) + return 0; + + /* Return an access denied error, if we couldn't load + * the AVC but enforcing mode was on, or we couldn't + * determine whether it is one. */ + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to open the SELinux AVC: %s", strerror(saved_errno)); + } + + selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback); + selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback); initialized = true; - return 0; + return 1; } -#endif /* This function communicates with the kernel to check whether or not it should @@ -193,8 +184,7 @@ int mac_selinux_generic_access_check( const char *permission, sd_bus_error *error) { -#ifdef HAVE_SELINUX - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; const char *tclass = NULL, *scon = NULL; struct audit_info audit_info = {}; _cleanup_free_ char *cl = NULL; @@ -206,11 +196,8 @@ int mac_selinux_generic_access_check( assert(permission); assert(error); - if (!mac_selinux_use()) - return 0; - - r = mac_selinux_access_init(error); - if (r < 0) + r = access_init(error); + if (r <= 0) return r; r = sd_bus_query_sender_creds( @@ -277,7 +264,17 @@ finish: } return r; -#else - return 0; -#endif } + +#else + +int mac_selinux_generic_access_check( + sd_bus_message *message, + const char *path, + const char *permission, + sd_bus_error *error) { + + return 0; +} + +#endif diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h index 30725521c..8f1f058a3 100644 --- a/src/core/selinux-access.h +++ b/src/core/selinux-access.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,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 d4757e085..9a115a438 100644 --- a/src/core/selinux-setup.c +++ b/src/core/selinux-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/selinux-setup.h b/src/core/selinux-setup.h index 9ac227657..7b613249b 100644 --- a/src/core/selinux-setup.h +++ b/src/core/selinux-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/service.c b/src/core/service.c index c27b70fa3..ac7e41d77 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -112,14 +110,13 @@ static void service_init(Unit *u) { s->timeout_start_usec = u->manager->default_timeout_start_usec; s->timeout_stop_usec = u->manager->default_timeout_stop_usec; s->restart_usec = u->manager->default_restart_usec; + s->runtime_max_usec = USEC_INFINITY; s->type = _SERVICE_TYPE_INVALID; s->socket_fd = -1; s->bus_endpoint_fd = -1; s->stdin_fd = s->stdout_fd = s->stderr_fd = -1; s->guess_main_pid = true; - RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst); - s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID; } @@ -216,7 +213,7 @@ static void service_start_watchdog(Service *s) { return; if (s->watchdog_event_source) { - r = sd_event_source_set_time(s->watchdog_event_source, s->watchdog_timestamp.monotonic + s->watchdog_usec); + r = sd_event_source_set_time(s->watchdog_event_source, usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec)); if (r < 0) { log_unit_warning_errno(UNIT(s), r, "Failed to reset watchdog timer: %m"); return; @@ -228,7 +225,7 @@ static void service_start_watchdog(Service *s) { UNIT(s)->manager->event, &s->watchdog_event_source, CLOCK_MONOTONIC, - s->watchdog_timestamp.monotonic + s->watchdog_usec, 0, + usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec), 0, service_dispatch_watchdog, s); if (r < 0) { log_unit_warning_errno(UNIT(s), r, "Failed to add watchdog timer: %m"); @@ -301,7 +298,6 @@ static void service_done(Unit *u) { s->pid_file = mfree(s->pid_file); s->status_text = mfree(s->status_text); - s->reboot_arg = mfree(s->reboot_arg); s->exec_runtime = exec_runtime_unref(s->exec_runtime); exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX); @@ -323,6 +319,8 @@ static void service_done(Unit *u) { s->bus_name = mfree(s->bus_name); } + s->bus_name_owner = mfree(s->bus_name_owner); + s->bus_endpoint_fd = safe_close(s->bus_endpoint_fd); service_close_socket_fd(s); service_connection_unref(s); @@ -431,18 +429,21 @@ static int service_arm_timer(Service *s, usec_t usec) { assert(s); if (s->timer_event_source) { - r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + usec); + r = sd_event_source_set_time(s->timer_event_source, usec); if (r < 0) return r; return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); } + if (usec == USEC_INFINITY) + return 0; + r = sd_event_add_time( UNIT(s)->manager->event, &s->timer_event_source, CLOCK_MONOTONIC, - now(CLOCK_MONOTONIC) + usec, 0, + usec, 0, service_dispatch_timer, s); if (r < 0) return r; @@ -507,6 +508,9 @@ static int service_verify(Service *s) { if (!s->usb_function_descriptors && s->usb_function_strings) log_unit_warning(UNIT(s), "Service has USBFunctionStrings= setting, but no USBFunctionDescriptors=. Ignoring."); + if (s->runtime_max_usec != USEC_INFINITY && s->type == SERVICE_ONESHOT) + log_unit_warning(UNIT(s), "MaxRuntimeSec= has no effect in combination with Type=oneshot. Ignoring."); + return 0; } @@ -622,7 +626,7 @@ static int service_add_extras(Service *s) { /* Oneshot services have disabled start timeout by default */ if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined) - s->timeout_start_usec = 0; + s->timeout_start_usec = USEC_INFINITY; service_fix_output(s); @@ -880,6 +884,7 @@ static void service_set_state(Service *s, ServiceState state) { if (!IN_SET(state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, + SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, @@ -952,6 +957,37 @@ static void service_set_state(Service *s, ServiceState state) { unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS); } +static usec_t service_coldplug_timeout(Service *s) { + assert(s); + + switch (s->deserialized_state) { + + case SERVICE_START_PRE: + case SERVICE_START: + case SERVICE_START_POST: + case SERVICE_RELOAD: + return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec); + + case SERVICE_RUNNING: + return usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec); + + case SERVICE_STOP: + case SERVICE_STOP_SIGABRT: + case SERVICE_STOP_SIGTERM: + case SERVICE_STOP_SIGKILL: + case SERVICE_STOP_POST: + case SERVICE_FINAL_SIGTERM: + case SERVICE_FINAL_SIGKILL: + return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec); + + case SERVICE_AUTO_RESTART: + return usec_add(UNIT(s)->inactive_enter_timestamp.monotonic, s->restart_usec); + + default: + return USEC_INFINITY; + } +} + static int service_coldplug(Unit *u) { Service *s = SERVICE(u); int r; @@ -962,31 +998,9 @@ static int service_coldplug(Unit *u) { if (s->deserialized_state == s->state) return 0; - if (IN_SET(s->deserialized_state, - SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, - SERVICE_RELOAD, - SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, - SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { - - usec_t k; - - k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec; - - /* For the start/stop timeouts 0 means off */ - if (k > 0) { - r = service_arm_timer(s, k); - if (r < 0) - return r; - } - } - - if (s->deserialized_state == SERVICE_AUTO_RESTART) { - - /* The restart timeouts 0 means immediately */ - r = service_arm_timer(s, s->restart_usec); - if (r < 0) - return r; - } + r = service_arm_timer(s, service_coldplug_timeout(s)); + if (r < 0) + return r; if (s->main_pid > 0 && pid_is_unwaited(s->main_pid) && @@ -1173,7 +1187,7 @@ static int service_spawn( r = unit_setup_exec_runtime(UNIT(s)); if (r < 0) - goto fail; + return r; if (pass_fds || s->exec_context.std_input == EXEC_INPUT_SOCKET || @@ -1182,55 +1196,42 @@ static int service_spawn( r = service_collect_fds(s, &fds, &fd_names); if (r < 0) - goto fail; + return r; n_fds = r; } - if (timeout > 0) { - r = service_arm_timer(s, timeout); - if (r < 0) - goto fail; - } else - s->timer_event_source = sd_event_source_unref(s->timer_event_source); + r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), timeout)); + if (r < 0) + return r; r = unit_full_printf_strv(UNIT(s), c->argv, &argv); if (r < 0) - goto fail; + return r; our_env = new0(char*, 6); - if (!our_env) { - r = -ENOMEM; - goto fail; - } + if (!our_env) + return -ENOMEM; if (is_control ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE) - if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) { - r = -ENOMEM; - goto fail; - } + if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) + return -ENOMEM; if (s->main_pid > 0) - if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0) { - r = -ENOMEM; - goto fail; - } + if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0) + return -ENOMEM; if (UNIT(s)->manager->running_as != MANAGER_SYSTEM) - if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0) { - r = -ENOMEM; - goto fail; - } + if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0) + return -ENOMEM; if (s->socket_fd >= 0) { union sockaddr_union sa; socklen_t salen = sizeof(sa); r = getpeername(s->socket_fd, &sa.sa, &salen); - if (r < 0) { - r = -errno; - goto fail; - } + if (r < 0) + return -errno; if (IN_SET(sa.sa.sa_family, AF_INET, AF_INET6)) { _cleanup_free_ char *addr = NULL; @@ -1239,34 +1240,26 @@ static int service_spawn( r = sockaddr_pretty(&sa.sa, salen, true, false, &addr); if (r < 0) - goto fail; + return r; t = strappend("REMOTE_ADDR=", addr); - if (!t) { - r = -ENOMEM; - goto fail; - } + if (!t) + return -ENOMEM; our_env[n_env++] = t; port = sockaddr_port(&sa.sa); - if (port < 0) { - r = port; - goto fail; - } + if (port < 0) + return port; - if (asprintf(&t, "REMOTE_PORT=%u", port) < 0) { - r = -ENOMEM; - goto fail; - } + if (asprintf(&t, "REMOTE_PORT=%u", port) < 0) + return -ENOMEM; our_env[n_env++] = t; } } final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL); - if (!final_env) { - r = -ENOMEM; - goto fail; - } + if (!final_env) + return -ENOMEM; if (is_control && UNIT(s)->cgroup_path) { path = strjoina(UNIT(s)->cgroup_path, "/control"); @@ -1278,7 +1271,7 @@ static int service_spawn( r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == MANAGER_SYSTEM ? "system" : "user", UNIT(s)->id, &bus_endpoint_path); if (r < 0) - goto fail; + return r; /* Pass the fd to the exec_params so that the child process can upload the policy. * Keep a reference to the fd in the service, so the endpoint is kept alive as long @@ -1312,22 +1305,16 @@ static int service_spawn( s->exec_runtime, &pid); if (r < 0) - goto fail; + return r; r = unit_watch_pid(UNIT(s), pid); if (r < 0) /* FIXME: we need to do something here */ - goto fail; + return r; *_pid = pid; return 0; - -fail: - if (timeout) - s->timer_event_source = sd_event_source_unref(s->timer_event_source); - - return r; } static int main_pid_good(Service *s) { @@ -1430,12 +1417,12 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) if (s->result != SERVICE_SUCCESS) { log_unit_warning(UNIT(s), "Failed with result '%s'.", service_result_to_string(s->result)); - failure_action(UNIT(s)->manager, s->failure_action, s->reboot_arg); + failure_action(UNIT(s)->manager, s->failure_action, UNIT(s)->reboot_arg); } if (allow_restart && service_shall_restart(s)) { - r = service_arm_timer(s, s->restart_usec); + r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec)); if (r < 0) goto fail; @@ -1456,7 +1443,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) * out-of-date, and some software might be confused by it, so * let's remove it. */ if (s->pid_file) - unlink_noerrno(s->pid_file); + (void) unlink(s->pid_file); return; @@ -1543,11 +1530,9 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f goto fail; if (r > 0) { - if (s->timeout_stop_usec > 0) { - r = service_arm_timer(s, s->timeout_stop_usec); - if (r < 0) - goto fail; - } + r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec)); + if (r < 0) + goto fail; service_set_state(s, state); } else if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM) && s->kill_context.send_sigkill) @@ -1575,8 +1560,7 @@ static void service_enter_stop_by_notify(Service *s) { unit_watch_all_pids(UNIT(s)); - if (s->timeout_stop_usec > 0) - service_arm_timer(s, s->timeout_stop_usec); + service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec)); /* The service told us it's stopping, so it's as if we SIGTERM'd it. */ service_set_state(s, SERVICE_STOP_SIGTERM); @@ -1646,6 +1630,8 @@ static void service_enter_running(Service *s, ServiceResult f) { if (f != SERVICE_SUCCESS) s->result = f; + service_unwatch_control_pid(s); + if (service_good(s)) { /* If there are any queued up sd_notify() @@ -1654,8 +1640,10 @@ static void service_enter_running(Service *s, ServiceResult f) { service_enter_reload_by_notify(s); else if (s->notify_state == NOTIFY_STOPPING) service_enter_stop_by_notify(s); - else + else { service_set_state(s, SERVICE_RUNNING); + service_arm_timer(s, usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec)); + } } else if (s->remain_after_exit) service_set_state(s, SERVICE_EXITED); @@ -1709,6 +1697,7 @@ static void service_kill_control_processes(Service *s) { static void service_enter_start(Service *s) { ExecCommand *c; + usec_t timeout; pid_t pid; int r; @@ -1740,9 +1729,16 @@ static void service_enter_start(Service *s) { return; } + if (IN_SET(s->type, SERVICE_SIMPLE, SERVICE_IDLE)) + /* For simple + idle this is the main process. We don't apply any timeout here, but + * service_enter_running() will later apply the .runtime_max_usec timeout. */ + timeout = USEC_INFINITY; + else + timeout = s->timeout_start_usec; + r = service_spawn(s, c, - IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_ONESHOT) ? s->timeout_start_usec : 0, + timeout, true, true, true, @@ -1752,7 +1748,7 @@ static void service_enter_start(Service *s) { if (r < 0) goto fail; - if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) { + if (IN_SET(s->type, SERVICE_SIMPLE, SERVICE_IDLE)) { /* For simple services we immediately start * the START_POST binaries. */ @@ -1767,9 +1763,7 @@ static void service_enter_start(Service *s) { s->control_pid = pid; service_set_state(s, SERVICE_START); - } else if (s->type == SERVICE_ONESHOT || - s->type == SERVICE_DBUS || - s->type == SERVICE_NOTIFY) { + } else if (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, SERVICE_NOTIFY)) { /* For oneshot services we wait until the start * process exited, too, but it is our main process. */ @@ -1829,7 +1823,7 @@ fail: } static void service_enter_restart(Service *s) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(s); @@ -1838,7 +1832,7 @@ static void service_enter_restart(Service *s) { /* Don't restart things if we are going down anyway */ log_unit_info(UNIT(s), "Stop job pending for unit, delaying automatic restart."); - r = service_arm_timer(s, s->restart_usec); + r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec)); if (r < 0) goto fail; @@ -1868,9 +1862,7 @@ fail: static void service_enter_reload_by_notify(Service *s) { assert(s); - if (s->timeout_start_usec > 0) - service_arm_timer(s, s->timeout_start_usec); - + service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_start_usec)); service_set_state(s, SERVICE_RELOAD); } @@ -1911,6 +1903,7 @@ fail: } static void service_run_next_control(Service *s) { + usec_t timeout; int r; assert(s); @@ -1922,9 +1915,14 @@ static void service_run_next_control(Service *s) { s->control_command = s->control_command->command_next; service_unwatch_control_pid(s); + if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) + timeout = s->timeout_start_usec; + else + timeout = s->timeout_stop_usec; + r = service_spawn(s, s->control_command, - IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec, + timeout, false, !s->permissions_start_only, !s->root_directory_start_only, @@ -1986,20 +1984,8 @@ fail: service_enter_stop(s, SERVICE_FAILURE_RESOURCES); } -static int service_start_limit_test(Service *s) { - assert(s); - - if (ratelimit_test(&s->start_limit)) - return 0; - - log_unit_warning(UNIT(s), "Start request repeated too quickly."); - - return failure_action(UNIT(s)->manager, s->start_limit_action, s->reboot_arg); -} - static int service_start(Unit *u) { Service *s = SERVICE(u); - int r; assert(s); @@ -2026,13 +2012,6 @@ static int service_start(Unit *u) { assert(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED)); - /* Make sure we don't enter a busy loop of some kind. */ - r = service_start_limit_test(s); - if (r < 0) { - service_enter_dead(s, SERVICE_FAILURE_START_LIMIT, false); - return r; - } - s->result = SERVICE_SUCCESS; s->reload_result = SERVICE_SUCCESS; s->main_pid_known = false; @@ -2122,6 +2101,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) { unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known)); unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good)); + unit_serialize_item(u, f, "bus-name-owner", s->bus_name_owner); r = unit_serialize_item_escaped(u, f, "status-text", s->status_text); if (r < 0) @@ -2249,6 +2229,10 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, log_unit_debug(u, "Failed to parse bus-name-good value: %s", value); else s->bus_name_good = b; + } else if (streq(key, "bus-name-owner")) { + r = free_and_strdup(&s->bus_name_owner, value); + if (r < 0) + log_unit_error_errno(u, r, "Unable to deserialize current bus owner %s: %m", value); } else if (streq(key, "status-text")) { char *t; @@ -2356,6 +2340,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, else { asynchronous_close(s->stdin_fd); s->stdin_fd = fdset_remove(fds, fd); + s->exec_context.stdio_as_fds = true; } } else if (streq(key, "stdout-fd")) { int fd; @@ -2365,6 +2350,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, else { asynchronous_close(s->stdout_fd); s->stdout_fd = fdset_remove(fds, fd); + s->exec_context.stdio_as_fds = true; } } else if (streq(key, "stderr-fd")) { int fd; @@ -2374,6 +2360,7 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value, else { asynchronous_close(s->stderr_fd); s->stderr_fd = fdset_remove(fds, fd); + s->exec_context.stdio_as_fds = true; } } else log_unit_debug(u, "Unknown serialization key: %s", key); @@ -2779,7 +2766,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { case SERVICE_START_POST: if (f != SERVICE_SUCCESS) { - service_enter_stop(s, f); + service_enter_signal(s, SERVICE_STOP_SIGTERM, f); break; } @@ -2869,12 +2856,16 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us case SERVICE_START_POST: log_unit_warning(UNIT(s), "Start-post operation timed out. Stopping."); + service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT); + break; + + case SERVICE_RUNNING: + log_unit_warning(UNIT(s), "Service reached runtime time limit. Stopping."); service_enter_stop(s, SERVICE_FAILURE_TIMEOUT); break; case SERVICE_RELOAD: - log_unit_warning(UNIT(s), "Reload operation timed out. Stopping."); - service_unwatch_control_pid(s); + log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process."); service_kill_control_processes(s); s->reload_result = SERVICE_FAILURE_TIMEOUT; service_enter_running(s, SERVICE_SUCCESS); @@ -3096,17 +3087,21 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds) unit_add_to_dbus_queue(u); } -static int service_get_timeout(Unit *u, uint64_t *timeout) { +static int service_get_timeout(Unit *u, usec_t *timeout) { Service *s = SERVICE(u); + uint64_t t; int r; if (!s->timer_event_source) return 0; - r = sd_event_source_get_time(s->timer_event_source, timeout); + r = sd_event_source_get_time(s->timer_event_source, &t); if (r < 0) return r; + if (t == USEC_INFINITY) + return 0; + *timeout = t; return 1; } @@ -3134,6 +3129,13 @@ static void service_bus_name_owner_change( s->bus_name_good = !!new_owner; + /* Track the current owner, so we can reconstruct changes after a daemon reload */ + r = free_and_strdup(&s->bus_name_owner, new_owner); + if (r < 0) { + log_unit_error_errno(u, r, "Unable to set new bus name owner %s: %m", new_owner); + return; + } + if (s->type == SERVICE_DBUS) { /* service_enter_running() will figure out what to @@ -3150,7 +3152,7 @@ static void service_bus_name_owner_change( s->state == SERVICE_RUNNING || s->state == SERVICE_RELOAD)) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; pid_t pid; /* Try to acquire PID from bus service */ @@ -3187,7 +3189,7 @@ int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context if (s->state != SERVICE_DEAD) return -EAGAIN; - if (getpeername_pretty(fd, &peer) >= 0) { + if (getpeername_pretty(fd, true, &peer) >= 0) { if (UNIT(s)->description) { _cleanup_free_ char *a; @@ -3222,8 +3224,6 @@ static void service_reset_failed(Unit *u) { s->result = SERVICE_SUCCESS; s->reload_result = SERVICE_SUCCESS; - - RATELIMIT_RESET(s->start_limit); } static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { @@ -3291,7 +3291,6 @@ static const char* const service_result_table[_SERVICE_RESULT_MAX] = { [SERVICE_FAILURE_SIGNAL] = "signal", [SERVICE_FAILURE_CORE_DUMP] = "core-dump", [SERVICE_FAILURE_WATCHDOG] = "watchdog", - [SERVICE_FAILURE_START_LIMIT] = "start-limit" }; DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult); diff --git a/src/core/service.h b/src/core/service.h index e76566824..d342e000b 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,10 +22,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, @@ -88,7 +86,6 @@ typedef enum ServiceResult { SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP, SERVICE_FAILURE_WATCHDOG, - SERVICE_FAILURE_START_LIMIT, _SERVICE_RESULT_MAX, _SERVICE_RESULT_INVALID = -1 } ServiceResult; @@ -118,6 +115,7 @@ struct Service { usec_t restart_usec; usec_t timeout_start_usec; usec_t timeout_stop_usec; + usec_t runtime_max_usec; dual_timestamp watchdog_timestamp; usec_t watchdog_usec; @@ -172,14 +170,12 @@ struct Service { bool reset_cpu_usage:1; char *bus_name; + char *bus_name_owner; /* unique name of the current owner */ char *status_text; int status_errno; - RateLimit start_limit; - FailureAction start_limit_action; FailureAction failure_action; - char *reboot_arg; UnitRef accept_socket; diff --git a/src/core/show-status.c b/src/core/show-status.c index e4e12a336..59ebdc721 100644 --- a/src/core/show-status.c +++ b/src/core/show-status.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/show-status.h b/src/core/show-status.h index c79d4acb6..9a29e7264 100644 --- a/src/core/show-status.h +++ b/src/core/show-status.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/shutdown.c b/src/core/shutdown.c index 3a95b5fd7..6296b4c94 100644 --- a/src/core/shutdown.c +++ b/src/core/shutdown.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/slice.c b/src/core/slice.c index 06ac6f845..d65364c6f 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/slice.h b/src/core/slice.h index 0c356651e..c9f3f6106 100644 --- a/src/core/slice.h +++ b/src/core/slice.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index 0661ff9ec..0c26e8546 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -197,6 +195,75 @@ static int write_cipso2_rules(const char* srcdir) { return r; } +static int write_netlabel_rules(const char* srcdir) { + _cleanup_fclose_ FILE *dst = NULL; + _cleanup_closedir_ DIR *dir = NULL; + struct dirent *entry; + char buf[NAME_MAX]; + int dfd = -1; + int r = 0; + + dst = fopen("/sys/fs/smackfs/netlabel", "we"); + if (!dst) { + if (errno != ENOENT) + log_warning_errno(errno, "Failed to open /sys/fs/smackfs/netlabel: %m"); + return -errno; /* negative error */ + } + + /* write rules to dst from every file in the directory */ + dir = opendir(srcdir); + if (!dir) { + if (errno != ENOENT) + log_warning_errno(errno, "Failed to opendir %s: %m", srcdir); + return errno; /* positive on purpose */ + } + + dfd = dirfd(dir); + assert(dfd >= 0); + + FOREACH_DIRENT(entry, dir, return 0) { + int fd; + _cleanup_fclose_ FILE *policy = NULL; + + fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC); + if (fd < 0) { + if (r == 0) + r = -errno; + log_warning_errno(errno, "Failed to open %s: %m", entry->d_name); + continue; + } + + policy = fdopen(fd, "re"); + if (!policy) { + if (r == 0) + r = -errno; + safe_close(fd); + log_error_errno(errno, "Failed to open %s: %m", entry->d_name); + continue; + } + + /* load2 write rules in the kernel require a line buffered stream */ + FOREACH_LINE(buf, policy, + log_error_errno(errno, "Failed to read line from %s: %m", + entry->d_name)) { + if (!fputs(buf, dst)) { + if (r == 0) + r = -EINVAL; + log_error_errno(errno, "Failed to write line to /sys/fs/smackfs/netlabel"); + break; + } + if (fflush(dst)) { + if (r == 0) + r = -errno; + log_error_errno(errno, "Failed to flush writes to /sys/fs/smackfs/netlabel: %m"); + break; + } + } + } + + return r; +} + #endif int mac_smack_setup(bool *loaded_policy) { @@ -225,8 +292,18 @@ int mac_smack_setup(bool *loaded_policy) { #ifdef SMACK_RUN_LABEL r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0); - if (r) - log_warning_errno(r, "Failed to set SMACK label \"%s\" on self: %m", SMACK_RUN_LABEL); + if (r < 0) + log_warning_errno(r, "Failed to set SMACK label \"" SMACK_RUN_LABEL "\" on self: %m"); + r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, 0); + if (r < 0) + log_warning_errno(r, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL "\": %m"); + r = write_string_file("/sys/fs/smackfs/netlabel", + "0.0.0.0/0 " SMACK_RUN_LABEL, 0); + if (r < 0) + log_warning_errno(r, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL "\": %m"); + r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", 0); + if (r < 0) + log_warning_errno(r, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m"); #endif r = write_cipso2_rules("/etc/smack/cipso.d/"); @@ -236,13 +313,29 @@ int mac_smack_setup(bool *loaded_policy) { return 0; case ENOENT: log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found"); - return 0; + break; case 0: log_info("Successfully loaded Smack/CIPSO policies."); break; default: log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m"); + break; + } + + r = write_netlabel_rules("/etc/smack/netlabel.d/"); + switch(r) { + case -ENOENT: + log_debug("Smack/CIPSO is not enabled in the kernel."); return 0; + case ENOENT: + log_debug("Smack network host rules directory '/etc/smack/netlabel.d/' not found"); + break; + case 0: + log_info("Successfully loaded Smack network host rules."); + break; + default: + log_warning_errno(r, "Failed to load Smack network host rules: %m, ignoring."); + break; } *loaded_policy = true; diff --git a/src/core/smack-setup.h b/src/core/smack-setup.h index 1cab7718f..78164c85e 100644 --- a/src/core/smack-setup.h +++ b/src/core/smack-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/socket.c b/src/core/socket.c index 5b9e32ce9..976687af4 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -28,9 +26,9 @@ #include #include #include +#include #include "sd-event.h" - #include "alloc-util.h" #include "bus-error.h" #include "bus-util.h" @@ -156,41 +154,41 @@ static void socket_done(Unit *u) { s->tcp_congestion = mfree(s->tcp_congestion); s->bind_to_device = mfree(s->bind_to_device); - free(s->smack); - free(s->smack_ip_in); - free(s->smack_ip_out); + s->smack = mfree(s->smack); + s->smack_ip_in = mfree(s->smack_ip_in); + s->smack_ip_out = mfree(s->smack_ip_out); strv_free(s->symlinks); - free(s->user); - free(s->group); + s->user = mfree(s->user); + s->group = mfree(s->group); + + s->fdname = mfree(s->fdname); s->timer_event_source = sd_event_source_unref(s->timer_event_source); } -static int socket_arm_timer(Socket *s) { +static int socket_arm_timer(Socket *s, usec_t usec) { int r; assert(s); - if (s->timeout_usec <= 0) { - s->timer_event_source = sd_event_source_unref(s->timer_event_source); - return 0; - } - if (s->timer_event_source) { - r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec); + r = sd_event_source_set_time(s->timer_event_source, usec); if (r < 0) return r; return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); } + if (usec == USEC_INFINITY) + return 0; + r = sd_event_add_time( UNIT(s)->manager->event, &s->timer_event_source, CLOCK_MONOTONIC, - now(CLOCK_MONOTONIC) + s->timeout_usec, 0, + usec, 0, socket_dispatch_timer, s); if (r < 0) return r; @@ -289,7 +287,7 @@ static int socket_add_device_link(Socket *s) { return 0; t = strjoina("/sys/subsystem/net/devices/", s->bind_to_device); - return unit_add_node_link(UNIT(s), t, false); + return unit_add_node_link(UNIT(s), t, false, UNIT_BINDS_TO); } static int socket_add_default_dependencies(Socket *s) { @@ -875,8 +873,14 @@ static void socket_apply_socket_options(Socket *s, int fd) { if (s->no_delay) { int b = s->no_delay; - if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &b, sizeof(b)) < 0) - log_unit_warning_errno(UNIT(s), errno, "TCP_NODELAY failed: %m"); + + if (s->socket_protocol == IPPROTO_SCTP) { + if (setsockopt(fd, SOL_SCTP, SCTP_NODELAY, &b, sizeof(b)) < 0) + log_unit_warning_errno(UNIT(s), errno, "SCTP_NODELAY failed: %m"); + } else { + if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &b, sizeof(b)) < 0) + log_unit_warning_errno(UNIT(s), errno, "TCP_NODELAY failed: %m"); + } } if (s->broadcast) { @@ -1266,6 +1270,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, @@ -1473,7 +1490,7 @@ static int socket_coldplug(Unit *u) { if (r < 0) return r; - r = socket_arm_timer(s); + r = socket_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec)); if (r < 0) return r; } @@ -1486,6 +1503,7 @@ static int socket_coldplug(Unit *u) { SOCKET_STOP_PRE, SOCKET_STOP_PRE_SIGTERM, SOCKET_STOP_PRE_SIGKILL)) { + r = socket_open_fds(s); if (r < 0) return r; @@ -1527,15 +1545,15 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { r = unit_setup_exec_runtime(UNIT(s)); if (r < 0) - goto fail; + return r; - r = socket_arm_timer(s); + r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec)); if (r < 0) - goto fail; + return r; r = unit_full_printf_strv(UNIT(s), c->argv, &argv); if (r < 0) - goto fail; + return r; exec_params.argv = argv; exec_params.environment = UNIT(s)->manager->environment; @@ -1552,26 +1570,22 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { s->exec_runtime, &pid); if (r < 0) - goto fail; + return r; r = unit_watch_pid(UNIT(s), pid); if (r < 0) /* FIXME: we need to do something here */ - goto fail; + return r; *_pid = pid; return 0; - -fail: - s->timer_event_source = sd_event_source_unref(s->timer_event_source); - return r; } static int socket_chown(Socket *s, pid_t *_pid) { pid_t pid; int r; - r = socket_arm_timer(s); + r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec)); if (r < 0) goto fail; @@ -1714,7 +1728,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) { goto fail; if (r > 0) { - r = socket_arm_timer(s); + r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec)); if (r < 0) goto fail; @@ -1867,7 +1881,7 @@ fail: } static void socket_enter_running(Socket *s, int cfd) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(s); @@ -2686,23 +2700,6 @@ static void socket_reset_failed(Unit *u) { s->result = SOCKET_SUCCESS; } -static void socket_notify_service_dead(Socket *s, bool failed_permanent) { - assert(s); - - /* The service is dead. Dang! - * - * This is strictly for one-instance-for-all-connections - * services. */ - - if (s->state == SOCKET_RUNNING) { - log_unit_debug(UNIT(s), "Got notified about service death (failed permanently: %s)", yes_no(failed_permanent)); - if (failed_permanent) - socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_FAILED_PERMANENT); - else - socket_enter_listening(s); - } -} - void socket_connection_unref(Socket *s) { assert(s); @@ -2719,34 +2716,30 @@ void socket_connection_unref(Socket *s) { static void socket_trigger_notify(Unit *u, Unit *other) { Socket *s = SOCKET(u); - Service *se; assert(u); assert(other); /* Don't propagate state changes from the service if we are already down or accepting connections */ - if ((s->state != SOCKET_RUNNING && - s->state != SOCKET_LISTENING) || - s->accept) + if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING) || s->accept) return; - if (other->load_state != UNIT_LOADED || - other->type != UNIT_SERVICE) + if (other->start_limit_hit) { + socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT); + return; + } + + if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE) return; - se = SERVICE(other); + if (IN_SET(SERVICE(other)->state, + SERVICE_DEAD, SERVICE_FAILED, + SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, + SERVICE_AUTO_RESTART)) + socket_enter_listening(s); - if (se->state == SERVICE_FAILED) - socket_notify_service_dead(s, se->result == SERVICE_FAILURE_START_LIMIT); - - if (se->state == SERVICE_DEAD || - se->state == SERVICE_FINAL_SIGTERM || - se->state == SERVICE_FINAL_SIGKILL || - se->state == SERVICE_AUTO_RESTART) - socket_notify_service_dead(s, false); - - if (se->state == SERVICE_RUNNING) + if (SERVICE(other)->state == SERVICE_RUNNING) socket_set_state(s, SOCKET_RUNNING); } @@ -2754,17 +2747,21 @@ static int socket_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, SOCKET(u)->control_pid, error); } -static int socket_get_timeout(Unit *u, uint64_t *timeout) { +static int socket_get_timeout(Unit *u, usec_t *timeout) { Socket *s = SOCKET(u); + usec_t t; int r; if (!s->timer_event_source) return 0; - r = sd_event_source_get_time(s->timer_event_source, timeout); + r = sd_event_source_get_time(s->timer_event_source, &t); if (r < 0) return r; + if (t == USEC_INFINITY) + return 0; + *timeout = t; return 1; } @@ -2798,7 +2795,7 @@ static const char* const socket_result_table[_SOCKET_RESULT_MAX] = { [SOCKET_FAILURE_EXIT_CODE] = "exit-code", [SOCKET_FAILURE_SIGNAL] = "signal", [SOCKET_FAILURE_CORE_DUMP] = "core-dump", - [SOCKET_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent" + [SOCKET_FAILURE_SERVICE_START_LIMIT_HIT] = "service-start-limit-hit" }; DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult); diff --git a/src/core/socket.h b/src/core/socket.h index 94cda8a90..b537b026a 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,9 +21,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, @@ -54,7 +52,7 @@ typedef enum SocketResult { SOCKET_FAILURE_EXIT_CODE, SOCKET_FAILURE_SIGNAL, SOCKET_FAILURE_CORE_DUMP, - SOCKET_FAILURE_SERVICE_FAILED_PERMANENT, + SOCKET_FAILURE_SERVICE_START_LIMIT_HIT, _SOCKET_RESULT_MAX, _SOCKET_RESULT_INVALID = -1 } SocketResult; @@ -120,6 +118,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 ee0838e67..1bf0c0a80 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -160,29 +158,27 @@ static void swap_done(Unit *u) { s->timer_event_source = sd_event_source_unref(s->timer_event_source); } -static int swap_arm_timer(Swap *s) { +static int swap_arm_timer(Swap *s, usec_t usec) { int r; assert(s); - if (s->timeout_usec <= 0) { - s->timer_event_source = sd_event_source_unref(s->timer_event_source); - return 0; - } - if (s->timer_event_source) { - r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec); + r = sd_event_source_set_time(s->timer_event_source, usec); if (r < 0) return r; return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT); } + if (usec == USEC_INFINITY) + return 0; + r = sd_event_add_time( UNIT(s)->manager->event, &s->timer_event_source, CLOCK_MONOTONIC, - now(CLOCK_MONOTONIC) + s->timeout_usec, 0, + usec, 0, swap_dispatch_timer, s); if (r < 0) return r; @@ -202,7 +198,7 @@ static int swap_add_device_links(Swap *s) { return 0; if (is_device_path(s->what)) - return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM); + return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == MANAGER_SYSTEM, UNIT_BINDS_TO); else /* File based swap devices need to be ordered after * systemd-remount-fs.service, since they might need a @@ -211,6 +207,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 +220,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); } @@ -544,7 +548,7 @@ static int swap_coldplug(Unit *u) { if (r < 0) return r; - r = swap_arm_timer(s); + r = swap_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec)); if (r < 0) return r; } @@ -625,7 +629,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { if (r < 0) goto fail; - r = swap_arm_timer(s); + r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec)); if (r < 0) goto fail; @@ -702,7 +706,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) { goto fail; if (r > 0) { - r = swap_arm_timer(s); + r = swap_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec)); if (r < 0) goto fail; @@ -1390,17 +1394,21 @@ static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) { return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error); } -static int swap_get_timeout(Unit *u, uint64_t *timeout) { +static int swap_get_timeout(Unit *u, usec_t *timeout) { Swap *s = SWAP(u); + usec_t t; int r; if (!s->timer_event_source) return 0; - r = sd_event_source_get_time(s->timer_event_source, timeout); + r = sd_event_source_get_time(s->timer_event_source, &t); if (r < 0) return r; + if (t == USEC_INFINITY) + return 0; + *timeout = t; return 1; } diff --git a/src/core/swap.h b/src/core/swap.h index 303b92656..ac7a63d81 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/target.c b/src/core/target.c index 14f9b2e26..61a91aad0 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/target.h b/src/core/target.h index 3cc6c07bf..339aea154 100644 --- a/src/core/target.h +++ b/src/core/target.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/timer.c b/src/core/timer.c index 0587452cf..6f3e6a8db 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -27,6 +25,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" @@ -330,14 +329,46 @@ 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; + Unit *trigger; int r; + assert(t); + + trigger = UNIT_TRIGGER(UNIT(t)); + if (!trigger) { + log_unit_error(UNIT(t), "Unit to trigger vanished."); + timer_enter_dead(t, TIMER_FAILURE_RESOURCES); + return; + } + /* If we shall wake the system we use the boottime clock * rather than the monotonic clock. */ @@ -396,7 +427,7 @@ static void timer_enter_waiting(Timer *t, bool initial) { case TIMER_UNIT_ACTIVE: leave_around = true; - base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic; + base = trigger->inactive_exit_timestamp.monotonic; if (base <= 0) base = t->last_trigger.monotonic; @@ -408,7 +439,7 @@ static void timer_enter_waiting(Timer *t, bool initial) { case TIMER_UNIT_INACTIVE: leave_around = true; - base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic; + base = trigger->inactive_enter_timestamp.monotonic; if (base <= 0) base = t->last_trigger.monotonic; @@ -452,6 +483,8 @@ static void timer_enter_waiting(Timer *t, bool initial) { char buf[FORMAT_TIMESPAN_MAX]; usec_t left; + 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)); @@ -486,6 +519,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) { @@ -525,7 +561,8 @@ fail: } static void timer_enter_running(Timer *t) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + Unit *trigger; int r; assert(t); @@ -534,7 +571,14 @@ static void timer_enter_running(Timer *t) { if (unit_stop_pending(UNIT(t))) return; - r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)), JOB_REPLACE, &error, NULL); + trigger = UNIT_TRIGGER(UNIT(t)); + if (!trigger) { + log_unit_error(UNIT(t), "Unit to trigger vanished."); + timer_enter_dead(t, TIMER_FAILURE_RESOURCES); + return; + } + + r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL); if (r < 0) goto fail; @@ -554,12 +598,16 @@ fail: static int timer_start(Unit *u) { Timer *t = TIMER(u); TimerValue *v; + Unit *trigger; assert(t); assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED); - if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED) + trigger = UNIT_TRIGGER(u); + if (!trigger || trigger->load_state != UNIT_LOADED) { + log_unit_error(u, "Refusing to start, unit to trigger not loaded."); return -ENOENT; + } t->last_trigger = DUAL_TIMESTAMP_NULL; diff --git a/src/core/timer.h b/src/core/timer.h index 6bc9fbed3..698e6da2f 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -58,6 +56,7 @@ struct Timer { Unit meta; usec_t accuracy_usec; + usec_t random_usec; LIST_HEAD(TimerValue, values); usec_t next_elapse_realtime; diff --git a/src/core/transaction.c b/src/core/transaction.c index 15e79d00b..b28fc7678 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -27,6 +25,7 @@ #include "bus-error.h" #include "terminal-util.h" #include "transaction.h" +#include "dbus-unit.h" static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies); @@ -860,30 +859,12 @@ int transaction_add_job_and_dependencies( if (!IN_SET(unit->load_state, UNIT_LOADED, UNIT_ERROR, UNIT_NOT_FOUND, UNIT_MASKED)) return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id); - if (type != JOB_STOP && unit->load_state == UNIT_ERROR) { - if (unit->load_error == -ENOENT || unit->manager->test_run) - return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, - "Unit %s failed to load: %s.", - unit->id, - strerror(-unit->load_error)); - else - return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, - "Unit %s failed to load: %s. " - "See system logs and 'systemctl status %s' for details.", - unit->id, - strerror(-unit->load_error), - unit->id); + if (type != JOB_STOP) { + r = bus_unit_check_load_state(unit, e); + if (r < 0) + return r; } - if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND) - return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED, - "Unit %s failed to load: %s.", - unit->id, strerror(-unit->load_error)); - - if (type != JOB_STOP && unit->load_state == UNIT_MASKED) - return sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED, - "Unit %s is masked.", unit->id); - if (!unit_job_is_applicable(unit, type)) return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", @@ -929,7 +910,7 @@ int transaction_add_job_and_dependencies( SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e); if (r < 0) { - if (r != -EBADR) + if (r != -EBADR) /* job type not applicable */ goto fail; sd_bus_error_free(e); @@ -939,7 +920,7 @@ int transaction_add_job_and_dependencies( SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e); if (r < 0) { - if (r != -EBADR) + if (r != -EBADR) /* job type not applicable */ goto fail; sd_bus_error_free(e); @@ -949,9 +930,10 @@ int transaction_add_job_and_dependencies( SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) { r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e); if (r < 0) { + /* unit masked, job type not applicable and unit not found are not considered as errors. */ log_unit_full(dep, - r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r, - "Cannot add dependency job, ignoring: %s", + IN_SET(r, -ESHUTDOWN, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING, + r, "Cannot add dependency job, ignoring: %s", bus_error_message(e, r)); sd_bus_error_free(e); } @@ -960,7 +942,7 @@ int transaction_add_job_and_dependencies( SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) { r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e); if (r < 0) { - if (r != -EBADR) + if (r != -EBADR) /* job type not applicable */ goto fail; sd_bus_error_free(e); @@ -970,7 +952,7 @@ int transaction_add_job_and_dependencies( SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) { r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e); if (r < 0) { - if (r != -EBADR) + if (r != -EBADR) /* job type not applicable */ goto fail; sd_bus_error_free(e); @@ -1015,7 +997,7 @@ int transaction_add_job_and_dependencies( r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, false, false, ignore_order, e); if (r < 0) { - if (r != -EBADR) + if (r != -EBADR) /* job type not applicable */ goto fail; sd_bus_error_free(e); @@ -1026,7 +1008,13 @@ int transaction_add_job_and_dependencies( if (type == JOB_RELOAD) { SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) { - r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, false, false, ignore_order, e); + JobType nt; + + nt = job_type_collapse(JOB_TRY_RELOAD, dep); + if (nt == JOB_NOP) + continue; + + r = transaction_add_job_and_dependencies(tr, nt, dep, ret, false, false, false, ignore_order, e); if (r < 0) { log_unit_warning(dep, "Cannot add dependency reload job, ignoring: %s", diff --git a/src/core/transaction.h b/src/core/transaction.h index f7aa3df08..6a3f927b0 100644 --- a/src/core/transaction.h +++ b/src/core/transaction.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,10 +21,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 index 141f42dbc..9e18a39a6 100644 --- a/src/core/triggers.systemd.in +++ b/src/core/triggers.systemd.in @@ -19,8 +19,46 @@ # The contents of this are an example to be copied into systemd.spec. -%transfiletriggerin -- @systemunitdir@ /etc/systemd/system -systemctl daemon-reload &>/dev/null || : +%transfiletriggerin -P 900900 -p -- @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. -%transfiletriggerun -- @systemunitdir@ /etc/systemd/system -systemctl daemon-reload &>/dev/null || : +pid = posix.fork() +if pid == 0 then + assert(posix.exec("%{_bindir}/systemctl", "daemon-reload")) +elseif pid > 0 then + posix.wait(pid) +end + +%transfiletriggerun -p -- @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 -- @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/umount.c b/src/core/umount.c index 9d1f7660d..a458768e7 100644 --- a/src/core/umount.c +++ b/src/core/umount.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/umount.h b/src/core/umount.h index 8439ffe58..4e2215a47 100644 --- a/src/core/umount.h +++ b/src/core/umount.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index f587a5a14..fc057d965 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/core/unit-printf.h b/src/core/unit-printf.h index 51acad63e..4fc853122 100644 --- a/src/core/unit-printf.h +++ b/src/core/unit-printf.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/core/unit.c b/src/core/unit.c index 0a02e38aa..d39e3dcae 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -51,6 +49,7 @@ #include "set.h" #include "special.h" #include "stat-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "unit-name.h" @@ -98,7 +97,9 @@ Unit *unit_new(Manager *m, size_t size) { u->unit_file_preset = -1; u->on_failure_job_mode = JOB_REPLACE; u->cgroup_inotify_wd = -1; + u->job_timeout = USEC_INFINITY; + RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst); RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16); return u; @@ -457,7 +458,6 @@ static void unit_free_requires_mounts_for(Unit *u) { static void unit_done(Unit *u) { ExecContext *ec; CGroupContext *cc; - int r; assert(u); @@ -474,10 +474,6 @@ static void unit_done(Unit *u) { cc = unit_get_cgroup_context(u); if (cc) cgroup_context_done(cc); - - r = unit_remove_from_netclass_cgroup(u); - if (r < 0) - log_warning_errno(r, "Unable to remove unit from netclass group: %m"); } void unit_free(Unit *u) { @@ -557,6 +553,8 @@ void unit_free(Unit *u) { condition_free_list(u->conditions); condition_free_list(u->asserts); + free(u->reboot_arg); + unit_ref_unset(&u->slice); while (u->refs) @@ -868,6 +866,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { Iterator i; const char *prefix2; char + timestamp0[FORMAT_TIMESTAMP_MAX], timestamp1[FORMAT_TIMESTAMP_MAX], timestamp2[FORMAT_TIMESTAMP_MAX], timestamp3[FORMAT_TIMESTAMP_MAX], @@ -889,6 +888,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { "%s\tInstance: %s\n" "%s\tUnit Load State: %s\n" "%s\tUnit Active State: %s\n" + "%s\nState Change Timestamp: %s\n" "%s\tInactive Exit Timestamp: %s\n" "%s\tActive Enter Timestamp: %s\n" "%s\tActive Exit Timestamp: %s\n" @@ -906,6 +906,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { prefix, strna(u->instance), prefix, unit_load_state_to_string(u->load_state), prefix, unit_active_state_to_string(unit_active_state(u)), + prefix, strna(format_timestamp(timestamp0, sizeof(timestamp0), u->state_change_timestamp.realtime)), prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)), prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)), prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)), @@ -946,7 +947,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) { STRV_FOREACH(j, u->dropin_paths) fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j); - if (u->job_timeout > 0) + if (u->job_timeout != USEC_INFINITY) fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0)); if (u->job_timeout_action != FAILURE_ACTION_NONE) @@ -1257,14 +1258,6 @@ int unit_load(Unit *u) { } unit_update_cgroup_members_masks(u); - - /* If we are reloading, we need to wait for the deserializer - * to restore the net_cls ids that have been set previously */ - if (u->manager->n_reloading <= 0) { - r = unit_add_to_netclass_cgroup(u); - if (r < 0) - return r; - } } assert((u->load_state != UNIT_MERGED) == !u->merged_into); @@ -1412,7 +1405,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) { format = unit_get_status_message_format(u, t); DISABLE_WARNING_FORMAT_NONLITERAL; - snprintf(buf, sizeof(buf), format, unit_description(u)); + xsprintf(buf, format, unit_description(u)); REENABLE_WARNING; mid = t == JOB_START ? SD_MESSAGE_UNIT_STARTING : @@ -1441,23 +1434,36 @@ void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) { unit_status_print_starting_stopping(u, t); } +static int unit_start_limit_test(Unit *u) { + assert(u); + + if (ratelimit_test(&u->start_limit)) { + u->start_limit_hit = false; + return 0; + } + + log_unit_warning(u, "Start request repeated too quickly."); + u->start_limit_hit = true; + + return failure_action(u->manager, u->start_limit_action, u->reboot_arg); +} + /* Errors: - * -EBADR: This unit type does not support starting. - * -EALREADY: Unit is already started. - * -EAGAIN: An operation is already in progress. Retry later. - * -ECANCELED: Too many requests for now. - * -EPROTO: Assert failed + * -EBADR: This unit type does not support starting. + * -EALREADY: Unit is already started. + * -EAGAIN: An operation is already in progress. Retry later. + * -ECANCELED: Too many requests for now. + * -EPROTO: Assert failed + * -EINVAL: Unit not loaded + * -EOPNOTSUPP: Unit type not supported */ int unit_start(Unit *u) { UnitActiveState state; Unit *following; + int r; assert(u); - /* Units that aren't loaded cannot be started */ - if (u->load_state != UNIT_LOADED) - return -EINVAL; - /* If this is already started, then this will succeed. Note * that this will even succeed if this unit is not startable * by the user. This is relied on to detect when we need to @@ -1466,6 +1472,15 @@ int unit_start(Unit *u) { if (UNIT_IS_ACTIVE_OR_RELOADING(state)) return -EALREADY; + /* Make sure we don't enter a busy loop of some kind. */ + r = unit_start_limit_test(u); + if (r < 0) + return r; + + /* Units that aren't loaded cannot be started */ + if (u->load_state != UNIT_LOADED) + return -EINVAL; + /* If the conditions failed, don't do anything at all. If we * already are activating this call might still be useful to * speed up activation in case there is some hold-off time, @@ -1613,7 +1628,7 @@ bool unit_can_reload(Unit *u) { static void unit_check_unneeded(Unit *u) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; static const UnitDependency needed_dependencies[] = { UNIT_REQUIRED_BY, @@ -1660,7 +1675,7 @@ static void unit_check_unneeded(Unit *u) { } static void unit_check_binds_to(Unit *u) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; bool stop = false; Unit *other; Iterator i; @@ -1820,19 +1835,17 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su /* Update timestamps for state changes */ if (m->n_reloading <= 0) { - dual_timestamp ts; - - dual_timestamp_get(&ts); + dual_timestamp_get(&u->state_change_timestamp); if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns)) - u->inactive_exit_timestamp = ts; + u->inactive_exit_timestamp = u->state_change_timestamp; else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns)) - u->inactive_enter_timestamp = ts; + u->inactive_enter_timestamp = u->state_change_timestamp; if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns)) - u->active_enter_timestamp = ts; + u->active_enter_timestamp = u->state_change_timestamp; else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns)) - u->active_exit_timestamp = ts; + u->active_exit_timestamp = u->state_change_timestamp; } /* Keep track of failed units */ @@ -1893,6 +1906,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su case JOB_RELOAD: case JOB_RELOAD_OR_START: + case JOB_TRY_RELOAD: if (u->job->state == JOB_RUNNING) { if (ns == UNIT_ACTIVE) @@ -2106,6 +2120,7 @@ bool unit_job_is_applicable(Unit *u, JobType j) { return unit_can_start(u); case JOB_RELOAD: + case JOB_TRY_RELOAD: return unit_can_reload(u); case JOB_RELOAD_OR_START: @@ -2550,10 +2565,13 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { } } + dual_timestamp_serialize(f, "state-change-timestamp", &u->state_change_timestamp); + dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp); dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp); dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp); dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp); + dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp); dual_timestamp_serialize(f, "assert-timestamp", &u->assert_timestamp); @@ -2570,9 +2588,6 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { unit_serialize_item(u, f, "cgroup", u->cgroup_path); unit_serialize_item(u, f, "cgroup-realized", yes_no(u->cgroup_realized)); - if (u->cgroup_netclass_id) - unit_serialize_item_format(u, f, "netclass-id", "%" PRIu32, u->cgroup_netclass_id); - if (serialize_jobs) { if (u->job) { fprintf(f, "job\n"); @@ -2692,7 +2707,7 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { /* End marker */ if (isempty(l)) - return 0; + break; k = strcspn(l, "="); @@ -2732,6 +2747,9 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { } else /* legacy for pre-44 */ log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v); continue; + } else if (streq(l, "state-change-timestamp")) { + dual_timestamp_deserialize(v, &u->state_change_timestamp); + continue; } else if (streq(l, "inactive-exit-timestamp")) { dual_timestamp_deserialize(v, &u->inactive_exit_timestamp); continue; @@ -2806,17 +2824,6 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { else u->cgroup_realized = b; - continue; - } else if (streq(l, "netclass-id")) { - r = safe_atou32(v, &u->cgroup_netclass_id); - if (r < 0) - log_unit_debug(u, "Failed to parse netclass ID %s, ignoring.", v); - else { - r = unit_add_to_netclass_cgroup(u); - if (r < 0) - log_unit_debug_errno(u, r, "Failed to add unit to netclass cgroup, ignoring: %m"); - } - continue; } @@ -2838,9 +2845,18 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l); } } + + /* Versions before 228 did not carry a state change timestamp. In this case, take the current time. This is + * useful, so that timeouts based on this timestamp don't trigger too early, and is in-line with the logic from + * before 228 where the base for timeouts was not persistent across reboots. */ + + if (!dual_timestamp_is_set(&u->state_change_timestamp)) + dual_timestamp_get(&u->state_change_timestamp); + + return 0; } -int unit_add_node_link(Unit *u, const char *what, bool wants) { +int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) { Unit *device; _cleanup_free_ char *e = NULL; int r; @@ -2867,7 +2883,9 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) { if (r < 0) return r; - r = unit_add_two_dependencies(u, UNIT_AFTER, u->manager->running_as == MANAGER_SYSTEM ? UNIT_BINDS_TO : UNIT_WANTS, device, true); + r = unit_add_two_dependencies(u, UNIT_AFTER, + u->manager->running_as == MANAGER_SYSTEM ? dep : UNIT_WANTS, + device, true); if (r < 0) return r; @@ -2966,6 +2984,9 @@ void unit_reset_failed(Unit *u) { if (UNIT_VTABLE(u)->reset_failed) UNIT_VTABLE(u)->reset_failed(u); + + RATELIMIT_RESET(u->start_limit); + u->start_limit_hit = false; } Unit *unit_following(Unit *u) { @@ -3117,7 +3138,7 @@ int unit_kill_common( killed = true; } - if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL, KILL_ALL_FAIL)) + if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL)) return -ESRCH; return r; @@ -3229,7 +3250,7 @@ int unit_patch_contexts(Unit *u) { ec->no_new_privileges = true; if (ec->private_devices) - ec->capability_bounding_set_drop |= (uint64_t) 1ULL << (uint64_t) CAP_MKNOD; + ec->capability_bounding_set &= ~(UINT64_C(1) << CAP_MKNOD); } cc = unit_get_cgroup_context(u); diff --git a/src/core/unit.h b/src/core/unit.h index a69d624fa..601e763ce 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -30,11 +28,11 @@ typedef struct UnitVTable UnitVTable; typedef struct UnitRef UnitRef; typedef struct UnitStatusMessageFormats UnitStatusMessageFormats; -#include "list.h" #include "condition.h" -#include "install.h" -#include "unit-name.h" #include "failure-action.h" +#include "install.h" +#include "list.h" +#include "unit-name.h" typedef enum KillOperation { KILL_TERMINATE, @@ -121,6 +119,10 @@ struct Unit { dual_timestamp condition_timestamp; dual_timestamp assert_timestamp; + /* Updated whenever the low-level state changes */ + dual_timestamp state_change_timestamp; + + /* Updated whenever the (high-level) active state enters or leaves the active or inactive states */ dual_timestamp inactive_exit_timestamp; dual_timestamp active_enter_timestamp; dual_timestamp active_exit_timestamp; @@ -163,6 +165,11 @@ struct Unit { /* Error code when we didn't manage to load the unit (negative) */ int load_error; + /* Put a ratelimit on unit starting */ + RateLimit start_limit; + FailureAction start_limit_action; + char *reboot_arg; + /* Make sure we never enter endless loops with the check unneeded logic, or the BindsTo= logic */ RateLimit auto_stop_ratelimit; @@ -226,6 +233,8 @@ struct Unit { bool cgroup_members_mask_valid:1; bool cgroup_subtree_mask_valid:1; + bool start_limit_hit:1; + /* Did we already invoke unit_coldplug() for this unit? */ bool coldplugged:1; }; @@ -242,16 +251,16 @@ typedef enum UnitSetPropertiesMode { UNIT_PERSISTENT = 2, } UnitSetPropertiesMode; -#include "socket.h" -#include "busname.h" -#include "target.h" -#include "device.h" #include "automount.h" -#include "swap.h" -#include "timer.h" -#include "slice.h" +#include "busname.h" +#include "device.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 */ @@ -375,7 +384,8 @@ struct UnitVTable { /* Called whenever CLOCK_REALTIME made a jump */ void (*time_change)(Unit *u); - int (*get_timeout)(Unit *u, uint64_t *timeout); + /* Returns the next timeout of a unit */ + int (*get_timeout)(Unit *u, usec_t *timeout); /* This is called for each unit type and should be used to * enumerate existing devices and load them. However, @@ -528,7 +538,7 @@ int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *v int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd); void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5); -int unit_add_node_link(Unit *u, const char *what, bool wants); +int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency d); int unit_coldplug(Unit *u); diff --git a/src/resolve-host/Makefile b/src/coredump/Makefile similarity index 100% rename from src/resolve-host/Makefile rename to src/coredump/Makefile diff --git a/src/journal/coredump-vacuum.c b/src/coredump/coredump-vacuum.c similarity index 99% rename from src/journal/coredump-vacuum.c rename to src/coredump/coredump-vacuum.c index 09ab60c6c..f02b6dbd8 100644 --- a/src/journal/coredump-vacuum.c +++ b/src/coredump/coredump-vacuum.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/coredump-vacuum.h b/src/coredump/coredump-vacuum.h similarity index 93% rename from src/journal/coredump-vacuum.h rename to src/coredump/coredump-vacuum.h index 7779c9757..4b7b9f2d9 100644 --- a/src/journal/coredump-vacuum.h +++ b/src/coredump/coredump-vacuum.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/coredump.c b/src/coredump/coredump.c similarity index 52% rename from src/journal/coredump.c rename to src/coredump/coredump.c index f750ddfcb..085909c20 100644 --- a/src/journal/coredump.c +++ b/src/coredump/coredump.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -26,12 +24,13 @@ #include #ifdef HAVE_ELFUTILS -# include -# include +#include +#include #endif #include "sd-journal.h" #include "sd-login.h" +#include "sd-daemon.h" #include "acl-util.h" #include "alloc-util.h" @@ -53,6 +52,7 @@ #include "mkdir.h" #include "parse-util.h" #include "process-util.h" +#include "socket-util.h" #include "special.h" #include "stacktrace.h" #include "string-table.h" @@ -64,12 +64,10 @@ /* The maximum size up to which we process coredumps */ #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU)) -/* The maximum size up to which we leave the coredump around on - * disk */ +/* The maximum size up to which we leave the coredump around on disk */ #define EXTERNAL_SIZE_MAX PROCESS_SIZE_MAX -/* The maximum size up to which we store the coredump in the - * journal */ +/* The maximum size up to which we store the coredump in the journal */ #define JOURNAL_SIZE_MAX ((size_t) (767LU*1024LU*1024LU)) /* Make sure to not make this larger than the maximum journal entry @@ -77,14 +75,17 @@ assert_cc(JOURNAL_SIZE_MAX <= DATA_SIZE_MAX); enum { - INFO_PID, - INFO_UID, - INFO_GID, - INFO_SIGNAL, - INFO_TIMESTAMP, - INFO_COMM, - INFO_EXE, - _INFO_LEN + /* We use this as array indexes for a couple of special fields we use for naming coredumping files, and + * attaching xattrs */ + CONTEXT_PID, + CONTEXT_UID, + CONTEXT_GID, + CONTEXT_SIGNAL, + CONTEXT_TIMESTAMP, + CONTEXT_RLIMIT, + CONTEXT_COMM, + CONTEXT_EXE, + _CONTEXT_MAX }; typedef enum CoredumpStorage { @@ -175,16 +176,16 @@ static int fix_acl(int fd, uid_t uid) { return 0; } -static int fix_xattr(int fd, const char *info[_INFO_LEN]) { +static int fix_xattr(int fd, const char *context[_CONTEXT_MAX]) { - static const char * const xattrs[_INFO_LEN] = { - [INFO_PID] = "user.coredump.pid", - [INFO_UID] = "user.coredump.uid", - [INFO_GID] = "user.coredump.gid", - [INFO_SIGNAL] = "user.coredump.signal", - [INFO_TIMESTAMP] = "user.coredump.timestamp", - [INFO_COMM] = "user.coredump.comm", - [INFO_EXE] = "user.coredump.exe", + static const char * const xattrs[_CONTEXT_MAX] = { + [CONTEXT_PID] = "user.coredump.pid", + [CONTEXT_UID] = "user.coredump.uid", + [CONTEXT_GID] = "user.coredump.gid", + [CONTEXT_SIGNAL] = "user.coredump.signal", + [CONTEXT_TIMESTAMP] = "user.coredump.timestamp", + [CONTEXT_COMM] = "user.coredump.comm", + [CONTEXT_EXE] = "user.coredump.exe", }; int r = 0; @@ -195,13 +196,13 @@ static int fix_xattr(int fd, const char *info[_INFO_LEN]) { /* Attach some metadata to coredumps via extended * attributes. Just because we can. */ - for (i = 0; i < _INFO_LEN; i++) { + for (i = 0; i < _CONTEXT_MAX; i++) { int k; - if (isempty(info[i]) || !xattrs[i]) + if (isempty(context[i]) || !xattrs[i]) continue; - k = fsetxattr(fd, xattrs[i], info[i], strlen(info[i]), XATTR_CREATE); + k = fsetxattr(fd, xattrs[i], context[i], strlen(context[i]), XATTR_CREATE); if (k < 0 && r == 0) r = -errno; } @@ -215,18 +216,18 @@ static int fix_permissions( int fd, const char *filename, const char *target, - const char *info[_INFO_LEN], + const char *context[_CONTEXT_MAX], uid_t uid) { assert(fd >= 0); assert(filename); assert(target); - assert(info); + assert(context); /* Ignore errors on these */ - fchmod(fd, 0640); - fix_acl(fd, uid); - fix_xattr(fd, info); + (void) fchmod(fd, 0640); + (void) fix_acl(fd, uid); + (void) fix_xattr(fd, context); if (fsync(fd) < 0) return log_error_errno(errno, "Failed to sync coredump %s: %m", filename); @@ -254,18 +255,18 @@ static int maybe_remove_external_coredump(const char *filename, uint64_t size) { return 1; } -static int make_filename(const char *info[_INFO_LEN], char **ret) { +static int make_filename(const char *context[_CONTEXT_MAX], char **ret) { _cleanup_free_ char *c = NULL, *u = NULL, *p = NULL, *t = NULL; sd_id128_t boot = {}; int r; - assert(info); + assert(context); - c = filename_escape(info[INFO_COMM]); + c = filename_escape(context[CONTEXT_COMM]); if (!c) return -ENOMEM; - u = filename_escape(info[INFO_UID]); + u = filename_escape(context[CONTEXT_UID]); if (!u) return -ENOMEM; @@ -273,11 +274,11 @@ static int make_filename(const char *info[_INFO_LEN], char **ret) { if (r < 0) return r; - p = filename_escape(info[INFO_PID]); + p = filename_escape(context[CONTEXT_PID]); if (!p) return -ENOMEM; - t = filename_escape(info[INFO_TIMESTAMP]); + t = filename_escape(context[CONTEXT_TIMESTAMP]); if (!t) return -ENOMEM; @@ -294,23 +295,43 @@ static int make_filename(const char *info[_INFO_LEN], char **ret) { } static int save_external_coredump( - const char *info[_INFO_LEN], - uid_t uid, + const char *context[_CONTEXT_MAX], + int input_fd, char **ret_filename, - int *ret_fd, + int *ret_node_fd, + int *ret_data_fd, uint64_t *ret_size) { _cleanup_free_ char *fn = NULL, *tmp = NULL; _cleanup_close_ int fd = -1; + uint64_t rlimit, max_size; struct stat st; + uid_t uid; int r; - assert(info); + assert(context); assert(ret_filename); - assert(ret_fd); + assert(ret_node_fd); + assert(ret_data_fd); assert(ret_size); - r = make_filename(info, &fn); + r = parse_uid(context[CONTEXT_UID], &uid); + if (r < 0) + return log_error_errno(r, "Failed to parse UID: %m"); + + r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit); + if (r < 0) + return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]); + if (rlimit <= 0) { + /* Is coredumping disabled? Then don't bother saving/processing the coredump */ + log_info("Core Dumping has been disabled for process %s (%s).", context[CONTEXT_PID], context[CONTEXT_COMM]); + return -EBADSLT; + } + + /* Never store more than the process configured, or than we actually shall keep or process */ + max_size = MIN(rlimit, MAX(arg_process_size_max, arg_external_size_max)); + + r = make_filename(context, &fn); if (r < 0) return log_error_errno(r, "Failed to determine coredump file name: %m"); @@ -324,12 +345,12 @@ static int save_external_coredump( if (fd < 0) return log_error_errno(errno, "Failed to create coredump file %s: %m", tmp); - r = copy_bytes(STDIN_FILENO, fd, arg_process_size_max, false); + r = copy_bytes(input_fd, fd, max_size, false); if (r == -EFBIG) { - log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", info[INFO_PID], info[INFO_COMM]); + log_error("Coredump of %s (%s) is larger than configured processing limit, refusing.", context[CONTEXT_PID], context[CONTEXT_COMM]); goto fail; } else if (IN_SET(r, -EDQUOT, -ENOSPC)) { - log_error("Not enough disk space for coredump of %s (%s), refusing.", info[INFO_PID], info[INFO_COMM]); + log_error("Not enough disk space for coredump of %s (%s), refusing.", context[CONTEXT_PID], context[CONTEXT_COMM]); goto fail; } else if (r < 0) { log_error_errno(r, "Failed to dump coredump to file: %m"); @@ -378,7 +399,7 @@ static int save_external_coredump( goto fail_compressed; } - r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, info, uid); + r = fix_permissions(fd_compressed, tmp_compressed, fn_compressed, context, uid); if (r < 0) goto fail_compressed; @@ -386,26 +407,29 @@ static int save_external_coredump( unlink_noerrno(tmp); *ret_filename = fn_compressed; /* compressed */ - *ret_fd = fd; /* uncompressed */ + *ret_node_fd = fd_compressed; /* compressed */ + *ret_data_fd = fd; /* uncompressed */ *ret_size = (uint64_t) st.st_size; /* uncompressed */ fn_compressed = NULL; - fd = -1; + fd = fd_compressed = -1; return 0; fail_compressed: - unlink_noerrno(tmp_compressed); + (void) unlink(tmp_compressed); } uncompressed: #endif - r = fix_permissions(fd, tmp, fn, info, uid); + + r = fix_permissions(fd, tmp, fn, context, uid); if (r < 0) goto fail; *ret_filename = fn; - *ret_fd = fd; + *ret_data_fd = fd; + *ret_node_fd = -1; *ret_size = (uint64_t) st.st_size; fn = NULL; @@ -414,7 +438,7 @@ uncompressed: return 0; fail: - unlink_noerrno(tmp); + (void) unlink(tmp); return r; } @@ -527,7 +551,7 @@ static int compose_open_fds(pid_t pid, char **open_fds) { errno = 0; stream = safe_fclose(stream); - if (errno != 0) + if (errno > 0) return -errno; *open_fds = buffer; @@ -536,308 +560,89 @@ static int compose_open_fds(pid_t pid, char **open_fds) { return 0; } -int main(int argc, char* argv[]) { - - /* The small core field we allocate on the stack, to keep things simple */ - char - *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, - *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL, - *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL, - *core_slice = NULL; - - /* The larger ones we allocate on the heap */ - _cleanup_free_ char - *core_timestamp = NULL, *core_message = NULL, *coredump_data = NULL, *core_owner_uid = NULL, - *core_open_fds = NULL, *core_proc_status = NULL, *core_proc_maps = NULL, *core_proc_limits = NULL, - *core_proc_cgroup = NULL, *core_environ = NULL; - - _cleanup_free_ char *exe = NULL, *comm = NULL, *filename = NULL; - const char *info[_INFO_LEN]; - - _cleanup_close_ int coredump_fd = -1; - - struct iovec iovec[26]; - uint64_t coredump_size; - int r, j = 0; - uid_t uid, owner_uid; +static int change_uid_gid(const char *context[]) { + uid_t uid; gid_t gid; - pid_t pid; - char *t; - const char *p; + int r; - /* Make sure we never enter a loop */ - prctl(PR_SET_DUMPABLE, 0); + r = parse_uid(context[CONTEXT_UID], &uid); + if (r < 0) + return r; - /* First, log to a safe place, since we don't know what - * crashed and it might be journald which we'd rather not log - * to then. */ - log_set_target(LOG_TARGET_KMSG); - log_open(); + if (uid <= SYSTEM_UID_MAX) { + const char *user = "systemd-coredump"; - if (argc < INFO_COMM + 1) { - log_error("Not enough arguments passed from kernel (%d, expected %d).", - argc - 1, INFO_COMM + 1 - 1); - r = -EINVAL; - goto finish; - } - - /* Ignore all parse errors */ - parse_config(); - - log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage)); - log_debug("Selected compression %s.", yes_no(arg_compress)); - - r = parse_uid(argv[INFO_UID + 1], &uid); - if (r < 0) { - log_error("Failed to parse UID."); - goto finish; - } - - r = parse_pid(argv[INFO_PID + 1], &pid); - if (r < 0) { - log_error("Failed to parse PID."); - goto finish; - } - - r = parse_gid(argv[INFO_GID + 1], &gid); - if (r < 0) { - log_error("Failed to parse GID."); - goto finish; - } - - if (get_process_comm(pid, &comm) < 0) { - log_warning("Failed to get COMM, falling back to the command line."); - comm = strv_join(argv + INFO_COMM + 1, " "); - } - - if (get_process_exe(pid, &exe) < 0) - log_warning("Failed to get EXE."); - - info[INFO_PID] = argv[INFO_PID + 1]; - info[INFO_UID] = argv[INFO_UID + 1]; - info[INFO_GID] = argv[INFO_GID + 1]; - info[INFO_SIGNAL] = argv[INFO_SIGNAL + 1]; - info[INFO_TIMESTAMP] = argv[INFO_TIMESTAMP + 1]; - info[INFO_COMM] = comm; - info[INFO_EXE] = exe; - - if (cg_pid_get_unit(pid, &t) >= 0) { - - if (streq(t, SPECIAL_JOURNALD_SERVICE)) { - free(t); - - /* If we are journald, we cut things short, - * don't write to the journal, but still - * create a coredump. */ - - if (arg_storage != COREDUMP_STORAGE_NONE) - arg_storage = COREDUMP_STORAGE_EXTERNAL; - - r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); - if (r < 0) - goto finish; - - r = maybe_remove_external_coredump(filename, coredump_size); - if (r < 0) - goto finish; - - log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename); - goto finish; + r = get_user_creds(&user, &uid, &gid, NULL, NULL); + if (r < 0) { + log_warning_errno(r, "Cannot resolve %s user. Proceeding to dump core as root: %m", user); + uid = gid = 0; } - - core_unit = strjoina("COREDUMP_UNIT=", t); - free(t); - - } else if (cg_pid_get_user_unit(pid, &t) >= 0) { - core_unit = strjoina("COREDUMP_USER_UNIT=", t); - free(t); + } else { + r = parse_gid(context[CONTEXT_GID], &gid); + if (r < 0) + return r; } - if (core_unit) - IOVEC_SET_STRING(iovec[j++], core_unit); + return drop_privileges(uid, gid, 0); +} - /* OK, now we know it's not the journal, hence we can make use - * of it now. */ - log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); - log_open(); +static int submit_coredump( + const char *context[_CONTEXT_MAX], + struct iovec *iovec, + size_t n_iovec_allocated, + size_t n_iovec, + int input_fd) { - core_pid = strjoina("COREDUMP_PID=", info[INFO_PID]); - IOVEC_SET_STRING(iovec[j++], core_pid); + _cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1; + _cleanup_free_ char *core_message = NULL, *filename = NULL, *coredump_data = NULL; + uint64_t coredump_size; + int r; - core_uid = strjoina("COREDUMP_UID=", info[INFO_UID]); - IOVEC_SET_STRING(iovec[j++], core_uid); - - core_gid = strjoina("COREDUMP_GID=", info[INFO_GID]); - IOVEC_SET_STRING(iovec[j++], core_gid); - - core_signal = strjoina("COREDUMP_SIGNAL=", info[INFO_SIGNAL]); - IOVEC_SET_STRING(iovec[j++], core_signal); - - if (sd_pid_get_session(pid, &t) >= 0) { - core_session = strjoina("COREDUMP_SESSION=", t); - free(t); - - IOVEC_SET_STRING(iovec[j++], core_session); - } - - if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) { - r = asprintf(&core_owner_uid, - "COREDUMP_OWNER_UID=" UID_FMT, owner_uid); - if (r > 0) - IOVEC_SET_STRING(iovec[j++], core_owner_uid); - } - - if (sd_pid_get_slice(pid, &t) >= 0) { - core_slice = strjoina("COREDUMP_SLICE=", t); - free(t); - - IOVEC_SET_STRING(iovec[j++], core_slice); - } - - if (comm) { - core_comm = strjoina("COREDUMP_COMM=", comm); - IOVEC_SET_STRING(iovec[j++], core_comm); - } - - if (exe) { - core_exe = strjoina("COREDUMP_EXE=", exe); - IOVEC_SET_STRING(iovec[j++], core_exe); - } - - if (get_process_cmdline(pid, 0, false, &t) >= 0) { - core_cmdline = strjoina("COREDUMP_CMDLINE=", t); - free(t); - - IOVEC_SET_STRING(iovec[j++], core_cmdline); - } - - if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) { - core_cgroup = strjoina("COREDUMP_CGROUP=", t); - free(t); - - IOVEC_SET_STRING(iovec[j++], core_cgroup); - } - - if (compose_open_fds(pid, &t) >= 0) { - core_open_fds = strappend("COREDUMP_OPEN_FDS=", t); - free(t); - - if (core_open_fds) - IOVEC_SET_STRING(iovec[j++], core_open_fds); - } - - p = procfs_file_alloca(pid, "status"); - if (read_full_file(p, &t, NULL) >= 0) { - core_proc_status = strappend("COREDUMP_PROC_STATUS=", t); - free(t); - - if (core_proc_status) - IOVEC_SET_STRING(iovec[j++], core_proc_status); - } - - p = procfs_file_alloca(pid, "maps"); - if (read_full_file(p, &t, NULL) >= 0) { - core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t); - free(t); - - if (core_proc_maps) - IOVEC_SET_STRING(iovec[j++], core_proc_maps); - } - - p = procfs_file_alloca(pid, "limits"); - if (read_full_file(p, &t, NULL) >= 0) { - core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t); - free(t); - - if (core_proc_limits) - IOVEC_SET_STRING(iovec[j++], core_proc_limits); - } - - p = procfs_file_alloca(pid, "cgroup"); - if (read_full_file(p, &t, NULL) >=0) { - core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t); - free(t); - - if (core_proc_cgroup) - IOVEC_SET_STRING(iovec[j++], core_proc_cgroup); - } - - if (get_process_cwd(pid, &t) >= 0) { - core_cwd = strjoina("COREDUMP_CWD=", t); - free(t); - - IOVEC_SET_STRING(iovec[j++], core_cwd); - } - - if (get_process_root(pid, &t) >= 0) { - core_root = strjoina("COREDUMP_ROOT=", t); - free(t); - - IOVEC_SET_STRING(iovec[j++], core_root); - } - - if (get_process_environ(pid, &t) >= 0) { - core_environ = strappend("COREDUMP_ENVIRON=", t); - free(t); - - if (core_environ) - IOVEC_SET_STRING(iovec[j++], core_environ); - } - - core_timestamp = strjoin("COREDUMP_TIMESTAMP=", info[INFO_TIMESTAMP], "000000", NULL); - if (core_timestamp) - IOVEC_SET_STRING(iovec[j++], core_timestamp); - - IOVEC_SET_STRING(iovec[j++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); - IOVEC_SET_STRING(iovec[j++], "PRIORITY=2"); + assert(context); + assert(iovec); + assert(n_iovec_allocated >= n_iovec + 3); + assert(input_fd >= 0); /* Vacuum before we write anything again */ - coredump_vacuum(-1, arg_keep_free, arg_max_use); + (void) coredump_vacuum(-1, arg_keep_free, arg_max_use); /* Always stream the coredump to disk, if that's possible */ - r = save_external_coredump(info, uid, &filename, &coredump_fd, &coredump_size); + r = save_external_coredump(context, input_fd, &filename, &coredump_node_fd, &coredump_fd, &coredump_size); if (r < 0) - /* skip whole core dumping part */ + /* Skip whole core dumping part */ goto log; - /* If we don't want to keep the coredump on disk, remove it - * now, as later on we will lack the privileges for - * it. However, we keep the fd to it, so that we can still - * process it and log it. */ + /* If we don't want to keep the coredump on disk, remove it now, as later on we will lack the privileges for + * it. However, we keep the fd to it, so that we can still process it and log it. */ r = maybe_remove_external_coredump(filename, coredump_size); if (r < 0) - goto finish; + return r; if (r == 0) { const char *coredump_filename; coredump_filename = strjoina("COREDUMP_FILENAME=", filename); - IOVEC_SET_STRING(iovec[j++], coredump_filename); + IOVEC_SET_STRING(iovec[n_iovec++], coredump_filename); } /* Vacuum again, but exclude the coredump we just created */ - coredump_vacuum(coredump_fd, arg_keep_free, arg_max_use); + (void) coredump_vacuum(coredump_node_fd >= 0 ? coredump_node_fd : coredump_fd, arg_keep_free, arg_max_use); - /* Now, let's drop privileges to become the user who owns the - * segfaulted process and allocate the coredump memory under - * the user's uid. This also ensures that the credentials - * journald will see are the ones of the coredumping user, - * thus making sure the user gets access to the core - * dump. Let's also get rid of all capabilities, if we run as - * root, we won't need them anymore. */ - r = drop_privileges(uid, gid, 0); - if (r < 0) { - log_error_errno(r, "Failed to drop privileges: %m"); - goto finish; - } + /* Now, let's drop privileges to become the user who owns the segfaulted process and allocate the coredump + * memory under the user's uid. This also ensures that the credentials journald will see are the ones of the + * coredumping user, thus making sure the user gets access to the core dump. Let's also get rid of all + * capabilities, if we run as root, we won't need them anymore. */ + r = change_uid_gid(context); + if (r < 0) + return log_error_errno(r, "Failed to drop privileges: %m"); #ifdef HAVE_ELFUTILS /* Try to get a strack trace if we can */ if (coredump_size <= arg_process_size_max) { _cleanup_free_ char *stacktrace = NULL; - r = coredump_make_stack_trace(coredump_fd, exe, &stacktrace); + r = coredump_make_stack_trace(coredump_fd, context[CONTEXT_EXE], &stacktrace); if (r >= 0) - core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.\n\n", stacktrace, NULL); + core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], " (", context[CONTEXT_COMM], ") of user ", context[CONTEXT_UID], " dumped core.\n\n", stacktrace, NULL); else if (r == -EINVAL) log_warning("Failed to generate stack trace: %s", dwfl_errmsg(dwfl_errno())); else @@ -847,9 +652,9 @@ int main(int argc, char* argv[]) { if (!core_message) #endif log: - core_message = strjoin("MESSAGE=Process ", info[INFO_PID], " (", comm, ") of user ", info[INFO_UID], " dumped core.", NULL); + core_message = strjoin("MESSAGE=Process ", context[CONTEXT_PID], " (", context[CONTEXT_COMM], ") of user ", context[CONTEXT_UID], " dumped core.", NULL); if (core_message) - IOVEC_SET_STRING(iovec[j++], core_message); + IOVEC_SET_STRING(iovec[n_iovec++], core_message); /* Optionally store the entire coredump in the journal */ if (IN_SET(arg_storage, COREDUMP_STORAGE_JOURNAL, COREDUMP_STORAGE_BOTH) && @@ -860,15 +665,483 @@ log: r = allocate_journal_field(coredump_fd, (size_t) coredump_size, &coredump_data, &sz); if (r >= 0) { - iovec[j].iov_base = coredump_data; - iovec[j].iov_len = sz; - j++; + iovec[n_iovec].iov_base = coredump_data; + iovec[n_iovec].iov_len = sz; + n_iovec++; } } - r = sd_journal_sendv(iovec, j); + assert(n_iovec <= n_iovec_allocated); + + r = sd_journal_sendv(iovec, n_iovec); if (r < 0) - log_error_errno(r, "Failed to log coredump: %m"); + return log_error_errno(r, "Failed to log coredump: %m"); + + return 0; +} + +static void map_context_fields(const struct iovec *iovec, const char *context[]) { + + static const char * const context_field_names[_CONTEXT_MAX] = { + [CONTEXT_PID] = "COREDUMP_PID=", + [CONTEXT_UID] = "COREDUMP_UID=", + [CONTEXT_GID] = "COREDUMP_GID=", + [CONTEXT_SIGNAL] = "COREDUMP_SIGNAL=", + [CONTEXT_TIMESTAMP] = "COREDUMP_TIMESTAMP=", + [CONTEXT_COMM] = "COREDUMP_COMM=", + [CONTEXT_EXE] = "COREDUMP_EXE=", + [CONTEXT_RLIMIT] = "COREDUMP_RLIMIT=", + }; + + unsigned i; + + assert(iovec); + assert(context); + + for (i = 0; i < _CONTEXT_MAX; i++) { + size_t l; + + l = strlen(context_field_names[i]); + if (iovec->iov_len < l) + continue; + + if (memcmp(iovec->iov_base, context_field_names[i], l) != 0) + continue; + + /* Note that these strings are NUL terminated, because we made sure that a trailing NUL byte is in the + * buffer, though not included in the iov_len count. (see below) */ + context[i] = (char*) iovec->iov_base + l; + break; + } +} + +static int process_socket(int fd) { + _cleanup_close_ int coredump_fd = -1; + struct iovec *iovec = NULL; + size_t n_iovec = 0, n_iovec_allocated = 0, i; + const char *context[_CONTEXT_MAX] = {}; + int r; + + assert(fd >= 0); + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + for (;;) { + union { + struct cmsghdr cmsghdr; + uint8_t buf[CMSG_SPACE(sizeof(int))]; + } control = {}; + struct msghdr mh = { + .msg_control = &control, + .msg_controllen = sizeof(control), + .msg_iovlen = 1, + }; + ssize_t n; + int l; + + if (!GREEDY_REALLOC(iovec, n_iovec_allocated, n_iovec + 3)) { + r = log_oom(); + goto finish; + } + + if (ioctl(fd, FIONREAD, &l) < 0) { + r = log_error_errno(errno, "FIONREAD failed: %m"); + goto finish; + } + + assert(l >= 0); + + iovec[n_iovec].iov_len = l; + iovec[n_iovec].iov_base = malloc(l + 1); + + if (!iovec[n_iovec].iov_base) { + r = log_oom(); + goto finish; + } + + mh.msg_iov = iovec + n_iovec; + + n = recvmsg(fd, &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC); + if (n < 0) { + free(iovec[n_iovec].iov_base); + r = log_error_errno(errno, "Failed to receive datagram: %m"); + goto finish; + } + + if (n == 0) { + struct cmsghdr *cmsg, *found = NULL; + /* The final zero-length datagram carries the file descriptor and tells us that we're done. */ + + free(iovec[n_iovec].iov_base); + + CMSG_FOREACH(cmsg, &mh) { + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_RIGHTS && + cmsg->cmsg_len == CMSG_LEN(sizeof(int))) { + assert(!found); + found = cmsg; + } + } + + if (!found) { + log_error("Coredump file descriptor missing."); + r = -EBADMSG; + goto finish; + } + + assert(coredump_fd < 0); + coredump_fd = *(int*) CMSG_DATA(found); + break; + } + + /* Add trailing NUL byte, in case these are strings */ + ((char*) iovec[n_iovec].iov_base)[n] = 0; + iovec[n_iovec].iov_len = (size_t) n; + + cmsg_close_all(&mh); + map_context_fields(iovec + n_iovec, context); + n_iovec++; + } + + if (!GREEDY_REALLOC(iovec, n_iovec_allocated, n_iovec + 3)) { + r = log_oom(); + goto finish; + } + + /* Make sure we we got all data we really need */ + assert(context[CONTEXT_PID]); + assert(context[CONTEXT_UID]); + assert(context[CONTEXT_GID]); + assert(context[CONTEXT_SIGNAL]); + assert(context[CONTEXT_TIMESTAMP]); + assert(context[CONTEXT_RLIMIT]); + assert(context[CONTEXT_COMM]); + assert(coredump_fd >= 0); + + r = submit_coredump(context, iovec, n_iovec_allocated, n_iovec, coredump_fd); + +finish: + for (i = 0; i < n_iovec; i++) + free(iovec[i].iov_base); + free(iovec); + + return r; +} + +static int send_iovec(const struct iovec iovec[], size_t n_iovec, int input_fd) { + + static const union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + .un.sun_path = "/run/systemd/coredump", + }; + _cleanup_close_ int fd = -1; + size_t i; + int r; + + assert(iovec || n_iovec <= 0); + assert(input_fd >= 0); + + fd = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0); + if (fd < 0) + return log_error_errno(errno, "Failed to create coredump socket: %m"); + + if (connect(fd, &sa.sa, offsetof(union sockaddr_union, un.sun_path) + strlen(sa.un.sun_path)) < 0) + return log_error_errno(errno, "Failed to connect to coredump service: %m"); + + for (i = 0; i < n_iovec; i++) { + ssize_t n; + assert(iovec[i].iov_len > 0); + + n = send(fd, iovec[i].iov_base, iovec[i].iov_len, MSG_NOSIGNAL); + if (n < 0) + return log_error_errno(errno, "Failed to send coredump datagram: %m"); + } + + r = send_one_fd(fd, input_fd, 0); + if (r < 0) + return log_error_errno(r, "Failed to send coredump fd: %m"); + + return 0; +} + +static int process_journald_crash(const char *context[], int input_fd) { + _cleanup_close_ int coredump_fd = -1, coredump_node_fd = -1; + _cleanup_free_ char *filename = NULL; + uint64_t coredump_size; + int r; + + assert(context); + assert(input_fd >= 0); + + /* If we are journald, we cut things short, don't write to the journal, but still create a coredump. */ + + if (arg_storage != COREDUMP_STORAGE_NONE) + arg_storage = COREDUMP_STORAGE_EXTERNAL; + + r = save_external_coredump(context, input_fd, &filename, &coredump_node_fd, &coredump_fd, &coredump_size); + if (r < 0) + return r; + + r = maybe_remove_external_coredump(filename, coredump_size); + if (r < 0) + return r; + + log_info("Detected coredump of the journal daemon itself, diverted to %s.", filename); + return 0; +} + +static int process_kernel(int argc, char* argv[]) { + + /* The small core field we allocate on the stack, to keep things simple */ + char + *core_pid = NULL, *core_uid = NULL, *core_gid = NULL, *core_signal = NULL, + *core_session = NULL, *core_exe = NULL, *core_comm = NULL, *core_cmdline = NULL, + *core_cgroup = NULL, *core_cwd = NULL, *core_root = NULL, *core_unit = NULL, + *core_user_unit = NULL, *core_slice = NULL, *core_timestamp = NULL, *core_rlimit = NULL; + + /* The larger ones we allocate on the heap */ + _cleanup_free_ char + *core_owner_uid = NULL, *core_open_fds = NULL, *core_proc_status = NULL, + *core_proc_maps = NULL, *core_proc_limits = NULL, *core_proc_cgroup = NULL, *core_environ = NULL; + + _cleanup_free_ char *exe = NULL, *comm = NULL; + const char *context[_CONTEXT_MAX]; + struct iovec iovec[25]; + size_t n_iovec = 0; + uid_t owner_uid; + const char *p; + pid_t pid; + char *t; + int r; + + if (argc < CONTEXT_COMM + 1) { + log_error("Not enough arguments passed from kernel (%i, expected %i).", argc - 1, CONTEXT_COMM + 1 - 1); + return -EINVAL; + } + + r = parse_pid(argv[CONTEXT_PID + 1], &pid); + if (r < 0) + return log_error_errno(r, "Failed to parse PID."); + + r = get_process_comm(pid, &comm); + if (r < 0) { + log_warning_errno(r, "Failed to get COMM, falling back to the command line: %m"); + comm = strv_join(argv + CONTEXT_COMM + 1, " "); + if (!comm) + return log_oom(); + } + + r = get_process_exe(pid, &exe); + if (r < 0) + log_warning_errno(r, "Failed to get EXE, ignoring: %m"); + + context[CONTEXT_PID] = argv[CONTEXT_PID + 1]; + context[CONTEXT_UID] = argv[CONTEXT_UID + 1]; + context[CONTEXT_GID] = argv[CONTEXT_GID + 1]; + context[CONTEXT_SIGNAL] = argv[CONTEXT_SIGNAL + 1]; + context[CONTEXT_TIMESTAMP] = argv[CONTEXT_TIMESTAMP + 1]; + context[CONTEXT_RLIMIT] = argv[CONTEXT_RLIMIT + 1]; + context[CONTEXT_COMM] = comm; + context[CONTEXT_EXE] = exe; + + if (cg_pid_get_unit(pid, &t) >= 0) { + + if (streq(t, SPECIAL_JOURNALD_SERVICE)) { + free(t); + return process_journald_crash(context, STDIN_FILENO); + } + + core_unit = strjoina("COREDUMP_UNIT=", t); + free(t); + + IOVEC_SET_STRING(iovec[n_iovec++], core_unit); + } + + /* OK, now we know it's not the journal, hence we can make use of it now. */ + log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); + log_open(); + + if (cg_pid_get_user_unit(pid, &t) >= 0) { + core_user_unit = strjoina("COREDUMP_USER_UNIT=", t); + free(t); + + IOVEC_SET_STRING(iovec[n_iovec++], core_user_unit); + } + + core_pid = strjoina("COREDUMP_PID=", context[CONTEXT_PID]); + IOVEC_SET_STRING(iovec[n_iovec++], core_pid); + + core_uid = strjoina("COREDUMP_UID=", context[CONTEXT_UID]); + IOVEC_SET_STRING(iovec[n_iovec++], core_uid); + + core_gid = strjoina("COREDUMP_GID=", context[CONTEXT_GID]); + IOVEC_SET_STRING(iovec[n_iovec++], core_gid); + + core_signal = strjoina("COREDUMP_SIGNAL=", context[CONTEXT_SIGNAL]); + IOVEC_SET_STRING(iovec[n_iovec++], core_signal); + + core_rlimit = strjoina("COREDUMP_RLIMIT=", context[CONTEXT_RLIMIT]); + IOVEC_SET_STRING(iovec[n_iovec++], core_rlimit); + + if (sd_pid_get_session(pid, &t) >= 0) { + core_session = strjoina("COREDUMP_SESSION=", t); + free(t); + + IOVEC_SET_STRING(iovec[n_iovec++], core_session); + } + + if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) { + r = asprintf(&core_owner_uid, "COREDUMP_OWNER_UID=" UID_FMT, owner_uid); + if (r > 0) + IOVEC_SET_STRING(iovec[n_iovec++], core_owner_uid); + } + + if (sd_pid_get_slice(pid, &t) >= 0) { + core_slice = strjoina("COREDUMP_SLICE=", t); + free(t); + + IOVEC_SET_STRING(iovec[n_iovec++], core_slice); + } + + if (comm) { + core_comm = strjoina("COREDUMP_COMM=", comm); + IOVEC_SET_STRING(iovec[n_iovec++], core_comm); + } + + if (exe) { + core_exe = strjoina("COREDUMP_EXE=", exe); + IOVEC_SET_STRING(iovec[n_iovec++], core_exe); + } + + if (get_process_cmdline(pid, 0, false, &t) >= 0) { + core_cmdline = strjoina("COREDUMP_CMDLINE=", t); + free(t); + + IOVEC_SET_STRING(iovec[n_iovec++], core_cmdline); + } + + if (cg_pid_get_path_shifted(pid, NULL, &t) >= 0) { + core_cgroup = strjoina("COREDUMP_CGROUP=", t); + free(t); + + IOVEC_SET_STRING(iovec[n_iovec++], core_cgroup); + } + + if (compose_open_fds(pid, &t) >= 0) { + core_open_fds = strappend("COREDUMP_OPEN_FDS=", t); + free(t); + + if (core_open_fds) + IOVEC_SET_STRING(iovec[n_iovec++], core_open_fds); + } + + p = procfs_file_alloca(pid, "status"); + if (read_full_file(p, &t, NULL) >= 0) { + core_proc_status = strappend("COREDUMP_PROC_STATUS=", t); + free(t); + + if (core_proc_status) + IOVEC_SET_STRING(iovec[n_iovec++], core_proc_status); + } + + p = procfs_file_alloca(pid, "maps"); + if (read_full_file(p, &t, NULL) >= 0) { + core_proc_maps = strappend("COREDUMP_PROC_MAPS=", t); + free(t); + + if (core_proc_maps) + IOVEC_SET_STRING(iovec[n_iovec++], core_proc_maps); + } + + p = procfs_file_alloca(pid, "limits"); + if (read_full_file(p, &t, NULL) >= 0) { + core_proc_limits = strappend("COREDUMP_PROC_LIMITS=", t); + free(t); + + if (core_proc_limits) + IOVEC_SET_STRING(iovec[n_iovec++], core_proc_limits); + } + + p = procfs_file_alloca(pid, "cgroup"); + if (read_full_file(p, &t, NULL) >=0) { + core_proc_cgroup = strappend("COREDUMP_PROC_CGROUP=", t); + free(t); + + if (core_proc_cgroup) + IOVEC_SET_STRING(iovec[n_iovec++], core_proc_cgroup); + } + + if (get_process_cwd(pid, &t) >= 0) { + core_cwd = strjoina("COREDUMP_CWD=", t); + free(t); + + IOVEC_SET_STRING(iovec[n_iovec++], core_cwd); + } + + if (get_process_root(pid, &t) >= 0) { + core_root = strjoina("COREDUMP_ROOT=", t); + free(t); + + IOVEC_SET_STRING(iovec[n_iovec++], core_root); + } + + if (get_process_environ(pid, &t) >= 0) { + core_environ = strappend("COREDUMP_ENVIRON=", t); + free(t); + + if (core_environ) + IOVEC_SET_STRING(iovec[n_iovec++], core_environ); + } + + core_timestamp = strjoina("COREDUMP_TIMESTAMP=", context[CONTEXT_TIMESTAMP], "000000", NULL); + IOVEC_SET_STRING(iovec[n_iovec++], core_timestamp); + + IOVEC_SET_STRING(iovec[n_iovec++], "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1"); + + assert_cc(2 == LOG_CRIT); + IOVEC_SET_STRING(iovec[n_iovec++], "PRIORITY=2"); + + assert(n_iovec <= ELEMENTSOF(iovec)); + + return send_iovec(iovec, n_iovec, STDIN_FILENO); +} + +int main(int argc, char *argv[]) { + int r; + + /* First, log to a safe place, since we don't know what crashed and it might be journald which we'd rather not + * log to then. */ + + log_set_target(LOG_TARGET_KMSG); + log_open(); + + /* Make sure we never enter a loop */ + (void) prctl(PR_SET_DUMPABLE, 0); + + /* Ignore all parse errors */ + (void) parse_config(); + + log_debug("Selected storage '%s'.", coredump_storage_to_string(arg_storage)); + log_debug("Selected compression %s.", yes_no(arg_compress)); + + r = sd_listen_fds(false); + if (r < 0) { + log_error_errno(r, "Failed to determine number of file descriptor: %m"); + goto finish; + } + + /* If we got an fd passed, we are running in coredumpd mode. Otherwise we are invoked from the kernel as + * coredump handler */ + if (r == 0) + r = process_kernel(argc, argv); + else if (r == 1) + r = process_socket(SD_LISTEN_FDS_START); + else { + log_error("Received unexpected number of file descriptors."); + r = -EINVAL; + } finish: return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; diff --git a/src/journal/coredump.conf b/src/coredump/coredump.conf similarity index 100% rename from src/journal/coredump.conf rename to src/coredump/coredump.conf diff --git a/src/journal/coredumpctl.c b/src/coredump/coredumpctl.c similarity index 99% rename from src/journal/coredumpctl.c rename to src/coredump/coredumpctl.c index 1df28d774..0034a1a0a 100644 --- a/src/journal/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -792,7 +790,7 @@ finish: } int main(int argc, char *argv[]) { - _cleanup_journal_close_ sd_journal*j = NULL; + _cleanup_(sd_journal_closep) sd_journal*j = NULL; const char* match; Iterator it; int r = 0; diff --git a/src/journal/stacktrace.c b/src/coredump/stacktrace.c similarity index 98% rename from src/journal/stacktrace.c rename to src/coredump/stacktrace.c index 4305462f8..68806992f 100644 --- a/src/journal/stacktrace.c +++ b/src/coredump/stacktrace.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/stacktrace.h b/src/coredump/stacktrace.h similarity index 92% rename from src/journal/stacktrace.h rename to src/coredump/stacktrace.h index 189e5c459..15e9c0446 100644 --- a/src/journal/stacktrace.h +++ b/src/coredump/stacktrace.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/test-coredump-vacuum.c b/src/coredump/test-coredump-vacuum.c similarity index 93% rename from src/journal/test-coredump-vacuum.c rename to src/coredump/test-coredump-vacuum.c index 514dadc1d..70a57f183 100644 --- a/src/journal/test-coredump-vacuum.c +++ b/src/coredump/test-coredump-vacuum.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index ae53bac60..8ac5ab730 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 98fe52a81..2ef966257 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -268,7 +266,7 @@ static char* disk_description(const char *path) { "ID_MODEL_FROM_DATABASE\0" "ID_MODEL\0"; - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; struct stat st; const char *i; int r; diff --git a/src/dbus1-generator/dbus1-generator.c b/src/dbus1-generator/dbus1-generator.c index 6861a592f..717cb9558 100644 --- a/src/dbus1-generator/dbus1-generator.c +++ b/src/dbus1-generator/dbus1-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c index 413cfd038..7e80af78e 100644 --- a/src/debug-generator/debug-generator.c +++ b/src/debug-generator/debug-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/delta/delta.c b/src/delta/delta.c index 8bf678c28..a54fc89de 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -430,18 +428,16 @@ static int process_suffix(const char *suffix, const char *onlyprefix) { } finish: - if (top) - hashmap_free_free(top); - if (bottom) - hashmap_free_free(bottom); - if (drops) { - HASHMAP_FOREACH_KEY(h, key, drops, i){ - hashmap_free_free(hashmap_remove(drops, key)); - hashmap_remove(drops, key); - free(key); - } - hashmap_free(drops); + hashmap_free_free(top); + hashmap_free_free(bottom); + + HASHMAP_FOREACH_KEY(h, key, drops, i){ + hashmap_free_free(hashmap_remove(drops, key)); + hashmap_remove(drops, key); + free(key); } + hashmap_free(drops); + return r < 0 ? r : n_found; } @@ -453,9 +449,10 @@ static int process_suffixes(const char *onlyprefix) { r = process_suffix(n, onlyprefix); if (r < 0) return r; - else - n_found += r; + + n_found += r; } + return n_found; } @@ -469,7 +466,9 @@ static int process_suffix_chop(const char *arg) { /* Strip prefix from the suffix */ NULSTR_FOREACH(p, prefixes) { - const char *suffix = startswith(arg, p); + const char *suffix; + + suffix = startswith(arg, p); if (suffix) { suffix += strspn(suffix, "/"); if (*suffix) @@ -577,10 +576,9 @@ static int parse_argv(int argc, char *argv[]) { if (b < 0) { log_error("Failed to parse diff boolean."); return -EINVAL; - } else if (b) - arg_diff = 1; - else - arg_diff = 0; + } + + arg_diff = b; } break; @@ -595,8 +593,7 @@ static int parse_argv(int argc, char *argv[]) { } int main(int argc, char *argv[]) { - int r = 0, k; - int n_found = 0; + int r, k, n_found = 0; log_parse_environment(); log_open(); @@ -620,6 +617,7 @@ int main(int argc, char *argv[]) { for (i = optind; i < argc; i++) { path_kill_slashes(argv[i]); + k = process_suffix_chop(argv[i]); if (k < 0) r = k; @@ -636,8 +634,7 @@ int main(int argc, char *argv[]) { } if (r >= 0) - printf("%s%i overridden configuration files found.\n", - n_found ? "\n" : "", n_found); + printf("%s%i overridden configuration files found.\n", n_found ? "\n" : "", n_found); finish: pager_close(); diff --git a/src/detect-virt/detect-virt.c b/src/detect-virt/detect-virt.c index 0a256c29b..5d51589a3 100644 --- a/src/detect-virt/detect-virt.c +++ b/src/detect-virt/detect-virt.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/escape/escape.c b/src/escape/escape.c index e857affbc..9f3904957 100644 --- a/src/escape/escape.c +++ b/src/escape/escape.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 469ee7af6..7790ab865 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -502,7 +500,7 @@ static int write_root_shadow(const char *path, const struct spwd *p) { errno = 0; if (putspent(p, f) != 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return fflush_and_check(f); } diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index e0436d794..6f56066da 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -67,8 +65,8 @@ static bool arg_show_progress = false; static const char *arg_repair = "-a"; static void start_target(const char *target, const char *mode) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; assert(target); @@ -276,7 +274,7 @@ static int fsck_progress_socket(void) { int main(int argc, char *argv[]) { _cleanup_close_pair_ int progress_pipe[2] = { -1, -1 }; - _cleanup_device_unref_ sd_device *dev = NULL; + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; const char *device, *type; bool root_directory; siginfo_t status; diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index f7c8d11ac..97a48764a 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -248,6 +246,7 @@ static int add_mount( assert(what); assert(where); assert(opts); + assert(post); assert(source); if (streq_ptr(fstype, "autofs")) @@ -297,7 +296,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 +336,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 +367,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); @@ -465,8 +461,6 @@ static int parse_fstab(bool initrd) { "x-systemd.automount\0"); if (initrd) post = SPECIAL_INITRD_FS_TARGET; - else if (mount_in_initrd(me)) - post = SPECIAL_INITRD_ROOT_FS_TARGET; else if (mount_is_network(me)) post = SPECIAL_REMOTE_FS_TARGET; else @@ -578,7 +572,7 @@ static int add_sysroot_usr_mount(void) { false, false, false, - SPECIAL_INITRD_ROOT_FS_TARGET, + SPECIAL_INITRD_FS_TARGET, "/proc/cmdline"); } diff --git a/src/getty-generator/getty-generator.c b/src/getty-generator/getty-generator.c index 03df7365b..b15c76b5b 100644 --- a/src/getty-generator/getty-generator.c +++ b/src/getty-generator/getty-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -112,7 +110,7 @@ static int verify_tty(const char *name) { errno = 0; if (isatty(fd) <= 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return 0; } diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c index ce8cecc5c..af96adec0 100644 --- a/src/gpt-auto-generator/gpt-auto-generator.c +++ b/src/gpt-auto-generator/gpt-auto-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -515,14 +513,15 @@ static int add_boot(const char *what) { return log_error_errno(errno ?: EIO, "Failed to probe %s: %m", what); (void) blkid_probe_lookup_value(b, "TYPE", &fstype, NULL); - if (!streq(fstype, "vfat")) { + if (!streq_ptr(fstype, "vfat")) { log_debug("Partition for /boot is not a FAT filesystem, ignoring."); return 0; } + errno = 0; r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &uuid, NULL); if (r != 0) { - log_debug_errno(r, "Partition for /boot does not have a UUID, ignoring. %m"); + log_debug_errno(errno, "Partition for /boot does not have a UUID, ignoring."); return 0; } @@ -635,16 +634,19 @@ static int enumerate_partitions(dev_t devnum) { if (r == 1) return 0; /* no results */ else if (r == -2) { - log_warning("%s: probe gave ambiguous results, ignoring", node); + log_warning("%s: probe gave ambiguous results, ignoring.", node); return 0; } else if (r != 0) return log_error_errno(errno ?: EIO, "%s: failed to probe: %m", node); errno = 0; r = blkid_probe_lookup_value(b, "PTTYPE", &pttype, NULL); - if (r != 0) - return log_error_errno(errno ?: EIO, - "%s: failed to determine partition table type: %m", node); + if (r != 0) { + if (errno == 0) + return 0; /* No partition table found. */ + + return log_error_errno(errno, "%s: failed to determine partition table type: %m", node); + } /* We only do this all for GPT... */ if (!streq_ptr(pttype, "gpt")) { diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c index da719f2a3..d7ee80d58 100644 --- a/src/hibernate-resume/hibernate-resume-generator.c +++ b/src/hibernate-resume/hibernate-resume-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c index 2e1259ef6..21df3c446 100644 --- a/src/hibernate-resume/hibernate-resume.c +++ b/src/hibernate-resume/hibernate-resume.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index bf09fb8fb..c16a32423 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -127,8 +125,8 @@ static void print_status_info(StatusInfo *i) { } static int show_one_name(sd_bus *bus, const char* attr) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *s; int r; @@ -233,7 +231,7 @@ static int show_status(sd_bus *bus, char **args, unsigned n) { } static int set_simple_string(sd_bus *bus, const char *method, const char *value) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r = 0; polkit_agent_open_if_enabled(); @@ -507,7 +505,7 @@ static int hostnamectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index dde2baf66..c37e32e96 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -28,7 +26,6 @@ #include "bus-util.h" #include "def.h" #include "env-util.h" -#include "event-util.h" #include "fileio-label.h" #include "hostname-util.h" #include "parse-util.h" @@ -213,10 +210,10 @@ try_dmi: unreliable enough, so let's not do any additional guesswork on top of that. - See the SMBIOS Specification 2.7.1 section 7.4.1 for + See the SMBIOS Specification 3.0 section 7.4.1 for details about the values listed here: - http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf + https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf */ switch (t) { @@ -238,7 +235,11 @@ try_dmi: case 0x11: case 0x1C: + case 0x1D: return "server"; + + case 0x1E: + return "tablet"; } return NULL; @@ -665,7 +666,7 @@ static const sd_bus_vtable hostname_vtable[] = { }; static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; assert(c); @@ -696,8 +697,8 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { int main(int argc, char *argv[]) { Context context = {}; - _cleanup_event_unref_ sd_event *event = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; log_set_target(LOG_TARGET_AUTO); diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index de59b797a..1160dacdf 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -571,7 +571,7 @@ static int import_file(struct trie *trie, const char *filename) { } static int hwdb_query(int argc, char *argv[], void *userdata) { - _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; const char *key, *value; const char *modalias; int r; diff --git a/src/import/aufs-util.c b/src/import/aufs-util.c index 82f519958..44aa6e217 100644 --- a/src/import/aufs-util.c +++ b/src/import/aufs-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -69,7 +67,7 @@ int aufs_resolve(const char *path) { errno = 0; r = nftw(path, nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL); if (r == FTW_STOP) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return 0; } diff --git a/src/import/aufs-util.h b/src/import/aufs-util.h index 712fb81ce..e474a5089 100644 --- a/src/import/aufs-util.h +++ b/src/import/aufs-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/import/curl-util.c b/src/import/curl-util.c index 8e531a64f..a04c8c49f 100644 --- a/src/import/curl-util.c +++ b/src/import/curl-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/curl-util.h b/src/import/curl-util.h index 6a2aa81c7..a758cc564 100644 --- a/src/import/curl-util.h +++ b/src/import/curl-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "sd-event.h" diff --git a/src/import/export-raw.c b/src/import/export-raw.c index 28c87594d..db06e11b8 100644 --- a/src/import/export-raw.c +++ b/src/import/export-raw.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/export-raw.h b/src/import/export-raw.h index b71de6cb8..8e723d490 100644 --- a/src/import/export-raw.h +++ b/src/import/export-raw.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,8 +20,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.c b/src/import/export-tar.c index 2bbec661e..d79c27f2d 100644 --- a/src/import/export-tar.c +++ b/src/import/export-tar.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/export-tar.h b/src/import/export-tar.h index ce27a9fc1..1e3c8bb80 100644 --- a/src/import/export-tar.h +++ b/src/import/export-tar.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,8 +20,9 @@ ***/ #include "sd-event.h" -#include "macro.h" + #include "import-compress.h" +#include "macro.h" typedef struct TarExport TarExport; diff --git a/src/import/export.c b/src/import/export.c index 2b33d778d..cc98c33ef 100644 --- a/src/import/export.c +++ b/src/import/export.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -24,7 +22,6 @@ #include "sd-event.h" #include "alloc-util.h" -#include "event-util.h" #include "export-raw.h" #include "export-tar.h" #include "fd-util.h" @@ -76,7 +73,7 @@ static void on_tar_finished(TarExport *export, int error, void *userdata) { static int export_tar(int argc, char *argv[], void *userdata) { _cleanup_(tar_export_unrefp) TarExport *export = NULL; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(image_unrefp) Image *image = NULL; const char *path = NULL, *local = NULL; _cleanup_close_ int open_fd = -1; @@ -155,7 +152,7 @@ static void on_raw_finished(RawExport *export, int error, void *userdata) { static int export_raw(int argc, char *argv[], void *userdata) { _cleanup_(raw_export_unrefp) RawExport *export = NULL; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(image_unrefp) Image *image = NULL; const char *path = NULL, *local = NULL; _cleanup_close_ int open_fd = -1; diff --git a/src/import/import-common.c b/src/import/import-common.c index a8551ca9e..18a30be36 100644 --- a/src/import/import-common.c +++ b/src/import/import-common.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -134,7 +132,7 @@ int import_fork_tar_x(const char *path, pid_t *ret) { if (unshare(CLONE_NEWNET) < 0) log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m"); - r = capability_bounding_set_drop(~retain, true); + r = capability_bounding_set_drop(retain, true); if (r < 0) log_error_errno(r, "Failed to drop capabilities, ignoring: %m"); @@ -208,7 +206,7 @@ int import_fork_tar_c(const char *path, pid_t *ret) { if (unshare(CLONE_NEWNET) < 0) log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m"); - r = capability_bounding_set_drop(~retain, true); + r = capability_bounding_set_drop(retain, true); if (r < 0) log_error_errno(r, "Failed to drop capabilities, ignoring: %m"); diff --git a/src/import/import-common.h b/src/import/import-common.h index 7b60de80c..07d3250e7 100644 --- a/src/import/import-common.h +++ b/src/import/import-common.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/import/import-compress.c b/src/import/import-compress.c index d4ff178f6..f1766bbe3 100644 --- a/src/import/import-compress.c +++ b/src/import/import-compress.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/import-compress.h b/src/import/import-compress.h index 50d91f732..6b59d0724 100644 --- a/src/import/import-compress.h +++ b/src/import/import-compress.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,11 +19,10 @@ along with systemd; If not, see . ***/ -#include - -#include -#include #include +#include +#include +#include #include "macro.h" diff --git a/src/import/import-raw.c b/src/import/import-raw.c index 7593f064f..fd6b9f770 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/import-raw.h b/src/import/import-raw.h index bf7c77034..4f543e088 100644 --- a/src/import/import-raw.h +++ b/src/import/import-raw.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,8 +20,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.c b/src/import/import-tar.c index c7983c04b..8b81324fd 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/import-tar.h b/src/import/import-tar.h index aaecb5139..24abe06c8 100644 --- a/src/import/import-tar.h +++ b/src/import/import-tar.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,8 +20,9 @@ ***/ #include "sd-event.h" -#include "macro.h" + #include "import-util.h" +#include "macro.h" typedef struct TarImport TarImport; diff --git a/src/import/import.c b/src/import/import.c index 018b94d4c..4e442ee84 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -24,7 +22,6 @@ #include "sd-event.h" #include "alloc-util.h" -#include "event-util.h" #include "fd-util.h" #include "fs-util.h" #include "hostname-util.h" @@ -58,7 +55,7 @@ static void on_tar_finished(TarImport *import, int error, void *userdata) { static int import_tar(int argc, char *argv[], void *userdata) { _cleanup_(tar_import_unrefp) TarImport *import = NULL; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; const char *path = NULL, *local = NULL; _cleanup_free_ char *ll = NULL; _cleanup_close_ int open_fd = -1; @@ -153,7 +150,7 @@ static void on_raw_finished(RawImport *import, int error, void *userdata) { static int import_raw(int argc, char *argv[], void *userdata) { _cleanup_(raw_import_unrefp) RawImport *import = NULL; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; const char *path = NULL, *local = NULL; _cleanup_free_ char *ll = NULL; _cleanup_close_ int open_fd = -1; diff --git a/src/import/importd.c b/src/import/importd.c index 4228681ce..d2a5867a6 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -55,7 +53,6 @@ typedef enum TransferType { TRANSFER_EXPORT_RAW, TRANSFER_PULL_TAR, TRANSFER_PULL_RAW, - TRANSFER_PULL_DKR, _TRANSFER_TYPE_MAX, _TRANSFER_TYPE_INVALID = -1, } TransferType; @@ -74,7 +71,6 @@ struct Transfer { bool force_local; bool read_only; - char *dkr_index_url; char *format; pid_t pid; @@ -117,7 +113,6 @@ static const char* const transfer_type_table[_TRANSFER_TYPE_MAX] = { [TRANSFER_EXPORT_RAW] = "export-raw", [TRANSFER_PULL_TAR] = "pull-tar", [TRANSFER_PULL_RAW] = "pull-raw", - [TRANSFER_PULL_DKR] = "pull-dkr", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(transfer_type, TransferType); @@ -134,7 +129,6 @@ static Transfer *transfer_unref(Transfer *t) { free(t->remote); free(t->local); - free(t->dkr_index_url); free(t->format); free(t->object_path); @@ -383,12 +377,11 @@ static int transfer_start(Transfer *t) { if (t->pid == 0) { const char *cmd[] = { NULL, /* systemd-import, systemd-export or systemd-pull */ - NULL, /* tar, raw, dkr */ + NULL, /* tar, raw */ NULL, /* --verify= */ NULL, /* verify argument */ NULL, /* maybe --force */ NULL, /* maybe --read-only */ - NULL, /* maybe --dkr-index-url */ NULL, /* if so: the actual URL */ NULL, /* maybe --format= */ NULL, /* if so: the actual format */ @@ -471,10 +464,8 @@ static int transfer_start(Transfer *t) { if (IN_SET(t->type, TRANSFER_IMPORT_TAR, TRANSFER_EXPORT_TAR, TRANSFER_PULL_TAR)) cmd[k++] = "tar"; - else if (IN_SET(t->type, TRANSFER_IMPORT_RAW, TRANSFER_EXPORT_RAW, TRANSFER_PULL_RAW)) - cmd[k++] = "raw"; else - cmd[k++] = "dkr"; + cmd[k++] = "raw"; if (t->verify != _IMPORT_VERIFY_INVALID) { cmd[k++] = "--verify"; @@ -486,11 +477,6 @@ static int transfer_start(Transfer *t) { if (t->read_only) cmd[k++] = "--read-only"; - if (t->dkr_index_url) { - cmd[k++] = "--dkr-index-url"; - cmd[k++] = t->dkr_index_url; - } - if (t->format) { cmd[k++] = "--format"; cmd[k++] = t->format; @@ -707,7 +693,7 @@ static int manager_new(Manager **ret) { return 0; } -static Transfer *manager_find(Manager *m, TransferType type, const char *dkr_index_url, const char *remote) { +static Transfer *manager_find(Manager *m, TransferType type, const char *remote) { Transfer *t; Iterator i; @@ -718,8 +704,7 @@ static Transfer *manager_find(Manager *m, TransferType type, const char *dkr_ind HASHMAP_FOREACH(t, m->transfers, i) { if (t->type == type && - streq_ptr(t->remote, remote) && - streq_ptr(t->dkr_index_url, dkr_index_url)) + streq_ptr(t->remote, remote)) return t; } @@ -907,7 +892,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er type = streq_ptr(sd_bus_message_get_member(msg), "PullTar") ? TRANSFER_PULL_TAR : TRANSFER_PULL_RAW; - if (manager_find(m, type, NULL, remote)) + if (manager_find(m, type, remote)) return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote); r = transfer_new(m, &t); @@ -939,107 +924,8 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er return sd_bus_reply_method_return(msg, "uo", id, object); } -static int method_pull_dkr(sd_bus_message *msg, void *userdata, sd_bus_error *error) { - _cleanup_(transfer_unrefp) Transfer *t = NULL; - const char *index_url, *remote, *tag, *local, *verify, *object; - Manager *m = userdata; - ImportVerify v; - int force, r; - uint32_t id; - - assert(msg); - assert(m); - - r = bus_verify_polkit_async( - msg, - CAP_SYS_ADMIN, - "org.freedesktop.import1.pull", - NULL, - false, - UID_INVALID, - &m->polkit_registry, - error); - if (r < 0) - return r; - if (r == 0) - return 1; /* Will call us back */ - - r = sd_bus_message_read(msg, "sssssb", &index_url, &remote, &tag, &local, &verify, &force); - if (r < 0) - return r; - - if (isempty(index_url)) - index_url = DEFAULT_DKR_INDEX_URL; - if (!index_url) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Index URL must be specified."); - if (!http_url_is_valid(index_url)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Index URL %s is invalid", index_url); - - if (!dkr_name_is_valid(remote)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Remote name %s is not valid", remote); - - if (isempty(tag)) - tag = "latest"; - else if (!dkr_tag_is_valid(tag)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Tag %s is not valid", tag); - - if (isempty(local)) - local = NULL; - else if (!machine_name_is_valid(local)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); - - if (isempty(verify)) - v = IMPORT_VERIFY_SIGNATURE; - else - v = import_verify_from_string(verify); - if (v < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown verification mode %s", verify); - - if (v != IMPORT_VERIFY_NO) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "DKR does not support verification."); - - r = setup_machine_directory((uint64_t) -1, error); - if (r < 0) - return r; - - if (manager_find(m, TRANSFER_PULL_DKR, index_url, remote)) - return sd_bus_error_setf(error, BUS_ERROR_TRANSFER_IN_PROGRESS, "Transfer for %s already in progress.", remote); - - r = transfer_new(m, &t); - if (r < 0) - return r; - - t->type = TRANSFER_PULL_DKR; - t->verify = v; - t->force_local = force; - - t->dkr_index_url = strdup(index_url); - if (!t->dkr_index_url) - return -ENOMEM; - - t->remote = strjoin(remote, ":", tag, NULL); - if (!t->remote) - return -ENOMEM; - - if (local) { - t->local = strdup(local); - if (!t->local) - return -ENOMEM; - } - - r = transfer_start(t); - if (r < 0) - return r; - - object = t->object_path; - id = t->id; - t = NULL; - - return sd_bus_reply_method_return(msg, "uo", id, object); -} - static int method_list_transfers(sd_bus_message *msg, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; Transfer *t; Iterator i; @@ -1188,7 +1074,6 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_METHOD("ExportRaw", "shs", "uo", method_export_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("PullTar", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("PullRaw", "sssb", "uo", method_pull_tar_or_raw, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("PullDkr", "sssssb", "uo", method_pull_dkr, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("ListTransfers", NULL, "a(usssdo)", method_list_transfers, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("CancelTransfer", "u", NULL, method_cancel_transfer, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_SIGNAL("TransferNew", "uo", 0), diff --git a/src/import/org.freedesktop.import1.conf b/src/import/org.freedesktop.import1.conf index ae36af422..ed2539a03 100644 --- a/src/import/org.freedesktop.import1.conf +++ b/src/import/org.freedesktop.import1.conf @@ -52,10 +52,6 @@ send_interface="org.freedesktop.import1.Manager" send_member="PullRaw"/> - - diff --git a/src/import/pull-common.c b/src/import/pull-common.c index a83cffffa..d301d4d79 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/pull-common.h b/src/import/pull-common.h index 7e6db1862..929a131c8 100644 --- a/src/import/pull-common.h +++ b/src/import/pull-common.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,8 +21,8 @@ #include -#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.c b/src/import/pull-dkr.c deleted file mode 100644 index 831470ff1..000000000 --- a/src/import/pull-dkr.c +++ /dev/null @@ -1,1346 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 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 . -***/ - -#include -#include - -#include "sd-daemon.h" - -#include "alloc-util.h" -#include "aufs-util.h" -#include "btrfs-util.h" -#include "curl-util.h" -#include "fd-util.h" -#include "fileio.h" -#include "fs-util.h" -#include "hostname-util.h" -#include "import-common.h" -#include "import-util.h" -#include "json.h" -#include "mkdir.h" -#include "path-util.h" -#include "process-util.h" -#include "pull-common.h" -#include "pull-dkr.h" -#include "pull-job.h" -#include "rm-rf.h" -#include "string-util.h" -#include "strv.h" -#include "utf8.h" -#include "web-util.h" - -typedef enum DkrProgress { - DKR_SEARCHING, - DKR_RESOLVING, - DKR_METADATA, - DKR_DOWNLOADING, - DKR_COPYING, -} DkrProgress; - -struct DkrPull { - sd_event *event; - CurlGlue *glue; - - char *index_protocol; - char *index_address; - - char *index_url; - char *image_root; - - PullJob *images_job; - PullJob *tags_job; - PullJob *ancestry_job; - PullJob *json_job; - PullJob *layer_job; - - char *name; - char *reference; - char *id; - - char *response_digest; - char *response_token; - char **response_registries; - - char **ancestry; - unsigned n_ancestry; - unsigned current_ancestry; - - DkrPullFinished on_finished; - void *userdata; - - char *local; - bool force_local; - bool grow_machine_directory; - - char *temp_path; - char *final_path; - - pid_t tar_pid; -}; - -#define PROTOCOL_PREFIX "https://" - -#define HEADER_TOKEN "X-Do" /* the HTTP header for the auth token */ "cker-Token:" -#define HEADER_REGISTRY "X-Do" /* the HTTP header for the registry */ "cker-Endpoints:" -#define HEADER_DIGEST "Do" /* the HTTP header for the manifest digest */ "cker-Content-Digest:" -#define LAYERS_MAX 127 - -static void dkr_pull_job_on_finished(PullJob *j); - -DkrPull* dkr_pull_unref(DkrPull *i) { - if (!i) - return NULL; - - if (i->tar_pid > 1) { - (void) kill_and_sigcont(i->tar_pid, SIGKILL); - (void) wait_for_terminate(i->tar_pid, NULL); - } - - pull_job_unref(i->images_job); - pull_job_unref(i->tags_job); - pull_job_unref(i->ancestry_job); - pull_job_unref(i->json_job); - pull_job_unref(i->layer_job); - - curl_glue_unref(i->glue); - sd_event_unref(i->event); - - if (i->temp_path) { - (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); - free(i->temp_path); - } - - free(i->name); - free(i->reference); - free(i->id); - free(i->response_token); - strv_free(i->ancestry); - free(i->final_path); - free(i->index_address); - free(i->index_protocol); - free(i->index_url); - free(i->image_root); - free(i->local); - free(i); - - return NULL; -} - -int dkr_pull_new( - DkrPull **ret, - sd_event *event, - const char *index_url, - const char *image_root, - DkrPullFinished on_finished, - void *userdata) { - - _cleanup_(dkr_pull_unrefp) DkrPull *i = NULL; - char *e; - int r; - - assert(ret); - assert(index_url); - - if (!http_url_is_valid(index_url)) - return -EINVAL; - - i = new0(DkrPull, 1); - if (!i) - return -ENOMEM; - - i->on_finished = on_finished; - i->userdata = userdata; - - i->image_root = strdup(image_root ?: "/var/lib/machines"); - if (!i->image_root) - return -ENOMEM; - - i->grow_machine_directory = path_startswith(i->image_root, "/var/lib/machines"); - - i->index_url = strdup(index_url); - if (!i->index_url) - return -ENOMEM; - - e = endswith(i->index_url, "/"); - if (e) - *e = 0; - - if (event) - i->event = sd_event_ref(event); - else { - r = sd_event_default(&i->event); - if (r < 0) - return r; - } - - r = curl_glue_new(&i->glue, i->event); - if (r < 0) - return r; - - i->glue->on_finished = pull_job_curl_on_finished; - i->glue->userdata = i; - - *ret = i; - i = NULL; - - return 0; -} - -static void dkr_pull_report_progress(DkrPull *i, DkrProgress p) { - unsigned percent; - - assert(i); - - switch (p) { - - case DKR_SEARCHING: - percent = 0; - if (i->images_job) - percent += i->images_job->progress_percent * 5 / 100; - break; - - case DKR_RESOLVING: - percent = 5; - if (i->tags_job) - percent += i->tags_job->progress_percent * 5 / 100; - break; - - case DKR_METADATA: - percent = 10; - if (i->ancestry_job) - percent += i->ancestry_job->progress_percent * 5 / 100; - if (i->json_job) - percent += i->json_job->progress_percent * 5 / 100; - break; - - case DKR_DOWNLOADING: - percent = 20; - percent += 75 * i->current_ancestry / MAX(1U, i->n_ancestry); - if (i->layer_job) - percent += i->layer_job->progress_percent * 75 / MAX(1U, i->n_ancestry) / 100; - - break; - - case DKR_COPYING: - percent = 95; - break; - - default: - assert_not_reached("Unknown progress state"); - } - - sd_notifyf(false, "X_IMPORT_PROGRESS=%u", percent); - log_debug("Combined progress %u%%", percent); -} - -static int parse_id(const void *payload, size_t size, char **ret) { - _cleanup_free_ char *buf = NULL, *id = NULL, *other = NULL; - union json_value v = {}; - void *json_state = NULL; - const char *p; - int t; - - assert(payload); - assert(ret); - - if (size <= 0) - return -EBADMSG; - - if (memchr(payload, 0, size)) - return -EBADMSG; - - buf = strndup(payload, size); - if (!buf) - return -ENOMEM; - - p = buf; - t = json_tokenize(&p, &id, &v, &json_state, NULL); - if (t < 0) - return t; - if (t != JSON_STRING) - return -EBADMSG; - - t = json_tokenize(&p, &other, &v, &json_state, NULL); - if (t < 0) - return t; - if (t != JSON_END) - return -EBADMSG; - - if (!dkr_id_is_valid(id)) - return -EBADMSG; - - *ret = id; - id = NULL; - - return 0; -} - -static int parse_ancestry(const void *payload, size_t size, char ***ret) { - _cleanup_free_ char *buf = NULL; - void *json_state = NULL; - const char *p; - enum { - STATE_BEGIN, - STATE_ITEM, - STATE_COMMA, - STATE_END, - } state = STATE_BEGIN; - _cleanup_strv_free_ char **l = NULL; - size_t n = 0, allocated = 0; - - if (size <= 0) - return -EBADMSG; - - if (memchr(payload, 0, size)) - return -EBADMSG; - - buf = strndup(payload, size); - if (!buf) - return -ENOMEM; - - p = buf; - for (;;) { - _cleanup_free_ char *str; - union json_value v = {}; - int t; - - t = json_tokenize(&p, &str, &v, &json_state, NULL); - if (t < 0) - return t; - - switch (state) { - - case STATE_BEGIN: - if (t == JSON_ARRAY_OPEN) - state = STATE_ITEM; - else - return -EBADMSG; - - break; - - case STATE_ITEM: - if (t == JSON_STRING) { - if (!dkr_id_is_valid(str)) - return -EBADMSG; - - if (n+1 > LAYERS_MAX) - return -EFBIG; - - if (!GREEDY_REALLOC(l, allocated, n + 2)) - return -ENOMEM; - - l[n++] = str; - str = NULL; - l[n] = NULL; - - state = STATE_COMMA; - - } else if (t == JSON_ARRAY_CLOSE) - state = STATE_END; - else - return -EBADMSG; - - break; - - case STATE_COMMA: - if (t == JSON_COMMA) - state = STATE_ITEM; - else if (t == JSON_ARRAY_CLOSE) - state = STATE_END; - else - return -EBADMSG; - break; - - case STATE_END: - if (t == JSON_END) { - - if (strv_isempty(l)) - return -EBADMSG; - - if (!strv_is_uniq(l)) - return -EBADMSG; - - l = strv_reverse(l); - - *ret = l; - l = NULL; - return 0; - } else - return -EBADMSG; - } - - } -} - -static const char *dkr_pull_current_layer(DkrPull *i) { - assert(i); - - if (strv_isempty(i->ancestry)) - return NULL; - - return i->ancestry[i->current_ancestry]; -} - -static const char *dkr_pull_current_base_layer(DkrPull *i) { - assert(i); - - if (strv_isempty(i->ancestry)) - return NULL; - - if (i->current_ancestry <= 0) - return NULL; - - return i->ancestry[i->current_ancestry-1]; -} - -static int dkr_pull_add_token(DkrPull *i, PullJob *j) { - const char *t; - - assert(i); - assert(j); - - if (i->response_token) - t = strjoina("Authorization: Token ", i->response_token); - else - t = HEADER_TOKEN " true"; - - j->request_header = curl_slist_new("Accept: application/json", t, NULL); - if (!j->request_header) - return -ENOMEM; - - return 0; -} - -static int dkr_pull_add_bearer_token(DkrPull *i, PullJob *j) { - const char *t = NULL; - - assert(i); - assert(j); - - if (i->response_token) - t = strjoina("Authorization: Bearer ", i->response_token); - else - return -EINVAL; - - j->request_header = curl_slist_new("Accept: application/json", t, NULL); - if (!j->request_header) - return -ENOMEM; - - return 0; -} - -static bool dkr_pull_is_done(DkrPull *i) { - assert(i); - assert(i->images_job); - if (i->images_job->state != PULL_JOB_DONE) - return false; - - if (!i->tags_job || i->tags_job->state != PULL_JOB_DONE) - return false; - - if (!i->ancestry_job || i->ancestry_job->state != PULL_JOB_DONE) - return false; - - if (i->json_job && i->json_job->state != PULL_JOB_DONE) - return false; - - if (i->layer_job && i->layer_job->state != PULL_JOB_DONE) - return false; - - if (dkr_pull_current_layer(i)) - return false; - - return true; -} - -static int dkr_pull_make_local_copy(DkrPull *i, DkrPullVersion version) { - int r; - _cleanup_free_ char *p = NULL; - - assert(i); - - if (!i->local) - return 0; - - if (!i->final_path) { - i->final_path = strjoin(i->image_root, "/.dkr-", i->id, NULL); - if (!i->final_path) - return -ENOMEM; - } - - if (version == DKR_PULL_V2) { - p = dirname_malloc(i->image_root); - if (!p) - return -ENOMEM; - } - - r = pull_make_local_copy(i->final_path, p ?: i->image_root, i->local, i->force_local); - if (r < 0) - return r; - - if (version == DKR_PULL_V2) { - char **k; - - STRV_FOREACH(k, i->ancestry) { - _cleanup_free_ char *d; - - d = strjoin(i->image_root, "/.dkr-", *k, NULL); - if (!d) - return -ENOMEM; - - r = btrfs_subvol_remove(d, BTRFS_REMOVE_QUOTA); - if (r < 0) - return r; - } - - r = rmdir(i->image_root); - if (r < 0) - return r; - } - - return 0; -} - -static int dkr_pull_job_on_open_disk(PullJob *j) { - const char *base; - DkrPull *i; - int r; - - assert(j); - assert(j->userdata); - - i = j->userdata; - assert(i->layer_job == j); - assert(i->final_path); - assert(!i->temp_path); - assert(i->tar_pid <= 0); - - r = tempfn_random(i->final_path, NULL, &i->temp_path); - if (r < 0) - return log_oom(); - - mkdir_parents_label(i->temp_path, 0700); - - base = dkr_pull_current_base_layer(i); - if (base) { - const char *base_path; - - base_path = strjoina(i->image_root, "/.dkr-", base); - r = btrfs_subvol_snapshot(base_path, i->temp_path, BTRFS_SNAPSHOT_FALLBACK_COPY|BTRFS_SNAPSHOT_QUOTA); - } else - r = btrfs_subvol_make(i->temp_path); - if (r < 0) - return log_error_errno(r, "Failed to make btrfs subvolume %s: %m", i->temp_path); - - (void) import_assign_pool_quota_and_warn(i->temp_path); - - j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); - if (j->disk_fd < 0) - return j->disk_fd; - - return 0; -} - -static void dkr_pull_job_on_progress(PullJob *j) { - DkrPull *i; - - assert(j); - assert(j->userdata); - - i = j->userdata; - - dkr_pull_report_progress( - i, - j == i->images_job ? DKR_SEARCHING : - j == i->tags_job ? DKR_RESOLVING : - j == i->ancestry_job || j == i->json_job ? DKR_METADATA : - DKR_DOWNLOADING); -} - -static void dkr_pull_job_on_finished_v2(PullJob *j); - -static int dkr_pull_pull_layer_v2(DkrPull *i) { - _cleanup_free_ char *path = NULL; - const char *url, *layer = NULL; - int r; - - assert(i); - assert(!i->layer_job); - assert(!i->temp_path); - assert(!i->final_path); - - for (;;) { - layer = dkr_pull_current_layer(i); - if (!layer) - return 0; /* no more layers */ - - path = strjoin(i->image_root, "/.dkr-", layer, NULL); - if (!path) - return log_oom(); - - if (laccess(path, F_OK) < 0) { - if (errno == ENOENT) - break; - - return log_error_errno(errno, "Failed to check for container: %m"); - } - - log_info("Layer %s already exists, skipping.", layer); - - i->current_ancestry++; - - path = mfree(path); - } - - log_info("Pulling layer %s...", layer); - - i->final_path = path; - path = NULL; - - url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v2/", i->name, "/blobs/", layer); - r = pull_job_new(&i->layer_job, url, i->glue, i); - if (r < 0) - return log_error_errno(r, "Failed to allocate layer job: %m"); - - r = dkr_pull_add_bearer_token(i, i->layer_job); - if (r < 0) - return log_oom(); - - i->layer_job->on_finished = dkr_pull_job_on_finished_v2; - i->layer_job->on_open_disk = dkr_pull_job_on_open_disk; - i->layer_job->on_progress = dkr_pull_job_on_progress; - i->layer_job->grow_machine_directory = i->grow_machine_directory; - - r = pull_job_begin(i->layer_job); - if (r < 0) - return log_error_errno(r, "Failed to start layer job: %m"); - - return 0; -} - -static int dkr_pull_pull_layer(DkrPull *i) { - _cleanup_free_ char *path = NULL; - const char *url, *layer = NULL; - int r; - - assert(i); - assert(!i->layer_job); - assert(!i->temp_path); - assert(!i->final_path); - - for (;;) { - layer = dkr_pull_current_layer(i); - if (!layer) - return 0; /* no more layers */ - - path = strjoin(i->image_root, "/.dkr-", layer, NULL); - if (!path) - return log_oom(); - - if (laccess(path, F_OK) < 0) { - if (errno == ENOENT) - break; - - return log_error_errno(errno, "Failed to check for container: %m"); - } - - log_info("Layer %s already exists, skipping.", layer); - - i->current_ancestry++; - - path = mfree(path); - } - - log_info("Pulling layer %s...", layer); - - i->final_path = path; - path = NULL; - - url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", layer, "/layer"); - r = pull_job_new(&i->layer_job, url, i->glue, i); - if (r < 0) - return log_error_errno(r, "Failed to allocate layer job: %m"); - - r = dkr_pull_add_token(i, i->layer_job); - if (r < 0) - return log_oom(); - - i->layer_job->on_finished = dkr_pull_job_on_finished; - i->layer_job->on_open_disk = dkr_pull_job_on_open_disk; - i->layer_job->on_progress = dkr_pull_job_on_progress; - i->layer_job->grow_machine_directory = i->grow_machine_directory; - - r = pull_job_begin(i->layer_job); - if (r < 0) - return log_error_errno(r, "Failed to start layer job: %m"); - - return 0; -} - -static int dkr_pull_job_on_header(PullJob *j, const char *header, size_t sz) { - _cleanup_free_ char *registry = NULL; - char *token, *digest; - DkrPull *i; - int r; - - assert(j); - assert(j->userdata); - - i = j->userdata; - r = curl_header_strdup(header, sz, HEADER_TOKEN, &token); - if (r < 0) - return log_oom(); - if (r > 0) { - free(i->response_token); - i->response_token = token; - return 0; - } - - r = curl_header_strdup(header, sz, HEADER_DIGEST, &digest); - if (r < 0) - return log_oom(); - if (r > 0) { - free(i->response_digest); - i->response_digest = digest; - return 0; - } - - r = curl_header_strdup(header, sz, HEADER_REGISTRY, ®istry); - if (r < 0) - return log_oom(); - if (r > 0) { - char **l, **k; - - l = strv_split(registry, ","); - if (!l) - return log_oom(); - - STRV_FOREACH(k, l) { - if (!hostname_is_valid(*k, false)) { - log_error("Registry hostname is not valid."); - strv_free(l); - return -EBADMSG; - } - } - - strv_free(i->response_registries); - i->response_registries = l; - } - - return 0; -} - -static void dkr_pull_job_on_finished_v2(PullJob *j) { - DkrPull *i; - int r; - - assert(j); - assert(j->userdata); - - i = j->userdata; - if (j->error != 0) { - if (j == i->images_job) - log_error_errno(j->error, "Failed to retrieve images list. (Wrong index URL?)"); - else if (j == i->ancestry_job) - log_error_errno(j->error, "Failed to retrieve manifest."); - else if (j == i->json_job) - log_error_errno(j->error, "Failed to retrieve json data."); - else - log_error_errno(j->error, "Failed to retrieve layer data."); - - r = j->error; - goto finish; - } - - if (i->images_job == j) { - const char *url; - - assert(!i->tags_job); - assert(!i->ancestry_job); - assert(!i->json_job); - assert(!i->layer_job); - - if (strv_isempty(i->response_registries)) { - r = -EBADMSG; - log_error("Didn't get registry information."); - goto finish; - } - - log_info("Index lookup succeeded, directed to registry %s.", i->response_registries[0]); - dkr_pull_report_progress(i, DKR_RESOLVING); - - url = strjoina(i->index_protocol, "auth.", i->index_address, "/v2/token/?scope=repository:", - i->name, ":pull&service=registry.", i->index_address); - r = pull_job_new(&i->tags_job, url, i->glue, i); - if (r < 0) { - log_error_errno(r, "Failed to allocate tags job: %m"); - goto finish; - } - - i->tags_job->on_finished = dkr_pull_job_on_finished_v2; - i->tags_job->on_progress = dkr_pull_job_on_progress; - - r = pull_job_begin(i->tags_job); - if (r < 0) { - log_error_errno(r, "Failed to start tags job: %m"); - goto finish; - } - - } else if (i->tags_job == j) { - const char *url; - _cleanup_free_ char *buf; - _cleanup_json_variant_unref_ JsonVariant *doc = NULL; - JsonVariant *e = NULL; - - assert(!i->ancestry_job); - assert(!i->json_job); - assert(!i->layer_job); - - buf = strndup((const char *)j->payload, j->payload_size); - if (!buf) { - r = -ENOMEM; - log_oom(); - goto finish; - } - - r = json_parse(buf, &doc); - if (r < 0) { - log_error("Unable to parse bearer token\n%s", j->payload); - goto finish; - } - - e = json_variant_value(doc, "token"); - if (!e || e->type != JSON_VARIANT_STRING) { - r = -EBADMSG; - log_error("Invalid JSON format for Bearer token"); - goto finish; - } - - r = free_and_strdup(&i->response_token, json_variant_string(e)); - if (r < 0) { - log_oom(); - goto finish; - } - - url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v2/", i->name, "/manifests/", i->reference); - r = pull_job_new(&i->ancestry_job, url, i->glue, i); - if (r < 0) { - log_error_errno(r, "Failed to allocate ancestry job: %m"); - goto finish; - } - - r = dkr_pull_add_bearer_token(i, i->ancestry_job); - if (r < 0) - goto finish; - - i->ancestry_job->on_finished = dkr_pull_job_on_finished_v2; - i->ancestry_job->on_progress = dkr_pull_job_on_progress; - i->ancestry_job->on_header = dkr_pull_job_on_header; - - - r = pull_job_begin(i->ancestry_job); - if (r < 0) { - log_error_errno(r, "Failed to start ancestry job: %m"); - goto finish; - } - - } else if (i->ancestry_job == j) { - - _cleanup_json_variant_unref_ JsonVariant *doc = NULL, *compat = NULL; - JsonVariant *e = NULL; - _cleanup_strv_free_ char **ancestry = NULL; - size_t allocated = 0, size = 0; - char *path = NULL, **k = NULL; - - r = json_parse((const char *)j->payload, &doc); - if (r < 0) { - log_error("Invalid JSON Manifest"); - goto finish; - } - - e = json_variant_value(doc, "fsLayers"); - if (!e || e->type != JSON_VARIANT_ARRAY || e->size == 0) { - r = -EBADMSG; - goto finish; - } - - log_info("JSON manifest with schema v%"PRIi64" for %s parsed!", - json_variant_integer(json_variant_value(doc, "schemaVersion")), - json_variant_string(json_variant_value(doc, "name"))); - - for (unsigned z = 0; z < e->size; z++) { - JsonVariant *f = json_variant_element(e, z), *g = NULL; - const char *layer; - if (f->type != JSON_VARIANT_OBJECT) { - r = -EBADMSG; - goto finish; - } - - g = json_variant_value(f, "blobSum"); - - layer = json_variant_string(g); - if (!dkr_digest_is_valid(layer)) { - r = -EBADMSG; - goto finish; - } - - if (!GREEDY_REALLOC(ancestry, allocated, size + 2)) { - r = -ENOMEM; - log_oom(); - goto finish; - } - - ancestry[size] = strdup(layer); - if (!ancestry[size]) { - r = -ENOMEM; - log_oom(); - goto finish; - } - - ancestry[size+1] = NULL; - size += 1; - } - - e = json_variant_value(doc, "history"); - if (!e || e->type != JSON_VARIANT_ARRAY) { - r = -EBADMSG; - goto finish; - } - - e = json_variant_element(e, 0); - e = json_variant_value(e, "v1Compatibility"); - r = json_parse(json_variant_string(e), &compat); - if (r < 0) { - log_error("Invalid v1Compatibility JSON"); - goto finish; - } - - e = json_variant_value(compat, "id"); - - strv_free(i->ancestry); - i->ancestry = strv_reverse(strv_uniq(ancestry)); - i->n_ancestry = strv_length(i->ancestry); - i->current_ancestry = 0; - i->id = strdup(i->ancestry[i->n_ancestry - 1]); - if (!i->id) { - r = -ENOMEM; - log_oom(); - goto finish; - } - path = strjoin(i->image_root, "/.dkr-", json_variant_string(e), NULL); - if (!path) { - r = -ENOMEM; - log_oom(); - goto finish; - } - free(i->image_root); - i->image_root = path; - ancestry = NULL; - - log_info("Required layers:\n"); - STRV_FOREACH(k, i->ancestry) - log_info("\t%s", *k); - log_info("\nProvenance:\n\tImageID: %s\n\tDigest: %s", json_variant_string(e), i->response_digest); - - dkr_pull_report_progress(i, DKR_DOWNLOADING); - - r = dkr_pull_pull_layer_v2(i); - if (r < 0) - goto finish; - - } else if (i->layer_job == j) { - assert(i->temp_path); - assert(i->final_path); - - j->disk_fd = safe_close(j->disk_fd); - - if (i->tar_pid > 0) { - r = wait_for_terminate_and_warn("tar", i->tar_pid, true); - i->tar_pid = 0; - if (r < 0) - goto finish; - } - - r = aufs_resolve(i->temp_path); - if (r < 0) { - log_error_errno(r, "Failed to resolve aufs whiteouts: %m"); - goto finish; - } - - r = btrfs_subvol_set_read_only(i->temp_path, true); - if (r < 0) { - log_error_errno(r, "Failed to mark snapshot read-only: %m"); - goto finish; - } - - if (rename(i->temp_path, i->final_path) < 0) { - log_error_errno(errno, "Failed to rename snaphsot: %m"); - goto finish; - } - - log_info("Completed writing to layer %s.", i->final_path); - - i->layer_job = pull_job_unref(i->layer_job); - free(i->temp_path); - i->temp_path = NULL; - free(i->final_path); - i->final_path = NULL; - - i->current_ancestry ++; - r = dkr_pull_pull_layer_v2(i); - if (r < 0) - goto finish; - - } else if (i->json_job != j) - assert_not_reached("Got finished event for unknown curl object"); - - if (!dkr_pull_is_done(i)) - return; - - dkr_pull_report_progress(i, DKR_COPYING); - - r = dkr_pull_make_local_copy(i, DKR_PULL_V2); - if (r < 0) - goto finish; - - r = 0; - -finish: - if (i->on_finished) - i->on_finished(i, r, i->userdata); - else - sd_event_exit(i->event, r); - -} - -static void dkr_pull_job_on_finished(PullJob *j) { - DkrPull *i; - int r; - - assert(j); - assert(j->userdata); - - i = j->userdata; - if (j->error != 0) { - if (j == i->images_job) - log_error_errno(j->error, "Failed to retrieve images list. (Wrong index URL?)"); - else if (j == i->tags_job) - log_error_errno(j->error, "Failed to retrieve tags list."); - else if (j == i->ancestry_job) - log_error_errno(j->error, "Failed to retrieve ancestry list."); - else if (j == i->json_job) - log_error_errno(j->error, "Failed to retrieve json data."); - else - log_error_errno(j->error, "Failed to retrieve layer data."); - - r = j->error; - goto finish; - } - - if (i->images_job == j) { - const char *url; - - assert(!i->tags_job); - assert(!i->ancestry_job); - assert(!i->json_job); - assert(!i->layer_job); - - if (strv_isempty(i->response_registries)) { - r = -EBADMSG; - log_error("Didn't get registry information."); - goto finish; - } - - log_info("Index lookup succeeded, directed to registry %s.", i->response_registries[0]); - dkr_pull_report_progress(i, DKR_RESOLVING); - - url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/repositories/", i->name, "/tags/", i->reference); - r = pull_job_new(&i->tags_job, url, i->glue, i); - if (r < 0) { - log_error_errno(r, "Failed to allocate tags job: %m"); - goto finish; - } - - r = dkr_pull_add_token(i, i->tags_job); - if (r < 0) { - log_oom(); - goto finish; - } - - i->tags_job->on_finished = dkr_pull_job_on_finished; - i->tags_job->on_progress = dkr_pull_job_on_progress; - - r = pull_job_begin(i->tags_job); - if (r < 0) { - log_error_errno(r, "Failed to start tags job: %m"); - goto finish; - } - - } else if (i->tags_job == j) { - const char *url; - char *id = NULL; - - assert(!i->ancestry_job); - assert(!i->json_job); - assert(!i->layer_job); - - r = parse_id(j->payload, j->payload_size, &id); - if (r < 0) { - log_error_errno(r, "Failed to parse JSON id."); - goto finish; - } - - free(i->id); - i->id = id; - - log_info("Tag lookup succeeded, resolved to layer %s.", i->id); - dkr_pull_report_progress(i, DKR_METADATA); - - url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/ancestry"); - r = pull_job_new(&i->ancestry_job, url, i->glue, i); - if (r < 0) { - log_error_errno(r, "Failed to allocate ancestry job: %m"); - goto finish; - } - - r = dkr_pull_add_token(i, i->ancestry_job); - if (r < 0) { - log_oom(); - goto finish; - } - - i->ancestry_job->on_finished = dkr_pull_job_on_finished; - i->ancestry_job->on_progress = dkr_pull_job_on_progress; - - url = strjoina(PROTOCOL_PREFIX, i->response_registries[0], "/v1/images/", i->id, "/json"); - r = pull_job_new(&i->json_job, url, i->glue, i); - if (r < 0) { - log_error_errno(r, "Failed to allocate json job: %m"); - goto finish; - } - - r = dkr_pull_add_token(i, i->json_job); - if (r < 0) { - log_oom(); - goto finish; - } - - i->json_job->on_finished = dkr_pull_job_on_finished; - i->json_job->on_progress = dkr_pull_job_on_progress; - - r = pull_job_begin(i->ancestry_job); - if (r < 0) { - log_error_errno(r, "Failed to start ancestry job: %m"); - goto finish; - } - - r = pull_job_begin(i->json_job); - if (r < 0) { - log_error_errno(r, "Failed to start json job: %m"); - goto finish; - } - - } else if (i->ancestry_job == j) { - char **ancestry = NULL, **k; - unsigned n; - - assert(!i->layer_job); - - r = parse_ancestry(j->payload, j->payload_size, &ancestry); - if (r < 0) { - log_error_errno(r, "Failed to parse JSON id."); - goto finish; - } - - n = strv_length(ancestry); - if (n <= 0 || !streq(ancestry[n-1], i->id)) { - log_error("Ancestry doesn't end in main layer."); - strv_free(ancestry); - r = -EBADMSG; - goto finish; - } - - log_info("Ancestor lookup succeeded, requires layers:\n"); - STRV_FOREACH(k, ancestry) - log_info("\t%s", *k); - - strv_free(i->ancestry); - i->ancestry = ancestry; - i->n_ancestry = n; - i->current_ancestry = 0; - - dkr_pull_report_progress(i, DKR_DOWNLOADING); - - r = dkr_pull_pull_layer(i); - if (r < 0) - goto finish; - - } else if (i->layer_job == j) { - assert(i->temp_path); - assert(i->final_path); - - j->disk_fd = safe_close(j->disk_fd); - - if (i->tar_pid > 0) { - r = wait_for_terminate_and_warn("tar", i->tar_pid, true); - i->tar_pid = 0; - if (r < 0) - goto finish; - } - - r = aufs_resolve(i->temp_path); - if (r < 0) { - log_error_errno(r, "Failed to resolve aufs whiteouts: %m"); - goto finish; - } - - r = btrfs_subvol_set_read_only(i->temp_path, true); - if (r < 0) { - log_error_errno(r, "Failed to mark snapshot read-only: %m"); - goto finish; - } - - if (rename(i->temp_path, i->final_path) < 0) { - log_error_errno(errno, "Failed to rename snaphsot: %m"); - goto finish; - } - - log_info("Completed writing to layer %s.", i->final_path); - - i->layer_job = pull_job_unref(i->layer_job); - i->temp_path = mfree(i->temp_path); - i->final_path = mfree(i->final_path); - - i->current_ancestry ++; - r = dkr_pull_pull_layer(i); - if (r < 0) - goto finish; - - } else if (i->json_job != j) - assert_not_reached("Got finished event for unknown curl object"); - - if (!dkr_pull_is_done(i)) - return; - - dkr_pull_report_progress(i, DKR_COPYING); - - r = dkr_pull_make_local_copy(i, DKR_PULL_V1); - if (r < 0) - goto finish; - - r = 0; -finish: - if (i->on_finished) - i->on_finished(i, r, i->userdata); - else - sd_event_exit(i->event, r); -} - -static int get_protocol_address(char **protocol, char **address, const char *url) { - const char *sep, *dot; - _cleanup_free_ char *a = NULL, *p = NULL; - - sep = strstr(url, "://"); - if (!sep) - return -EINVAL; - - dot = strrchr(url, '.'); - if (!dot) - return -EINVAL; - dot--; - - p = strndup(url, (sep - url) + 3); - if (!p) - return log_oom(); - - while (dot > (sep + 3) && *dot != '.') - dot--; - - a = strdup(dot + 1); - if (!a) - return log_oom(); - - *address = a; - *protocol = p; - a = p = NULL; - - return 0; -} - -int dkr_pull_start(DkrPull *i, const char *name, const char *reference, const char *local, bool force_local, DkrPullVersion version) { - const char *url; - int r; - - assert(i); - - if (!dkr_name_is_valid(name)) - return -EINVAL; - - if (reference && !dkr_ref_is_valid(reference)) - return -EINVAL; - - if (local && !machine_name_is_valid(local)) - return -EINVAL; - - if (i->images_job) - return -EBUSY; - - if (!reference) - reference = "latest"; - - free(i->index_protocol); - free(i->index_address); - r = get_protocol_address(&i->index_protocol, &i->index_address, i->index_url); - if (r < 0) - return r; - - r = free_and_strdup(&i->local, local); - if (r < 0) - return r; - i->force_local = force_local; - - r = free_and_strdup(&i->name, name); - if (r < 0) - return r; - r = free_and_strdup(&i->reference, reference); - if (r < 0) - return r; - - url = strjoina(i->index_url, "/v1/repositories/", name, "/images"); - - r = pull_job_new(&i->images_job, url, i->glue, i); - if (r < 0) - return r; - - r = dkr_pull_add_token(i, i->images_job); - if (r < 0) - return r; - - if (version == DKR_PULL_V1) - i->images_job->on_finished = dkr_pull_job_on_finished; - else - i->images_job->on_finished = dkr_pull_job_on_finished_v2; - - i->images_job->on_header = dkr_pull_job_on_header; - i->images_job->on_progress = dkr_pull_job_on_progress; - - return pull_job_begin(i->images_job); -} diff --git a/src/import/pull-job.c b/src/import/pull-job.c index 824fa246e..6bcf35ef4 100644 --- a/src/import/pull-job.c +++ b/src/import/pull-job.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/pull-job.h b/src/import/pull-job.h index 1777bf1c3..998857035 100644 --- a/src/import/pull-job.h +++ b/src/import/pull-job.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,9 +21,9 @@ #include -#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.c b/src/import/pull-raw.c index 03bfb5175..8a16602c3 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/pull-raw.h b/src/import/pull-raw.h index b03b4f5c9..8f6d16eb3 100644 --- a/src/import/pull-raw.h +++ b/src/import/pull-raw.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,8 +20,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 2e48167c5..afb13366f 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/pull-tar.h b/src/import/pull-tar.h index 420845ae5..7e63e496d 100644 --- a/src/import/pull-tar.h +++ b/src/import/pull-tar.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,8 +20,9 @@ ***/ #include "sd-event.h" -#include "macro.h" + #include "import-util.h" +#include "macro.h" typedef struct TarPull TarPull; diff --git a/src/import/pull.c b/src/import/pull.c index 39f5b2d8e..72604a6a7 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -24,12 +22,10 @@ #include "sd-event.h" #include "alloc-util.h" -#include "event-util.h" #include "hostname-util.h" #include "import-util.h" #include "machine-image.h" #include "parse-util.h" -#include "pull-dkr.h" #include "pull-raw.h" #include "pull-tar.h" #include "signal-util.h" @@ -40,7 +36,6 @@ static bool arg_force = false; static const char *arg_image_root = "/var/lib/machines"; static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; -static const char* arg_dkr_index_url = DEFAULT_DKR_INDEX_URL; static bool arg_settings = true; static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { @@ -61,7 +56,7 @@ static void on_tar_finished(TarPull *pull, int error, void *userdata) { static int pull_tar(int argc, char *argv[], void *userdata) { _cleanup_(tar_pull_unrefp) TarPull *pull = NULL; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; const char *url, *local; _cleanup_free_ char *l = NULL, *ll = NULL; int r; @@ -147,7 +142,7 @@ static void on_raw_finished(RawPull *pull, int error, void *userdata) { static int pull_raw(int argc, char *argv[], void *userdata) { _cleanup_(raw_pull_unrefp) RawPull *pull = NULL; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; const char *url, *local; _cleanup_free_ char *l = NULL, *ll = NULL; int r; @@ -221,114 +216,6 @@ static int pull_raw(int argc, char *argv[], void *userdata) { return -r; } -static void on_dkr_finished(DkrPull *pull, int error, void *userdata) { - sd_event *event = userdata; - assert(pull); - - if (error == 0) - log_info("Operation completed successfully."); - - sd_event_exit(event, abs(error)); -} - -static int pull_dkr(int argc, char *argv[], void *userdata) { - _cleanup_(dkr_pull_unrefp) DkrPull *pull = NULL; - _cleanup_event_unref_ sd_event *event = NULL; - const char *name, *reference, *local, *digest; - int r; - - if (!arg_dkr_index_url) { - log_error("Please specify an index URL with --dkr-index-url="); - return -EINVAL; - } - - if (arg_verify != IMPORT_VERIFY_NO) { - log_error("Pulls from dkr do not support image verification, please pass --verify=no."); - return -EINVAL; - } - - digest = strchr(argv[1], '@'); - if (digest) { - reference = digest + 1; - name = strndupa(argv[1], digest - argv[1]); - } else { - reference = strchr(argv[1], ':'); - if (reference) { - name = strndupa(argv[1], reference - argv[1]); - reference++; - } else { - name = argv[1]; - reference = "latest"; - } - } - - if (!dkr_name_is_valid(name)) { - log_error("Remote name '%s' is not valid.", name); - return -EINVAL; - } - - if (!dkr_ref_is_valid(reference)) { - log_error("Tag name '%s' is not valid.", reference); - return -EINVAL; - } - - if (argc >= 3) - local = argv[2]; - else { - local = strchr(name, '/'); - if (local) - local++; - else - local = name; - } - - if (isempty(local) || streq(local, "-")) - local = NULL; - - if (local) { - if (!machine_name_is_valid(local)) { - log_error("Local image name '%s' is not valid.", local); - return -EINVAL; - } - - if (!arg_force) { - r = image_find(local, NULL); - if (r < 0) - return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); - else if (r > 0) { - log_error_errno(EEXIST, "Image '%s' already exists.", local); - return -EEXIST; - } - } - - log_info("Pulling '%s' with reference '%s', saving as '%s'.", name, reference, local); - } else - log_info("Pulling '%s' with reference '%s'.", name, reference); - - r = sd_event_default(&event); - if (r < 0) - return log_error_errno(r, "Failed to allocate event loop: %m"); - - assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0); - (void) sd_event_add_signal(event, NULL, SIGTERM, interrupt_signal_handler, NULL); - (void) sd_event_add_signal(event, NULL, SIGINT, interrupt_signal_handler, NULL); - - r = dkr_pull_new(&pull, event, arg_dkr_index_url, arg_image_root, on_dkr_finished, event); - if (r < 0) - return log_error_errno(r, "Failed to allocate puller: %m"); - - r = dkr_pull_start(pull, name, reference, local, arg_force, DKR_PULL_V2); - if (r < 0) - return log_error_errno(r, "Failed to pull image: %m"); - - r = sd_event_loop(event); - if (r < 0) - return log_error_errno(r, "Failed to run event loop: %m"); - - log_info("Exiting."); - return -r; -} - static int help(int argc, char *argv[], void *userdata) { printf("%s [OPTIONS...] {COMMAND} ...\n\n" @@ -339,12 +226,10 @@ static int help(int argc, char *argv[], void *userdata) { " --verify=MODE Verify downloaded image, one of: 'no',\n" " 'checksum', 'signature'\n" " --settings=BOOL Download settings file with image\n" - " --image-root=PATH Image root directory\n" - " --dkr-index-url=URL Specify index URL to use for downloads\n\n" + " --image-root=PATH Image root directory\n\n" "Commands:\n" " tar URL [NAME] Download a TAR image\n" - " raw URL [NAME] Download a RAW image\n" - " dkr REMOTE [NAME] Download a DKR image\n", + " raw URL [NAME] Download a RAW image\n", program_invocation_short_name); return 0; @@ -355,7 +240,6 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_FORCE, - ARG_DKR_INDEX_URL, ARG_IMAGE_ROOT, ARG_VERIFY, ARG_SETTINGS, @@ -365,7 +249,6 @@ static int parse_argv(int argc, char *argv[]) { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "force", no_argument, NULL, ARG_FORCE }, - { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL }, { "image-root", required_argument, NULL, ARG_IMAGE_ROOT }, { "verify", required_argument, NULL, ARG_VERIFY }, { "settings", required_argument, NULL, ARG_SETTINGS }, @@ -391,15 +274,6 @@ static int parse_argv(int argc, char *argv[]) { arg_force = true; break; - case ARG_DKR_INDEX_URL: - if (!http_url_is_valid(optarg)) { - log_error("Index URL is not valid: %s", optarg); - return -EINVAL; - } - - arg_dkr_index_url = optarg; - break; - case ARG_IMAGE_ROOT: arg_image_root = optarg; break; @@ -437,7 +311,6 @@ static int pull_main(int argc, char *argv[]) { { "help", VERB_ANY, VERB_ANY, 0, help }, { "tar", 2, 3, 0, pull_tar }, { "raw", 2, 3, 0, pull_raw }, - { "dkr", 2, 3, 0, pull_dkr }, {} }; diff --git a/src/import/qcow2-util.c b/src/import/qcow2-util.c index 47dabaa86..ee2121cc3 100644 --- a/src/import/qcow2-util.c +++ b/src/import/qcow2-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/import/qcow2-util.h b/src/import/qcow2-util.h index be7fd1d0c..6dddac8cd 100644 --- a/src/import/qcow2-util.h +++ b/src/import/qcow2-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/import/test-qcow2.c b/src/import/test-qcow2.c index 4b6007961..b820253d7 100644 --- a/src/import/test-qcow2.c +++ b/src/import/test-qcow2.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c index a35f2b541..3e57afb99 100644 --- a/src/initctl/initctl.c +++ b/src/initctl/initctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -101,7 +99,7 @@ static const char *translate_runlevel(int runlevel, bool *isolate) { static void change_runlevel(Server *s, int runlevel) { const char *target; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *mode; bool isolate = false; int r; diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 6b93a758f..60d897758 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -45,6 +43,8 @@ #include "sigbus.h" #include "util.h" +#define JOURNAL_WAIT_TIMEOUT (10*USEC_PER_SEC) + static char *arg_key_pem = NULL; static char *arg_cert_pem = NULL; static char *arg_trust_pem = NULL; @@ -181,11 +181,13 @@ static ssize_t request_reader_entries( } else if (r == 0) { if (m->follow) { - r = sd_journal_wait(m->journal, (uint64_t) -1); + r = sd_journal_wait(m->journal, (uint64_t) JOURNAL_WAIT_TIMEOUT); if (r < 0) { log_error_errno(r, "Couldn't wait for journal event: %m"); return MHD_CONTENT_READER_END_WITH_ERROR; } + if (r == SD_JOURNAL_NOP) + break; continue; } @@ -241,6 +243,8 @@ static ssize_t request_reader_entries( } n = m->size - pos; + if (n < 1) + return 0; if (n > max) n = max; @@ -694,7 +698,7 @@ static int request_handler_file( if (fstat(fd, &st) < 0) return mhd_respondf(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to stat file: %m\n"); - response = MHD_create_response_from_fd_at_offset(st.st_size, fd, 0); + response = MHD_create_response_from_fd_at_offset64(st.st_size, fd, 0); if (!response) return respond_oom(connection); @@ -709,7 +713,7 @@ static int request_handler_file( } static int get_virtualization(char **v) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; char *b = NULL; int r; @@ -834,7 +838,7 @@ static int request_handler( assert(method); if (!streq(method, "GET")) - return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE, + return mhd_respond(connection, MHD_HTTP_NOT_ACCEPTABLE, "Unsupported method.\n"); diff --git a/src/journal-remote/journal-remote-parse.c b/src/journal-remote/journal-remote-parse.c index 3ff40228a..3864647eb 100644 --- a/src/journal-remote/journal-remote-parse.c +++ b/src/journal-remote/journal-remote-parse.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal-remote/journal-remote-parse.h b/src/journal-remote/journal-remote-parse.h index 14bfadc13..0b8b6af73 100644 --- a/src/journal-remote/journal-remote-parse.h +++ b/src/journal-remote/journal-remote-parse.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,6 +20,7 @@ #pragma once #include "sd-event.h" + #include "journal-remote-write.h" typedef enum { diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c index d8250378b..5fab74e5c 100644 --- a/src/journal-remote/journal-remote-write.c +++ b/src/journal-remote/journal-remote-write.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal-remote/journal-remote-write.h b/src/journal-remote/journal-remote-write.h index 7f47f8b01..6b645a353 100644 --- a/src/journal-remote/journal-remote-write.h +++ b/src/journal-remote/journal-remote-write.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index b2f5fbf6b..3ce6fe27b 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -150,7 +148,7 @@ static int spawn_curl(const char* url) { return r; } -static int spawn_getter(const char *getter, const char *url) { +static int spawn_getter(const char *getter) { int r; _cleanup_strv_free_ char **words = NULL; @@ -159,10 +157,6 @@ static int spawn_getter(const char *getter, const char *url) { if (r < 0) return log_error_errno(r, "Failed to split getter option: %m"); - r = strv_extend(&words, url); - if (r < 0) - return log_error_errno(r, "Failed to create command line: %m"); - r = spawn_child(words[0], words); if (r < 0) log_error_errno(r, "Failed to spawn getter %s: %m", getter); @@ -447,7 +441,7 @@ static int add_raw_socket(RemoteServer *s, int fd) { static int setup_raw_socket(RemoteServer *s, const char *address) { int fd; - fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM | SOCK_CLOEXEC); + fd = make_socket_fd(LOG_INFO, address, SOCK_STREAM, SOCK_CLOEXEC); if (fd < 0) return fd; @@ -587,7 +581,7 @@ static int request_handler( *connection_cls); if (!streq(method, "POST")) - return mhd_respond(connection, MHD_HTTP_METHOD_NOT_ACCEPTABLE, + return mhd_respond(connection, MHD_HTTP_NOT_ACCEPTABLE, "Unsupported method.\n"); if (!streq(url, "/upload")) @@ -621,7 +615,7 @@ static int request_handler( if (r < 0) return code; } else { - r = getnameinfo_pretty(fd, &hostname); + r = getpeername_pretty(fd, false, &hostname); if (r < 0) return mhd_respond(connection, MHD_HTTP_INTERNAL_SERVER_ERROR, "Cannot check remote hostname"); @@ -649,7 +643,7 @@ static int setup_microhttpd_server(RemoteServer *s, { MHD_OPTION_NOTIFY_COMPLETED, (intptr_t) request_meta_free}, { MHD_OPTION_EXTERNAL_LOGGER, (intptr_t) microhttpd_logger}, { MHD_OPTION_LISTEN_SOCKET, fd}, - { MHD_OPTION_CONNECTION_MEMORY_LIMIT, DATA_SIZE_MAX}, + { MHD_OPTION_CONNECTION_MEMORY_LIMIT, 128*1024}, { MHD_OPTION_END}, { MHD_OPTION_END}, { MHD_OPTION_END}, @@ -765,7 +759,7 @@ static int setup_microhttpd_socket(RemoteServer *s, const char *trust) { int fd; - fd = make_socket_fd(LOG_DEBUG, address, SOCK_STREAM | SOCK_CLOEXEC); + fd = make_socket_fd(LOG_DEBUG, address, SOCK_STREAM, SOCK_CLOEXEC); if (fd < 0) return fd; @@ -879,7 +873,7 @@ static int remoteserver_init(RemoteServer *s, } else if (sd_is_socket(fd, AF_UNSPEC, 0, false)) { char *hostname; - r = getnameinfo_pretty(fd, &hostname); + r = getpeername_pretty(fd, false, &hostname); if (r < 0) return log_error_errno(r, "Failed to retrieve remote name: %m"); @@ -897,18 +891,32 @@ static int remoteserver_init(RemoteServer *s, fd); } + if (arg_getter) { + log_info("Spawning getter %s...", arg_getter); + fd = spawn_getter(arg_getter); + if (fd < 0) + return fd; + + r = add_source(s, fd, (char*) arg_output, false); + if (r < 0) + return r; + } + if (arg_url) { - const char *url, *hostname; + const char *url; + char *hostname, *p; - url = strjoina(arg_url, "/entries"); - - if (arg_getter) { - log_info("Spawning getter %s...", url); - fd = spawn_getter(arg_getter, url); - } else { - log_info("Spawning curl %s...", url); - fd = spawn_curl(url); + if (!strstr(arg_url, "/entries")) { + if (endswith(arg_url, "/")) + url = strjoina(arg_url, "entries"); + else + url = strjoina(arg_url, "/entries"); } + else + url = strdupa(arg_url); + + log_info("Spawning curl %s...", url); + fd = spawn_curl(url); if (fd < 0) return fd; @@ -917,7 +925,13 @@ static int remoteserver_init(RemoteServer *s, startswith(arg_url, "http://") ?: arg_url; - r = add_source(s, fd, (char*) hostname, false); + hostname = strdupa(hostname); + if ((p = strchr(hostname, '/'))) + *p = '\0'; + if ((p = strchr(hostname, ':'))) + *p = '\0'; + + r = add_source(s, fd, hostname, false); if (r < 0) return r; } @@ -1181,6 +1195,7 @@ static DEFINE_CONFIG_PARSE_ENUM(config_parse_write_split_mode, static int parse_config(void) { const ConfigTableItem items[] = { + { "Remote", "Seal", config_parse_bool, 0, &arg_seal }, { "Remote", "SplitMode", config_parse_write_split_mode, 0, &arg_split_mode }, { "Remote", "ServerKeyFile", config_parse_path, 0, &arg_key }, { "Remote", "ServerCertificateFile", config_parse_path, 0, &arg_cert }, diff --git a/src/journal-remote/journal-remote.conf.in b/src/journal-remote/journal-remote.conf.in index 3e32f34de..7122d6336 100644 --- a/src/journal-remote/journal-remote.conf.in +++ b/src/journal-remote/journal-remote.conf.in @@ -1,4 +1,5 @@ [Remote] +# Seal=false # SplitMode=host # ServerKeyFile=@CERTIFICATEROOT@/private/journal-remote.pem # ServerCertificateFile=@CERTIFICATEROOT@/certs/journal-remote.pem diff --git a/src/journal-remote/journal-remote.h b/src/journal-remote/journal-remote.h index 6c2ccb973..6466a1c10 100644 --- a/src/journal-remote/journal-remote.h +++ b/src/journal-remote/journal-remote.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,11 +21,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 a6d7c3b7e..fc8f63c9e 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -312,6 +310,9 @@ void close_journal_input(Uploader *u) { static int process_journal_input(Uploader *u, int skip) { int r; + if (u->uploading) + return 0; + r = sd_journal_next_skip(u->journal, skip); if (r < 0) return log_error_errno(r, "Failed to skip to next entry: %m"); @@ -349,10 +350,8 @@ static int dispatch_journal_input(sd_event_source *event, assert(u); - if (u->uploading) { - log_warning("dispatch_journal_input called when uploading, ignoring."); + if (u->uploading) return 0; - } log_debug("Detected journal input, checking for new data."); return check_journal_input(u); diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index 6302266cc..440563e7d 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal-remote/journal-upload.h b/src/journal-remote/journal-upload.h index 3b46fa8cb..b8cd04d52 100644 --- a/src/journal-remote/journal-upload.h +++ b/src/journal-remote/journal-upload.h @@ -2,8 +2,8 @@ #include -#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 09e6da003..c65c43186 100644 --- a/src/journal-remote/microhttpd-util.c +++ b/src/journal-remote/microhttpd-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h index b2feb9180..70c4d29c0 100644 --- a/src/journal-remote/microhttpd-util.h +++ b/src/journal-remote/microhttpd-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,11 +19,20 @@ #pragma once -#include #include +#include #include "macro.h" +/* Compatiblity with libmicrohttpd < 0.9.38 */ +#ifndef MHD_HTTP_NOT_ACCEPTABLE +#define MHD_HTTP_NOT_ACCEPTABLE MHD_HTTP_METHOD_NOT_ACCEPTABLE +#endif + +#if MHD_VERSION < 0x00094203 +#define MHD_create_response_from_fd_at_offset64 MHD_create_response_from_fd_at_offset +#endif + void microhttpd_logger(void *arg, const char *fmt, va_list ap) _printf_(2, 0); /* respond_oom() must be usable with return, hence this form. */ diff --git a/src/journal/audit-type.c b/src/journal/audit-type.c index 086bf7e7e..71e8790ca 100644 --- a/src/journal/audit-type.c +++ b/src/journal/audit-type.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/audit-type.h b/src/journal/audit-type.h index fa5284e02..1dd216370 100644 --- a/src/journal/audit-type.h +++ b/src/journal/audit-type.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/cat.c b/src/journal/cat.c index 7fd4198df..08c844d44 100644 --- a/src/journal/cat.c +++ b/src/journal/cat.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -34,7 +32,7 @@ #include "syslog-util.h" #include "util.h" -static char *arg_identifier = NULL; +static const char *arg_identifier = NULL; static int arg_priority = LOG_INFO; static bool arg_level_prefix = true; @@ -82,14 +80,10 @@ static int parse_argv(int argc, char *argv[]) { return version(); case 't': - free(arg_identifier); if (isempty(optarg)) arg_identifier = NULL; - else { - arg_identifier = strdup(optarg); - if (!arg_identifier) - return log_oom(); - } + else + arg_identifier = optarg; break; case 'p': diff --git a/src/journal/catalog.c b/src/journal/catalog.c index fcaa54aa0..164a3a15f 100644 --- a/src/journal/catalog.c +++ b/src/journal/catalog.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -94,25 +92,87 @@ const struct hash_ops catalog_hash_ops = { .compare = catalog_compare_func }; +static bool next_header(const char **s) { + const char *e; + + e = strchr(*s, '\n'); + + /* Unexpected end */ + if (!e) + return false; + + /* End of headers */ + if (e == *s) + return false; + + *s = e + 1; + return true; +} + +static const char *skip_header(const char *s) { + while (next_header(&s)) + ; + return s; +} + +static char *combine_entries(const char *one, const char *two) { + const char *b1, *b2; + size_t l1, l2, n; + char *dest, *p; + + /* Find split point of headers to body */ + b1 = skip_header(one); + b2 = skip_header(two); + + l1 = strlen(one); + l2 = strlen(two); + dest = new(char, l1 + l2 + 1); + if (!dest) { + log_oom(); + return NULL; + } + + p = dest; + + /* Headers from @one */ + n = b1 - one; + p = mempcpy(p, one, n); + + /* Headers from @two, these will only be found if not present above */ + n = b2 - two; + p = mempcpy(p, two, n); + + /* Body from @one */ + n = l1 - (b1 - one); + if (n > 0) { + memcpy(p, b1, n); + p += n; + + /* Body from @two */ + } else { + n = l2 - (b2 - two); + memcpy(p, b2, n); + p += n; + } + + assert(p - dest <= (ptrdiff_t)(l1 + l2)); + p[0] = '\0'; + return dest; +} + static int finish_item( Hashmap *h, - struct strbuf *sb, sd_id128_t id, const char *language, - const char *payload) { + char *payload) { - ssize_t offset; _cleanup_free_ CatalogItem *i = NULL; + _cleanup_free_ char *combined = NULL, *prev = NULL; int r; assert(h); - assert(sb); assert(payload); - offset = strbuf_add_string(sb, payload, strlen(payload)); - if (offset < 0) - return log_oom(); - i = new0(CatalogItem, 1); if (!i) return log_oom(); @@ -122,17 +182,27 @@ static int finish_item( assert(strlen(language) > 1 && strlen(language) < 32); strcpy(i->language, language); } - i->offset = htole64((uint64_t) offset); - r = hashmap_put(h, i, i); - if (r == -EEXIST) { - log_warning("Duplicate entry for " SD_ID128_FORMAT_STR ".%s, ignoring.", - SD_ID128_FORMAT_VAL(id), language ? language : "C"); - return 0; - } else if (r < 0) - return r; + prev = hashmap_get(h, i); + + /* Already have such an item, combine them */ + if (prev) { + combined = combine_entries(payload, prev); + if (!combined) + return log_oom(); + r = hashmap_update(h, i, combined); + if (r < 0) + return r; + combined = NULL; + + /* A new item */ + } else { + r = hashmap_put(h, i, payload); + if (r < 0) + return r; + i = NULL; + } - i = NULL; return 0; } @@ -189,7 +259,7 @@ static int catalog_entry_lang(const char* filename, int line, return 0; } -int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { +int catalog_import_file(Hashmap *h, const char *path) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *payload = NULL; unsigned n = 0; @@ -199,7 +269,6 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { int r; assert(h); - assert(sb); assert(path); f = fopen(path, "re"); @@ -254,10 +323,11 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { if (sd_id128_from_string(line + 2 + 1, &jd) >= 0) { if (got_id) { - r = finish_item(h, sb, id, lang ?: deflang, payload); + r = finish_item(h, id, lang ?: deflang, payload); if (r < 0) return r; + payload = NULL; lang = mfree(lang); } @@ -310,9 +380,10 @@ int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path) { } if (got_id) { - r = finish_item(h, sb, id, lang ?: deflang, payload); + r = finish_item(h, id, lang ?: deflang, payload); if (r < 0) return r; + payload = NULL; } return 0; @@ -389,8 +460,10 @@ int catalog_update(const char* database, const char* root, const char* const* di _cleanup_strv_free_ char **files = NULL; char **f; struct strbuf *sb = NULL; - _cleanup_hashmap_free_free_ Hashmap *h = NULL; + _cleanup_hashmap_free_free_free_ Hashmap *h = NULL; _cleanup_free_ CatalogItem *items = NULL; + ssize_t offset; + char *payload; CatalogItem *i; Iterator j; unsigned n; @@ -413,7 +486,7 @@ int catalog_update(const char* database, const char* root, const char* const* di STRV_FOREACH(f, files) { log_debug("Reading file '%s'", *f); - r = catalog_import_file(h, sb, *f); + r = catalog_import_file(h, *f); if (r < 0) { log_error_errno(r, "Failed to import file '%s': %m", *f); goto finish; @@ -426,8 +499,6 @@ int catalog_update(const char* database, const char* root, const char* const* di } else log_debug("Found %u items in catalog.", hashmap_size(h)); - strbuf_complete(sb); - items = new(CatalogItem, hashmap_size(h)); if (!items) { r = log_oom(); @@ -435,16 +506,25 @@ int catalog_update(const char* database, const char* root, const char* const* di } n = 0; - HASHMAP_FOREACH(i, h, j) { + HASHMAP_FOREACH_KEY(payload, i, h, j) { log_debug("Found " SD_ID128_FORMAT_STR ", language %s", SD_ID128_FORMAT_VAL(i->id), isempty(i->language) ? "C" : i->language); + + offset = strbuf_add_string(sb, payload, strlen(payload)); + if (offset < 0) { + r = log_oom(); + goto finish; + } + i->offset = htole64((uint64_t) offset); items[n++] = *i; } assert(n == hashmap_size(h)); qsort_safe(items, n, sizeof(CatalogItem), catalog_compare_func); + strbuf_complete(sb); + sz = write_catalog(database, sb, items, n); if (sz < 0) r = log_error_errno(sz, "Failed to write %s: %m", database); @@ -587,7 +667,7 @@ finish: static char *find_header(const char *s, const char *header) { for (;;) { - const char *v, *e; + const char *v; v = startswith(s, header); if (v) { @@ -595,16 +675,8 @@ static char *find_header(const char *s, const char *header) { return strndup(v, strcspn(v, NEWLINE)); } - /* End of text */ - e = strchr(s, '\n'); - if (!e) + if (!next_header(&s)) return NULL; - - /* End of header */ - if (e == s) - return NULL; - - s = e + 1; } } diff --git a/src/journal/catalog.h b/src/journal/catalog.h index a72ecf6de..1b1014b33 100644 --- a/src/journal/catalog.h +++ b/src/journal/catalog.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,10 +22,11 @@ #include #include "sd-id128.h" + #include "hashmap.h" #include "strbuf.h" -int catalog_import_file(Hashmap *h, struct strbuf *sb, const char *path); +int catalog_import_file(Hashmap *h, const char *path); int catalog_update(const char* database, const char* root, const char* const* dirs); int catalog_get(const char* database, sd_id128_t id, char **data); int catalog_list(FILE *f, const char* database, bool oneline); diff --git a/src/journal/compress.c b/src/journal/compress.c index e1ca0a881..1933b87b0 100644 --- a/src/journal/compress.c +++ b/src/journal/compress.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -58,7 +56,8 @@ static const char* const object_compressed_table[_OBJECT_COMPRESSED_MAX] = { DEFINE_STRING_TABLE_LOOKUP(object_compressed, int); -int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_size) { +int compress_blob_xz(const void *src, uint64_t src_size, + void *dst, size_t dst_alloc_size, size_t *dst_size) { #ifdef HAVE_XZ static const lzma_options_lzma opt = { 1u << 20u, NULL, 0, LZMA_LC_DEFAULT, LZMA_LP_DEFAULT, @@ -74,6 +73,7 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_ assert(src); assert(src_size > 0); assert(dst); + assert(dst_alloc_size > 0); assert(dst_size); /* Returns < 0 if we couldn't compress the data or the @@ -83,7 +83,7 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_ return -ENOBUFS; ret = lzma_stream_buffer_encode((lzma_filter*) filters, LZMA_CHECK_NONE, NULL, - src, src_size, dst, &out_pos, src_size - 1); + src, src_size, dst, &out_pos, dst_alloc_size); if (ret != LZMA_OK) return -ENOBUFS; @@ -94,13 +94,15 @@ int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_ #endif } -int compress_blob_lz4(const void *src, uint64_t src_size, void *dst, size_t *dst_size) { +int compress_blob_lz4(const void *src, uint64_t src_size, + void *dst, size_t dst_alloc_size, size_t *dst_size) { #ifdef HAVE_LZ4 int r; assert(src); assert(src_size > 0); assert(dst); + assert(dst_alloc_size > 0); assert(dst_size); /* Returns < 0 if we couldn't compress the data or the @@ -109,7 +111,7 @@ int compress_blob_lz4(const void *src, uint64_t src_size, void *dst, size_t *dst if (src_size < 9) return -ENOBUFS; - r = LZ4_compress_limitedOutput(src, dst + 8, src_size, src_size - 8 - 1); + r = LZ4_compress_limitedOutput(src, dst + 8, src_size, (int) dst_alloc_size - 8); if (r <= 0) return -ENOBUFS; @@ -201,7 +203,7 @@ int decompress_blob_lz4(const void *src, uint64_t src_size, return -EBADMSG; size = le64toh( *(le64_t*)src ); - if (size < 0 || (le64_t) size != *(le64_t*)src) + if (size < 0 || (unsigned) size != le64toh(*(le64_t*)src)) return -EFBIG; if ((size_t) size > *dst_alloc_size) { out = realloc(*dst, size); @@ -306,6 +308,7 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size, * prefix */ int r; + size_t size; assert(src); assert(src_size > 0); @@ -322,10 +325,18 @@ int decompress_startswith_lz4(const void *src, uint64_t src_size, r = LZ4_decompress_safe_partial(src + 8, *buffer, src_size - 8, prefix_len + 1, *buffer_size); + if (r >= 0) + size = (unsigned) r; + else { + /* lz4 always tries to decode full "sequence", so in + * pathological cases might need to decompress the + * full field. */ + r = decompress_blob_lz4(src, src_size, buffer, buffer_size, &size, 0); + if (r < 0) + return r; + } - if (r < 0) - return -EBADMSG; - if ((unsigned) r >= prefix_len + 1) + if (size >= prefix_len + 1) return memcmp(*buffer, prefix, prefix_len) == 0 && ((const uint8_t*) *buffer)[prefix_len] == extra; else @@ -438,7 +449,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { _cleanup_(LZ4F_freeCompressionContextp) LZ4F_compressionContext_t ctx = NULL; _cleanup_free_ char *buf = NULL; char *src = NULL; - size_t size, n, total_in = 0, total_out = 0, offset = 0, frame_size; + size_t size, n, total_in = 0, total_out, offset = 0, frame_size; struct stat st; int r; static const LZ4F_compressOptions_t options = { @@ -461,7 +472,7 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { if (!buf) return -ENOMEM; - n = offset = LZ4F_compressBegin(ctx, buf, size, &preferences); + n = offset = total_out = LZ4F_compressBegin(ctx, buf, size, &preferences); if (LZ4F_isError(n)) return -EINVAL; @@ -599,80 +610,8 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { #endif } +int decompress_stream_lz4(int in, int out, uint64_t max_bytes) { #ifdef HAVE_LZ4 -static int decompress_stream_lz4_v1(int fdf, int fdt, uint64_t max_bytes) { - - _cleanup_free_ char *buf = NULL, *out = NULL; - size_t buf_size = 0; - LZ4_streamDecode_t lz4_data = {}; - le32_t header; - size_t total_in = sizeof(header), total_out = 0; - - assert(fdf >= 0); - assert(fdt >= 0); - - out = malloc(4*LZ4_BUFSIZE); - if (!out) - return -ENOMEM; - - for (;;) { - ssize_t m; - int r; - - r = loop_read_exact(fdf, &header, sizeof(header), false); - if (r < 0) - return r; - - m = le32toh(header); - if (m == 0) - break; - - /* We refuse to use a bigger decompression buffer than - * the one used for compression by 4 times. This means - * that compression buffer size can be enlarged 4 - * times. This can be changed, but old binaries might - * not accept buffers compressed by newer binaries then. - */ - if (m > LZ4_COMPRESSBOUND(LZ4_BUFSIZE * 4)) { - log_debug("Compressed stream block too big: %zd bytes", m); - return -ENOBUFS; - } - - total_in += sizeof(header) + m; - - if (!GREEDY_REALLOC(buf, buf_size, m)) - return -ENOMEM; - - r = loop_read_exact(fdf, buf, m, false); - if (r < 0) - return r; - - r = LZ4_decompress_safe_continue(&lz4_data, buf, out, m, 4*LZ4_BUFSIZE); - if (r <= 0) { - log_debug("LZ4 decompression failed (legacy format)."); - return -EBADMSG; - } - - total_out += r; - - if (max_bytes != (uint64_t) -1 && (uint64_t) total_out > max_bytes) { - log_debug("Decompressed stream longer than %" PRIu64 " bytes", max_bytes); - return -EFBIG; - } - - r = loop_write(fdt, out, r, false); - if (r < 0) - return r; - } - - log_debug("LZ4 decompression finished (legacy format, %zu -> %zu bytes, %.1f%%)", - total_in, total_out, - (double) total_out / total_in * 100); - - return 0; -} - -static int decompress_stream_lz4_v2(int in, int out, uint64_t max_bytes) { size_t c; _cleanup_(LZ4F_freeDecompressionContextp) LZ4F_decompressionContext_t ctx = NULL; _cleanup_free_ char *buf = NULL; @@ -726,17 +665,6 @@ static int decompress_stream_lz4_v2(int in, int out, uint64_t max_bytes) { cleanup: munmap(src, st.st_size); return r; -} -#endif - -int decompress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { -#ifdef HAVE_LZ4 - int r; - - r = decompress_stream_lz4_v2(fdf, fdt, max_bytes); - if (r == -EBADMSG) - r = decompress_stream_lz4_v1(fdf, fdt, max_bytes); - return r; #else log_debug("Cannot decompress file. Compiled without LZ4 support."); return -EPROTONOSUPPORT; diff --git a/src/journal/compress.h b/src/journal/compress.h index 9a065eb76..c138099d9 100644 --- a/src/journal/compress.h +++ b/src/journal/compress.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -28,17 +26,20 @@ const char* object_compressed_to_string(int compression); int object_compressed_from_string(const char *compression); -int compress_blob_xz(const void *src, uint64_t src_size, void *dst, size_t *dst_size); -int compress_blob_lz4(const void *src, uint64_t src_size, void *dst, size_t *dst_size); +int compress_blob_xz(const void *src, uint64_t src_size, + void *dst, size_t dst_alloc_size, size_t *dst_size); +int compress_blob_lz4(const void *src, uint64_t src_size, + void *dst, size_t dst_alloc_size, size_t *dst_size); -static inline int compress_blob(const void *src, uint64_t src_size, void *dst, size_t *dst_size) { +static inline int compress_blob(const void *src, uint64_t src_size, + void *dst, size_t dst_alloc_size, size_t *dst_size) { int r; #ifdef HAVE_LZ4 - r = compress_blob_lz4(src, src_size, dst, dst_size); + r = compress_blob_lz4(src, src_size, dst, dst_alloc_size, dst_size); if (r == 0) return OBJECT_COMPRESSED_LZ4; #else - r = compress_blob_xz(src, src_size, dst, dst_size); + r = compress_blob_xz(src, src_size, dst, dst_alloc_size, dst_size); if (r == 0) return OBJECT_COMPRESSED_XZ; #endif diff --git a/src/journal/fsprg.c b/src/journal/fsprg.c index a9f564c24..8f7e137e7 100644 --- a/src/journal/fsprg.c +++ b/src/journal/fsprg.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /* * fsprg v0.1 - (seekable) forward-secure pseudorandom generator * Copyright (C) 2012 B. Poettering diff --git a/src/journal/fsprg.h b/src/journal/fsprg.h index 5959b1fed..829b56e24 100644 --- a/src/journal/fsprg.h +++ b/src/journal/fsprg.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef __fsprgh__ #define __fsprgh__ @@ -25,8 +23,8 @@ * */ -#include #include +#include #include "macro.h" #include "util.h" diff --git a/src/journal/journal-authenticate.c b/src/journal/journal-authenticate.c index aeec83da1..49f3c8f0f 100644 --- a/src/journal/journal-authenticate.c +++ b/src/journal/journal-authenticate.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/journal-authenticate.h b/src/journal/journal-authenticate.h index 118bb1367..6c87319ed 100644 --- a/src/journal/journal-authenticate.h +++ b/src/journal/journal-authenticate.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journal-def.h b/src/journal/journal-def.h index c003ac05d..67edb4396 100644 --- a/src/journal/journal-def.h +++ b/src/journal/journal-def.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index f9ff9545d..912eb94d0 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -39,6 +37,7 @@ #include "lookup3.h" #include "parse-util.h" #include "random-util.h" +#include "sd-event.h" #include "string-util.h" #include "xattr-util.h" @@ -99,7 +98,7 @@ static int journal_file_set_online(JournalFile *f) { if (mmap_cache_got_sigbus(f->mmap, f->fd)) return -EIO; - switch(f->header->state) { + switch (f->header->state) { case STATE_ONLINE: return 0; @@ -149,6 +148,17 @@ JournalFile* journal_file_close(JournalFile *f) { journal_file_append_tag(f); #endif + if (f->post_change_timer) { + int enabled; + + if (sd_event_source_get_enabled(f->post_change_timer, &enabled) >= 0) + if (enabled == SD_EVENT_ONESHOT) + journal_file_post_change(f); + + (void) sd_event_source_set_enabled(f->post_change_timer, SD_EVENT_OFF); + sd_event_source_unref(f->post_change_timer); + } + journal_file_set_offline(f); if (f->mmap && f->fd >= 0) @@ -169,8 +179,7 @@ JournalFile* journal_file_close(JournalFile *f) { safe_close(f->fd); free(f->path); - if (f->mmap) - mmap_cache_unref(f->mmap); + mmap_cache_unref(f->mmap); ordered_hashmap_free_free(f->chain_cache); @@ -236,6 +245,7 @@ static int journal_file_refresh_header(JournalFile *f) { int r; assert(f); + assert(f->header); r = sd_id128_get_machine(&f->header->machine_id); if (r < 0) @@ -262,6 +272,7 @@ static int journal_file_verify_header(JournalFile *f) { uint32_t flags; assert(f); + assert(f->header); if (memcmp(f->header->signature, HEADER_SIGNATURE, 8)) return -EBADMSG; @@ -370,6 +381,7 @@ static int journal_file_allocate(JournalFile *f, uint64_t offset, uint64_t size) int r; assert(f); + assert(f->header); /* We assume that this file is not sparse, and we know that * for sure, since we always call posix_fallocate() @@ -533,6 +545,7 @@ static uint64_t journal_file_entry_seqnum(JournalFile *f, uint64_t *seqnum) { uint64_t r; assert(f); + assert(f->header); r = le64toh(f->header->tail_entry_seqnum) + 1; @@ -562,6 +575,7 @@ int journal_file_append_object(JournalFile *f, ObjectType type, uint64_t size, O void *t; assert(f); + assert(f->header); assert(type > OBJECT_UNUSED && type < _OBJECT_TYPE_MAX); assert(size >= sizeof(ObjectHeader)); assert(offset); @@ -611,6 +625,7 @@ static int journal_file_setup_data_hash_table(JournalFile *f) { int r; assert(f); + assert(f->header); /* We estimate that we need 1 hash table entry per 768 bytes of journal file and we want to make sure we never get @@ -644,6 +659,7 @@ static int journal_file_setup_field_hash_table(JournalFile *f) { int r; assert(f); + assert(f->header); /* We use a fixed size hash table for the fields as this * number should grow very slowly only */ @@ -670,6 +686,7 @@ int journal_file_map_data_hash_table(JournalFile *f) { int r; assert(f); + assert(f->header); if (f->data_hash_table) return 0; @@ -695,6 +712,7 @@ int journal_file_map_field_hash_table(JournalFile *f) { int r; assert(f); + assert(f->header); if (f->field_hash_table) return 0; @@ -724,6 +742,8 @@ static int journal_file_link_field( int r; assert(f); + assert(f->header); + assert(f->field_hash_table); assert(o); assert(offset > 0); @@ -767,6 +787,8 @@ static int journal_file_link_data( int r; assert(f); + assert(f->header); + assert(f->data_hash_table); assert(o); assert(offset > 0); @@ -815,6 +837,7 @@ int journal_file_find_field_object_with_hash( int r; assert(f); + assert(f->header); assert(field && size > 0); /* If the field hash table is empty, we can't find anything */ @@ -886,6 +909,7 @@ int journal_file_find_data_object_with_hash( int r; assert(f); + assert(f->header); assert(data || size == 0); /* If there's no data hash table, then there's no entry. */ @@ -1085,7 +1109,7 @@ static int journal_file_append_data( if (JOURNAL_FILE_COMPRESS(f) && size >= COMPRESSION_SIZE_THRESHOLD) { size_t rsize = 0; - compression = compress_blob(data, size, o->data.payload, &rsize); + compression = compress_blob(data, size, o->data.payload, size - 1, &rsize); if (compression >= 0) { o->object.size = htole64(offsetof(Object, data.payload) + rsize); @@ -1182,6 +1206,7 @@ static int link_entry_into_array(JournalFile *f, Object *o; assert(f); + assert(f->header); assert(first); assert(idx); assert(p > 0); @@ -1302,6 +1327,7 @@ static int journal_file_link_entry(JournalFile *f, Object *o, uint64_t offset) { int r; assert(f); + assert(f->header); assert(o); assert(offset > 0); @@ -1352,6 +1378,7 @@ static int journal_file_append_entry_internal( int r; assert(f); + assert(f->header); assert(items || n_items == 0); assert(ts); @@ -1398,7 +1425,84 @@ void journal_file_post_change(JournalFile *f) { __sync_synchronize(); if (ftruncate(f->fd, f->last_stat.st_size) < 0) - log_error_errno(errno, "Failed to truncate file to its own size: %m"); + log_debug_errno(errno, "Failed to truncate file to its own size: %m"); +} + +static int post_change_thunk(sd_event_source *timer, uint64_t usec, void *userdata) { + assert(userdata); + + journal_file_post_change(userdata); + + return 1; +} + +static void schedule_post_change(JournalFile *f) { + sd_event_source *timer; + int enabled, r; + uint64_t now; + + assert(f); + assert(f->post_change_timer); + + timer = f->post_change_timer; + + r = sd_event_source_get_enabled(timer, &enabled); + if (r < 0) { + log_debug_errno(r, "Failed to get ftruncate timer state: %m"); + goto fail; + } + + if (enabled == SD_EVENT_ONESHOT) + return; + + r = sd_event_now(sd_event_source_get_event(timer), CLOCK_MONOTONIC, &now); + if (r < 0) { + log_debug_errno(r, "Failed to get clock's now for scheduling ftruncate: %m"); + goto fail; + } + + r = sd_event_source_set_time(timer, now+f->post_change_timer_period); + if (r < 0) { + log_debug_errno(r, "Failed to set time for scheduling ftruncate: %m"); + goto fail; + } + + r = sd_event_source_set_enabled(timer, SD_EVENT_ONESHOT); + if (r < 0) { + log_debug_errno(r, "Failed to enable scheduled ftruncate: %m"); + goto fail; + } + + return; + +fail: + /* On failure, let's simply post the change immediately. */ + journal_file_post_change(f); +} + +/* Enable coalesced change posting in a timer on the provided sd_event instance */ +int journal_file_enable_post_change_timer(JournalFile *f, sd_event *e, usec_t t) { + _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL; + int r; + + assert(f); + assert_return(!f->post_change_timer, -EINVAL); + assert(e); + assert(t); + + r = sd_event_add_time(e, &timer, CLOCK_MONOTONIC, 0, 0, post_change_thunk, f); + if (r < 0) + return r; + + r = sd_event_source_set_enabled(timer, SD_EVENT_OFF); + if (r < 0) + return r; + + f->post_change_timer = timer; + timer = NULL; + f->post_change_timer_period = t; + + return r; } static int entry_item_cmp(const void *_a, const void *_b) { @@ -1419,6 +1523,7 @@ int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const st struct dual_timestamp _ts; assert(f); + assert(f->header); assert(iovec || n_iovec == 0); if (!ts) { @@ -1426,10 +1531,6 @@ int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const st ts = &_ts; } - if (f->tail_entry_monotonic_valid && - ts->monotonic < le64toh(f->header->tail_entry_monotonic)) - return -EINVAL; - #ifdef HAVE_GCRYPT r = journal_file_maybe_append_tag(f, ts->realtime); if (r < 0) @@ -1466,7 +1567,10 @@ int journal_file_append_entry(JournalFile *f, const dual_timestamp *ts, const st if (mmap_cache_got_sigbus(f->mmap, f->fd)) r = -EIO; - journal_file_post_change(f); + if (f->post_change_timer) + schedule_post_change(f); + else + journal_file_post_change(f); return r; } @@ -1931,6 +2035,8 @@ int journal_file_move_to_entry_by_seqnum( direction_t direction, Object **ret, uint64_t *offset) { + assert(f); + assert(f->header); return generic_array_bisect(f, le64toh(f->header->entry_array_offset), @@ -1966,6 +2072,8 @@ int journal_file_move_to_entry_by_realtime( direction_t direction, Object **ret, uint64_t *offset) { + assert(f); + assert(f->header); return generic_array_bisect(f, le64toh(f->header->entry_array_offset), @@ -2058,7 +2166,9 @@ void journal_file_save_location(JournalFile *f, Object *o, uint64_t offset) { int journal_file_compare_locations(JournalFile *af, JournalFile *bf) { assert(af); + assert(af->header); assert(bf); + assert(bf->header); assert(af->location_type == LOCATION_SEEK); assert(bf->location_type == LOCATION_SEEK); @@ -2118,6 +2228,7 @@ int journal_file_next_entry( int r; assert(f); + assert(f->header); n = le64toh(f->header->n_entries); if (n <= 0) @@ -2400,6 +2511,7 @@ void journal_file_dump(JournalFile *f) { uint64_t p; assert(f); + assert(f->header); journal_file_print_header(f); @@ -2484,6 +2596,7 @@ void journal_file_print_header(JournalFile *f) { char bytes[FORMAT_BYTES_MAX]; assert(f); + assert(f->header); printf("File Path: %s\n" "File ID: %s\n" @@ -2768,6 +2881,16 @@ int journal_file_open( goto fail; } + if (template && template->post_change_timer) { + r = journal_file_enable_post_change_timer( + f, + sd_event_source_get_event(template->post_change_timer), + template->post_change_timer_period); + + if (r < 0) + goto fail; + } + *ret = f; return 0; @@ -3079,6 +3202,7 @@ void journal_default_metrics(JournalMetrics *m, int fd) { int journal_file_get_cutoff_realtime_usec(JournalFile *f, usec_t *from, usec_t *to) { assert(f); + assert(f->header); assert(from || to); if (from) { @@ -3142,6 +3266,7 @@ int journal_file_get_cutoff_monotonic_usec(JournalFile *f, sd_id128_t boot_id, u bool journal_file_rotate_suggested(JournalFile *f, usec_t max_file_usec) { assert(f); + assert(f->header); /* If we gained new header fields we gained new features, * hence suggest a rotation */ diff --git a/src/journal/journal-file.h b/src/journal/journal-file.h index 898d12d99..07b9561b8 100644 --- a/src/journal/journal-file.h +++ b/src/journal/journal-file.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -29,11 +27,12 @@ #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 "sd-event.h" +#include "sparse-endian.h" typedef struct JournalMetrics { /* For all these: -1 means "pick automatically", and 0 means "no limit enforced" */ @@ -101,6 +100,9 @@ typedef struct JournalFile { JournalMetrics metrics; MMapCache *mmap; + sd_event_source *post_change_timer; + usec_t post_change_timer_period; + OrderedHashmap *chain_cache; #if defined(HAVE_XZ) || defined(HAVE_LZ4) @@ -224,6 +226,7 @@ void journal_file_print_header(JournalFile *f); int journal_file_rotate(JournalFile **f, bool compress, bool seal); void journal_file_post_change(JournalFile *f); +int journal_file_enable_post_change_timer(JournalFile *f, sd_event *e, usec_t t); void journal_reset_metrics(JournalMetrics *m); void journal_default_metrics(JournalMetrics *m, int fd); diff --git a/src/journal/journal-internal.h b/src/journal/journal-internal.h index 06847402e..7639325ac 100644 --- a/src/journal/journal-internal.h +++ b/src/journal/journal-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,9 +19,9 @@ along with systemd; If not, see . ***/ -#include #include #include +#include #include "sd-id128.h" #include "sd-journal.h" @@ -103,18 +101,29 @@ struct sd_journal { unsigned current_invalidate_counter, last_invalidate_counter; usec_t last_process_usec; + /* Iterating through unique fields and their data values */ char *unique_field; JournalFile *unique_file; uint64_t unique_offset; + /* Iterating through known fields */ + JournalFile *fields_file; + uint64_t fields_offset; + uint64_t fields_hash_table_index; + char *fields_buffer; + size_t fields_buffer_allocated; + int flags; - bool on_network; - bool no_new_files; - bool unique_file_lost; /* File we were iterating over got - removed, and there were no more - files, so sd_j_enumerate_unique - will return a value equal to 0. */ + bool on_network:1; + bool no_new_files:1; + bool unique_file_lost:1; /* File we were iterating over got + removed, and there were no more + files, so sd_j_enumerate_unique + will return a value equal to 0. */ + bool fields_file_lost:1; + bool has_runtime_files:1; + bool has_persistent_files:1; size_t data_threshold; @@ -127,8 +136,5 @@ struct sd_journal { char *journal_make_match_string(sd_journal *j); void journal_print_header(sd_journal *j); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_journal*, sd_journal_close); -#define _cleanup_journal_close_ _cleanup_(sd_journal_closep) - #define JOURNAL_FOREACH_DATA_RETVAL(j, data, l, retval) \ for (sd_journal_restart_data(j); ((retval) = sd_journal_enumerate_data((j), &(data), &(l))) > 0; ) diff --git a/src/journal/journal-qrcode.c b/src/journal/journal-qrcode.c index 257ddb302..e38730d65 100644 --- a/src/journal/journal-qrcode.c +++ b/src/journal/journal-qrcode.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/journal-qrcode.h b/src/journal/journal-qrcode.h index 7d14e8754..ef3908556 100644 --- a/src/journal/journal-qrcode.h +++ b/src/journal/journal-qrcode.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index fa5dee73c..c7d670f4f 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -225,8 +223,8 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { assert_return(iov, -EINVAL); assert_return(n > 0, -EINVAL); - w = alloca(sizeof(struct iovec) * n * 5 + 3); - l = alloca(sizeof(uint64_t) * n); + w = newa(struct iovec, n * 5 + 3); + l = newa(uint64_t, n); for (i = 0; i < n; i++) { char *c, *nl; @@ -337,7 +335,11 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) { return r; } - return send_one_fd(fd, buffer_fd, 0); + r = send_one_fd_sa(fd, buffer_fd, mh.msg_name, mh.msg_namelen, 0); + if (r == -ENOENT) + /* Fail silently if the journal is not available */ + return 0; + return r; } static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) { @@ -368,6 +370,7 @@ static int fill_iovec_perror_and_send(const char *message, int skip, struct iove xsprintf(error, "ERRNO=%i", _saved_errno_); + assert_cc(3 == LOG_ERR); IOVEC_SET_STRING(iov[skip+0], "PRIORITY=3"); IOVEC_SET_STRING(iov[skip+1], buffer); IOVEC_SET_STRING(iov[skip+2], error); diff --git a/src/journal/journal-vacuum.c b/src/journal/journal-vacuum.c index 4b5fc76eb..05e97620a 100644 --- a/src/journal/journal-vacuum.c +++ b/src/journal/journal-vacuum.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/journal-vacuum.h b/src/journal/journal-vacuum.h index 49ab90af9..1e750a217 100644 --- a/src/journal/journal-vacuum.h +++ b/src/journal/journal-vacuum.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c index 715847e01..b968e89bb 100644 --- a/src/journal/journal-verify.c +++ b/src/journal/journal-verify.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/journal-verify.h b/src/journal/journal-verify.h index e392ab61d..8f0eaf6da 100644 --- a/src/journal/journal-verify.h +++ b/src/journal/journal-verify.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index d9a8063d3..273242bea 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -69,6 +67,8 @@ #include "strv.h" #include "syslog-util.h" #include "terminal-util.h" +#include "udev.h" +#include "udev-util.h" #include "unit-name.h" #include "user-util.h" @@ -136,6 +136,8 @@ static enum { ACTION_SYNC, ACTION_ROTATE, ACTION_VACUUM, + ACTION_LIST_FIELDS, + ACTION_LIST_FIELD_NAMES, } arg_action = ACTION_SHOW; typedef struct BootId { @@ -145,6 +147,84 @@ typedef struct BootId { LIST_FIELDS(struct BootId, boot_list); } BootId; +static int add_matches_for_device(sd_journal *j, const char *devpath) { + int r; + _cleanup_udev_unref_ struct udev *udev = NULL; + _cleanup_udev_device_unref_ struct udev_device *device = NULL; + struct udev_device *d = NULL; + struct stat st; + + assert(j); + assert(devpath); + + if (!path_startswith(devpath, "/dev/")) { + log_error("Devpath does not start with /dev/"); + return -EINVAL; + } + + udev = udev_new(); + if (!udev) + return log_oom(); + + r = stat(devpath, &st); + if (r < 0) + log_error_errno(errno, "Couldn't stat file: %m"); + + d = device = udev_device_new_from_devnum(udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev); + if (!device) + return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev)); + + while (d) { + _cleanup_free_ char *match = NULL; + const char *subsys, *sysname, *devnode; + + subsys = udev_device_get_subsystem(d); + if (!subsys) { + d = udev_device_get_parent(d); + continue; + } + + sysname = udev_device_get_sysname(d); + if (!sysname) { + d = udev_device_get_parent(d); + continue; + } + + match = strjoin("_KERNEL_DEVICE=+", subsys, ":", sysname, NULL); + if (!match) + return log_oom(); + + r = sd_journal_add_match(j, match, 0); + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); + + devnode = udev_device_get_devnode(d); + if (devnode) { + _cleanup_free_ char *match1 = NULL; + + r = stat(devnode, &st); + if (r < 0) + return log_error_errno(r, "Failed to stat() device node \"%s\": %m", devnode); + + r = asprintf(&match1, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st.st_mode) ? 'b' : 'c', major(st.st_rdev), minor(st.st_rdev)); + if (r < 0) + return log_oom(); + + r = sd_journal_add_match(j, match1, 0); + if (r < 0) + return log_error_errno(r, "Failed to add match: %m"); + } + + d = udev_device_get_parent(d); + } + + r = add_match_this_boot(j, arg_machine); + if (r < 0) + return log_error_errno(r, "Failed to add match for the current boot: %m"); + + return 0; +} + static void pager_open_if_enabled(void) { if (arg_no_pager) @@ -244,6 +324,7 @@ static void help(void) { "\nCommands:\n" " -h --help Show this help text\n" " --version Show package version\n" + " -N --fields List all field names currently used\n" " -F --field=FIELD List all values that a specified field takes\n" " --disk-usage Show total disk usage of all journal files\n" " --vacuum-size=BYTES Reduce disk usage below specified size\n" @@ -340,6 +421,7 @@ static int parse_argv(int argc, char *argv[]) { { "unit", required_argument, NULL, 'u' }, { "user-unit", required_argument, NULL, ARG_USER_UNIT }, { "field", required_argument, NULL, 'F' }, + { "fields", no_argument, NULL, 'N' }, { "catalog", no_argument, NULL, 'x' }, { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG }, { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG }, @@ -361,7 +443,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:NF:xrM:", options, NULL)) >= 0) switch (c) { @@ -698,9 +780,14 @@ static int parse_argv(int argc, char *argv[]) { break; case 'F': + arg_action = ACTION_LIST_FIELDS; arg_field = optarg; break; + case 'N': + arg_action = ACTION_LIST_FIELD_NAMES; + break; + case 'x': arg_catalog = true; break; @@ -825,13 +912,12 @@ static int add_matches(sd_journal *j, char **args) { have_term = false; } else if (path_is_absolute(*i)) { - _cleanup_free_ char *p, *t = NULL, *t2 = NULL; + _cleanup_free_ char *p, *t = NULL, *t2 = NULL, *interpreter = NULL; const char *path; - _cleanup_free_ char *interpreter = NULL; struct stat st; p = canonicalize_file_name(*i); - path = p ? p : *i; + path = p ?: *i; if (lstat(path, &st) < 0) return log_error_errno(errno, "Couldn't stat file: %m"); @@ -845,34 +931,37 @@ static int add_matches(sd_journal *j, char **args) { return log_oom(); t = strappend("_COMM=", comm); + if (!t) + return log_oom(); /* Append _EXE only if the interpreter is not a link. Otherwise, it might be outdated often. */ - if (lstat(interpreter, &st) == 0 && - !S_ISLNK(st.st_mode)) { + if (lstat(interpreter, &st) == 0 && !S_ISLNK(st.st_mode)) { t2 = strappend("_EXE=", interpreter); if (!t2) return log_oom(); } - } else + } else { t = strappend("_EXE=", path); - } else if (S_ISCHR(st.st_mode)) - (void) asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev)); - else if (S_ISBLK(st.st_mode)) - (void) asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev)); - else { + if (!t) + return log_oom(); + } + + r = sd_journal_add_match(j, t, 0); + + if (r >=0 && t2) + r = sd_journal_add_match(j, t2, 0); + + } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) { + r = add_matches_for_device(j, path); + if (r < 0) + return r; + } else { log_error("File is neither a device node, nor regular file, nor executable: %s", *i); return -EINVAL; } - if (!t) - return log_oom(); - - r = sd_journal_add_match(j, t, 0); - if (t2) - r = sd_journal_add_match(j, t2, 0); have_term = true; - } else { r = sd_journal_add_match(j, *i, 0); have_term = true; @@ -1136,10 +1225,11 @@ static int add_boot(sd_journal *j) { const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r); if (sd_id128_is_null(arg_boot_id)) - log_error("Failed to look up boot %+i: %s", arg_boot_offset, reason); + log_error("Data from the specified boot (%+i) is not available: %s", + arg_boot_offset, reason); else - log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+i: %s", - SD_ID128_FORMAT_VAL(arg_boot_id), arg_boot_offset, reason); + log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s", + SD_ID128_FORMAT_VAL(arg_boot_id), reason); return r == 0 ? -ENODATA : r; } @@ -1766,8 +1856,8 @@ static int access_check(sd_journal *j) { } static int flush_to_var(void) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_close_ int watch_fd = -1; int r; @@ -1828,7 +1918,7 @@ static int flush_to_var(void) { } static int send_signal_and_wait(int sig, const char *watch_path) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_close_ int watch_fd = -1; usec_t start; int r; @@ -1857,7 +1947,7 @@ static int send_signal_and_wait(int sig, const char *watch_path) { /* Let's ask for a sync, but only once. */ if (!bus) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; r = bus_connect_system_systemd(&bus); if (r < 0) @@ -1920,7 +2010,7 @@ static int sync_journal(void) { int main(int argc, char *argv[]) { int r; - _cleanup_journal_close_ sd_journal *j = NULL; + _cleanup_(sd_journal_closep) sd_journal *j = NULL; bool need_seek = false; sd_id128_t previous_boot_id; bool previous_boot_id_valid = false, first_line = true; @@ -2002,6 +2092,8 @@ int main(int argc, char *argv[]) { case ACTION_DISK_USAGE: case ACTION_LIST_BOOTS: case ACTION_VACUUM: + case ACTION_LIST_FIELDS: + case ACTION_LIST_FIELD_NAMES: /* These ones require access to the journal files, continue below. */ break; @@ -2084,13 +2176,33 @@ int main(int argc, char *argv[]) { goto finish; } + case ACTION_LIST_FIELD_NAMES: { + const char *field; + + SD_JOURNAL_FOREACH_FIELD(j, field) { + printf("%s\n", field); + n_shown ++; + } + + r = 0; + goto finish; + } + case ACTION_SHOW: + case ACTION_LIST_FIELDS: break; default: assert_not_reached("Unknown action"); } + if (arg_boot_offset != 0 && + sd_journal_has_runtime_files(j) > 0 && + sd_journal_has_persistent_files(j) == 0) { + log_info("Specifying boot ID has no effect, no persistent journal was found"); + r = 0; + goto finish; + } /* add_boot() must be called first! * It may need to seek the journal to find parent boot IDs. */ r = add_boot(j); @@ -2131,10 +2243,12 @@ int main(int argc, char *argv[]) { log_debug("Journal filter: %s", filter); } - if (arg_field) { + if (arg_action == ACTION_LIST_FIELDS) { const void *data; size_t size; + assert(arg_field); + r = sd_journal_set_data_threshold(j, 0); if (r < 0) { log_error_errno(r, "Failed to unset data size threshold: %m"); @@ -2336,7 +2450,7 @@ int main(int argc, char *argv[]) { flags = arg_all * OUTPUT_SHOW_ALL | arg_full * OUTPUT_FULL_WIDTH | - on_tty() * OUTPUT_COLOR | + colors_enabled() * OUTPUT_COLOR | arg_catalog * OUTPUT_CATALOG | arg_utc * OUTPUT_UTC; diff --git a/src/journal/journald-audit.c b/src/journal/journald-audit.c index 3c13fe0d6..b2eb8a33e 100644 --- a/src/journal/journald-audit.c +++ b/src/journal/journald-audit.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -397,8 +395,8 @@ static void process_audit_string(Server *s, int type, const char *data, size_t s sprintf(id_field, "_AUDIT_ID=%" PRIu64, id); IOVEC_SET_STRING(iov[n_iov++], id_field); - assert_cc(32 == LOG_AUTH); - IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=32"); + assert_cc(4 == LOG_FAC(LOG_AUTH)); + IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_FACILITY=4"); IOVEC_SET_STRING(iov[n_iov++], "SYSLOG_IDENTIFIER=audit"); type_name = audit_type_name_alloca(type); diff --git a/src/journal/journald-audit.h b/src/journal/journald-audit.h index 68cdfb341..8c7457778 100644 --- a/src/journal/journald-audit.h +++ b/src/journal/journald-audit.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#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 04487c29b..fcc9f2581 100644 --- a/src/journal/journald-console.c +++ b/src/journal/journald-console.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/journald-console.h b/src/journal/journald-console.h index d8af2267e..dda07e2c2 100644 --- a/src/journal/journald-console.h +++ b/src/journal/journald-console.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journald-kmsg.c b/src/journal/journald-kmsg.c index e048e0471..eb1ac90e9 100644 --- a/src/journal/journald-kmsg.c +++ b/src/journal/journald-kmsg.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -158,8 +156,10 @@ static void dev_kmsg_record(Server *s, const char *p, size_t l) { /* Did we lose any? */ if (serial > *s->kernel_seqnum) - server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED, "Missed %"PRIu64" kernel messages", - serial - *s->kernel_seqnum); + server_driver_message(s, SD_MESSAGE_JOURNAL_MISSED, + LOG_MESSAGE("Missed %"PRIu64" kernel messages", + serial - *s->kernel_seqnum), + NULL); /* Make sure we never read this one again. Note that * we always store the next message serial we expect diff --git a/src/journal/journald-kmsg.h b/src/journal/journald-kmsg.h index 9a9d08996..dab49f1e8 100644 --- a/src/journal/journald-kmsg.h +++ b/src/journal/journald-kmsg.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 69a685c06..3d8f05996 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -480,7 +478,7 @@ int server_open_native_socket(Server*s) { return log_error_errno(errno, "SO_PASSCRED failed: %m"); #ifdef HAVE_SELINUX - if (mac_selinux_use()) { + if (mac_selinux_have()) { r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); if (r < 0) log_warning_errno(errno, "SO_PASSSEC failed: %m"); @@ -495,5 +493,9 @@ int server_open_native_socket(Server*s) { if (r < 0) return log_error_errno(r, "Failed to add native server fd to event loop: %m"); + r = sd_event_source_set_priority(s->native_event_source, SD_EVENT_PRIORITY_NORMAL+5); + if (r < 0) + return log_error_errno(r, "Failed to adjust native event source priority: %m"); + return 0; } diff --git a/src/journal/journald-native.h b/src/journal/journald-native.h index 2f9d458fb..c13b80aa4 100644 --- a/src/journal/journald-native.h +++ b/src/journal/journald-native.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journald-rate-limit.c b/src/journal/journald-rate-limit.c index 1c406aef8..6f6a90fe4 100644 --- a/src/journal/journald-rate-limit.c +++ b/src/journal/journald-rate-limit.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/journald-rate-limit.h b/src/journal/journald-rate-limit.h index 466239d3c..bb0abb7ee 100644 --- a/src/journal/journald-rate-limit.h +++ b/src/journal/journald-rate-limit.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 7d11a568a..ee2db8d29 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -67,9 +65,11 @@ #include "selinux-util.h" #include "signal-util.h" #include "socket-util.h" +#include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "user-util.h" +#include "log.h" #define USER_JOURNALS_MAX 1024 @@ -82,6 +82,9 @@ #define NOTIFY_SNDBUF_SIZE (8*1024*1024) +/* The period to insert between posting changes for coalescing */ +#define POST_CHANGE_TIMER_INTERVAL_USEC (250*USEC_PER_MSEC) + static int determine_space_for( Server *s, JournalMetrics *metrics, @@ -142,7 +145,7 @@ static int determine_space_for( sum += (uint64_t) st.st_blocks * 512UL; } - /* If request, then let's bump the min_use limit to the + /* If requested, then let's bump the min_use limit to the * current usage on disk. We do this when starting up and * first opening the journal files. This way sudden spikes in * disk usage will not cause journald to vacuum files without @@ -162,19 +165,31 @@ static int determine_space_for( if (verbose) { char fb1[FORMAT_BYTES_MAX], fb2[FORMAT_BYTES_MAX], fb3[FORMAT_BYTES_MAX], fb4[FORMAT_BYTES_MAX], fb5[FORMAT_BYTES_MAX], fb6[FORMAT_BYTES_MAX]; + format_bytes(fb1, sizeof(fb1), sum); + format_bytes(fb2, sizeof(fb2), metrics->max_use); + format_bytes(fb3, sizeof(fb3), metrics->keep_free); + format_bytes(fb4, sizeof(fb4), ss_avail); + format_bytes(fb5, sizeof(fb5), s->cached_space_limit); + format_bytes(fb6, sizeof(fb6), s->cached_space_available); server_driver_message(s, SD_MESSAGE_JOURNAL_USAGE, - "%s (%s) is currently using %s.\n" - "Maximum allowed usage is set to %s.\n" - "Leaving at least %s free (of currently available %s of space).\n" - "Enforced usage limit is thus %s, of which %s are still available.", - name, path, - format_bytes(fb1, sizeof(fb1), sum), - format_bytes(fb2, sizeof(fb2), metrics->max_use), - format_bytes(fb3, sizeof(fb3), metrics->keep_free), - format_bytes(fb4, sizeof(fb4), ss_avail), - format_bytes(fb5, sizeof(fb5), s->cached_space_limit), - format_bytes(fb6, sizeof(fb6), s->cached_space_available)); + LOG_MESSAGE("%s (%s) is %s, max %s, %s free.", + name, path, fb1, fb5, fb6), + "JOURNAL_NAME=%s", name, + "JOURNAL_PATH=%s", path, + "CURRENT_USE=%"PRIu64, sum, + "CURRENT_USE_PRETTY=%s", fb1, + "MAX_USE=%"PRIu64, metrics->max_use, + "MAX_USE_PRETTY=%s", fb2, + "DISK_KEEP_FREE=%"PRIu64, metrics->keep_free, + "DISK_KEEP_FREE_PRETTY=%s", fb3, + "DISK_AVAILABLE=%"PRIu64, ss_avail, + "DISK_AVAILABLE_PRETTY=%s", fb4, + "LIMIT=%"PRIu64, s->cached_space_limit, + "LIMIT_PRETTY=%s", fb5, + "AVAILABLE=%"PRIu64, s->cached_space_available, + "AVAILABLE_PRETTY=%s", fb6, + NULL); } if (available) @@ -204,61 +219,54 @@ static int determine_space(Server *s, bool verbose, bool patch_min_use, uint64_t return determine_space_for(s, metrics, path, name, verbose, patch_min_use, available, limit); } -void server_fix_perms(Server *s, JournalFile *f, uid_t uid) { - int r; +static void server_add_acls(JournalFile *f, uid_t uid) { #ifdef HAVE_ACL - _cleanup_(acl_freep) acl_t acl = NULL; - acl_entry_t entry; - acl_permset_t permset; + int r; #endif - assert(f); - r = fchmod(f->fd, 0640); - if (r < 0) - log_warning_errno(errno, "Failed to fix access mode on %s, ignoring: %m", f->path); - #ifdef HAVE_ACL if (uid <= SYSTEM_UID_MAX) return; - acl = acl_get_fd(f->fd); - if (!acl) { - log_warning_errno(errno, "Failed to read ACL on %s, ignoring: %m", f->path); - return; - } - - r = acl_find_uid(acl, uid, &entry); - if (r <= 0) { - - if (acl_create_entry(&acl, &entry) < 0 || - acl_set_tag_type(entry, ACL_USER) < 0 || - acl_set_qualifier(entry, &uid) < 0) { - log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path); - return; - } - } - - /* We do not recalculate the mask unconditionally here, - * so that the fchmod() mask above stays intact. */ - if (acl_get_permset(entry, &permset) < 0 || - acl_add_perm(permset, ACL_READ) < 0) { - log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path); - return; - } - - r = calc_acl_mask_if_needed(&acl); - if (r < 0) { - log_warning_errno(r, "Failed to patch ACL on %s, ignoring: %m", f->path); - return; - } - - if (acl_set_fd(f->fd, acl) < 0) - log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path); - + r = add_acls_for_user(f->fd, uid); + if (r < 0) + log_warning_errno(r, "Failed to set ACL on %s, ignoring: %m", f->path); #endif } +static int open_journal( + Server *s, + bool reliably, + const char *fname, + int flags, + bool seal, + JournalMetrics *metrics, + JournalFile **ret) { + int r; + JournalFile *f; + + assert(s); + assert(fname); + assert(ret); + + if (reliably) + r = journal_file_open_reliably(fname, flags, 0640, s->compress, seal, metrics, s->mmap, NULL, &f); + else + r = journal_file_open(fname, flags, 0640, s->compress, seal, metrics, s->mmap, NULL, &f); + if (r < 0) + return r; + + r = journal_file_enable_post_change_timer(f, s->event, POST_CHANGE_TIMER_INTERVAL_USEC); + if (r < 0) { + journal_file_close(f); + return r; + } + + *ret = f; + return r; +} + static JournalFile* find_journal(Server *s, uid_t uid) { _cleanup_free_ char *p = NULL; int r; @@ -297,11 +305,11 @@ static JournalFile* find_journal(Server *s, uid_t uid) { journal_file_close(f); } - r = journal_file_open_reliably(p, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &f); + r = open_journal(s, true, p, O_RDWR|O_CREAT, s->seal, &s->system_metrics, &f); if (r < 0) return s->system_journal; - server_fix_perms(s, f, uid); + server_add_acls(f, uid); r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f); if (r < 0) { @@ -332,7 +340,7 @@ static int do_rotate( else log_error_errno(r, "Failed to create new %s journal: %m", name); else - server_fix_perms(s, *f, uid); + server_add_acls(*f, uid); return r; } @@ -707,7 +715,7 @@ static void dispatch_message_real( } #ifdef HAVE_SELINUX - if (mac_selinux_use()) { + if (mac_selinux_have()) { if (label) { x = alloca(strlen("_SELINUX_CONTEXT=") + label_len + 1); @@ -847,37 +855,56 @@ static void dispatch_message_real( void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) { char mid[11 + 32 + 1]; - char buffer[16 + LINE_MAX + 1]; - struct iovec iovec[N_IOVEC_META_FIELDS + 6]; - int n = 0; + struct iovec iovec[N_IOVEC_META_FIELDS + 5 + N_IOVEC_PAYLOAD_FIELDS]; + unsigned n = 0, m; + int r; va_list ap; struct ucred ucred = {}; assert(s); assert(format); + assert_cc(3 == LOG_FAC(LOG_DAEMON)); IOVEC_SET_STRING(iovec[n++], "SYSLOG_FACILITY=3"); IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=systemd-journald"); - IOVEC_SET_STRING(iovec[n++], "PRIORITY=6"); IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=driver"); - - memcpy(buffer, "MESSAGE=", 8); - va_start(ap, format); - vsnprintf(buffer + 8, sizeof(buffer) - 8, format, ap); - va_end(ap); - IOVEC_SET_STRING(iovec[n++], buffer); + assert_cc(6 == LOG_INFO); + IOVEC_SET_STRING(iovec[n++], "PRIORITY=6"); if (!sd_id128_equal(message_id, SD_ID128_NULL)) { snprintf(mid, sizeof(mid), LOG_MESSAGE_ID(message_id)); IOVEC_SET_STRING(iovec[n++], mid); } + m = n; + + va_start(ap, format); + r = log_format_iovec(iovec, ELEMENTSOF(iovec), &n, false, 0, format, ap); + /* Error handling below */ + va_end(ap); + ucred.pid = getpid(); ucred.uid = getuid(); ucred.gid = getgid(); - dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, LOG_INFO, 0); + if (r >= 0) + dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, LOG_INFO, 0); + + while (m < n) + free(iovec[m++].iov_base); + + if (r < 0) { + /* We failed to format the message. Emit a warning instead. */ + char buf[LINE_MAX]; + + xsprintf(buf, "MESSAGE=Entry printing failed: %s", strerror(-r)); + + n = 3; + IOVEC_SET_STRING(iovec[n++], "PRIORITY=4"); + IOVEC_SET_STRING(iovec[n++], buf); + dispatch_message_real(s, iovec, n, ELEMENTSOF(iovec), &ucred, NULL, NULL, 0, NULL, LOG_INFO, 0); + } } void server_dispatch_message( @@ -940,7 +967,8 @@ void server_dispatch_message( /* Write a suppression message if we suppressed something */ if (rl > 1) server_driver_message(s, SD_MESSAGE_JOURNAL_DROPPED, - "Suppressed %u messages from %s", rl - 1, path); + LOG_MESSAGE("Suppressed %u messages from %s", rl - 1, path), + NULL); finish: dispatch_message_real(s, iovec, n, m, ucred, tv, label, label_len, unit_id, priority, object_pid); @@ -969,9 +997,9 @@ static int system_journal_open(Server *s, bool flush_requested) { (void) mkdir(fn, 0755); fn = strjoina(fn, "/system.journal"); - r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal); + r = open_journal(s, true, fn, O_RDWR|O_CREAT, s->seal, &s->system_metrics, &s->system_journal); if (r >= 0) { - server_fix_perms(s, s->system_journal, 0); + server_add_acls(s->system_journal, 0); (void) determine_space_for(s, &s->system_metrics, "/var/log/journal/", "System journal", true, true, NULL, NULL); } else if (r < 0) { if (r != -ENOENT && r != -EROFS) @@ -992,7 +1020,7 @@ static int system_journal_open(Server *s, bool flush_requested) { * if it already exists, so that we can flush * it into the system journal */ - r = journal_file_open(fn, O_RDWR, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); + r = open_journal(s, false, fn, O_RDWR, false, &s->runtime_metrics, &s->runtime_journal); if (r < 0) { if (r != -ENOENT) log_warning_errno(r, "Failed to open runtime journal: %m"); @@ -1009,13 +1037,13 @@ static int system_journal_open(Server *s, bool flush_requested) { (void) mkdir("/run/log/journal", 0755); (void) mkdir_parents(fn, 0750); - r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, false, &s->runtime_metrics, s->mmap, NULL, &s->runtime_journal); + r = open_journal(s, true, fn, O_RDWR|O_CREAT, false, &s->runtime_metrics, &s->runtime_journal); if (r < 0) return log_error_errno(r, "Failed to open runtime journal: %m"); } if (s->runtime_journal) { - server_fix_perms(s, s->runtime_journal, 0); + server_add_acls(s->runtime_journal, 0); (void) determine_space_for(s, &s->runtime_metrics, "/run/log/journal/", "Runtime journal", true, true, NULL, NULL); } } @@ -1112,7 +1140,11 @@ finish: sd_journal_close(j); - server_driver_message(s, SD_ID128_NULL, "Time spent on flushing to /var is %s for %u entries.", format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0), n); + server_driver_message(s, SD_ID128_NULL, + LOG_MESSAGE("Time spent on flushing to /var is %s for %u entries.", + format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0), + n), + NULL); return r; } @@ -1369,7 +1401,7 @@ static int server_parse_proc_cmdline(Server *s) { p = line; for(;;) { - _cleanup_free_ char *word; + _cleanup_free_ char *word = NULL; r = extract_first_word(&p, &word, NULL, 0); if (r < 0) diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index dcc21bb7c..b9551dda1 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -157,9 +155,10 @@ struct Server { #define N_IOVEC_KERNEL_FIELDS 64 #define N_IOVEC_UDEV_FIELDS 32 #define N_IOVEC_OBJECT_FIELDS 12 +#define N_IOVEC_PAYLOAD_FIELDS 15 void server_dispatch_message(Server *s, struct iovec *iovec, unsigned n, unsigned m, const struct ucred *ucred, const struct timeval *tv, const char *label, size_t label_len, const char *unit_id, int priority, pid_t object_pid); -void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,4); +void server_driver_message(Server *s, sd_id128_t message_id, const char *format, ...) _printf_(3,0) _sentinel_; /* gperf lookup function */ const struct ConfigPerfItem* journald_gperf_lookup(const char *key, unsigned length); @@ -174,7 +173,6 @@ int config_parse_split_mode(const char *unit, const char *filename, unsigned lin const char *split_mode_to_string(SplitMode s) _const_; SplitMode split_mode_from_string(const char *s) _pure_; -void server_fix_perms(Server *s, JournalFile *f, uid_t uid); int server_init(Server *s); void server_done(Server *s); void server_sync(Server *s); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index fb800782f..6e8b405b5 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -239,14 +237,14 @@ static int stdout_stream_log(StdoutStream *s, const char *p) { assert(s); assert(p); - if (isempty(p)) - return 0; - priority = s->priority; if (s->level_prefix) syslog_parse_priority(&p, &priority, false); + if (isempty(p)) + return 0; + if (s->forward_to_syslog || s->server->forward_to_syslog) server_forward_syslog(s->server, syslog_fixup_facility(priority), s->identifier, p, &s->ucred, NULL); @@ -286,10 +284,12 @@ static int stdout_stream_log(StdoutStream *s, const char *p) { static int stdout_stream_line(StdoutStream *s, char *p) { int r; + char *orig; assert(s); assert(p); + orig = p; p = strstrip(p); switch (s->state) { @@ -378,7 +378,7 @@ static int stdout_stream_line(StdoutStream *s, char *p) { return 0; case STDOUT_STREAM_RUNNING: - return stdout_stream_log(s, p); + return stdout_stream_log(s, orig); } assert_not_reached("Unknown stream state"); @@ -491,7 +491,7 @@ static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) { if (r < 0) return log_error_errno(r, "Failed to determine peer credentials: %m"); - if (mac_selinux_use()) { + if (mac_selinux_have()) { r = getpeersec(fd, &stream->label); if (r < 0 && r != -EOPNOTSUPP) (void) log_warning_errno(r, "Failed to determine peer security context: %m"); @@ -731,7 +731,7 @@ int server_open_stdout_socket(Server *s) { if (r < 0) return log_error_errno(r, "Failed to add stdout server fd to event source: %m"); - r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+10); + r = sd_event_source_set_priority(s->stdout_event_source, SD_EVENT_PRIORITY_NORMAL+5); if (r < 0) return log_error_errno(r, "Failed to adjust priority of stdout server event source: %m"); diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h index e3497f0de..db4c67fae 100644 --- a/src/journal/journald-stream.h +++ b/src/journal/journald-stream.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index f3ac1a7ae..5153fd0cc 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -326,7 +324,7 @@ void server_process_syslog_message( size_t label_len) { char syslog_priority[sizeof("PRIORITY=") + DECIMAL_STR_MAX(int)], - syslog_facility[sizeof("SYSLOG_FACILITY") + DECIMAL_STR_MAX(int)]; + syslog_facility[sizeof("SYSLOG_FACILITY=") + DECIMAL_STR_MAX(int)]; const char *message = NULL, *syslog_identifier = NULL, *syslog_pid = NULL; struct iovec iovec[N_IOVEC_META_FIELDS + 6]; unsigned n = 0; @@ -357,11 +355,11 @@ void server_process_syslog_message( IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=syslog"); - sprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK); + xsprintf(syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK); IOVEC_SET_STRING(iovec[n++], syslog_priority); if (priority & LOG_FACMASK) { - sprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)); + xsprintf(syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)); IOVEC_SET_STRING(iovec[n++], syslog_facility); } @@ -415,7 +413,7 @@ int server_open_syslog_socket(Server *s) { return log_error_errno(errno, "SO_PASSCRED failed: %m"); #ifdef HAVE_SELINUX - if (mac_selinux_use()) { + if (mac_selinux_have()) { r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)); if (r < 0) log_warning_errno(errno, "SO_PASSSEC failed: %m"); @@ -430,6 +428,10 @@ int server_open_syslog_socket(Server *s) { if (r < 0) return log_error_errno(r, "Failed to add syslog server fd to event loop: %m"); + r = sd_event_source_set_priority(s->syslog_event_source, SD_EVENT_PRIORITY_NORMAL+5); + if (r < 0) + return log_error_errno(r, "Failed to adjust syslog event source priority: %m"); + return 0; } @@ -444,7 +446,10 @@ void server_maybe_warn_forward_syslog_missed(Server *s) { if (s->last_warn_forward_syslog_missed + WARN_FORWARD_SYSLOG_MISSED_USEC > n) return; - server_driver_message(s, SD_MESSAGE_FORWARD_SYSLOG_MISSED, "Forwarding to syslog missed %u messages.", s->n_forward_syslog_missed); + server_driver_message(s, SD_MESSAGE_FORWARD_SYSLOG_MISSED, + LOG_MESSAGE("Forwarding to syslog missed %u messages.", + s->n_forward_syslog_missed), + NULL); s->n_forward_syslog_missed = 0; s->last_warn_forward_syslog_missed = n; diff --git a/src/journal/journald-syslog.h b/src/journal/journald-syslog.h index 3774ebdf0..46ad71531 100644 --- a/src/journal/journald-syslog.h +++ b/src/journal/journald-syslog.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journald-wall.c b/src/journal/journald-wall.c index 88bea3b86..4d91fafff 100644 --- a/src/journal/journald-wall.c +++ b/src/journal/journald-wall.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/journald-wall.h b/src/journal/journald-wall.h index 45c52854a..ebc2b89fa 100644 --- a/src/journal/journald-wall.h +++ b/src/journal/journald-wall.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/journald.c b/src/journal/journald.c index b9f5c099e..272acb71c 100644 --- a/src/journal/journald.c +++ b/src/journal/journald.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -58,7 +56,9 @@ int main(int argc, char *argv[]) { server_flush_dev_kmsg(&server); log_debug("systemd-journald running as pid "PID_FMT, getpid()); - server_driver_message(&server, SD_MESSAGE_JOURNAL_START, "Journal started"); + server_driver_message(&server, SD_MESSAGE_JOURNAL_START, + LOG_MESSAGE("Journal started"), + NULL); for (;;) { usec_t t = USEC_INFINITY, n; @@ -109,7 +109,9 @@ int main(int argc, char *argv[]) { } log_debug("systemd-journald stopped as pid "PID_FMT, getpid()); - server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, "Journal stopped"); + server_driver_message(&server, SD_MESSAGE_JOURNAL_STOP, + LOG_MESSAGE("Journal stopped"), + NULL); finish: server_done(&server); diff --git a/src/journal/lookup3.h b/src/journal/lookup3.h index 3224473a6..787921ffb 100644 --- a/src/journal/lookup3.h +++ b/src/journal/lookup3.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once #include diff --git a/src/journal/mmap-cache.c b/src/journal/mmap-cache.c index 5a07ddda7..9c0ce8ccb 100644 --- a/src/journal/mmap-cache.c +++ b/src/journal/mmap-cache.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -40,9 +38,9 @@ typedef struct FileDescriptor FileDescriptor; struct Window { MMapCache *cache; - bool invalidated; - bool keep_always; - bool in_unused; + bool invalidated:1; + bool keep_always:1; + bool in_unused:1; int prot; void *ptr; @@ -78,7 +76,6 @@ struct MMapCache { unsigned n_hit, n_missed; - Hashmap *fds; Context *contexts[MMAP_CACHE_MAX_CONTEXTS]; @@ -174,10 +171,11 @@ _pure_ static bool window_matches(Window *w, int fd, int prot, uint64_t offset, offset + size <= w->offset + w->size; } -static Window *window_add(MMapCache *m) { +static Window *window_add(MMapCache *m, FileDescriptor *fd, int prot, bool keep_always, uint64_t offset, size_t size, void *ptr) { Window *w; assert(m); + assert(fd); if (!m->last_unused || m->n_windows <= WINDOWS_MIN) { @@ -195,6 +193,15 @@ static Window *window_add(MMapCache *m) { } w->cache = m; + w->fd = fd; + w->prot = prot; + w->keep_always = keep_always; + w->offset = offset; + w->size = size; + w->ptr = ptr; + + LIST_PREPEND(by_fd, fd->windows, w); + return w; } @@ -348,7 +355,10 @@ static void mmap_cache_free(MMapCache *m) { } MMapCache* mmap_cache_unref(MMapCache *m) { - assert(m); + + if (!m) + return NULL; + assert(m->n_ref > 0); m->n_ref --; @@ -405,7 +415,7 @@ static int try_context( if (c->window->fd->sigbus) return -EIO; - c->window->keep_always |= keep_always; + c->window->keep_always = c->window->keep_always || keep_always; *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset); return 1; @@ -451,12 +461,39 @@ static int find_mmap( return -ENOMEM; context_attach_window(c, w); - w->keep_always += keep_always; + w->keep_always = w->keep_always || keep_always; *ret = (uint8_t*) w->ptr + (offset - w->offset); return 1; } +static int mmap_try_harder(MMapCache *m, void *addr, int fd, int prot, int flags, uint64_t offset, size_t size, void **res) { + void *ptr; + + assert(m); + assert(fd >= 0); + assert(res); + + for (;;) { + int r; + + ptr = mmap(addr, size, prot, flags, fd, offset); + if (ptr != MAP_FAILED) + break; + if (errno != ENOMEM) + return -errno; + + r = make_room(m); + if (r < 0) + return r; + if (r == 0) + return -ENOMEM; + } + + *res = ptr; + return 0; +} + static int add_mmap( MMapCache *m, int fd, @@ -510,19 +547,9 @@ static int add_mmap( wsize = PAGE_ALIGN(st->st_size - woffset); } - for (;;) { - d = mmap(NULL, wsize, prot, MAP_SHARED, fd, woffset); - if (d != MAP_FAILED) - break; - if (errno != ENOMEM) - return -errno; - - r = make_room(m); - if (r < 0) - return r; - if (r == 0) - return -ENOMEM; - } + r = mmap_try_harder(m, NULL, fd, prot, MAP_SHARED, woffset, wsize, &d); + if (r < 0) + return r; c = context_add(m, context); if (!c) @@ -532,19 +559,10 @@ static int add_mmap( if (!f) goto outofmem; - w = window_add(m); + w = window_add(m, f, prot, keep_always, woffset, wsize, d); if (!w) goto outofmem; - w->keep_always = keep_always; - w->ptr = d; - w->offset = woffset; - w->prot = prot; - w->size = wsize; - w->fd = f; - - LIST_PREPEND(by_fd, f->windows, w); - context_detach_window(c); c->window = w; LIST_PREPEND(by_window, w->contexts, c); diff --git a/src/journal/mmap-cache.h b/src/journal/mmap-cache.h index 37ea7b4a9..199d94464 100644 --- a/src/journal/mmap-cache.h +++ b/src/journal/mmap-cache.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 5cde7f17f..5a2a28a8d 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -1292,6 +1290,12 @@ static int add_file(sd_journal *j, const char *prefix, const char *filename) { return 0; path = strjoina(prefix, "/", filename); + + if (!j->has_runtime_files && path_startswith(path, "/run/log/journal")) + j->has_runtime_files = true; + else if (!j->has_persistent_files && path_startswith(path, "/var/log/journal")) + j->has_persistent_files = true; + return add_any_file(j, path); } @@ -1332,6 +1336,13 @@ static void remove_file_real(sd_journal *j, JournalFile *f) { j->unique_file_lost = true; } + if (j->fields_file == f) { + j->fields_file = ordered_hashmap_next(j->files, j->fields_file->path); + j->fields_offset = 0; + if (!j->fields_file) + j->fields_file_lost = true; + } + journal_file_close(f); j->current_invalidate_counter ++; @@ -1800,6 +1811,7 @@ _public_ void sd_journal_close(sd_journal *j) { free(j->path); free(j->prefix); free(j->unique_field); + free(j->fields_buffer); free(j); } @@ -1940,10 +1952,14 @@ _public_ int sd_journal_get_data(sd_journal *j, const char *field, const void ** compression = o->object.flags & OBJECT_COMPRESSION_MASK; if (compression) { #if defined(HAVE_XZ) || defined(HAVE_LZ4) - if (decompress_startswith(compression, + r = decompress_startswith(compression, o->data.payload, l, &f->compress_buffer, &f->compress_buffer_size, - field, field_length, '=')) { + field, field_length, '='); + if (r < 0) + log_debug_errno(r, "Cannot decompress %s object of length %zu at offset "OFSfmt": %m", + object_compressed_to_string(compression), l, p); + else if (r > 0) { size_t rsize; @@ -2502,24 +2518,20 @@ _public_ int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_ * traversed files. */ found = false; ORDERED_HASHMAP_FOREACH(of, j->files, i) { - Object *oo; - uint64_t op; - if (of == j->unique_file) break; - /* Skip this file it didn't have any fields - * indexed */ - if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && - le64toh(of->header->n_fields) <= 0) + /* Skip this file it didn't have any fields indexed */ + if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0) continue; - r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), &oo, &op); + r = journal_file_find_data_object_with_hash(of, odata, ol, le64toh(o->data.hash), NULL, NULL); if (r < 0) return r; - - if (r > 0) + if (r > 0) { found = true; + break; + } } if (found) @@ -2542,6 +2554,154 @@ _public_ void sd_journal_restart_unique(sd_journal *j) { j->unique_file_lost = false; } +_public_ int sd_journal_enumerate_fields(sd_journal *j, const char **field) { + int r; + + assert_return(j, -EINVAL); + assert_return(!journal_pid_changed(j), -ECHILD); + assert_return(field, -EINVAL); + + if (!j->fields_file) { + if (j->fields_file_lost) + return 0; + + j->fields_file = ordered_hashmap_first(j->files); + if (!j->fields_file) + return 0; + + j->fields_hash_table_index = 0; + j->fields_offset = 0; + } + + for (;;) { + JournalFile *f, *of; + Iterator i; + uint64_t m; + Object *o; + size_t sz; + bool found; + + f = j->fields_file; + + if (j->fields_offset == 0) { + bool eof = false; + + /* We are not yet positioned at any field. Let's pick the first one */ + r = journal_file_map_field_hash_table(f); + if (r < 0) + return r; + + m = le64toh(f->header->field_hash_table_size) / sizeof(HashItem); + for (;;) { + if (j->fields_hash_table_index >= m) { + /* Reached the end of the hash table, go to the next file. */ + eof = true; + break; + } + + j->fields_offset = le64toh(f->field_hash_table[j->fields_hash_table_index].head_hash_offset); + + if (j->fields_offset != 0) + break; + + /* Empty hash table bucket, go to next one */ + j->fields_hash_table_index++; + } + + if (eof) { + /* Proceed with next file */ + j->fields_file = ordered_hashmap_next(j->files, f->path); + if (!j->fields_file) { + *field = NULL; + return 0; + } + + j->fields_offset = 0; + j->fields_hash_table_index = 0; + continue; + } + + } else { + /* We are already positioned at a field. If so, let's figure out the next field from it */ + + r = journal_file_move_to_object(f, OBJECT_FIELD, j->fields_offset, &o); + if (r < 0) + return r; + + j->fields_offset = le64toh(o->field.next_hash_offset); + if (j->fields_offset == 0) { + /* Reached the end of the hash table chain */ + j->fields_hash_table_index++; + continue; + } + } + + /* We use OBJECT_UNUSED here, so that the iterator below doesn't remove our mmap window */ + r = journal_file_move_to_object(f, OBJECT_UNUSED, j->fields_offset, &o); + if (r < 0) + return r; + + /* Because we used OBJECT_UNUSED above, we need to do our type check manually */ + if (o->object.type != OBJECT_FIELD) { + log_debug("%s:offset " OFSfmt ": object has type %i, expected %i", f->path, j->fields_offset, o->object.type, OBJECT_FIELD); + return -EBADMSG; + } + + sz = le64toh(o->object.size) - offsetof(Object, field.payload); + + /* Let's see if we already returned this field name before. */ + found = false; + ORDERED_HASHMAP_FOREACH(of, j->files, i) { + if (of == f) + break; + + /* Skip this file it didn't have any fields indexed */ + if (JOURNAL_HEADER_CONTAINS(of->header, n_fields) && le64toh(of->header->n_fields) <= 0) + continue; + + r = journal_file_find_field_object_with_hash(of, o->field.payload, sz, le64toh(o->field.hash), NULL, NULL); + if (r < 0) + return r; + if (r > 0) { + found = true; + break; + } + } + + if (found) + continue; + + /* Check if this is really a valid string containing no NUL byte */ + if (memchr(o->field.payload, 0, sz)) + return -EBADMSG; + + if (sz > j->data_threshold) + sz = j->data_threshold; + + if (!GREEDY_REALLOC(j->fields_buffer, j->fields_buffer_allocated, sz + 1)) + return -ENOMEM; + + memcpy(j->fields_buffer, o->field.payload, sz); + j->fields_buffer[sz] = 0; + + if (!field_is_valid(j->fields_buffer)) + return -EBADMSG; + + *field = j->fields_buffer; + return 1; + } +} + +_public_ void sd_journal_restart_fields(sd_journal *j) { + if (!j) + return; + + j->fields_file = NULL; + j->fields_hash_table_index = 0; + j->fields_offset = 0; + j->fields_file_lost = false; +} + _public_ int sd_journal_reliable_fd(sd_journal *j) { assert_return(j, -EINVAL); assert_return(!journal_pid_changed(j), -ECHILD); @@ -2626,3 +2786,15 @@ _public_ int sd_journal_get_data_threshold(sd_journal *j, size_t *sz) { *sz = j->data_threshold; return 0; } + +_public_ int sd_journal_has_runtime_files(sd_journal *j) { + assert_return(j, -EINVAL); + + return j->has_runtime_files; +} + +_public_ int sd_journal_has_persistent_files(sd_journal *j) { + assert_return(j, -EINVAL); + + return j->has_persistent_files; +} diff --git a/src/journal/test-audit-type.c b/src/journal/test-audit-type.c index 7946cf3c4..88a2e6d9d 100644 --- a/src/journal/test-audit-type.c +++ b/src/journal/test-audit-type.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/test-catalog.c b/src/journal/test-catalog.c index 25980b774..da6fcbca4 100644 --- a/src/journal/test-catalog.c +++ b/src/journal/test-catalog.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -46,61 +44,135 @@ static const char *no_catalog_dirs[] = { NULL }; -static void test_import(Hashmap *h, struct strbuf *sb, - const char* contents, ssize_t size, int code) { +static Hashmap * test_import(const char* contents, ssize_t size, int code) { int r; char name[] = "/tmp/test-catalog.XXXXXX"; _cleanup_close_ int fd; + Hashmap *h; + + if (size < 0) + size = strlen(contents); + + assert_se(h = hashmap_new(&catalog_hash_ops)); fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); assert_se(write(fd, contents, size) == size); - r = catalog_import_file(h, sb, name); + r = catalog_import_file(h, name); assert_se(r == code); unlink(name); + + return h; } -static void test_catalog_importing(void) { - Hashmap *h; - struct strbuf *sb; +static void test_catalog_import_invalid(void) { + _cleanup_hashmap_free_free_free_ Hashmap *h = NULL; - assert_se(h = hashmap_new(&catalog_hash_ops)); - assert_se(sb = strbuf_new()); - -#define BUF "xxx" - test_import(h, sb, BUF, sizeof(BUF), -EINVAL); -#undef BUF + h = test_import("xxx", -1, -EINVAL); assert_se(hashmap_isempty(h)); - log_debug("----------------------------------------"); +} -#define BUF \ +static void test_catalog_import_badid(void) { + _cleanup_hashmap_free_free_free_ Hashmap *h = NULL; + const char *input = "-- 0027229ca0644181a76c4e92458afaff dededededededededededededededede\n" \ "Subject: message\n" \ "\n" \ -"payload\n" - test_import(h, sb, BUF, sizeof(BUF), -EINVAL); -#undef BUF +"payload\n"; + h = test_import(input, -1, -EINVAL); +} - log_debug("----------------------------------------"); +static void test_catalog_import_one(void) { + _cleanup_hashmap_free_free_free_ Hashmap *h = NULL; + char *payload; + Iterator j; -#define BUF \ + const char *input = "-- 0027229ca0644181a76c4e92458afaff dededededededededededededededed\n" \ "Subject: message\n" \ "\n" \ -"payload\n" - test_import(h, sb, BUF, sizeof(BUF), 0); -#undef BUF +"payload\n"; + const char *expect = +"Subject: message\n" \ +"\n" \ +"payload\n"; + h = test_import(input, -1, 0); assert_se(hashmap_size(h) == 1); - log_debug("----------------------------------------"); - - hashmap_free_free(h); - strbuf_cleanup(sb); + HASHMAP_FOREACH(payload, h, j) { + assert_se(streq(expect, payload)); + } } +static void test_catalog_import_merge(void) { + _cleanup_hashmap_free_free_free_ Hashmap *h = NULL; + char *payload; + Iterator j; + + const char *input = +"-- 0027229ca0644181a76c4e92458afaff dededededededededededededededed\n" \ +"Subject: message\n" \ +"Defined-By: me\n" \ +"\n" \ +"payload\n" \ +"\n" \ +"-- 0027229ca0644181a76c4e92458afaff dededededededededededededededed\n" \ +"Subject: override subject\n" \ +"X-Header: hello\n" \ +"\n" \ +"override payload\n"; + + const char *combined = +"Subject: override subject\n" \ +"X-Header: hello\n" \ +"Subject: message\n" \ +"Defined-By: me\n" \ +"\n" \ +"override payload\n"; + + h = test_import(input, -1, 0); + assert_se(hashmap_size(h) == 1); + + HASHMAP_FOREACH(payload, h, j) { + assert_se(streq(combined, payload)); + } +} + +static void test_catalog_import_merge_no_body(void) { + _cleanup_hashmap_free_free_free_ Hashmap *h = NULL; + char *payload; + Iterator j; + + const char *input = +"-- 0027229ca0644181a76c4e92458afaff dededededededededededededededed\n" \ +"Subject: message\n" \ +"Defined-By: me\n" \ +"\n" \ +"payload\n" \ +"\n" \ +"-- 0027229ca0644181a76c4e92458afaff dededededededededededededededed\n" \ +"Subject: override subject\n" \ +"X-Header: hello\n" \ +"\n"; + + const char *combined = +"Subject: override subject\n" \ +"X-Header: hello\n" \ +"Subject: message\n" \ +"Defined-By: me\n" \ +"\n" \ +"payload\n"; + + h = test_import(input, -1, 0); + assert_se(hashmap_size(h) == 1); + + HASHMAP_FOREACH(payload, h, j) { + assert_se(streq(combined, payload)); + } +} static const char* database = NULL; @@ -166,7 +238,11 @@ int main(int argc, char *argv[]) { test_catalog_file_lang(); - test_catalog_importing(); + test_catalog_import_invalid(); + test_catalog_import_badid(); + test_catalog_import_one(); + test_catalog_import_merge(); + test_catalog_import_merge_no_body(); test_catalog_update(); diff --git a/src/journal/test-compress-benchmark.c b/src/journal/test-compress-benchmark.c index 93ea9c631..5b2d130cd 100644 --- a/src/journal/test-compress-benchmark.c +++ b/src/journal/test-compress-benchmark.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd @@ -27,7 +25,8 @@ #include "string-util.h" #include "util.h" -typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, size_t *dst_size); +typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, + size_t dst_alloc_size, size_t *dst_size); typedef int (decompress_t)(const void *src, uint64_t src_size, void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max); @@ -111,8 +110,8 @@ static void test_compress_decompress(const char* label, const char* type, memzero(buf, MIN(size + 1000, MAX_SIZE)); - r = compress(text, size, buf, &j); - /* assume compression must be successful except for small inputs */ + r = compress(text, size, buf, size, &j); + /* assume compression must be successful except for small or random inputs */ assert_se(r == 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random")); /* check for overwrites */ diff --git a/src/journal/test-compress.c b/src/journal/test-compress.c index b9d90a898..68c9a4d76 100644 --- a/src/journal/test-compress.c +++ b/src/journal/test-compress.c @@ -17,6 +17,10 @@ along with systemd; If not, see . ***/ +#ifdef HAVE_LZ4 +#include +#endif + #include "alloc-util.h" #include "compress.h" #include "fd-util.h" @@ -38,7 +42,7 @@ #endif typedef int (compress_blob_t)(const void *src, uint64_t src_size, - void *dst, size_t *dst_size); + void *dst, size_t dst_alloc_size, size_t *dst_size); typedef int (decompress_blob_t)(const void *src, uint64_t src_size, void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max); @@ -57,15 +61,14 @@ static void test_compress_decompress(int compression, size_t data_len, bool may_fail) { char compressed[512]; - size_t csize = 512; - size_t usize = 0; + size_t csize, usize = 0; _cleanup_free_ char *decompressed = NULL; int r; log_info("/* testing %s %s blob compression/decompression */", object_compressed_to_string(compression), data); - r = compress(data, data_len, compressed, &csize); + r = compress(data, data_len, compressed, sizeof(compressed), &csize); if (r == -ENOBUFS) { log_info_errno(r, "compression failed: %m"); assert_se(may_fail); @@ -101,43 +104,45 @@ static void test_decompress_startswith(int compression, size_t data_len, bool may_fail) { - char compressed[512]; - size_t csize = 512; - size_t usize = 0; - _cleanup_free_ char *decompressed = NULL; + char *compressed; + _cleanup_free_ char *compressed1 = NULL, *compressed2 = NULL, *decompressed = NULL; + size_t csize, usize = 0, len; int r; - log_info("/* testing decompress_startswith with %s on %s text*/", + log_info("/* testing decompress_startswith with %s on %.20s text*/", object_compressed_to_string(compression), data); - r = compress(data, data_len, compressed, &csize); +#define BUFSIZE_1 512 +#define BUFSIZE_2 20000 + + compressed = compressed1 = malloc(BUFSIZE_1); + assert_se(compressed1); + r = compress(data, data_len, compressed, BUFSIZE_1, &csize); if (r == -ENOBUFS) { log_info_errno(r, "compression failed: %m"); assert_se(may_fail); - return; + + compressed = compressed2 = malloc(BUFSIZE_2); + assert_se(compressed2); + r = compress(data, data_len, compressed, BUFSIZE_2, &csize); + assert(r == 0); } assert_se(r == 0); - assert_se(decompress_sw(compressed, - csize, - (void **) &decompressed, - &usize, - data, strlen(data), '\0') > 0); - assert_se(decompress_sw(compressed, - csize, - (void **) &decompressed, - &usize, - data, strlen(data), 'w') == 0); - assert_se(decompress_sw(compressed, - csize, - (void **) &decompressed, - &usize, - "barbarbar", 9, ' ') == 0); - assert_se(decompress_sw(compressed, - csize, - (void **) &decompressed, - &usize, - data, strlen(data), '\0') > 0); + len = strlen(data); + + r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len, '\0'); + assert_se(r > 0); + r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len, 'w'); + assert_se(r == 0); + r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, "barbarbar", 9, ' '); + assert_se(r == 0); + r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len - 1, data[len-1]); + assert_se(r > 0); + r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len - 1, 'w'); + assert_se(r == 0); + r = decompress_sw(compressed, csize, (void **) &decompressed, &usize, data, len, '\0'); + assert_se(r > 0); } static void test_compress_stream(int compression, @@ -199,6 +204,44 @@ static void test_compress_stream(int compression, assert_se(unlink(pattern2) == 0); } +#ifdef HAVE_LZ4 +static void test_lz4_decompress_partial(void) { + char buf[20000]; + size_t buf_size = sizeof(buf), compressed; + int r; + _cleanup_free_ char *huge = NULL; + +#define HUGE_SIZE (4096*1024) + huge = malloc(HUGE_SIZE); + memset(huge, 'x', HUGE_SIZE); + memcpy(huge, "HUGE=", 5); + + r = LZ4_compress_limitedOutput(huge, buf, HUGE_SIZE, buf_size); + assert_se(r >= 0); + compressed = r; + log_info("Compressed %i → %zu", HUGE_SIZE, compressed); + + r = LZ4_decompress_safe(buf, huge, r, HUGE_SIZE); + assert_se(r >= 0); + log_info("Decompressed → %i", r); + + r = LZ4_decompress_safe_partial(buf, huge, + compressed, + 12, HUGE_SIZE); + assert_se(r >= 0); + log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE, r); + + /* We expect this to fail, because that's how current lz4 works. If this + * call succeeds, then lz4 has been fixed, and we need to change our code. + */ + r = LZ4_decompress_safe_partial(buf, huge, + compressed, + 12, HUGE_SIZE-1); + assert_se(r < 0); + log_info("Decompressed partial %i/%i → %i", 12, HUGE_SIZE-1, r); +} +#endif + int main(int argc, char *argv[]) { const char text[] = "text\0foofoofoofoo AAAA aaaaaaaaa ghost busters barbarbar FFF" @@ -206,6 +249,11 @@ int main(int argc, char *argv[]) { char data[512] = "random\0"; + char huge[4096*1024]; + memset(huge, 'x', sizeof(huge)); + memcpy(huge, "HUGE=", 5); + char_array_0(huge); + log_set_max_level(LOG_DEBUG); random_bytes(data + 7, sizeof(data) - 7); @@ -215,12 +263,17 @@ int main(int argc, char *argv[]) { text, sizeof(text), false); test_compress_decompress(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_blob_xz, data, sizeof(data), true); + test_decompress_startswith(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_startswith_xz, text, sizeof(text), false); test_decompress_startswith(OBJECT_COMPRESSED_XZ, compress_blob_xz, decompress_startswith_xz, data, sizeof(data), true); + test_decompress_startswith(OBJECT_COMPRESSED_XZ, + compress_blob_xz, decompress_startswith_xz, + huge, sizeof(huge), true); + test_compress_stream(OBJECT_COMPRESSED_XZ, "xzcat", compress_stream_xz, decompress_stream_xz, argv[0]); #else @@ -232,15 +285,21 @@ int main(int argc, char *argv[]) { text, sizeof(text), false); test_compress_decompress(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_blob_lz4, data, sizeof(data), true); + test_decompress_startswith(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_startswith_lz4, text, sizeof(text), false); test_decompress_startswith(OBJECT_COMPRESSED_LZ4, compress_blob_lz4, decompress_startswith_lz4, data, sizeof(data), true); + test_decompress_startswith(OBJECT_COMPRESSED_LZ4, + compress_blob_lz4, decompress_startswith_lz4, + huge, sizeof(huge), true); test_compress_stream(OBJECT_COMPRESSED_LZ4, "lz4cat", compress_stream_lz4, decompress_stream_lz4, argv[0]); + + test_lz4_decompress_partial(); #else log_info("/* LZ4 test skipped */"); #endif diff --git a/src/journal/test-journal-enum.c b/src/journal/test-journal-enum.c index 8f56ea190..e5e9d9dcb 100644 --- a/src/journal/test-journal-enum.c +++ b/src/journal/test-journal-enum.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -29,7 +27,7 @@ int main(int argc, char *argv[]) { unsigned n = 0; - _cleanup_journal_close_ sd_journal*j = NULL; + _cleanup_(sd_journal_closep) sd_journal*j = NULL; log_set_max_level(LOG_DEBUG); diff --git a/src/journal/test-journal-flush.c b/src/journal/test-journal-flush.c index 03d1522e2..7bd9c4036 100644 --- a/src/journal/test-journal-flush.c +++ b/src/journal/test-journal-flush.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/test-journal-init.c b/src/journal/test-journal-init.c index 142da8504..ef21e2d05 100644 --- a/src/journal/test-journal-init.c +++ b/src/journal/test-journal-init.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/test-journal-interleaving.c b/src/journal/test-journal-interleaving.c index 5c055ef74..7f9499088 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/journal/test-journal-interleaving.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/test-journal-match.c b/src/journal/test-journal-match.c index abefedb99..3ab554b9b 100644 --- a/src/journal/test-journal-match.c +++ b/src/journal/test-journal-match.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -30,7 +28,7 @@ #include "util.h" int main(int argc, char *argv[]) { - _cleanup_journal_close_ sd_journal*j; + _cleanup_(sd_journal_closep) sd_journal*j = NULL; _cleanup_free_ char *t; log_set_max_level(LOG_DEBUG); diff --git a/src/journal/test-journal-send.c b/src/journal/test-journal-send.c index 694376670..d70f0b0bc 100644 --- a/src/journal/test-journal-send.c +++ b/src/journal/test-journal-send.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,59 +17,84 @@ along with systemd; If not, see . ***/ +#include #include #include #include "sd-journal.h" -#include "log.h" +#include "macro.h" int main(int argc, char *argv[]) { char huge[4096*1024]; - log_set_max_level(LOG_DEBUG); + /* utf-8 and non-utf-8, message-less and message-ful iovecs */ + struct iovec graph1[] = { + {(char*) "GRAPH=graph", strlen("GRAPH=graph")} + }; + struct iovec graph2[] = { + {(char*) "GRAPH=graph\n", strlen("GRAPH=graph\n")} + }; + struct iovec message1[] = { + {(char*) "MESSAGE=graph", strlen("MESSAGE=graph")} + }; + struct iovec message2[] = { + {(char*) "MESSAGE=graph\n", strlen("MESSAGE=graph\n")} + }; - sd_journal_print(LOG_INFO, "piepapo"); + assert_se(sd_journal_print(LOG_INFO, "piepapo") == 0); - sd_journal_send("MESSAGE=foobar", - "VALUE=%i", 7, - NULL); + assert_se(sd_journal_send("MESSAGE=foobar", + "VALUE=%i", 7, + NULL) == 0); errno = ENOENT; - sd_journal_perror("Foobar"); + assert_se(sd_journal_perror("Foobar") == 0); - sd_journal_perror(""); + assert_se(sd_journal_perror("") == 0); memset(huge, 'x', sizeof(huge)); memcpy(huge, "HUGE=", 5); char_array_0(huge); - sd_journal_send("MESSAGE=Huge field attached", - huge, - NULL); + assert_se(sd_journal_send("MESSAGE=Huge field attached", + huge, + NULL) == 0); - sd_journal_send("MESSAGE=uiui", - "VALUE=A", - "VALUE=B", - "VALUE=C", - "SINGLETON=1", - "OTHERVALUE=X", - "OTHERVALUE=Y", - "WITH_BINARY=this is a binary value \a", - NULL); + assert_se(sd_journal_send("MESSAGE=uiui", + "VALUE=A", + "VALUE=B", + "VALUE=C", + "SINGLETON=1", + "OTHERVALUE=X", + "OTHERVALUE=Y", + "WITH_BINARY=this is a binary value \a", + NULL) == 0); syslog(LOG_NOTICE, "Hello World!"); - sd_journal_print(LOG_NOTICE, "Hello World"); + assert_se(sd_journal_print(LOG_NOTICE, "Hello World") == 0); - sd_journal_send("MESSAGE=Hello World!", - "MESSAGE_ID=52fb62f99e2c49d89cfbf9d6de5e3555", - "PRIORITY=5", - "HOME=%s", getenv("HOME"), - "TERM=%s", getenv("TERM"), - "PAGE_SIZE=%li", sysconf(_SC_PAGESIZE), - "N_CPUS=%li", sysconf(_SC_NPROCESSORS_ONLN), - NULL); + assert_se(sd_journal_send("MESSAGE=Hello World!", + "MESSAGE_ID=52fb62f99e2c49d89cfbf9d6de5e3555", + "PRIORITY=5", + "HOME=%s", getenv("HOME"), + "TERM=%s", getenv("TERM"), + "PAGE_SIZE=%li", sysconf(_SC_PAGESIZE), + "N_CPUS=%li", sysconf(_SC_NPROCESSORS_ONLN), + NULL) == 0); + + assert_se(sd_journal_sendv(graph1, 1) == 0); + assert_se(sd_journal_sendv(graph2, 1) == 0); + assert_se(sd_journal_sendv(message1, 1) == 0); + assert_se(sd_journal_sendv(message2, 1) == 0); + + /* test without location fields */ +#undef sd_journal_sendv + assert_se(sd_journal_sendv(graph1, 1) == 0); + assert_se(sd_journal_sendv(graph2, 1) == 0); + assert_se(sd_journal_sendv(message1, 1) == 0); + assert_se(sd_journal_sendv(message2, 1) == 0); sleep(1); diff --git a/src/journal/test-journal-stream.c b/src/journal/test-journal-stream.c index 0cbef4b8c..4e6f8c0f7 100644 --- a/src/journal/test-journal-stream.c +++ b/src/journal/test-journal-stream.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -79,7 +77,7 @@ int main(int argc, char *argv[]) { JournalFile *one, *two, *three; char t[] = "/tmp/journal-stream-XXXXXX"; unsigned i; - _cleanup_journal_close_ sd_journal *j = NULL; + _cleanup_(sd_journal_closep) sd_journal *j = NULL; char *z; const void *data; size_t l; diff --git a/src/journal/test-journal-syslog.c b/src/journal/test-journal-syslog.c index 1784187fe..4ff7f3ec2 100644 --- a/src/journal/test-journal-syslog.c +++ b/src/journal/test-journal-syslog.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/test-journal-verify.c b/src/journal/test-journal-verify.c index a7abb11fb..a26c624f4 100644 --- a/src/journal/test-journal-verify.c +++ b/src/journal/test-journal-verify.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/test-journal.c b/src/journal/test-journal.c index 266e0d547..0334b1cd1 100644 --- a/src/journal/test-journal.c +++ b/src/journal/test-journal.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/journal/test-mmap-cache.c b/src/journal/test-mmap-cache.c index fdd48e531..009aabf55 100644 --- a/src/journal/test-mmap-cache.c +++ b/src/journal/test-mmap-cache.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd-network/arp-util.h b/src/libsystemd-network/arp-util.h index 44e5c893a..3ef56b002 100644 --- a/src/libsystemd-network/arp-util.h +++ b/src/libsystemd-network/arp-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,8 +21,8 @@ #include -#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 d7ae86555..1d9ec7be8 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index 2291736f8..93f06f593 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd-network/dhcp-internal.h b/src/libsystemd-network/dhcp-internal.h index a5daaa543..a3b842cda 100644 --- a/src/libsystemd-network/dhcp-internal.h +++ b/src/libsystemd-network/dhcp-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -47,8 +45,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, @@ -62,13 +59,10 @@ void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_client*, sd_dhcp_client_unref); -#define _cleanup_dhcp_client_unref_ _cleanup_(sd_dhcp_client_unrefp) - /* If we are invoking callbacks of a dhcp-client, ensure unreffing the * client from the callback doesn't destroy the object we are working * on */ #define DHCP_CLIENT_DONT_DESTROY(client) \ - _cleanup_dhcp_client_unref_ _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client) + _cleanup_(sd_dhcp_client_unrefp) _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client) #define log_dhcp_client(client, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCP CLIENT (0x%x): " fmt, client->xid, ##__VA_ARGS__) diff --git a/src/libsystemd-network/dhcp-lease-internal.h b/src/libsystemd-network/dhcp-lease-internal.h index c6b97ca8f..82cae2300 100644 --- a/src/libsystemd-network/dhcp-lease-internal.h +++ b/src/libsystemd-network/dhcp-lease-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,12 +23,11 @@ #include #include -#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; @@ -103,6 +100,3 @@ int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file); int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file); - -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_lease*, sd_dhcp_lease_unref); -#define _cleanup_dhcp_lease_unref_ _cleanup_(sd_dhcp_lease_unrefp) diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index a6c410ba9..df1996c8c 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -24,6 +22,9 @@ #include #include +#include "alloc-util.h" +#include "utf8.h" + #include "dhcp-internal.h" static int option_append(uint8_t options[], size_t size, size_t *offset, @@ -31,14 +32,14 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, assert(options); assert(offset); - if (code != DHCP_OPTION_END) + if (code != SD_DHCP_OPTION_END) /* always make sure there is space for an END option */ size --; switch (code) { - case DHCP_OPTION_PAD: - case DHCP_OPTION_END: + case SD_DHCP_OPTION_PAD: + case SD_DHCP_OPTION_END: if (size < *offset + 1) return -ENOBUFS; @@ -88,7 +89,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, else if (r == -ENOBUFS && (file || sname)) { /* did not fit, but we have more buffers to try close the options array and move the offset to its end */ - r = option_append(message->options, size, offset, DHCP_OPTION_END, 0, NULL); + r = option_append(message->options, size, offset, SD_DHCP_OPTION_END, 0, NULL); if (r < 0) return r; @@ -109,7 +110,7 @@ int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, } else if (r == -ENOBUFS && sname) { /* did not fit, but we have more buffers to try close the file array and move the offset to its end */ - r = option_append(message->options, size, offset, DHCP_OPTION_END, 0, NULL); + r = option_append(message->options, size, offset, SD_DHCP_OPTION_END, 0, NULL); if (r < 0) return r; @@ -139,72 +140,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 SD_DHCP_OPTION_PAD: + continue; - case DHCP_OPTION_END: + case SD_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]; + len = options[offset ++]; + + if (buflen < offset + len) + return -EINVAL; + + option = &options[offset]; + + switch (code) { + case SD_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; + case SD_DHCP_OPTION_ERROR_MESSAGE: + if (len == 0) + return -EINVAL; - len = options[++offset]; + if (error_message) { + _cleanup_free_ char *string = NULL; + + /* Accept a trailing NUL byte */ + if (memchr(option, 0, len - 1)) + return -EINVAL; + + string = strndup((const char *) option, len); + if (!string) + return -ENOMEM; + + if (!ascii_is_valid(string)) + return -EINVAL; + + free(*error_message); + *error_message = string; + string = NULL; + } + + break; + case SD_DHCP_OPTION_OVERLOAD: if (len != 1) return -EINVAL; if (overload) - *overload = options[++offset]; - else - offset++; - - offset++; + *overload = *option; break; default: - if (buflen < offset + 3) - return -ENOBUFS; - - code = options[offset]; - len = options[++offset]; - - if (buflen < ++offset + len) - return -EINVAL; - if (cb) - cb(code, len, &options[offset], userdata); - - offset += len; + cb(code, len, option, userdata); break; } + + offset += len; } if (offset < buflen) @@ -213,8 +226,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 +240,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; - return -ENOMSG; + if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) { + *_error_message = error_message; + error_message = NULL; + } + + return message_type; } diff --git a/src/libsystemd-network/dhcp-packet.c b/src/libsystemd-network/dhcp-packet.c index 9ff42b155..8d75d4969 100644 --- a/src/libsystemd-network/dhcp-packet.c +++ b/src/libsystemd-network/dhcp-packet.c @@ -44,7 +44,7 @@ int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, message->magic = htobe32(DHCP_MAGIC_COOKIE); r = dhcp_option_append(message, optlen, &offset, 0, - DHCP_OPTION_MESSAGE_TYPE, 1, &type); + SD_DHCP_OPTION_MESSAGE_TYPE, 1, &type); if (r < 0) return r; diff --git a/src/libsystemd-network/dhcp-protocol.h b/src/libsystemd-network/dhcp-protocol.h index 88a81d286..3e32484c1 100644 --- a/src/libsystemd-network/dhcp-protocol.h +++ b/src/libsystemd-network/dhcp-protocol.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#include #include +#include #include #include "macro.h" @@ -105,42 +103,11 @@ enum { DHCP_OVERLOAD_SNAME = 2, }; +#define DHCP_MAX_FQDN_LENGTH 255 + enum { - DHCP_OPTION_PAD = 0, - DHCP_OPTION_SUBNET_MASK = 1, - DHCP_OPTION_TIME_OFFSET = 2, - DHCP_OPTION_ROUTER = 3, - DHCP_OPTION_DOMAIN_NAME_SERVER = 6, - DHCP_OPTION_HOST_NAME = 12, - DHCP_OPTION_BOOT_FILE_SIZE = 13, - DHCP_OPTION_DOMAIN_NAME = 15, - DHCP_OPTION_ROOT_PATH = 17, - DHCP_OPTION_ENABLE_IP_FORWARDING = 19, - DHCP_OPTION_ENABLE_IP_FORWARDING_NL = 20, - DHCP_OPTION_POLICY_FILTER = 21, - DHCP_OPTION_INTERFACE_MDR = 22, - DHCP_OPTION_INTERFACE_TTL = 23, - DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24, - DHCP_OPTION_INTERFACE_MTU = 26, - DHCP_OPTION_BROADCAST = 28, - DHCP_OPTION_STATIC_ROUTE = 33, - DHCP_OPTION_NTP_SERVER = 42, - DHCP_OPTION_VENDOR_SPECIFIC = 43, - DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, - DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, - DHCP_OPTION_OVERLOAD = 52, - DHCP_OPTION_MESSAGE_TYPE = 53, - DHCP_OPTION_SERVER_IDENTIFIER = 54, - DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, - 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_NEW_POSIX_TIMEZONE = 100, - DHCP_OPTION_NEW_TZDB_TIMEZONE = 101, - DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, - DHCP_OPTION_PRIVATE_BASE = 224, - DHCP_OPTION_PRIVATE_LAST = 254, - DHCP_OPTION_END = 255, + 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 3b88b93d9..bf123f143 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,14 +20,13 @@ #pragma once -#include "sd-event.h" #include "sd-dhcp-server.h" - -#include "hashmap.h" -#include "util.h" -#include "log.h" +#include "sd-event.h" #include "dhcp-internal.h" +#include "hashmap.h" +#include "log.h" +#include "util.h" typedef struct DHCPClientId { size_t length; @@ -85,9 +82,6 @@ typedef struct DHCPRequest { uint32_t lifetime; } DHCPRequest; -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp_server*, sd_dhcp_server_unref); -#define _cleanup_dhcp_server_unref_ _cleanup_(sd_dhcp_server_unrefp) - #define log_dhcp_server(client, fmt, ...) log_internal(LOG_DEBUG, 0, __FILE__, __LINE__, __func__, "DHCP SERVER: " fmt, ##__VA_ARGS__) int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index ecc220f2f..749086d33 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd-network/dhcp6-lease-internal.h b/src/libsystemd-network/dhcp6-lease-internal.h index 4edecf771..14e708ef6 100644 --- a/src/libsystemd-network/dhcp6-lease-internal.h +++ b/src/libsystemd-network/dhcp6-lease-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,6 +23,7 @@ #include #include "sd-dhcp6-lease.h" + #include "dhcp6-internal.h" struct sd_dhcp6_lease { @@ -73,6 +72,3 @@ int dhcp6_lease_set_sntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) ; int dhcp6_lease_new(sd_dhcp6_lease **ret); - -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_lease*, sd_dhcp6_lease_unref); -#define _cleanup_dhcp6_lease_free_ _cleanup_(sd_dhcp6_lease_unrefp) diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 62023a9e4..b07390666 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,6 +21,8 @@ #include #include +#include "sd-dhcp6-client.h" + #include "alloc-util.h" #include "dhcp6-internal.h" #include "dhcp6-protocol.h" @@ -90,11 +90,11 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { assert_return(buf && *buf && buflen && ia, -EINVAL); switch (ia->type) { - case DHCP6_OPTION_IA_NA: + case SD_DHCP6_OPTION_IA_NA: len = DHCP6_OPTION_IA_NA_LEN; break; - case DHCP6_OPTION_IA_TA: + case SD_DHCP6_OPTION_IA_TA: len = DHCP6_OPTION_IA_TA_LEN; break; @@ -117,7 +117,7 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, DHCP6IA *ia) { *buflen -= len; LIST_FOREACH(addresses, addr, ia->addresses) { - r = option_append_hdr(buf, buflen, DHCP6_OPTION_IAADDR, + r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IAADDR, sizeof(addr->iaaddr)); if (r < 0) return r; @@ -196,7 +196,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, assert_return(!ia->addresses, -EINVAL); switch (iatype) { - case DHCP6_OPTION_IA_NA: + case SD_DHCP6_OPTION_IA_NA: if (*buflen < DHCP6_OPTION_IA_NA_LEN + sizeof(DHCP6Option) + sizeof(addr->iaaddr)) { @@ -219,7 +219,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, break; - case DHCP6_OPTION_IA_TA: + case SD_DHCP6_OPTION_IA_TA: if (*buflen < DHCP6_OPTION_IA_TA_LEN + sizeof(DHCP6Option) + sizeof(addr->iaaddr)) { r = -ENOBUFS; @@ -247,7 +247,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, while ((r = option_parse_hdr(buf, buflen, &opt, &optlen)) >= 0) { switch (opt) { - case DHCP6_OPTION_IAADDR: + case SD_DHCP6_OPTION_IAADDR: addr = new0(DHCP6Address, 1); if (!addr) { @@ -274,7 +274,7 @@ int dhcp6_option_parse_ia(uint8_t **buf, size_t *buflen, uint16_t iatype, break; - case DHCP6_OPTION_STATUS_CODE: + case SD_DHCP6_OPTION_STATUS_CODE: if (optlen < sizeof(status)) break; @@ -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/dhcp6-protocol.h b/src/libsystemd-network/dhcp6-protocol.h index b3a28f88b..ee4bdfb07 100644 --- a/src/libsystemd-network/dhcp6-protocol.h +++ b/src/libsystemd-network/dhcp6-protocol.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -98,41 +96,6 @@ enum { _DHCP6_MESSAGE_MAX = 14, }; -enum { - DHCP6_OPTION_CLIENTID = 1, - DHCP6_OPTION_SERVERID = 2, - DHCP6_OPTION_IA_NA = 3, - DHCP6_OPTION_IA_TA = 4, - DHCP6_OPTION_IAADDR = 5, - DHCP6_OPTION_ORO = 6, - DHCP6_OPTION_PREFERENCE = 7, - DHCP6_OPTION_ELAPSED_TIME = 8, - DHCP6_OPTION_RELAY_MSG = 9, - /* option code 10 is unassigned */ - DHCP6_OPTION_AUTH = 11, - DHCP6_OPTION_UNICAST = 12, - DHCP6_OPTION_STATUS_CODE = 13, - DHCP6_OPTION_RAPID_COMMIT = 14, - DHCP6_OPTION_USER_CLASS = 15, - DHCP6_OPTION_VENDOR_CLASS = 16, - DHCP6_OPTION_VENDOR_OPTS = 17, - DHCP6_OPTION_INTERFACE_ID = 18, - DHCP6_OPTION_RECONF_MSG = 19, - DHCP6_OPTION_RECONF_ACCEPT = 20, - - DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ - DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ - - DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */ - - /* option code 35 is unassigned */ - - DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */ - - /* option codes 89-142 are unassigned */ - /* option codes 144-65535 are unassigned */ -}; - enum { DHCP6_NTP_SUBOPTION_SRV_ADDR = 1, DHCP6_NTP_SUBOPTION_MC_ADDR = 2, diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index 91308bf6c..acad9d7d6 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/icmp6-util.h b/src/libsystemd-network/icmp6-util.h index 4eb17e152..2b4dbc76c 100644 --- a/src/libsystemd-network/icmp6-util.h +++ b/src/libsystemd-network/icmp6-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd-network/lldp-internal.c b/src/libsystemd-network/lldp-internal.c index 583be2f55..c8740ce5f 100644 --- a/src/libsystemd-network/lldp-internal.c +++ b/src/libsystemd-network/lldp-internal.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -335,7 +333,7 @@ int lldp_chassis_new(tlv_packet *tlv, } int lldp_receive_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { - _cleanup_lldp_packet_unref_ tlv_packet *packet = NULL; + _cleanup_(sd_lldp_packet_unrefp) tlv_packet *packet = NULL; tlv_packet *p; uint16_t length; int r; diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index 5d19fa0fe..15b4a11b1 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index f483cd9c8..42058c444 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd-network/lldp-network.h b/src/libsystemd-network/lldp-network.h index 74ee13a41..dcf31faa9 100644 --- a/src/libsystemd-network/lldp-network.h +++ b/src/libsystemd-network/lldp-network.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd-network/lldp-port.c b/src/libsystemd-network/lldp-port.c index 1f1a49adb..c86f62a6c 100644 --- a/src/libsystemd-network/lldp-port.c +++ b/src/libsystemd-network/lldp-port.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd-network/lldp-port.h b/src/libsystemd-network/lldp-port.h index 517b162a6..96092f8df 100644 --- a/src/libsystemd-network/lldp-port.h +++ b/src/libsystemd-network/lldp-port.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd-network/lldp-tlv.c b/src/libsystemd-network/lldp-tlv.c index 66343147a..9170b5069 100644 --- a/src/libsystemd-network/lldp-tlv.c +++ b/src/libsystemd-network/lldp-tlv.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd-network/lldp-tlv.h b/src/libsystemd-network/lldp-tlv.h index ca1da113d..8e7706c61 100644 --- a/src/libsystemd-network/lldp-tlv.h +++ b/src/libsystemd-network/lldp-tlv.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -24,12 +22,12 @@ #include -#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; @@ -74,9 +72,6 @@ struct sd_lldp_packet { int tlv_packet_new(tlv_packet **ret); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_lldp_packet*, sd_lldp_packet_unref); -#define _cleanup_lldp_packet_unref_ _cleanup_(sd_lldp_packet_unrefp) - int lldp_tlv_packet_open_container(tlv_packet *m, uint16_t type); int lldp_tlv_packet_close_container(tlv_packet *m); diff --git a/src/libsystemd-network/lldp.h b/src/libsystemd-network/lldp.h index 19e5cc5f4..d2c716463 100644 --- a/src/libsystemd-network/lldp.h +++ b/src/libsystemd-network/lldp.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index a4d4f1ae2..fdafcd84d 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -437,7 +435,7 @@ int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { return size; } -void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size) { +void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) { unsigned i; assert(f); @@ -448,10 +446,15 @@ void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *route fprintf(f, "%s=", key); for (i = 0; i < size; i++) { - fprintf(f, "%s/%" PRIu8, inet_ntoa(routes[i].dst_addr), - routes[i].dst_prefixlen); - fprintf(f, ",%s%s", inet_ntoa(routes[i].gw_addr), - (i < (size - 1)) ? " ": ""); + struct in_addr dest, gw; + uint8_t length; + + assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0); + assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0); + assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0); + + fprintf(f, "%s/%" PRIu8, inet_ntoa(dest), length); + fprintf(f, ",%s%s", inet_ntoa(gw), (i < (size - 1)) ? " ": ""); } fputs("\n", f); diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index d516f2daf..c8a531ab0 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,8 +21,10 @@ #include -#include "udev.h" +#include "sd-dhcp-lease.h" + #include "condition.h" +#include "udev.h" bool net_match_config(const struct ether_addr *match_mac, char * const *match_path, @@ -74,7 +74,7 @@ int deserialize_in6_addrs(struct in6_addr **addresses, const char *string); /* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */ struct sd_dhcp_route; -void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route *routes, size_t size); +void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size); int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t *ret_allocated, const char *string); int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 137537253..cad1a52c0 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" @@ -41,6 +43,9 @@ #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) +#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC) +#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE) + struct sd_dhcp_client { unsigned n_ref; @@ -99,14 +104,15 @@ struct sd_dhcp_client { sd_dhcp_client_cb_t cb; void *userdata; sd_dhcp_lease *lease; + usec_t start_delay; }; static const uint8_t default_req_opts[] = { - DHCP_OPTION_SUBNET_MASK, - DHCP_OPTION_ROUTER, - DHCP_OPTION_HOST_NAME, - DHCP_OPTION_DOMAIN_NAME, - DHCP_OPTION_DOMAIN_NAME_SERVER, + SD_DHCP_OPTION_SUBNET_MASK, + SD_DHCP_OPTION_ROUTER, + SD_DHCP_OPTION_HOST_NAME, + SD_DHCP_OPTION_DOMAIN_NAME, + SD_DHCP_OPTION_DOMAIN_NAME_SERVER, }; static int client_receive_message_raw(sd_event_source *s, int fd, @@ -141,11 +147,11 @@ int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { DHCP_STATE_STOPPED), -EBUSY); switch(option) { - case DHCP_OPTION_PAD: - case DHCP_OPTION_OVERLOAD: - case DHCP_OPTION_MESSAGE_TYPE: - case DHCP_OPTION_PARAMETER_REQUEST_LIST: - case DHCP_OPTION_END: + case SD_DHCP_OPTION_PAD: + case SD_DHCP_OPTION_OVERLOAD: + case SD_DHCP_OPTION_MESSAGE_TYPE: + case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST: + case SD_DHCP_OPTION_END: return -EINVAL; default: @@ -298,6 +304,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; @@ -481,7 +490,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, Identifier option is not set */ if (client->client_id_len) { r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_CLIENT_IDENTIFIER, + SD_DHCP_OPTION_CLIENT_IDENTIFIER, client->client_id_len, &client->client_id); if (r < 0) @@ -497,7 +506,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, messages. */ r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_PARAMETER_REQUEST_LIST, + SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, client->req_opts_size, client->req_opts); if (r < 0) return r; @@ -526,7 +535,7 @@ static int client_message_init(sd_dhcp_client *client, DHCPPacket **ret, */ max_size = htobe16(size); r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, - DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, + SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, 2, &max_size); if (r < 0) return r; @@ -539,6 +548,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, false); + if (r > 0) + r = dhcp_option_append(message, optlen, optoffset, 0, + SD_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, @@ -570,26 +597,34 @@ static int client_send_discover(sd_dhcp_client *client) { */ if (client->last_addr != INADDR_ANY) { r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_REQUESTED_IP_ADDRESS, + SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, 4, &client->last_addr); if (r < 0) 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, + SD_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; } if (client->vendor_class_identifier) { r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, + SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, strlen(client->vendor_class_identifier), client->vendor_class_identifier); if (r < 0) @@ -597,7 +632,7 @@ static int client_send_discover(sd_dhcp_client *client) { } r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_END, 0, NULL); + SD_DHCP_OPTION_END, 0, NULL); if (r < 0) return r; @@ -636,13 +671,13 @@ static int client_send_request(sd_dhcp_client *client) { */ r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_SERVER_IDENTIFIER, + SD_DHCP_OPTION_SERVER_IDENTIFIER, 4, &client->lease->server_address); if (r < 0) return r; r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_REQUESTED_IP_ADDRESS, + SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, 4, &client->lease->address); if (r < 0) return r; @@ -655,7 +690,7 @@ static int client_send_request(sd_dhcp_client *client) { assigned address. ’ciaddr’ MUST be zero. */ r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_REQUESTED_IP_ADDRESS, + SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, 4, &client->last_addr); if (r < 0) return r; @@ -688,15 +723,19 @@ 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, + SD_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; } r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - DHCP_OPTION_END, 0, NULL); + SD_DHCP_OPTION_END, 0, NULL); if (r < 0) return r; @@ -910,6 +949,7 @@ error: } static int client_initialize_time_events(sd_dhcp_client *client) { + uint64_t usec = 0; int r; assert(client); @@ -917,10 +957,15 @@ static int client_initialize_time_events(sd_dhcp_client *client) { client->timeout_resend = sd_event_source_unref(client->timeout_resend); + if (client->start_delay) { + sd_event_now(client->event, clock_boottime_or_monotonic(), &usec); + usec += client->start_delay; + } + r = sd_event_add_time(client->event, &client->timeout_resend, clock_boottime_or_monotonic(), - 0, 0, + usec, 0, client_timeout_resend, client); if (r < 0) goto error; @@ -950,7 +995,7 @@ static int client_initialize_events(sd_dhcp_client *client, return 0; } -static int client_start(sd_dhcp_client *client) { +static int client_start_delayed(sd_dhcp_client *client) { int r; assert_return(client, -EINVAL); @@ -978,6 +1023,11 @@ static int client_start(sd_dhcp_client *client) { return client_initialize_events(client, client_receive_message_raw); } +static int client_start(sd_dhcp_client *client) { + client->start_delay = 0; + return client_start_delayed(client); +} + static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) { sd_dhcp_client *client = userdata; @@ -1032,7 +1082,7 @@ static int client_timeout_t1(sd_event_source *s, uint64_t usec, static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) { - _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; + _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; int r; r = dhcp_lease_new(&lease); @@ -1047,7 +1097,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 +1136,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; @@ -1097,7 +1147,8 @@ 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_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; + _cleanup_free_ char *error_message = NULL; int r; r = dhcp_lease_new(&lease); @@ -1112,9 +1163,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; } @@ -1326,6 +1377,7 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) { DHCP_CLIENT_DONT_DESTROY(client); + char time_string[FORMAT_TIMESPAN_MAX]; int r = 0, notify_event = 0; assert(client); @@ -1373,6 +1425,7 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, r = client_handle_ack(client, message, len); if (r >= 0) { + client->start_delay = 0; client->timeout_resend = sd_event_source_unref(client->timeout_resend); client->receive_message = @@ -1422,11 +1475,15 @@ static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, if (r < 0) goto error; - r = client_start(client); + r = client_start_delayed(client); if (r < 0) goto error; - log_dhcp_client(client, "REBOOTED"); + log_dhcp_client(client, "REBOOT in %s", format_timespan(time_string, FORMAT_TIMESPAN_MAX, + client->start_delay, USEC_PER_SEC)); + + client->start_delay = CLAMP(client->start_delay * 2, + RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC); return 0; } else if (r == -ENOMSG) @@ -1478,9 +1535,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 +1546,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 +1581,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 +1594,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 +1623,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 +1637,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; @@ -1714,7 +1772,7 @@ sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client) { } int sd_dhcp_client_new(sd_dhcp_client **ret) { - _cleanup_dhcp_client_unref_ sd_dhcp_client *client = NULL; + _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = NULL; assert_return(ret, -EINVAL); diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 8befedc50..7a119fd48 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -37,6 +37,7 @@ #include "in-addr-util.h" #include "network-internal.h" #include "parse-util.h" +#include "stdio-util.h" #include "string-util.h" #include "unaligned.h" @@ -205,14 +206,28 @@ int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) { return 0; } -int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes) { +/* + * The returned routes array must be freed by the caller. + * Route objects have the same lifetime of the lease and must not be freed. + */ +int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes) { + sd_dhcp_route **ret; + unsigned i; + assert_return(lease, -EINVAL); assert_return(routes, -EINVAL); if (lease->static_route_size <= 0) return -ENODATA; - *routes = lease->static_route; + ret = new(sd_dhcp_route *, lease->static_route_size); + if (!ret) + return -ENOMEM; + + for (i = 0; i < lease->static_route_size; i++) + ret[i] = &lease->static_route[i]; + + *routes = ret; return (int) lease->static_route_size; } @@ -338,6 +353,38 @@ static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { return 0; } +static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) { + _cleanup_free_ char *name = NULL, *normalized = NULL; + int r; + + assert(option); + assert(ret); + + r = lease_parse_string(option, len, &name); + if (r < 0) + return r; + if (!name) { + *ret = mfree(*ret); + return 0; + } + + r = dns_name_normalize(name, &normalized); + if (r < 0) + return r; + + if (is_localhost(normalized)) + return -EINVAL; + + if (dns_name_is_root(normalized)) + return -EINVAL; + + free(*ret); + *ret = normalized; + normalized = NULL; + + return 0; +} + static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { assert(option); assert(ret); @@ -452,7 +499,7 @@ static int lease_parse_classless_routes( if (len < 4) return -EINVAL; - lease_parse_be32(option, 4, &route->gw_addr.s_addr); + assert_se(lease_parse_be32(option, 4, &route->gw_addr.s_addr) >= 0); option += 4; len -= 4; @@ -470,21 +517,21 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void switch(code) { - case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: + case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME: r = lease_parse_u32(option, len, &lease->lifetime, 1); if (r < 0) log_debug_errno(r, "Failed to parse lease time, ignoring: %m"); break; - case DHCP_OPTION_SERVER_IDENTIFIER: + case SD_DHCP_OPTION_SERVER_IDENTIFIER: r = lease_parse_be32(option, len, &lease->server_address); if (r < 0) log_debug_errno(r, "Failed to parse server identifier, ignoring: %m"); break; - case DHCP_OPTION_SUBNET_MASK: + case SD_DHCP_OPTION_SUBNET_MASK: r = lease_parse_be32(option, len, &lease->subnet_mask); if (r < 0) log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m"); @@ -492,7 +539,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void lease->have_subnet_mask = true; break; - case DHCP_OPTION_BROADCAST: + case SD_DHCP_OPTION_BROADCAST: r = lease_parse_be32(option, len, &lease->broadcast); if (r < 0) log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m"); @@ -500,7 +547,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void lease->have_broadcast = true; break; - case DHCP_OPTION_ROUTER: + case SD_DHCP_OPTION_ROUTER: if (len >= 4) { r = lease_parse_be32(option, 4, &lease->router); if (r < 0) @@ -508,103 +555,67 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void } break; - case DHCP_OPTION_DOMAIN_NAME_SERVER: + case SD_DHCP_OPTION_DOMAIN_NAME_SERVER: r = lease_parse_in_addrs(option, len, &lease->dns, &lease->dns_size); if (r < 0) log_debug_errno(r, "Failed to parse DNS server, ignoring: %m"); break; - case DHCP_OPTION_NTP_SERVER: + case SD_DHCP_OPTION_NTP_SERVER: r = lease_parse_in_addrs(option, len, &lease->ntp, &lease->ntp_size); if (r < 0) log_debug_errno(r, "Failed to parse NTP server, ignoring: %m"); break; - case DHCP_OPTION_STATIC_ROUTE: + case SD_DHCP_OPTION_STATIC_ROUTE: r = lease_parse_routes(option, len, &lease->static_route, &lease->static_route_size, &lease->static_route_allocated); if (r < 0) log_debug_errno(r, "Failed to parse static routes, ignoring: %m"); break; - case DHCP_OPTION_INTERFACE_MTU: + case SD_DHCP_OPTION_INTERFACE_MTU: r = lease_parse_u16(option, len, &lease->mtu, 68); if (r < 0) log_debug_errno(r, "Failed to parse MTU, ignoring: %m"); break; - case DHCP_OPTION_DOMAIN_NAME: { - _cleanup_free_ char *domainname = NULL, *normalized = NULL; - - r = lease_parse_string(option, len, &domainname); + case SD_DHCP_OPTION_DOMAIN_NAME: + r = lease_parse_domain(option, len, &lease->domainname); if (r < 0) { log_debug_errno(r, "Failed to parse domain name, ignoring: %m"); return 0; } - r = dns_name_normalize(domainname, &normalized); - if (r < 0) { - log_debug_errno(r, "Failed to normalize domain name '%s': %m", domainname); - return 0; - } - - if (is_localhost(normalized)) { - log_debug_errno(r, "Detected 'localhost' as suggested domain name, ignoring."); - break; - } - - free(lease->domainname); - lease->domainname = normalized; - normalized = NULL; - break; - } - case DHCP_OPTION_HOST_NAME: { - _cleanup_free_ char *hostname = NULL, *normalized = NULL; - - r = lease_parse_string(option, len, &hostname); + case SD_DHCP_OPTION_HOST_NAME: + r = lease_parse_domain(option, len, &lease->hostname); if (r < 0) { log_debug_errno(r, "Failed to parse host name, ignoring: %m"); return 0; } - r = dns_name_normalize(hostname, &normalized); - if (r < 0) { - log_debug_errno(r, "Failed to normalize host name '%s', ignoring: %m", hostname); - return 0; - } - - if (is_localhost(normalized)) { - log_debug_errno(r, "Detected 'localhost' as suggested host name, ignoring."); - return 0; - } - - free(lease->hostname); - lease->hostname = normalized; - normalized = NULL; - break; - } - case DHCP_OPTION_ROOT_PATH: + case SD_DHCP_OPTION_ROOT_PATH: r = lease_parse_string(option, len, &lease->root_path); if (r < 0) log_debug_errno(r, "Failed to parse root path, ignoring: %m"); break; - case DHCP_OPTION_RENEWAL_T1_TIME: + case SD_DHCP_OPTION_RENEWAL_T1_TIME: r = lease_parse_u32(option, len, &lease->t1, 1); if (r < 0) log_debug_errno(r, "Failed to parse T1 time, ignoring: %m"); break; - case DHCP_OPTION_REBINDING_T2_TIME: + case SD_DHCP_OPTION_REBINDING_T2_TIME: r = lease_parse_u32(option, len, &lease->t2, 1); if (r < 0) log_debug_errno(r, "Failed to parse T2 time, ignoring: %m"); break; - case DHCP_OPTION_CLASSLESS_STATIC_ROUTE: + case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE: r = lease_parse_classless_routes( option, len, &lease->static_route, @@ -614,7 +625,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void log_debug_errno(r, "Failed to parse classless routes, ignoring: %m"); break; - case DHCP_OPTION_NEW_TZDB_TIMEZONE: { + case SD_DHCP_OPTION_NEW_TZDB_TIMEZONE: { _cleanup_free_ char *tz = NULL; r = lease_parse_string(option, len, &tz); @@ -635,7 +646,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void break; } - case DHCP_OPTION_VENDOR_SPECIFIC: + case SD_DHCP_OPTION_VENDOR_SPECIFIC: if (len <= 0) lease->vendor_specific = mfree(lease->vendor_specific); @@ -653,7 +664,7 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void lease->vendor_specific_len = len; break; - case DHCP_OPTION_PRIVATE_BASE ... DHCP_OPTION_PRIVATE_LAST: + case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST: r = dhcp_lease_insert_private_option(lease, code, option, len); if (r < 0) return r; @@ -661,7 +672,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; } @@ -722,7 +733,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { size_t client_id_len, data_len; const char *string; uint16_t mtu; - struct sd_dhcp_route *routes; + _cleanup_free_ sd_dhcp_route **routes = NULL; uint32_t t1, t2, lifetime; int r; @@ -839,7 +850,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { LIST_FOREACH(options, option, lease->private_options) { char key[strlen("OPTION_000")+1]; - snprintf(key, sizeof(key), "OPTION_%"PRIu8, option->tag); + xsprintf(key, "OPTION_%" PRIu8, option->tag); r = serialize_dhcp_option(f, key, option->data, option->length); if (r < 0) goto fail; @@ -865,7 +876,7 @@ fail: int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { - _cleanup_dhcp_lease_unref_ sd_dhcp_lease *lease = NULL; + _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; _cleanup_free_ char *address = NULL, *router = NULL, @@ -882,7 +893,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { *lifetime = NULL, *t1 = NULL, *t2 = NULL, - *options[DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE + 1] = {}; + *options[SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1] = {}; int r, i; @@ -1050,7 +1061,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex); } - for (i = 0; i <= DHCP_OPTION_PRIVATE_LAST - DHCP_OPTION_PRIVATE_BASE; i++) { + for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) { _cleanup_free_ void *data = NULL; size_t len; @@ -1063,7 +1074,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { continue; } - r = dhcp_lease_insert_private_option(lease, DHCP_OPTION_PRIVATE_BASE + i, data, len); + r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len); if (r < 0) return r; } @@ -1141,3 +1152,27 @@ int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) { *tz = lease->timezone; return 0; } + +int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) { + assert_return(route, -EINVAL); + assert_return(destination, -EINVAL); + + *destination = route->dst_addr; + return 0; +} + +int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) { + assert_return(route, -EINVAL); + assert_return(length, -EINVAL); + + *length = route->dst_prefixlen; + return 0; +} + +int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) { + assert_return(route, -EINVAL); + assert_return(gateway, -EINVAL); + + *gateway = route->gw_addr; + return 0; +} diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 277c88e2b..ad3a37b72 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -185,7 +183,7 @@ sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { } int sd_dhcp_server_new(sd_dhcp_server **ret, int ifindex) { - _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; + _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL; assert_return(ret, -EINVAL); assert_return(ifindex > 0, -EINVAL); @@ -354,13 +352,13 @@ int dhcp_server_send_packet(sd_dhcp_server *server, assert(packet); r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0, - DHCP_OPTION_SERVER_IDENTIFIER, + SD_DHCP_OPTION_SERVER_IDENTIFIER, 4, &server->address); if (r < 0) return r; r = dhcp_option_append(&packet->dhcp, req->max_optlen, &optoffset, 0, - DHCP_OPTION_END, 0, NULL); + SD_DHCP_OPTION_END, 0, NULL); if (r < 0) return r; @@ -457,18 +455,18 @@ static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req, lease_time = htobe32(req->lifetime); r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, + SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time); if (r < 0) return r; r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - DHCP_OPTION_SUBNET_MASK, 4, &server->netmask); + SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask); if (r < 0) return r; r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - DHCP_OPTION_ROUTER, 4, &server->address); + SD_DHCP_OPTION_ROUTER, 4, &server->address); if (r < 0) return r; @@ -494,25 +492,25 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, lease_time = htobe32(req->lifetime); r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, + SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, &lease_time); if (r < 0) return r; r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - DHCP_OPTION_SUBNET_MASK, 4, &server->netmask); + SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask); if (r < 0) return r; r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - DHCP_OPTION_ROUTER, 4, &server->address); + SD_DHCP_OPTION_ROUTER, 4, &server->address); if (r < 0) return r; if (server->n_dns > 0) { r = dhcp_option_append( &packet->dhcp, req->max_optlen, &offset, 0, - DHCP_OPTION_DOMAIN_NAME_SERVER, + SD_DHCP_OPTION_DOMAIN_NAME_SERVER, sizeof(struct in_addr) * server->n_dns, server->dns); if (r < 0) return r; @@ -521,7 +519,7 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, if (server->n_ntp > 0) { r = dhcp_option_append( &packet->dhcp, req->max_optlen, &offset, 0, - DHCP_OPTION_NTP_SERVER, + SD_DHCP_OPTION_NTP_SERVER, sizeof(struct in_addr) * server->n_ntp, server->ntp); if (r < 0) return r; @@ -530,7 +528,7 @@ static int server_send_ack(sd_dhcp_server *server, DHCPRequest *req, if (server->timezone) { r = dhcp_option_append( &packet->dhcp, req->max_optlen, &offset, 0, - DHCP_OPTION_NEW_TZDB_TIMEZONE, + SD_DHCP_OPTION_NEW_TZDB_TIMEZONE, strlen(server->timezone), server->timezone); if (r < 0) return r; @@ -576,7 +574,7 @@ static int server_send_forcerenew(sd_dhcp_server *server, be32_t address, return r; r = dhcp_option_append(&packet->dhcp, DHCP_MIN_OPTIONS_SIZE, - &optoffset, 0, DHCP_OPTION_END, 0, NULL); + &optoffset, 0, SD_DHCP_OPTION_END, 0, NULL); if (r < 0) return r; @@ -596,22 +594,22 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us assert(req); switch(code) { - case DHCP_OPTION_IP_ADDRESS_LEASE_TIME: + case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME: if (len == 4) req->lifetime = be32toh(*(be32_t*)option); break; - case DHCP_OPTION_REQUESTED_IP_ADDRESS: + case SD_DHCP_OPTION_REQUESTED_IP_ADDRESS: if (len == 4) req->requested_ip = *(be32_t*)option; break; - case DHCP_OPTION_SERVER_IDENTIFIER: + case SD_DHCP_OPTION_SERVER_IDENTIFIER: if (len == 4) req->server_id = *(be32_t*)option; break; - case DHCP_OPTION_CLIENT_IDENTIFIER: + case SD_DHCP_OPTION_CLIENT_IDENTIFIER: if (len >= 2) { uint8_t *data; @@ -625,7 +623,7 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us } break; - case DHCP_OPTION_MAXIMUM_MESSAGE_SIZE: + case SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE: if (len == 2) req->max_optlen = be16toh(*(be16_t*)option) - - sizeof(DHCPPacket); @@ -699,6 +697,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 +713,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; @@ -784,8 +783,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 +961,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 +972,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 801331d27..5b6b9cbca 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -72,10 +70,10 @@ struct sd_dhcp6_client { }; static const uint16_t default_req_opts[] = { - DHCP6_OPTION_DNS_SERVERS, - DHCP6_OPTION_DOMAIN_LIST, - DHCP6_OPTION_NTP_SERVER, - DHCP6_OPTION_SNTP_SERVERS, + SD_DHCP6_OPTION_DNS_SERVERS, + SD_DHCP6_OPTION_DOMAIN_LIST, + SD_DHCP6_OPTION_NTP_SERVER, + SD_DHCP6_OPTION_SNTP_SERVERS, }; const char * dhcp6_message_type_table[_DHCP6_MESSAGE_MAX] = { @@ -107,11 +105,8 @@ const char * dhcp6_message_status_table[_DHCP6_STATUS_MAX] = { DEFINE_STRING_TABLE_LOOKUP(dhcp6_message_status, int); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_dhcp6_client*, sd_dhcp6_client_unref); -#define _cleanup_dhcp6_client_unref_ _cleanup_(sd_dhcp6_client_unrefp) - #define DHCP6_CLIENT_DONT_DESTROY(client) \ - _cleanup_dhcp6_client_unref_ _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client) + _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client) static int client_start(sd_dhcp6_client *client, enum DHCP6State state); @@ -248,10 +243,10 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); switch(option) { - case DHCP6_OPTION_DNS_SERVERS: - case DHCP6_OPTION_DOMAIN_LIST: - case DHCP6_OPTION_SNTP_SERVERS: - case DHCP6_OPTION_NTP_SERVER: + case SD_DHCP6_OPTION_DNS_SERVERS: + case SD_DHCP6_OPTION_DOMAIN_LIST: + case SD_DHCP6_OPTION_SNTP_SERVERS: + case SD_DHCP6_OPTION_NTP_SERVER: break; default: @@ -365,7 +360,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { message->type = DHCP6_SOLICIT; r = dhcp6_option_append(&opt, &optlen, - DHCP6_OPTION_RAPID_COMMIT, 0, NULL); + SD_DHCP6_OPTION_RAPID_COMMIT, 0, NULL); if (r < 0) return r; @@ -383,7 +378,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { else message->type = DHCP6_RENEW; - r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_SERVERID, + r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_SERVERID, client->lease->serverid_len, client->lease->serverid); if (r < 0) @@ -409,14 +404,14 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { return -EINVAL; } - r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ORO, + r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO, client->req_opts_len * sizeof(be16_t), client->req_opts); if (r < 0) return r; assert (client->duid_len); - r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_CLIENTID, + r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_CLIENTID, client->duid_len, &client->duid); if (r < 0) return r; @@ -427,7 +422,7 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { else elapsed_time = 0xffff; - r = dhcp6_option_append(&opt, &optlen, DHCP6_OPTION_ELAPSED_TIME, + r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ELAPSED_TIME, sizeof(elapsed_time), &elapsed_time); if (r < 0) return r; @@ -690,7 +685,7 @@ static int client_parse_message(sd_dhcp6_client *client, while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen, &optval)) >= 0) { switch (optcode) { - case DHCP6_OPTION_CLIENTID: + case SD_DHCP6_OPTION_CLIENTID: if (clientid) { log_dhcp6_client(client, "%s contains multiple clientids", dhcp6_message_type_to_string(message->type)); @@ -708,7 +703,7 @@ static int client_parse_message(sd_dhcp6_client *client, break; - case DHCP6_OPTION_SERVERID: + case SD_DHCP6_OPTION_SERVERID: r = dhcp6_lease_get_serverid(lease, &id, &id_len); if (r >= 0 && id) { log_dhcp6_client(client, "%s contains multiple serverids", @@ -722,7 +717,7 @@ static int client_parse_message(sd_dhcp6_client *client, break; - case DHCP6_OPTION_PREFERENCE: + case SD_DHCP6_OPTION_PREFERENCE: if (optlen != 1) return -EINVAL; @@ -732,7 +727,7 @@ static int client_parse_message(sd_dhcp6_client *client, break; - case DHCP6_OPTION_STATUS_CODE: + case SD_DHCP6_OPTION_STATUS_CODE: if (optlen < 2) return -EINVAL; @@ -746,7 +741,7 @@ static int client_parse_message(sd_dhcp6_client *client, break; - case DHCP6_OPTION_IA_NA: + case SD_DHCP6_OPTION_IA_NA: if (client->state == DHCP6_STATE_INFORMATION_REQUEST) { log_dhcp6_client(client, "Information request ignoring IA NA option"); @@ -770,35 +765,35 @@ static int client_parse_message(sd_dhcp6_client *client, break; - case DHCP6_OPTION_RAPID_COMMIT: + case SD_DHCP6_OPTION_RAPID_COMMIT: r = dhcp6_lease_set_rapid_commit(lease); if (r < 0) return r; break; - case DHCP6_OPTION_DNS_SERVERS: + case SD_DHCP6_OPTION_DNS_SERVERS: r = dhcp6_lease_set_dns(lease, optval, optlen); if (r < 0) return r; break; - case DHCP6_OPTION_DOMAIN_LIST: + case SD_DHCP6_OPTION_DOMAIN_LIST: r = dhcp6_lease_set_domains(lease, optval, optlen); if (r < 0) return r; break; - case DHCP6_OPTION_NTP_SERVER: + case SD_DHCP6_OPTION_NTP_SERVER: r = dhcp6_lease_set_ntp(lease, optval, optlen); if (r < 0) return r; break; - case DHCP6_OPTION_SNTP_SERVERS: + case SD_DHCP6_OPTION_SNTP_SERVERS: r = dhcp6_lease_set_sntp(lease, optval, optlen); if (r < 0) return r; @@ -829,7 +824,7 @@ static int client_parse_message(sd_dhcp6_client *client, static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, size_t len) { int r; - _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; + _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; bool rapid_commit; if (reply->type != DHCP6_REPLY) @@ -860,7 +855,7 @@ static int client_receive_reply(sd_dhcp6_client *client, DHCP6Message *reply, si static int client_receive_advertise(sd_dhcp6_client *client, DHCP6Message *advertise, size_t len) { int r; - _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; + _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; uint8_t pref_advertise = 0, pref_lease = 0; if (advertise->type != DHCP6_ADVERTISE) @@ -895,7 +890,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); @@ -903,18 +898,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: @@ -1269,7 +1272,7 @@ sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client) { } int sd_dhcp6_client_new(sd_dhcp6_client **ret) { - _cleanup_dhcp6_client_unref_ sd_dhcp6_client *client = NULL; + _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; size_t t; assert_return(ret, -EINVAL); @@ -1280,7 +1283,7 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) { client->n_ref = 1; - client->ia_na.type = DHCP6_OPTION_IA_NA; + client->ia_na.type = SD_DHCP6_OPTION_IA_NA; client->index = -1; diff --git a/src/libsystemd-network/sd-dhcp6-lease.c b/src/libsystemd-network/sd-dhcp6-lease.c index 3f32ba35e..5c10a6326 100644 --- a/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libsystemd-network/sd-dhcp6-lease.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -256,7 +254,7 @@ int dhcp6_lease_set_ntp(sd_dhcp6_lease *lease, uint8_t *optval, size_t optlen) { assert_return(lease, -EINVAL); assert_return(optval, -EINVAL); - free(lease->ntp); + lease->ntp = mfree(lease->ntp); lease->ntp_count = 0; lease->ntp_allocated = 0; diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 5340fdc0c..f7880a891 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -28,7 +28,6 @@ #include "alloc-util.h" #include "arp-util.h" -#include "event-util.h" #include "fd-util.h" #include "in-addr-util.h" #include "list.h" @@ -120,11 +119,8 @@ sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll) { return NULL; } -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4acd*, sd_ipv4acd_unref); -#define _cleanup_ipv4acd_unref_ _cleanup_(sd_ipv4acd_unrefp) - int sd_ipv4acd_new(sd_ipv4acd **ret) { - _cleanup_ipv4acd_unref_ sd_ipv4acd *ll = NULL; + _cleanup_(sd_ipv4acd_unrefp) sd_ipv4acd *ll = NULL; assert_return(ret, -EINVAL); @@ -189,7 +185,7 @@ int sd_ipv4acd_stop(sd_ipv4acd *ll) { static int ipv4acd_on_timeout(sd_event_source *s, uint64_t usec, void *userdata); static int ipv4acd_set_next_wakeup(sd_ipv4acd *ll, int sec, int random_sec) { - _cleanup_event_source_unref_ sd_event_source *timer = NULL; + _cleanup_(sd_event_source_unrefp) sd_event_source *timer = NULL; usec_t next_timeout; usec_t time_now; int r; diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 30a7ef578..db6cf22aa 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -28,7 +28,6 @@ #include "sd-ipv4ll.h" #include "alloc-util.h" -#include "event-util.h" #include "in-addr-util.h" #include "list.h" #include "random-util.h" @@ -41,7 +40,7 @@ #define IPV4LL_NETMASK 0xFFFF0000L #define IPV4LL_DONT_DESTROY(ll) \ - _cleanup_ipv4ll_unref_ _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll) + _cleanup_(sd_ipv4ll_unrefp) _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll) struct sd_ipv4ll { unsigned n_ref; @@ -86,13 +85,10 @@ sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll) { return NULL; } -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ipv4ll*, sd_ipv4ll_unref); -#define _cleanup_ipv4ll_unref_ _cleanup_(sd_ipv4ll_unrefp) - static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); int sd_ipv4ll_new(sd_ipv4ll **ret) { - _cleanup_ipv4ll_unref_ sd_ipv4ll *ll = NULL; + _cleanup_(sd_ipv4ll_unrefp) sd_ipv4ll *ll = NULL; int r; assert_return(ret, -EINVAL); diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 4ebe8053f..885ca6242 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -31,7 +29,6 @@ #include "lldp-internal.h" #include "lldp-port.h" #include "lldp-tlv.h" -#include "lldp-util.h" #include "prioq.h" #include "siphash24.h" #include "string-util.h" @@ -146,12 +143,9 @@ static int lldp_receive_frame(sd_lldp *lldp, tlv_packet *tlv) { /* 10.3.2 LLDPDU validation: rxProcessFrame() */ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { + bool system_description = false, system_name = false, chassis_id = false; + bool malformed = false, port_id = false, ttl = false, end = false; uint16_t type, len, i, l, t; - bool chassis_id = false; - bool malformed = false; - bool port_id = false; - bool ttl = false; - bool end = false; lldp_port *port; uint8_t *p, *q; sd_lldp *lldp; @@ -164,8 +158,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { lldp = (sd_lldp *) port->userdata; if (lldp->port->status == LLDP_PORT_STATUS_DISABLED) { - log_lldp("Port is disabled : %s . Dropping ...", - lldp->port->ifname); + log_lldp("Port: %s is disabled. Dropping.", lldp->port->ifname); goto out; } @@ -183,8 +176,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (type == LLDP_TYPE_END) { if (len != 0) { - log_lldp("TLV type end is not length 0. Length:%d received . Dropping ...", - len); + log_lldp("TLV type end must be length 0 (not %d). Dropping.", len); malformed = true; goto out; @@ -194,8 +186,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { break; } else if (type >=_LLDP_TYPE_MAX) { - log_lldp("TLV type not recognized %d . Dropping ...", - type); + log_lldp("TLV type: %d not recognized. Dropping.", type); malformed = true; goto out; @@ -210,7 +201,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { if (i <= 3) { if (i != type) { - log_lldp("TLV missing or out of order. Dropping ..."); + log_lldp("TLV missing or out of order. Dropping."); malformed = true; goto out; @@ -221,25 +212,22 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { case LLDP_TYPE_CHASSIS_ID: if (len < 2) { - log_lldp("Received malformed Chassis ID TLV len = %d. Dropping", - len); + log_lldp("Received malformed Chassis ID TLV length: %d. Dropping.", len); malformed = true; goto out; } if (chassis_id) { - log_lldp("Duplicate Chassis ID TLV found. Dropping ..."); + log_lldp("Duplicate Chassis ID TLV found. Dropping."); malformed = true; goto out; } /* Look what subtype it has */ - if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED || - *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) { - log_lldp("Unknown subtype: %d found in Chassis ID TLV . Dropping ...", - *q); + if (*q == LLDP_CHASSIS_SUBTYPE_RESERVED || *q > LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED) { + log_lldp("Unknown subtype: %d found in Chassis ID TLV. Dropping.", *q); malformed = true; goto out; @@ -252,25 +240,22 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { case LLDP_TYPE_PORT_ID: if (len < 2) { - log_lldp("Received malformed Port ID TLV len = %d. Dropping", - len); + log_lldp("Received malformed Port ID TLV length: %d. Dropping.", len); malformed = true; goto out; } if (port_id) { - log_lldp("Duplicate Port ID TLV found. Dropping ..."); + log_lldp("Duplicate Port ID TLV found. Dropping."); malformed = true; goto out; } /* Look what subtype it has */ - if (*q == LLDP_PORT_SUBTYPE_RESERVED || - *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) { - log_lldp("Unknown subtype: %d found in Port ID TLV . Dropping ...", - *q); + if (*q == LLDP_PORT_SUBTYPE_RESERVED || *q > LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED) { + log_lldp("Unknown subtype: %d found in Port ID TLV. Dropping.", *q); malformed = true; goto out; @@ -283,16 +268,14 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { case LLDP_TYPE_TTL: if(len != 2) { - log_lldp( - "Received invalid lenth: %d TTL TLV. Dropping ...", - len); + log_lldp("Received invalid TTL TLV lenth: %d. Dropping.", len); malformed = true; goto out; } if (ttl) { - log_lldp("Duplicate TTL TLV found. Dropping ..."); + log_lldp("Duplicate TTL TLV found. Dropping."); malformed = true; goto out; @@ -300,12 +283,46 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { ttl = true; + break; + case LLDP_TYPE_SYSTEM_NAME: + + /* According to RFC 1035 the length of a FQDN is limited to 255 characters */ + if (len > 255) { + log_lldp("Received invalid system name length: %d. Dropping.", len); + malformed = true; + goto out; + } + + if (system_name) { + log_lldp("Duplicate system name found. Dropping."); + malformed = true; + goto out; + } + + system_name = true; + + break; + case LLDP_TYPE_SYSTEM_DESCRIPTION: + + /* 0 <= n <= 255 octets */ + if (len > 255) { + log_lldp("Received invalid system description length: %d. Dropping.", len); + malformed = true; + goto out; + } + + if (system_description) { + log_lldp("Duplicate system description found. Dropping."); + malformed = true; + goto out; + } + + system_description = true; break; default: if (len == 0) { - log_lldp("TLV type = %d's, length 0 received . Dropping ...", - type); + log_lldp("TLV type: %d length 0 received. Dropping.", type); malformed = true; goto out; @@ -315,7 +332,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { } if(!chassis_id || !port_id || !ttl || !end) { - log_lldp( "One or more mandotory TLV missing . Dropping ..."); + log_lldp("One or more mandatory TLV missing. Dropping."); malformed = true; goto out; @@ -324,7 +341,7 @@ int lldp_handle_packet(tlv_packet *tlv, uint16_t length) { r = tlv_packet_parse_pdu(tlv, length); if (r < 0) { - log_lldp( "Failed to parse the TLV. Dropping ..."); + log_lldp("Failed to parse the TLV. Dropping."); malformed = true; goto out; @@ -652,10 +669,10 @@ int sd_lldp_set_callback(sd_lldp *lldp, sd_lldp_cb_t cb, void *userdata) { return 0; } -void sd_lldp_free(sd_lldp *lldp) { +sd_lldp* sd_lldp_unref(sd_lldp *lldp) { if (!lldp) - return; + return NULL; /* Drop all packets */ lldp_mib_objects_flush(lldp); @@ -666,13 +683,14 @@ void sd_lldp_free(sd_lldp *lldp) { prioq_free(lldp->by_expiry); free(lldp); + return NULL; } int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret) { - _cleanup_lldp_free_ sd_lldp *lldp = NULL; + _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL; int r; assert_return(ret, -EINVAL); diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index 6703d87bc..519d2aa36 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 @@ -111,7 +112,7 @@ static NDiscPrefix *ndisc_prefix_unref(NDiscPrefix *prefix) { } static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) { - _cleanup_free_ NDiscPrefix *prefix = NULL; + NDiscPrefix *prefix; assert(ret); @@ -124,8 +125,6 @@ static int ndisc_prefix_new(sd_ndisc *nd, NDiscPrefix **ret) { prefix->nd = nd; *ret = prefix; - prefix = NULL; - return 0; } @@ -244,11 +243,8 @@ sd_ndisc *sd_ndisc_unref(sd_ndisc *nd) { return NULL; } -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_ndisc*, sd_ndisc_unref); -#define _cleanup_sd_ndisc_free_ _cleanup_(sd_ndisc_unrefp) - int sd_ndisc_new(sd_ndisc **ret) { - _cleanup_sd_ndisc_free_ sd_ndisc *nd = NULL; + _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL; assert(ret); @@ -316,7 +312,6 @@ static int ndisc_prefix_match(sd_ndisc *nd, const struct in6_addr *addr, LIST_FOREACH_SAFE(prefixes, prefix, p, nd->prefixes) { if (prefix->valid_until < time_now) { prefix = ndisc_prefix_unref(prefix); - continue; } @@ -357,14 +352,13 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, r = ndisc_prefix_match(nd, &prefix_opt->nd_opt_pi_prefix, prefix_opt->nd_opt_pi_prefix_len, &prefix); + if (r < 0) { + if (r != -EADDRNOTAVAIL) + return r; - if (r < 0 && r != -EADDRNOTAVAIL) - return r; + /* if router advertisment prefix valid timeout is zero, the timeout + callback will be called immediately to clean up the prefix */ - /* if router advertisment prefix valid timeout is zero, the timeout - callback will be called immediately to clean up the prefix */ - - if (r == -EADDRNOTAVAIL) { r = ndisc_prefix_new(nd, &prefix); if (r < 0) return r; @@ -375,9 +369,9 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, sizeof(prefix->addr)); log_ndisc(nd, "New prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len, lifetime_valid, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); + SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), + prefix->len, lifetime_valid, + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); LIST_PREPEND(prefixes, nd->prefixes, prefix); @@ -388,17 +382,17 @@ static int ndisc_prefix_update(sd_ndisc *nd, ssize_t len, prefixlen = MIN(prefix->len, prefix_opt->nd_opt_pi_prefix_len); log_ndisc(nd, "Prefix length mismatch %d/%d using %d", - prefix->len, - prefix_opt->nd_opt_pi_prefix_len, - prefixlen); + prefix->len, + prefix_opt->nd_opt_pi_prefix_len, + prefixlen); prefix->len = prefixlen; } log_ndisc(nd, "Update prefix "SD_NDISC_ADDRESS_FORMAT_STR"/%d lifetime %d expires in %s", - SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), - prefix->len, lifetime_valid, - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); + SD_NDISC_ADDRESS_FORMAT_VAL(prefix->addr), + prefix->len, lifetime_valid, + format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_valid * USEC_PER_SEC, USEC_PER_SEC)); } r = sd_event_now(nd->event, clock_boottime_or_monotonic(), &time_now); @@ -417,8 +411,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; @@ -453,7 +446,7 @@ static int ndisc_ra_parse(sd_ndisc *nd, struct nd_router_advert *ra, nd->mtu = MAX(mtu, IP6_MIN_MTU); log_ndisc(nd, "Router Advertisement link MTU %d using %d", - mtu, nd->mtu); + mtu, nd->mtu); } break; @@ -481,30 +474,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; - ra = malloc(buflen); + iov.iov_len = 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 +593,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 +601,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 +614,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 { diff --git a/src/libsystemd-network/test-acd.c b/src/libsystemd-network/test-acd.c index 69eff5116..75564615b 100644 --- a/src/libsystemd-network/test-acd.c +++ b/src/libsystemd-network/test-acd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -30,7 +28,6 @@ #include "sd-ipv4acd.h" #include "sd-netlink.h" -#include "event-util.h" #include "in-addr-util.h" #include "netlink-util.h" #include "util.h" @@ -76,9 +73,9 @@ static int client_run(int ifindex, const struct in_addr *pa, const struct ether_ } static int test_acd(const char *ifname, const char *address) { - _cleanup_event_unref_ sd_event *e = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *reply = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL; union in_addr_union pa; struct ether_addr ha; int ifindex; diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index 1200a7c25..c3c08fef5 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -31,7 +29,6 @@ #include "dhcp-identifier.h" #include "dhcp-internal.h" #include "dhcp-protocol.h" -#include "event-util.h" #include "fd-util.h" #include "util.h" @@ -78,26 +75,26 @@ static void test_request_basic(sd_event *e) { assert_se(sd_dhcp_client_set_index(client, 1) == 0); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_SUBNET_MASK) == -EEXIST); + SD_DHCP_OPTION_SUBNET_MASK) == -EEXIST); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_ROUTER) == -EEXIST); + SD_DHCP_OPTION_ROUTER) == -EEXIST); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_HOST_NAME) == -EEXIST); + SD_DHCP_OPTION_HOST_NAME) == -EEXIST); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_DOMAIN_NAME) == -EEXIST); + SD_DHCP_OPTION_DOMAIN_NAME) == -EEXIST); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_DOMAIN_NAME_SERVER) == -EEXIST); + SD_DHCP_OPTION_DOMAIN_NAME_SERVER) == -EEXIST); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_PAD) == -EINVAL); + SD_DHCP_OPTION_PAD) == -EINVAL); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_END) == -EINVAL); + SD_DHCP_OPTION_END) == -EINVAL); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_MESSAGE_TYPE) == -EINVAL); + SD_DHCP_OPTION_MESSAGE_TYPE) == -EINVAL); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_OVERLOAD) == -EINVAL); + SD_DHCP_OPTION_OVERLOAD) == -EINVAL); assert_se(sd_dhcp_client_set_request_option(client, - DHCP_OPTION_PARAMETER_REQUEST_LIST) + SD_DHCP_OPTION_PARAMETER_REQUEST_LIST) == -EINVAL); assert_se(sd_dhcp_client_set_request_option(client, 33) == 0); @@ -123,7 +120,7 @@ static void test_checksum(void) { static int check_options(uint8_t code, uint8_t len, const void *option, void *userdata) { switch(code) { - case DHCP_OPTION_CLIENT_IDENTIFIER: + case SD_DHCP_OPTION_CLIENT_IDENTIFIER: { uint32_t iaid; struct duid duid; @@ -223,7 +220,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,11 +387,11 @@ 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); - assert_se(msg_bytes[size - 1] == DHCP_OPTION_END); + assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END); if (verbose) printf(" recv DHCP Request 0x%08x\n", be32toh(xid)); @@ -420,10 +417,10 @@ 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); + assert_se(msg_bytes[size - 1] == SD_DHCP_OPTION_END); xid = discover->xid; @@ -491,7 +488,7 @@ static void test_addr_acq(sd_event *e) { } int main(int argc, char *argv[]) { - _cleanup_event_unref_ sd_event *e; + _cleanup_(sd_event_unrefp) sd_event *e; log_set_max_level(LOG_DEBUG); log_parse_environment(); diff --git a/src/libsystemd-network/test-dhcp-option.c b/src/libsystemd-network/test-dhcp-option.c index 3607df63a..7d8a95722 100644 --- a/src/libsystemd-network/test-dhcp-option.c +++ b/src/libsystemd-network/test-dhcp-option.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #include #include #include @@ -29,7 +27,7 @@ static bool verbose = false; static struct option_desc option_tests[] = { { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69 }, 7, false, }, { {}, 0, {}, 0, { 42, 5, 65, 66, 67, 68, 69, 0, 0, - DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 12, true, }, + SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 12, true, }, { {}, 0, {}, 0, { 8, 255, 70, 71, 72 }, 5, false, }, { {}, 0, {}, 0, { 0x35, 0x01, 0x05, 0x36, 0x04, 0x01, 0x00, 0xa8, 0xc0, 0x33, 0x04, 0x00, 0x01, 0x51, 0x80, 0x01, @@ -37,17 +35,17 @@ static struct option_desc option_tests[] = { 0xa8, 0x00, 0x01, 0x06, 0x04, 0xc0, 0xa8, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, 40, true, }, - { {}, 0, {}, 0, { DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_OFFER, + { {}, 0, {}, 0, { SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_OFFER, 42, 3, 0, 0, 0 }, 8, true, }, { {}, 0, {}, 0, { 42, 2, 1, 2, 44 }, 5, false, }, { {}, 0, - { 222, 3, 1, 2, 3, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8, - { DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, }, + { 222, 3, 1, 2, 3, SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_NAK }, 8, + { SD_DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE }, 3, true, }, - { { 1, 4, 1, 2, 3, 4, DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 9, + { { 1, 4, 1, 2, 3, 4, SD_DHCP_OPTION_MESSAGE_TYPE, 1, DHCP_ACK }, 9, { 222, 3, 1, 2, 3 }, 5, - { DHCP_OPTION_OVERLOAD, 1, + { SD_DHCP_OPTION_OVERLOAD, 1, DHCP_OVERLOAD_FILE|DHCP_OVERLOAD_SNAME }, 3, true, }, }; @@ -75,9 +73,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 +98,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, @@ -130,12 +127,12 @@ static void test_ignore_opts(uint8_t *descoption, int *descpos, int *desclen) { while (*descpos < *desclen) { switch(descoption[*descpos]) { - case DHCP_OPTION_PAD: + case SD_DHCP_OPTION_PAD: *descpos += 1; break; - case DHCP_OPTION_MESSAGE_TYPE: - case DHCP_OPTION_OVERLOAD: + case SD_DHCP_OPTION_MESSAGE_TYPE: + case SD_DHCP_OPTION_OVERLOAD: *descpos += 3; break; @@ -158,10 +155,10 @@ static int test_options_cb(uint8_t code, uint8_t len, const void *option, void * if (!desc) return -EINVAL; - assert_se(code != DHCP_OPTION_PAD); - assert_se(code != DHCP_OPTION_END); - assert_se(code != DHCP_OPTION_MESSAGE_TYPE); - assert_se(code != DHCP_OPTION_OVERLOAD); + assert_se(code != SD_DHCP_OPTION_PAD); + assert_se(code != SD_DHCP_OPTION_END); + assert_se(code != SD_DHCP_OPTION_MESSAGE_TYPE); + assert_se(code != SD_DHCP_OPTION_OVERLOAD); while (desc->pos >= 0 || desc->filepos >= 0 || desc->snamepos >= 0) { @@ -264,19 +261,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)); @@ -306,27 +296,27 @@ static void test_option_set(void) { result->options[2] = 'C'; result->options[3] = 'D'; - assert_se(dhcp_option_append(result, 0, &offset, 0, DHCP_OPTION_PAD, + assert_se(dhcp_option_append(result, 0, &offset, 0, SD_DHCP_OPTION_PAD, 0, NULL) == -ENOBUFS); assert_se(offset == 0); offset = 4; - assert_se(dhcp_option_append(result, 5, &offset, 0, DHCP_OPTION_PAD, + assert_se(dhcp_option_append(result, 5, &offset, 0, SD_DHCP_OPTION_PAD, 0, NULL) == -ENOBUFS); assert_se(offset == 4); - assert_se(dhcp_option_append(result, 6, &offset, 0, DHCP_OPTION_PAD, + assert_se(dhcp_option_append(result, 6, &offset, 0, SD_DHCP_OPTION_PAD, 0, NULL) >= 0); assert_se(offset == 5); offset = pos = 4; len = 11; - while (pos < len && options[pos] != DHCP_OPTION_END) { + while (pos < len && options[pos] != SD_DHCP_OPTION_END) { assert_se(dhcp_option_append(result, len, &offset, DHCP_OVERLOAD_SNAME, options[pos], options[pos + 1], &options[pos + 2]) >= 0); - if (options[pos] == DHCP_OPTION_PAD) + if (options[pos] == SD_DHCP_OPTION_PAD) pos++; else pos += 2 + options[pos + 1]; @@ -344,15 +334,15 @@ static void test_option_set(void) { if (verbose) printf("%2d: 0x%02x(0x%02x) (options)\n", 9, result->options[9], - DHCP_OPTION_END); + SD_DHCP_OPTION_END); - assert_se(result->options[9] == DHCP_OPTION_END); + assert_se(result->options[9] == SD_DHCP_OPTION_END); if (verbose) printf("%2d: 0x%02x(0x%02x) (options)\n", 10, result->options[10], - DHCP_OPTION_PAD); + SD_DHCP_OPTION_PAD); - assert_se(result->options[10] == DHCP_OPTION_PAD); + assert_se(result->options[10] == SD_DHCP_OPTION_PAD); for (i = 0; i < pos - 8; i++) { if (verbose) diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index 2b5f59e4d..e81c508c7 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -26,10 +24,9 @@ #include "sd-event.h" #include "dhcp-server-internal.h" -#include "event-util.h" static void test_pool(struct in_addr *address, unsigned size, int ret) { - _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; + _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL; assert_se(sd_dhcp_server_new(&server, 1) >= 0); @@ -37,7 +34,7 @@ static void test_pool(struct in_addr *address, unsigned size, int ret) { } static int test_basic(sd_event *event) { - _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; + _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL; struct in_addr address_lo = { .s_addr = htonl(INADDR_LOOPBACK), }; @@ -86,7 +83,7 @@ static int test_basic(sd_event *event) { } static void test_message_handler(void) { - _cleanup_dhcp_server_unref_ sd_dhcp_server *server = NULL; + _cleanup_(sd_dhcp_server_unrefp) sd_dhcp_server *server = NULL; struct { DHCPMessage message; struct { @@ -116,10 +113,10 @@ static void test_message_handler(void) { .message.hlen = ETHER_ADDR_LEN, .message.xid = htobe32(0x12345678), .message.chaddr = { 'A', 'B', 'C', 'D', 'E', 'F' }, - .option_type.code = DHCP_OPTION_MESSAGE_TYPE, + .option_type.code = SD_DHCP_OPTION_MESSAGE_TYPE, .option_type.length = 1, .option_type.type = DHCP_DISCOVER, - .end = DHCP_OPTION_END, + .end = SD_DHCP_OPTION_END, }; struct in_addr address_lo = { .s_addr = htonl(INADDR_LOOPBACK), @@ -135,14 +132,14 @@ static void test_message_handler(void) { test.end = 0; /* TODO, shouldn't this fail? */ assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); - test.end = DHCP_OPTION_END; + test.end = SD_DHCP_OPTION_END; assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); test.option_type.code = 0; test.option_type.length = 0; test.option_type.type = 0; assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); - test.option_type.code = DHCP_OPTION_MESSAGE_TYPE; + test.option_type.code = SD_DHCP_OPTION_MESSAGE_TYPE; test.option_type.length = 1; test.option_type.type = DHCP_DISCOVER; assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_OFFER); @@ -164,11 +161,11 @@ static void test_message_handler(void) { test.option_type.type = DHCP_REQUEST; assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == 0); - test.option_requested_ip.code = DHCP_OPTION_REQUESTED_IP_ADDRESS; + test.option_requested_ip.code = SD_DHCP_OPTION_REQUESTED_IP_ADDRESS; test.option_requested_ip.length = 4; test.option_requested_ip.address = htobe32(0x12345678); assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_NAK); - test.option_server_id.code = DHCP_OPTION_SERVER_IDENTIFIER; + test.option_server_id.code = SD_DHCP_OPTION_SERVER_IDENTIFIER; test.option_server_id.length = 4; test.option_server_id.address = htobe32(INADDR_LOOPBACK); test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); @@ -183,7 +180,7 @@ static void test_message_handler(void) { test.option_requested_ip.address = htobe32(INADDR_LOOPBACK + 3); assert_se(dhcp_server_handle_message(server, (DHCPMessage*)&test, sizeof(test)) == DHCP_ACK); - test.option_client_id.code = DHCP_OPTION_CLIENT_IDENTIFIER; + test.option_client_id.code = SD_DHCP_OPTION_CLIENT_IDENTIFIER; test.option_client_id.length = 7; test.option_client_id.id[0] = 0x01; test.option_client_id.id[1] = 'A'; @@ -244,7 +241,7 @@ static void test_client_id_hash(void) { } int main(int argc, char *argv[]) { - _cleanup_event_unref_ sd_event *e; + _cleanup_(sd_event_unrefp) sd_event *e; int r; log_set_max_level(LOG_DEBUG); diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index 9e05fde8f..e74c8c72d 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -32,7 +30,6 @@ #include "dhcp6-internal.h" #include "dhcp6-lease-internal.h" #include "dhcp6-protocol.h" -#include "event-util.h" #include "fd-util.h" #include "macro.h" #include "socket-util.h" @@ -71,11 +68,11 @@ static int test_client_basic(sd_event *e) { sizeof (mac_addr), ARPHRD_ETHER) >= 0); - assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_CLIENTID) == -EINVAL); - assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EEXIST); - assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_NTP_SERVER) == -EEXIST); - assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_SNTP_SERVERS) == -EEXIST); - assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DOMAIN_LIST) == -EEXIST); + assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_CLIENTID) == -EINVAL); + assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EEXIST); + assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_NTP_SERVER) == -EEXIST); + assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_SNTP_SERVERS) == -EEXIST); + assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DOMAIN_LIST) == -EEXIST); assert_se(sd_dhcp6_client_set_request_option(client, 10) == -EINVAL); assert_se(sd_dhcp6_client_set_callback(client, NULL, NULL) >= 0); @@ -89,9 +86,9 @@ static int test_client_basic(sd_event *e) { static int test_option(sd_event *e) { uint8_t packet[] = { 'F', 'O', 'O', - 0x00, DHCP6_OPTION_ORO, 0x00, 0x07, + 0x00, SD_DHCP6_OPTION_ORO, 0x00, 0x07, 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 0x00, DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09, + 0x00, SD_DHCP6_OPTION_VENDOR_CLASS, 0x00, 0x09, '1', '2', '3', '4', '5', '6', '7', '8', '9', 'B', 'A', 'R', }; @@ -125,7 +122,7 @@ static int test_option(sd_event *e) { &optval) >= 0); pos += 4 + optlen; assert_se(buf == &packet[pos]); - assert_se(optcode == DHCP6_OPTION_ORO); + assert_se(optcode == SD_DHCP6_OPTION_ORO); assert_se(optlen == 7); assert_se(buflen + pos == sizeof(packet)); @@ -138,7 +135,7 @@ static int test_option(sd_event *e) { &optval) >= 0); pos += 4 + optlen; assert_se(buf == &packet[pos]); - assert_se(optcode == DHCP6_OPTION_VENDOR_CLASS); + assert_se(optcode == SD_DHCP6_OPTION_VENDOR_CLASS); assert_se(optlen == 9); assert_se(buflen + pos == sizeof(packet)); @@ -206,7 +203,7 @@ static uint8_t msg_reply[173] = { }; static int test_advertise_option(sd_event *e) { - _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; + _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; DHCP6Message *advertise = (DHCP6Message *)msg_advertise; uint8_t *optval, *opt = msg_advertise + sizeof(DHCP6Message); uint16_t optcode; @@ -233,13 +230,13 @@ static int test_advertise_option(sd_event *e) { &optval)) >= 0) { switch(optcode) { - case DHCP6_OPTION_CLIENTID: + case SD_DHCP6_OPTION_CLIENTID: assert_se(optlen == 14); opt_clientid = true; break; - case DHCP6_OPTION_IA_NA: + case SD_DHCP6_OPTION_IA_NA: assert_se(optlen == 94); assert_se(!memcmp(optval, &msg_advertise[26], optlen)); @@ -258,7 +255,7 @@ static int test_advertise_option(sd_event *e) { break; - case DHCP6_OPTION_SERVERID: + case SD_DHCP6_OPTION_SERVERID: assert_se(optlen == 14); assert_se(!memcmp(optval, &msg_advertise[179], optlen)); @@ -266,7 +263,7 @@ static int test_advertise_option(sd_event *e) { optlen) >= 0); break; - case DHCP6_OPTION_PREFERENCE: + case SD_DHCP6_OPTION_PREFERENCE: assert_se(optlen == 1); assert_se(!*optval); @@ -274,24 +271,24 @@ static int test_advertise_option(sd_event *e) { *optval) >= 0); break; - case DHCP6_OPTION_ELAPSED_TIME: + case SD_DHCP6_OPTION_ELAPSED_TIME: assert_se(optlen == 2); break; - case DHCP6_OPTION_DNS_SERVERS: + case SD_DHCP6_OPTION_DNS_SERVERS: assert_se(optlen == 16); assert_se(dhcp6_lease_set_dns(lease, optval, optlen) >= 0); break; - case DHCP6_OPTION_DOMAIN_LIST: + case SD_DHCP6_OPTION_DOMAIN_LIST: assert_se(optlen == 11); assert_se(dhcp6_lease_set_domains(lease, optval, optlen) >= 0); break; - case DHCP6_OPTION_SNTP_SERVERS: + case SD_DHCP6_OPTION_SNTP_SERVERS: assert_se(optlen == 16); assert_se(dhcp6_lease_set_sntp(lease, optval, optlen) >= 0); @@ -380,7 +377,7 @@ static void test_client_solicit_cb(sd_dhcp6_client *client, int event, assert_se(sd_dhcp6_lease_get_ntp_addrs(lease, &addrs) == 1); assert_se(!memcmp(addrs, &msg_advertise[159], 16)); - assert_se(sd_dhcp6_client_set_request_option(client, DHCP6_OPTION_DNS_SERVERS) == -EBUSY); + assert_se(sd_dhcp6_client_set_request_option(client, SD_DHCP6_OPTION_DNS_SERVERS) == -EBUSY); if (verbose) printf(" got DHCPv6 event %d\n", event); @@ -408,7 +405,7 @@ static int test_client_send_reply(DHCP6Message *request) { static int test_client_verify_request(DHCP6Message *request, uint8_t *option, size_t len) { - _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; + _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; uint8_t *optval; uint16_t optcode; size_t optlen; @@ -426,7 +423,7 @@ static int test_client_verify_request(DHCP6Message *request, uint8_t *option, while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen, &optval)) >= 0) { switch(optcode) { - case DHCP6_OPTION_CLIENTID: + case SD_DHCP6_OPTION_CLIENTID: assert_se(!found_clientid); found_clientid = true; @@ -435,7 +432,7 @@ static int test_client_verify_request(DHCP6Message *request, uint8_t *option, break; - case DHCP6_OPTION_IA_NA: + case SD_DHCP6_OPTION_IA_NA: assert_se(!found_iana); found_iana = true; @@ -454,7 +451,7 @@ static int test_client_verify_request(DHCP6Message *request, uint8_t *option, break; - case DHCP6_OPTION_SERVERID: + case SD_DHCP6_OPTION_SERVERID: assert_se(!found_serverid); found_serverid = true; @@ -463,7 +460,7 @@ static int test_client_verify_request(DHCP6Message *request, uint8_t *option, break; - case DHCP6_OPTION_ELAPSED_TIME: + case SD_DHCP6_OPTION_ELAPSED_TIME: assert_se(!found_elapsed_time); found_elapsed_time = true; @@ -522,7 +519,7 @@ static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option, while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen, &optval)) >= 0) { switch(optcode) { - case DHCP6_OPTION_CLIENTID: + case SD_DHCP6_OPTION_CLIENTID: assert_se(!found_clientid); found_clientid = true; @@ -531,7 +528,7 @@ static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option, break; - case DHCP6_OPTION_IA_NA: + case SD_DHCP6_OPTION_IA_NA: assert_se(!found_iana); found_iana = true; @@ -541,7 +538,7 @@ static int test_client_verify_solicit(DHCP6Message *solicit, uint8_t *option, break; - case DHCP6_OPTION_ELAPSED_TIME: + case SD_DHCP6_OPTION_ELAPSED_TIME: assert_se(!found_elapsed_time); found_elapsed_time = true; @@ -599,7 +596,7 @@ static void test_client_information_cb(sd_dhcp6_client *client, int event, static int test_client_verify_information_request(DHCP6Message *information_request, uint8_t *option, size_t len) { - _cleanup_dhcp6_lease_free_ sd_dhcp6_lease *lease = NULL; + _cleanup_(sd_dhcp6_lease_unrefp) sd_dhcp6_lease *lease = NULL; uint8_t *optval; uint16_t optcode; size_t optlen; @@ -615,7 +612,7 @@ static int test_client_verify_information_request(DHCP6Message *information_requ while ((r = dhcp6_option_parse(&option, &len, &optcode, &optlen, &optval)) >= 0) { switch(optcode) { - case DHCP6_OPTION_CLIENTID: + case SD_DHCP6_OPTION_CLIENTID: assert_se(!found_clientid); found_clientid = true; @@ -624,17 +621,17 @@ static int test_client_verify_information_request(DHCP6Message *information_requ break; - case DHCP6_OPTION_IA_NA: + case SD_DHCP6_OPTION_IA_NA: assert_not_reached("IA TA option must not be present"); break; - case DHCP6_OPTION_SERVERID: + case SD_DHCP6_OPTION_SERVERID: assert_not_reached("Server ID option must not be present"); break; - case DHCP6_OPTION_ELAPSED_TIME: + case SD_DHCP6_OPTION_ELAPSED_TIME: assert_se(!found_elapsed_time); found_elapsed_time = true; @@ -749,7 +746,7 @@ static int test_client_solicit(sd_event *e) { } int main(int argc, char *argv[]) { - _cleanup_event_unref_ sd_event *e; + _cleanup_(sd_event_unrefp) sd_event *e; assert_se(sd_event_new(&e) >= 0); diff --git a/src/libsystemd-network/test-ipv4ll-manual.c b/src/libsystemd-network/test-ipv4ll-manual.c index 913a92906..85dd61470 100644 --- a/src/libsystemd-network/test-ipv4ll-manual.c +++ b/src/libsystemd-network/test-ipv4ll-manual.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -30,7 +28,6 @@ #include "sd-netlink.h" #include "alloc-util.h" -#include "event-util.h" #include "in-addr-util.h" #include "netlink-util.h" #include "parse-util.h" @@ -91,9 +88,9 @@ static int client_run(int ifindex, const char *seed_str, const struct ether_addr } static int test_ll(const char *ifname, const char *seed) { - _cleanup_event_unref_ sd_event *e = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *reply = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL; struct ether_addr ha; int ifindex; diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index 6f416c51e..a233e0378 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -1,4 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*** This file is part of systemd. @@ -29,7 +28,6 @@ #include "sd-ipv4ll.h" #include "arp-util.h" -#include "event-util.h" #include "fd-util.h" #include "socket-util.h" #include "util.h" @@ -207,7 +205,7 @@ static void test_basic_request(sd_event *e) { } int main(int argc, char *argv[]) { - _cleanup_event_unref_ sd_event *e = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; log_set_max_level(LOG_DEBUG); log_parse_environment(); diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index 99545d0b8..b8490073d 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -29,7 +27,6 @@ #include "sd-lldp.h" #include "alloc-util.h" -#include "event-util.h" #include "fd-util.h" #include "lldp-network.h" #include "lldp-tlv.h" @@ -48,7 +45,7 @@ static struct ether_addr mac_addr = { }; static int lldp_build_tlv_packet(tlv_packet **ret) { - _cleanup_lldp_packet_unref_ tlv_packet *m = NULL; + _cleanup_(sd_lldp_packet_unrefp) tlv_packet *m = NULL; const uint8_t lldp_dst[] = LLDP_MULTICAST_ADDR; struct ether_header ether = { .ether_type = htons(ETHERTYPE_LLDP), @@ -237,7 +234,7 @@ static int lldp_parse_tlv_packet(tlv_packet *m, int len) { } static void test_parser(void) { - _cleanup_lldp_packet_unref_ tlv_packet *tlv = NULL; + _cleanup_(sd_lldp_packet_unrefp) tlv_packet *tlv = NULL; /* form a packet */ lldp_build_tlv_packet(&tlv); @@ -292,7 +289,7 @@ static int stop_lldp(sd_lldp *lldp) { if (r) return r; - sd_lldp_free(lldp); + sd_lldp_unref(lldp); safe_close(test_fd[1]); return 0; @@ -457,7 +454,7 @@ static void test_receive_oui_packet(sd_event *e) { } int main(int argc, char *argv[]) { - _cleanup_event_unref_ sd_event *e = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; test_parser(); diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c index a485be704..f7b2eb805 100644 --- a/src/libsystemd-network/test-ndisc-rs.c +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 043ff13e6..4ab637b68 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -481,3 +481,11 @@ global: sd_bus_path_encode_many; sd_listen_fds_with_names; } LIBSYSTEMD_226; + +LIBSYSTEMD_229 { +global: + sd_journal_has_runtime_files; + sd_journal_has_persistent_files; + sd_journal_enumerate_fields; + sd_journal_restart_fields; +} LIBSYSTEMD_227; diff --git a/src/libsystemd/sd-bus/bus-bloom.c b/src/libsystemd/sd-bus/bus-bloom.c index c0c5d445e..112769fcb 100644 --- a/src/libsystemd/sd-bus/bus-bloom.c +++ b/src/libsystemd/sd-bus/bus-bloom.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-bloom.h b/src/libsystemd/sd-bus/bus-bloom.h index 38892044f..c824622b9 100644 --- a/src/libsystemd/sd-bus/bus-bloom.h +++ b/src/libsystemd/sd-bus/bus-bloom.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index 8d486fcbb..3c19f2b10 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -39,7 +37,7 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_JOBS_CONFLICTING, EDEADLK), SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, EDEADLK), SD_BUS_ERROR_MAP(BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, EDEADLK), - SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED, EBADR), + SD_BUS_ERROR_MAP(BUS_ERROR_UNIT_MASKED, ESHUTDOWN), SD_BUS_ERROR_MAP(BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, EBADR), SD_BUS_ERROR_MAP(BUS_ERROR_NO_ISOLATION, EPERM), SD_BUS_ERROR_MAP(BUS_ERROR_SHUTTING_DOWN, ECANCELED), @@ -67,12 +65,20 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_PROCESS, ESRCH), - SD_BUS_ERROR_MAP(BUS_ERROR_NO_NAME_SERVERS, EIO), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_NAME_SERVERS, ESRCH), SD_BUS_ERROR_MAP(BUS_ERROR_INVALID_REPLY, EINVAL), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_RR, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_NO_RESOURCES, ENOMEM), SD_BUS_ERROR_MAP(BUS_ERROR_CNAME_LOOP, EDEADLK), SD_BUS_ERROR_MAP(BUS_ERROR_ABORTED, ECANCELED), + SD_BUS_ERROR_MAP(BUS_ERROR_CONNECTION_FAILURE, ECONNREFUSED), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_SERVICE, EUNATCH), + SD_BUS_ERROR_MAP(BUS_ERROR_DNSSEC_FAILED, EHOSTUNREACH), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_TRUST_ANCHOR, EHOSTUNREACH), + SD_BUS_ERROR_MAP(BUS_ERROR_RR_TYPE_UNSUPPORTED, EOPNOTSUPP), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_LINK, ENXIO), + SD_BUS_ERROR_MAP(BUS_ERROR_LINK_BUSY, EBUSY), + SD_BUS_ERROR_MAP(BUS_ERROR_NETWORK_DOWN, ENETDOWN), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_TRANSFER, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_TRANSFER_IN_PROGRESS, EBUSY), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index f2092795f..fab8748f4 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -72,6 +70,14 @@ #define BUS_ERROR_NO_RESOURCES "org.freedesktop.resolve1.NoResources" #define BUS_ERROR_CNAME_LOOP "org.freedesktop.resolve1.CNameLoop" #define BUS_ERROR_ABORTED "org.freedesktop.resolve1.Aborted" +#define BUS_ERROR_CONNECTION_FAILURE "org.freedesktop.resolve1.ConnectionFailure" +#define BUS_ERROR_NO_SUCH_SERVICE "org.freedesktop.resolve1.NoSuchService" +#define BUS_ERROR_DNSSEC_FAILED "org.freedesktop.resolve1.DnssecFailed" +#define BUS_ERROR_NO_TRUST_ANCHOR "org.freedesktop.resolve1.NoTrustAnchor" +#define BUS_ERROR_RR_TYPE_UNSUPPORTED "org.freedesktop.resolve1.ResourceRecordTypeUnsupported" +#define BUS_ERROR_NO_SUCH_LINK "org.freedesktop.resolve1.NoSuchLink" +#define BUS_ERROR_LINK_BUSY "org.freedesktop.resolve1.LinkBusy" +#define BUS_ERROR_NETWORK_DOWN "org.freedesktop.resolve1.NetworkDown" #define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError." #define BUS_ERROR_NO_SUCH_TRANSFER "org.freedesktop.import1.NoSuchTransfer" diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index 7da6ba990..3191d27de 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-container.h b/src/libsystemd/sd-bus/bus-container.h index c6f757a99..509ef4562 100644 --- a/src/libsystemd/sd-bus/bus-container.h +++ b/src/libsystemd/sd-bus/bus-container.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index 94251fe87..05222b8d3 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -91,7 +89,7 @@ static int bus_request_name_kernel(sd_bus *bus, const char *name, uint64_t flags } static int bus_request_name_dbus1(sd_bus *bus, const char *name, uint64_t flags) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; uint32_t ret, param = 0; int r; @@ -187,7 +185,7 @@ static int bus_release_name_kernel(sd_bus *bus, const char *name) { } static int bus_release_name_dbus1(sd_bus *bus, const char *name) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; uint32_t ret; int r; @@ -326,7 +324,7 @@ static int bus_list_names_kernel(sd_bus *bus, char ***acquired, char ***activata } static int bus_list_names_dbus1(sd_bus *bus, char ***acquired, char ***activatable) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_strv_free_ char **x = NULL, **y = NULL; int r; @@ -647,7 +645,7 @@ int bus_get_name_creds_kdbus( bool allow_activator, sd_bus_creds **creds) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; struct kdbus_cmd_info *cmd; struct kdbus_info *conn_info; size_t size, l; @@ -753,8 +751,8 @@ static int bus_get_name_creds_dbus1( uint64_t mask, sd_bus_creds **creds) { - _cleanup_bus_message_unref_ sd_bus_message *reply_unique = NULL, *reply = NULL; - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; const char *unique = NULL; pid_t pid = 0; int r; @@ -858,7 +856,7 @@ static int bus_get_name_creds_dbus1( } if (mask & SD_BUS_CREDS_SELINUX_CONTEXT) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const void *p = NULL; size_t sz = 0; @@ -930,7 +928,7 @@ _public_ int sd_bus_get_name_creds( } static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; struct kdbus_cmd_info cmd = { .size = sizeof(struct kdbus_cmd_info), }; @@ -979,7 +977,7 @@ static int bus_get_owner_creds_kdbus(sd_bus *bus, uint64_t mask, sd_bus_creds ** } static int bus_get_owner_creds_dbus1(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) { - _cleanup_bus_creds_unref_ sd_bus_creds *c = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; pid_t pid = 0; bool do_label; int r; @@ -1543,7 +1541,7 @@ int bus_remove_match_internal( } _public_ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machine) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; const char *mid; int r; diff --git a/src/libsystemd/sd-bus/bus-control.h b/src/libsystemd/sd-bus/bus-control.h index 5009ca8e6..c181aa795 100644 --- a/src/libsystemd/sd-bus/bus-control.h +++ b/src/libsystemd/sd-bus/bus-control.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,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-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c index 0afafc294..2d06bf541 100644 --- a/src/libsystemd/sd-bus/bus-convenience.c +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -33,7 +31,7 @@ _public_ int sd_bus_emit_signal( const char *member, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert_return(bus, -EINVAL); @@ -70,7 +68,7 @@ _public_ int sd_bus_call_method_async( void *userdata, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert_return(bus, -EINVAL); @@ -106,7 +104,7 @@ _public_ int sd_bus_call_method( sd_bus_message **reply, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; bus_assert_return(bus, -EINVAL, error); @@ -141,7 +139,7 @@ _public_ int sd_bus_reply_method_return( sd_bus_message *call, const char *types, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert_return(call, -EINVAL); @@ -177,7 +175,7 @@ _public_ int sd_bus_reply_method_error( sd_bus_message *call, const sd_bus_error *e) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert_return(call, -EINVAL); @@ -206,7 +204,7 @@ _public_ int sd_bus_reply_method_errorf( const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; va_list ap; assert_return(call, -EINVAL); @@ -233,7 +231,7 @@ _public_ int sd_bus_reply_method_errno( int error, const sd_bus_error *p) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; assert_return(call, -EINVAL); assert_return(call->sealed, -EPERM); @@ -261,7 +259,7 @@ _public_ int sd_bus_reply_method_errnof( const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; va_list ap; assert_return(call, -EINVAL); @@ -334,7 +332,7 @@ _public_ int sd_bus_get_property_trivial( sd_bus_error *error, char type, void *ptr) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; bus_assert_return(bus, -EINVAL, error); @@ -376,7 +374,7 @@ _public_ int sd_bus_get_property_string( sd_bus_error *error, char **ret) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *s; char *n; int r; @@ -426,7 +424,7 @@ _public_ int sd_bus_get_property_strv( sd_bus_error *error, char ***ret) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; bus_assert_return(bus, -EINVAL, error); @@ -467,7 +465,7 @@ _public_ int sd_bus_set_property( sd_bus_error *error, const char *type, ...) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; va_list ap; int r; @@ -555,7 +553,7 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b } _public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; uid_t our_uid; bool know_caps = false; int r; diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 2922da376..c4f693dee 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -75,7 +73,9 @@ void bus_creds_done(sd_bus_creds *c) { } _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) { - assert_return(c, NULL); + + if (!c) + return NULL; if (c->allocated) { assert(c->n_ref > 0); @@ -1118,7 +1118,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { } int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret) { - _cleanup_bus_creds_unref_ sd_bus_creds *n = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *n = NULL; int r; assert(c); diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h index 209d21612..df8a1f100 100644 --- a/src/libsystemd/sd-bus/bus-creds.h +++ b/src/libsystemd/sd-bus/bus-creds.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 43a7e67a6..7c81e7a25 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-dump.h b/src/libsystemd/sd-bus/bus-dump.h index d2522edeb..874e86d09 100644 --- a/src/libsystemd/sd-bus/bus-dump.h +++ b/src/libsystemd/sd-bus/bus-dump.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "sd-bus.h" diff --git a/src/libsystemd/sd-bus/bus-error.c b/src/libsystemd/sd-bus/bus-error.c index 404eaa3c8..26219bdee 100644 --- a/src/libsystemd/sd-bus/bus-error.c +++ b/src/libsystemd/sd-bus/bus-error.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -93,14 +91,14 @@ static int bus_error_name_to_errno(const char *name) { p = startswith(name, "System.Error."); if (p) { r = errno_from_name(p); - if (r <= 0) + if (r < 0) return EIO; return r; } - if (additional_error_maps) { - for (map = additional_error_maps; *map; map++) { + if (additional_error_maps) + for (map = additional_error_maps; *map; map++) for (m = *map;; m++) { /* For additional error maps the end marker is actually the end marker */ if (m->code == BUS_ERROR_MAP_END_MARKER) @@ -109,15 +107,13 @@ static int bus_error_name_to_errno(const char *name) { if (streq(m->name, name)) return m->code; } - } - } m = __start_BUS_ERROR_MAP; while (m < __stop_BUS_ERROR_MAP) { /* For magic ELF error maps, the end marker might * appear in the middle of things, since multiple maps * might appear in the same section. Hence, let's skip - * over it, but realign the pointer to the netx 8byte + * over it, but realign the pointer to the next 8 byte * boundary, which is the selected alignment for the * arrays. */ if (m->code == BUS_ERROR_MAP_END_MARKER) { @@ -258,25 +254,24 @@ int bus_error_setfv(sd_bus_error *e, const char *name, const char *format, va_li if (!name) return 0; - if (!e) - goto finish; - assert_return(!bus_error_is_dirty(e), -EINVAL); + if (e) { + assert_return(!bus_error_is_dirty(e), -EINVAL); - e->name = strdup(name); - if (!e->name) { - *e = BUS_ERROR_OOM; - return -ENOMEM; + e->name = strdup(name); + if (!e->name) { + *e = BUS_ERROR_OOM; + return -ENOMEM; + } + + /* If we hit OOM on formatting the pretty message, we ignore + * this, since we at least managed to write the error name */ + if (format) + (void) vasprintf((char**) &e->message, format, ap); + + e->_need_free = 1; } - /* If we hit OOM on formatting the pretty message, we ignore - * this, since we at least managed to write the error name */ - if (format) - (void) vasprintf((char**) &e->message, format, ap); - - e->_need_free = 1; - -finish: return -bus_error_name_to_errno(name); } @@ -582,27 +577,29 @@ const char *bus_error_message(const sd_bus_error *e, int error) { return strerror(error); } +static bool map_ok(const sd_bus_error_map *map) { + for (; map->code != BUS_ERROR_MAP_END_MARKER; map++) + if (!map->name || map->code <=0) + return false; + return true; +} + _public_ int sd_bus_error_add_map(const sd_bus_error_map *map) { const sd_bus_error_map **maps = NULL; unsigned n = 0; assert_return(map, -EINVAL); + assert_return(map_ok(map), -EINVAL); - if (additional_error_maps) { - for (;; n++) { - if (additional_error_maps[n] == NULL) - break; - + if (additional_error_maps) + for (; additional_error_maps[n] != NULL; n++) if (additional_error_maps[n] == map) return 0; - } - } maps = realloc_multiply(additional_error_maps, sizeof(struct sd_bus_error_map*), n + 2); if (!maps) return -ENOMEM; - maps[n] = map; maps[n+1] = NULL; diff --git a/src/libsystemd/sd-bus/bus-error.h b/src/libsystemd/sd-bus/bus-error.h index fb0199c94..e2c4cf4b3 100644 --- a/src/libsystemd/sd-bus/bus-error.h +++ b/src/libsystemd/sd-bus/bus-error.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,6 +22,7 @@ #include #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 ec027590b..58782767f 100644 --- a/src/libsystemd/sd-bus/bus-gvariant.c +++ b/src/libsystemd/sd-bus/bus-gvariant.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-gvariant.h b/src/libsystemd/sd-bus/bus-gvariant.h index 875d34b59..6da637fb0 100644 --- a/src/libsystemd/sd-bus/bus-gvariant.h +++ b/src/libsystemd/sd-bus/bus-gvariant.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c index d9f9cd1c5..caca67908 100644 --- a/src/libsystemd/sd-bus/bus-internal.c +++ b/src/libsystemd/sd-bus/bus-internal.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index 5fc0926f0..216d9f62b 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -381,7 +379,7 @@ char *bus_address_escape(const char *v); * bus from the callback doesn't destroy the object we are working * on */ #define BUS_DONT_DESTROY(bus) \ - _cleanup_bus_unref_ _unused_ sd_bus *_dont_destroy_##bus = sd_bus_ref(bus) + _cleanup_(sd_bus_unrefp) _unused_ sd_bus *_dont_destroy_##bus = sd_bus_ref(bus) int bus_set_address_system(sd_bus *bus); int bus_set_address_user(sd_bus *bus); diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c index a90536bac..8f93edb8d 100644 --- a/src/libsystemd/sd-bus/bus-introspect.c +++ b/src/libsystemd/sd-bus/bus-introspect.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h index 1914e6cb8..8e2f3800c 100644 --- a/src/libsystemd/sd-bus/bus-introspect.h +++ b/src/libsystemd/sd-bus/bus-introspect.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,6 +22,7 @@ #include #include "sd-bus.h" + #include "set.h" struct introspect { diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index 6716f6dac..0896eeb17 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -47,6 +45,7 @@ #include "formats-util.h" #include "memfd-util.h" #include "parse-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "user-util.h" @@ -269,8 +268,8 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { struct bus_body_part *part; struct kdbus_item *d; const char *destination; - bool well_known; - uint64_t unique; + bool well_known = false; + uint64_t dst_id; size_t sz, dl; unsigned i; int r; @@ -287,13 +286,21 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { destination = m->destination ?: m->destination_ptr; if (destination) { - r = bus_kernel_parse_unique_name(destination, &unique); + r = bus_kernel_parse_unique_name(destination, &dst_id); if (r < 0) return r; + if (r == 0) { + well_known = true; - well_known = r == 0; + /* verify_destination_id will usually be 0, which makes the kernel + * driver only look at the provided well-known name. Otherwise, + * the kernel will make sure the provided destination id matches + * the owner of the provided well-known-name, and fail if they + * differ. Currently, this is only needed for bus-proxyd. */ + dst_id = m->verify_destination_id; + } } else - well_known = false; + dst_id = KDBUS_DST_ID_BROADCAST; sz = offsetof(struct kdbus_msg, items); @@ -331,15 +338,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_NO_AUTO_START : 0) | ((m->header->type == SD_BUS_MESSAGE_SIGNAL) ? KDBUS_MSG_SIGNAL : 0); - if (well_known) - /* verify_destination_id will usually be 0, which makes the kernel driver only look - * at the provided well-known name. Otherwise, the kernel will make sure the provided - * destination id matches the owner of the provided weel-known-name, and fail if they - * differ. Currently, this is only needed for bus-proxyd. */ - m->kdbus->dst_id = m->verify_destination_id; - else - m->kdbus->dst_id = destination ? unique : KDBUS_DST_ID_BROADCAST; - + m->kdbus->dst_id = dst_id; m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS; m->kdbus->cookie = m->header->dbus2.cookie; m->kdbus->priority = m->priority; @@ -849,7 +848,8 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { if (k->src_id == KDBUS_SRC_ID_KERNEL) bus_message_set_sender_driver(bus, m); else { - snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id); + xsprintf(m->sender_buffer, ":1.%llu", + (unsigned long long)k->src_id); m->sender = m->creds.unique_name = m->sender_buffer; } @@ -860,7 +860,8 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) { else if (k->dst_id == KDBUS_DST_ID_NAME) m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */ else { - snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id); + xsprintf(m->destination_buffer, ":1.%llu", + (unsigned long long)k->dst_id); m->destination = m->destination_buffer; } @@ -1142,7 +1143,7 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call r = ioctl(bus->output_fd, KDBUS_CMD_SEND, &cmd); if (r < 0) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus_message *reply; if (errno == EAGAIN || errno == EINTR) @@ -1221,7 +1222,7 @@ static int push_name_owner_changed( const char *new_owner, const struct kdbus_timestamp *ts) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(bus); @@ -1308,7 +1309,7 @@ static int translate_reply( const struct kdbus_item *d, const struct kdbus_timestamp *ts) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(bus); diff --git a/src/libsystemd/sd-bus/bus-kernel.h b/src/libsystemd/sd-bus/bus-kernel.h index bb4dff6d8..53ba3bdcf 100644 --- a/src/libsystemd/sd-bus/bus-kernel.h +++ b/src/libsystemd/sd-bus/bus-kernel.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index 55dc7caa5..397baf6f3 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -317,7 +315,7 @@ int bus_match_run( /* Run the callback. And then invoke siblings. */ if (node->leaf.callback->callback) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; sd_bus_slot *slot; slot = container_of(node->leaf.callback, sd_bus_slot, match_callback); diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h index bc85af3ec..8cbbb63b1 100644 --- a/src/libsystemd/sd-bus/bus-match.h +++ b/src/libsystemd/sd-bus/bus-match.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 5c80095bf..7be28c509 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -802,7 +800,7 @@ _public_ int sd_bus_message_new_method_errorf( const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; va_list ap; assert_return(name, -EINVAL); @@ -821,7 +819,7 @@ _public_ int sd_bus_message_new_method_errno( int error, const sd_bus_error *p) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; if (sd_bus_error_is_set(p)) return sd_bus_message_new_method_error(call, m, p); @@ -838,7 +836,7 @@ _public_ int sd_bus_message_new_method_errnof( const char *format, ...) { - _cleanup_bus_error_free_ sd_bus_error berror = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL; va_list ap; va_start(ap, format); @@ -919,7 +917,9 @@ fail: } _public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { - assert_return(m, NULL); + + if (!m) + return NULL; assert(m->n_ref > 0); m->n_ref++; @@ -5838,7 +5838,7 @@ _public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) { } int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) { - _cleanup_bus_message_unref_ sd_bus_message *n = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL; usec_t timeout; int r; diff --git a/src/libsystemd/sd-bus/bus-message.h b/src/libsystemd/sd-bus/bus-message.h index 4c91dbae0..4710c106b 100644 --- a/src/libsystemd/sd-bus/bus-message.h +++ b/src/libsystemd/sd-bus/bus-message.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 303e49fa8..1f285ae8a 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -272,7 +270,7 @@ static int node_callbacks_run( assert(found_object); LIST_FOREACH(callbacks, c, first) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; sd_bus_slot *slot; if (bus->nodes_modified) @@ -357,7 +355,7 @@ static int method_callbacks_run( bool require_fallback, bool *found_object) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *signature; void *u; int r; @@ -580,8 +578,8 @@ static int property_get_set_callbacks_run( bool is_get, bool *found_object) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; sd_bus_slot *slot; void *u = NULL; int r; @@ -781,7 +779,7 @@ static int property_get_all_callbacks_run( const char *iface, bool *found_object) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; struct node_vtable *c; bool found_interface; int r; @@ -804,7 +802,7 @@ static int property_get_all_callbacks_run( streq(iface, "org.freedesktop.DBus.Introspectable"); LIST_FOREACH(vtables, c, first) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; void *u; if (require_fallback && !c->is_fallback) @@ -881,7 +879,7 @@ static int bus_node_exists( } LIST_FOREACH(vtables, c, n->vtables) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (require_fallback && !c->is_fallback) continue; @@ -903,8 +901,8 @@ static int process_introspect( bool require_fallback, bool *found_object) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_set_free_free_ Set *s = NULL; const char *previous_interface = NULL; struct introspect intro; @@ -1164,8 +1162,8 @@ static int process_get_managed_objects( bool require_fallback, bool *found_object) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_set_free_free_ Set *s = NULL; Iterator i; char *path; @@ -1881,8 +1879,8 @@ static int emit_properties_changed_on_interface( bool *found_interface, char **names) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; bool has_invalidating = false, has_changing = false; struct vtable_member key = {}; struct node_vtable *c; @@ -2176,7 +2174,7 @@ static int object_added_append_all_prefix( return 0; LIST_FOREACH(vtables, c, n->vtables) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; void *u = NULL; if (require_fallback && !c->is_fallback) @@ -2305,7 +2303,7 @@ static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *p _public_ int sd_bus_emit_object_added(sd_bus *bus, const char *path) { BUS_DONT_DESTROY(bus); - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; struct node *object_manager; int r; @@ -2389,7 +2387,7 @@ static int object_removed_append_all_prefix( return 0; LIST_FOREACH(vtables, c, n->vtables) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; void *u = NULL; if (require_fallback && !c->is_fallback) @@ -2475,7 +2473,7 @@ static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char _public_ int sd_bus_emit_object_removed(sd_bus *bus, const char *path) { BUS_DONT_DESTROY(bus); - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; struct node *object_manager; int r; @@ -2543,7 +2541,7 @@ static int interfaces_added_append_one_prefix( const char *interface, bool require_fallback) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; bool found_interface = false; struct node_vtable *c; struct node *n; @@ -2638,7 +2636,7 @@ static int interfaces_added_append_one( _public_ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **interfaces) { BUS_DONT_DESTROY(bus); - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; struct node *object_manager; char **i; int r; @@ -2722,7 +2720,7 @@ _public_ int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const c } _public_ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **interfaces) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; struct node *object_manager; int r; diff --git a/src/libsystemd/sd-bus/bus-objects.h b/src/libsystemd/sd-bus/bus-objects.h index 4373fae89..e0b8c534e 100644 --- a/src/libsystemd/sd-bus/bus-objects.h +++ b/src/libsystemd/sd-bus/bus-objects.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-protocol.h b/src/libsystemd/sd-bus/bus-protocol.h index 183af89a6..9d180cb28 100644 --- a/src/libsystemd/sd-bus/bus-protocol.h +++ b/src/libsystemd/sd-bus/bus-protocol.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-signature.c b/src/libsystemd/sd-bus/bus-signature.c index 1e5bf4821..7bc243494 100644 --- a/src/libsystemd/sd-bus/bus-signature.c +++ b/src/libsystemd/sd-bus/bus-signature.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-signature.h b/src/libsystemd/sd-bus/bus-signature.h index c4fed0b53..1e0cd7f58 100644 --- a/src/libsystemd/sd-bus/bus-signature.h +++ b/src/libsystemd/sd-bus/bus-signature.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-slot.c b/src/libsystemd/sd-bus/bus-slot.c index e405a04c5..a8c74011b 100644 --- a/src/libsystemd/sd-bus/bus-slot.c +++ b/src/libsystemd/sd-bus/bus-slot.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -57,7 +55,9 @@ sd_bus_slot *bus_slot_allocate( } _public_ sd_bus_slot* sd_bus_slot_ref(sd_bus_slot *slot) { - assert_return(slot, NULL); + + if (!slot) + return NULL; assert(slot->n_ref > 0); diff --git a/src/libsystemd/sd-bus/bus-slot.h b/src/libsystemd/sd-bus/bus-slot.h index 23a15e4d0..3b8b94dc6 100644 --- a/src/libsystemd/sd-bus/bus-slot.h +++ b/src/libsystemd/sd-bus/bus-slot.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,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/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 25873dea1..a2fb39123 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -609,7 +607,7 @@ static void bus_get_peercred(sd_bus *b) { b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; /* Get the SELinux context of the peer */ - if (mac_selinux_use()) { + if (mac_selinux_have()) { r = getpeersec(b->input_fd, &b->label); if (r < 0 && r != -EOPNOTSUPP) log_debug_errno(r, "Failed to determine peer security context: %m"); diff --git a/src/libsystemd/sd-bus/bus-socket.h b/src/libsystemd/sd-bus/bus-socket.h index 5a1c7d4cf..684feead7 100644 --- a/src/libsystemd/sd-bus/bus-socket.h +++ b/src/libsystemd/sd-bus/bus-socket.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c index fd7e58fcf..bdbf7d4a8 100644 --- a/src/libsystemd/sd-bus/bus-track.c +++ b/src/libsystemd/sd-bus/bus-track.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -111,7 +109,9 @@ _public_ int sd_bus_track_new( } _public_ sd_bus_track* sd_bus_track_ref(sd_bus_track *track) { - assert_return(track, NULL); + + if (!track) + return NULL; assert(track->n_ref > 0); @@ -161,7 +161,7 @@ static int on_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus } _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { - _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; + _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL; _cleanup_free_ char *n = NULL; const char *match; int r; @@ -207,7 +207,7 @@ _public_ int sd_bus_track_add_name(sd_bus_track *track, const char *name) { } _public_ int sd_bus_track_remove_name(sd_bus_track *track, const char *name) { - _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; + _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL; _cleanup_free_ char *n = NULL; assert_return(name, -EINVAL); diff --git a/src/libsystemd/sd-bus/bus-track.h b/src/libsystemd/sd-bus/bus-track.h index f8690a523..7d93a727d 100644 --- a/src/libsystemd/sd-bus/bus-track.h +++ b/src/libsystemd/sd-bus/bus-track.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/bus-type.c b/src/libsystemd/sd-bus/bus-type.c index 6bc7b880a..c692afc58 100644 --- a/src/libsystemd/sd-bus/bus-type.c +++ b/src/libsystemd/sd-bus/bus-type.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/bus-type.h b/src/libsystemd/sd-bus/bus-type.h index ad89e6c91..5c87eb5f0 100644 --- a/src/libsystemd/sd-bus/bus-type.h +++ b/src/libsystemd/sd-bus/bus-type.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/busctl-introspect.c b/src/libsystemd/sd-bus/busctl-introspect.c index 71f962b00..b09509f8e 100644 --- a/src/libsystemd/sd-bus/busctl-introspect.c +++ b/src/libsystemd/sd-bus/busctl-introspect.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/busctl-introspect.h b/src/libsystemd/sd-bus/busctl-introspect.h index ea807d597..d922e352d 100644 --- a/src/libsystemd/sd-bus/busctl-introspect.h +++ b/src/libsystemd/sd-bus/busctl-introspect.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-bus/busctl.c b/src/libsystemd/sd-bus/busctl.c index 452ac7c40..35fabf038 100644 --- a/src/libsystemd/sd-bus/busctl.c +++ b/src/libsystemd/sd-bus/busctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -137,7 +135,7 @@ static int list_bus_names(sd_bus *bus, char **argv) { } STRV_FOREACH(i, merged) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_id128_t mid; if (hashmap_get(names, *i) == NAME_IS_ACTIVATABLE) { @@ -334,8 +332,8 @@ static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *p .on_path = on_path, }; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *xml; int r; @@ -867,8 +865,8 @@ static int introspect(sd_bus *bus, char **argv) { .on_property = on_property, }; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(member_set_freep) Set *members = NULL; Iterator i; Member *m; @@ -1132,7 +1130,7 @@ static int monitor(sd_bus *bus, char *argv[], int (*dump)(sd_bus_message *m, FIL log_info("Monitoring bus message stream."); for (;;) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; r = sd_bus_process(bus, &m); if (r < 0) @@ -1182,7 +1180,7 @@ static int capture(sd_bus *bus, char *argv[]) { } static int status(sd_bus *bus, char *argv[]) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; pid_t pid; int r; @@ -1489,8 +1487,8 @@ static int message_append_cmdline(sd_bus_message *m, const char *signature, char } static int call(sd_bus *bus, char *argv[]) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; int r; assert(bus); @@ -1576,7 +1574,7 @@ static int call(sd_bus *bus, char *argv[]) { } static int get_property(sd_bus *bus, char *argv[]) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; unsigned n; char **i; int r; @@ -1590,7 +1588,7 @@ static int get_property(sd_bus *bus, char *argv[]) { } STRV_FOREACH(i, argv + 4) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *contents = NULL; char type; @@ -1634,8 +1632,8 @@ static int get_property(sd_bus *bus, char *argv[]) { } static int set_property(sd_bus *bus, char *argv[]) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; unsigned n; char **p; int r; @@ -1976,7 +1974,7 @@ static int busctl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; log_parse_environment(); diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 99780c8cc..c6f626d8a 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -419,7 +417,7 @@ static int hello_callback(sd_bus_message *reply, void *userdata, sd_bus_error *e } static int bus_send_hello(sd_bus *bus) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(bus); @@ -1480,7 +1478,9 @@ static void bus_enter_closing(sd_bus *bus) { } _public_ sd_bus *sd_bus_ref(sd_bus *bus) { - assert_return(bus, NULL); + + if (!bus) + return NULL; assert_se(REFCNT_INC(bus->n_ref) >= 2); @@ -1734,7 +1734,7 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd } static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie, bool hint_sync_call) { - _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m); int r; assert_return(m, -EINVAL); @@ -1882,8 +1882,8 @@ _public_ int sd_bus_call_async( void *userdata, uint64_t usec) { - _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); - _cleanup_bus_slot_unref_ sd_bus_slot *s = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m); + _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *s = NULL; int r; assert_return(m, -EINVAL); @@ -1981,7 +1981,7 @@ _public_ int sd_bus_call( sd_bus_error *error, sd_bus_message **reply) { - _cleanup_bus_message_unref_ sd_bus_message *m = sd_bus_message_ref(_m); + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m); usec_t timeout; uint64_t cookie; unsigned i; @@ -2220,8 +2220,8 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { } static int process_timeout(sd_bus *bus) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message* m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message* m = NULL; struct reply_callback *c; sd_bus_slot *slot; usec_t n; @@ -2302,8 +2302,8 @@ static int process_hello(sd_bus *bus, sd_bus_message *m) { } static int process_reply(sd_bus *bus, sd_bus_message *m) { - _cleanup_bus_message_unref_ sd_bus_message *synthetic_reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *synthetic_reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; struct reply_callback *c; sd_bus_slot *slot; int r; @@ -2382,7 +2382,7 @@ static int process_reply(sd_bus *bus, sd_bus_message *m) { } static int process_filter(sd_bus *bus, sd_bus_message *m) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; struct filter_callback *l; int r; @@ -2448,7 +2448,7 @@ static int process_match(sd_bus *bus, sd_bus_message *m) { } static int process_builtin(sd_bus *bus, sd_bus_message *m) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; assert(bus); @@ -2580,7 +2580,7 @@ static int dispatch_track(sd_bus *bus) { } static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **ret) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int r; assert(bus); @@ -2644,7 +2644,7 @@ null_message: } static int process_closing(sd_bus *bus, sd_bus_message **ret) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; struct reply_callback *c; int r; @@ -2653,7 +2653,7 @@ static int process_closing(sd_bus *bus, sd_bus_message **ret) { c = ordered_hashmap_first(bus->reply_callbacks); if (c) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; sd_bus_slot *slot; /* First, fail all outstanding method calls */ diff --git a/src/libsystemd/sd-bus/test-bus-benchmark.c b/src/libsystemd/sd-bus/test-bus-benchmark.c index 96a0929a1..56ac2ab3d 100644 --- a/src/libsystemd/sd-bus/test-bus-benchmark.c +++ b/src/libsystemd/sd-bus/test-bus-benchmark.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -46,7 +44,7 @@ static void server(sd_bus *b, size_t *result) { int r; for (;;) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; r = sd_bus_process(b, &m); assert_se(r >= 0); @@ -80,7 +78,7 @@ static void server(sd_bus *b, size_t *result) { } static void transaction(sd_bus *b, size_t sz, const char *server_name) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; uint8_t *p; assert_se(sd_bus_message_new_method_call(b, &m, server_name, "/", "benchmark.server", "Work") >= 0); @@ -92,7 +90,7 @@ static void transaction(sd_bus *b, size_t sz, const char *server_name) { } static void client_bisect(const char *address, const char *server_name) { - _cleanup_bus_message_unref_ sd_bus_message *x = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *x = NULL; size_t lsize, rsize, csize; sd_bus *b; int r; @@ -166,7 +164,7 @@ static void client_bisect(const char *address, const char *server_name) { } static void client_chart(Type type, const char *address, const char *server_name, int fd) { - _cleanup_bus_message_unref_ sd_bus_message *x = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *x = NULL; size_t csize; sd_bus *b; int r; diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index f20eced4a..048c0d19e 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -130,7 +128,7 @@ static int server(sd_bus *bus) { bool client1_gone = false, client2_gone = false; while (!client1_gone || !client2_gone) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; pid_t pid = 0; const char *label = NULL; @@ -261,9 +259,9 @@ fail: } static void* client1(void*p) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *hello; int r; _cleanup_close_pair_ int pp[2] = { -1, -1 }; @@ -331,7 +329,7 @@ static void* client1(void*p) { finish: if (bus) { - _cleanup_bus_message_unref_ sd_bus_message *q; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *q; r = sd_bus_message_new_method_call( bus, @@ -360,9 +358,9 @@ static int quit_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_er } static void* client2(void*p) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; bool quit = false; const char *mid; int r; @@ -499,7 +497,7 @@ static void* client2(void*p) { finish: if (bus) { - _cleanup_bus_message_unref_ sd_bus_message *q; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *q; r = sd_bus_message_new_method_call( bus, diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c index 51aa0a9ad..250a5b290 100644 --- a/src/libsystemd/sd-bus/test-bus-cleanup.c +++ b/src/libsystemd/sd-bus/test-bus-cleanup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -29,14 +27,14 @@ #include "refcnt.h" static void test_bus_new(void) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; assert_se(sd_bus_new(&bus) == 0); printf("after new: refcount %u\n", REFCNT_GET(bus->n_ref)); } static int test_bus_open(void) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; r = sd_bus_open_system(&bus); @@ -51,7 +49,7 @@ static int test_bus_open(void) { static void test_bus_new_method_call(void) { sd_bus *bus = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; assert_se(sd_bus_open_system(&bus) >= 0); @@ -59,13 +57,13 @@ static void test_bus_new_method_call(void) { printf("after message_new_method_call: refcount %u\n", REFCNT_GET(bus->n_ref)); - sd_bus_unref(bus); - printf("after bus_unref: refcount %u\n", m->n_ref); + sd_bus_flush_close_unref(bus); + printf("after bus_flush_close_unref: refcount %u\n", m->n_ref); } static void test_bus_new_signal(void) { sd_bus *bus = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; assert_se(sd_bus_open_system(&bus) >= 0); @@ -73,8 +71,8 @@ static void test_bus_new_signal(void) { printf("after message_new_signal: refcount %u\n", REFCNT_GET(bus->n_ref)); - sd_bus_unref(bus); - printf("after bus_unref: refcount %u\n", m->n_ref); + sd_bus_flush_close_unref(bus); + printf("after bus_flush_close_unref: refcount %u\n", m->n_ref); } int main(int argc, char **argv) { diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c index bd0101af9..e9ef483bd 100644 --- a/src/libsystemd/sd-bus/test-bus-creds.c +++ b/src/libsystemd/sd-bus/test-bus-creds.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -26,10 +24,10 @@ #include "cgroup-util.h" int main(int argc, char *argv[]) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; int r; - if (cg_unified() == -ENOEXEC) { + if (cg_unified() == -ENOMEDIUM) { puts("Skipping test: /sys/fs/cgroup/ not available"); return EXIT_TEST_SKIP; } diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 9d6c221eb..46d18abd2 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -27,7 +25,7 @@ #include "errno-list.h" static void test_error(void) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL; const sd_bus_error const_error = SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_FILE_EXISTS, "const error"); const sd_bus_error temporarily_const_error = { .name = SD_BUS_ERROR_ACCESS_DENIED, @@ -44,7 +42,15 @@ static void test_error(void) { assert_se(sd_bus_error_is_set(&error)); sd_bus_error_free(&error); + /* Check with no error */ assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_setf(&error, NULL, "yyy %i", -1) == 0); + assert_se(error.name == NULL); + assert_se(error.message == NULL); + assert_se(!sd_bus_error_has_name(&error, SD_BUS_ERROR_FILE_NOT_FOUND)); + assert_se(sd_bus_error_get_errno(&error) == 0); + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_setf(&error, SD_BUS_ERROR_FILE_NOT_FOUND, "yyy %i", -1) == -ENOENT); assert_se(streq(error.name, SD_BUS_ERROR_FILE_NOT_FOUND)); assert_se(streq(error.message, "yyy -1")); @@ -112,6 +118,16 @@ static void test_error(void) { assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_IO_ERROR)); assert_se(sd_bus_error_get_errno(&error) == EIO); assert_se(sd_bus_error_is_set(&error)); + sd_bus_error_free(&error); + + /* Check with no error */ + assert_se(!sd_bus_error_is_set(&error)); + assert_se(sd_bus_error_set_errnof(&error, 0, "Waldi %c", 'X') == 0); + assert_se(error.name == NULL); + assert_se(error.message == NULL); + assert_se(!sd_bus_error_has_name(&error, SD_BUS_ERROR_IO_ERROR)); + assert_se(sd_bus_error_get_errno(&error) == 0); + assert_se(!sd_bus_error_is_set(&error)); } extern const sd_bus_error_map __start_BUS_ERROR_MAP[]; @@ -167,6 +183,16 @@ static const sd_bus_error_map test_errors4[] = { SD_BUS_ERROR_MAP_END }; +static const sd_bus_error_map test_errors_bad1[] = { + SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-1", 0), + SD_BUS_ERROR_MAP_END +}; + +static const sd_bus_error_map test_errors_bad2[] = { + SD_BUS_ERROR_MAP("org.freedesktop.custom-dbus-error-1", -1), + SD_BUS_ERROR_MAP_END +}; + static void test_errno_mapping_custom(void) { assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error", NULL) == -5); assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-2", NULL) == -52); @@ -190,6 +216,9 @@ static void test_errno_mapping_custom(void) { assert_se(sd_bus_error_set(NULL, "org.freedesktop.custom-dbus-error-y", NULL) == -EIO); assert_se(sd_bus_error_set(NULL, BUS_ERROR_NO_SUCH_UNIT, NULL) == -ENOENT); + + assert_se(sd_bus_error_add_map(test_errors_bad1) == -EINVAL); + assert_se(sd_bus_error_add_map(test_errors_bad2) == -EINVAL); } int main(int argc, char *argv[]) { diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index 931c00178..83f114a0f 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -133,8 +131,8 @@ static void test_bus_gvariant_get_alignment(void) { } static void test_marshal(void) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *n = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *n = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ void *blob; size_t sz; int r; diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c index 26ba16d11..4425cfae2 100644 --- a/src/libsystemd/sd-bus/test-bus-introspect.c +++ b/src/libsystemd/sd-bus/test-bus-introspect.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c index dbdaa69fb..eb6179d7d 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel-bloom.c +++ b/src/libsystemd/sd-bus/test-bus-kernel-bloom.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -47,7 +45,7 @@ static void test_one( _cleanup_close_ int bus_ref = -1; _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; sd_bus *a, *b; int r, found = 0; diff --git a/src/libsystemd/sd-bus/test-bus-kernel.c b/src/libsystemd/sd-bus/test-bus-kernel.c index 0080f71d3..221481731 100644 --- a/src/libsystemd/sd-bus/test-bus-kernel.c +++ b/src/libsystemd/sd-bus/test-bus-kernel.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -34,8 +32,8 @@ int main(int argc, char *argv[]) { _cleanup_close_ int bus_ref = -1; _cleanup_free_ char *name = NULL, *bus_name = NULL, *address = NULL, *bname = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *ua = NULL, *ub = NULL, *the_string = NULL; sd_bus *a, *b; int r, pipe_fds[2]; diff --git a/src/libsystemd/sd-bus/test-bus-marshal.c b/src/libsystemd/sd-bus/test-bus-marshal.c index 0a6093e78..a28cc5b79 100644 --- a/src/libsystemd/sd-bus/test-bus-marshal.c +++ b/src/libsystemd/sd-bus/test-bus-marshal.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -123,7 +121,7 @@ static void test_bus_label_escape(void) { } int main(int argc, char *argv[]) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *copy = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *copy = NULL; int r, boolean; const char *x, *x2, *y, *z, *a, *b, *c, *d, *a_signature; uint8_t u, v; @@ -135,7 +133,7 @@ int main(int argc, char *argv[]) { _cleanup_free_ char *first = NULL, *second = NULL, *third = NULL; _cleanup_fclose_ FILE *ms = NULL; size_t first_size = 0, second_size = 0, third_size = 0; - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; double dbl; uint64_t u64; @@ -246,6 +244,8 @@ int main(int argc, char *argv[]) { log_error("%s", error.message); else dbus_message_unref(w); + + dbus_error_free(&error); } #endif diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c index 94896c196..29c4529f9 100644 --- a/src/libsystemd/sd-bus/test-bus-match.c +++ b/src/libsystemd/sd-bus/test-bus-match.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -90,8 +88,8 @@ int main(int argc, char *argv[]) { .type = BUS_MATCH_ROOT, }; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; enum bus_match_node_type i; sd_bus_slot slots[19]; int r; diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index edd63f9ea..f11cafd88 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -297,9 +295,9 @@ fail: } static int client(struct context *c) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_unref_ sd_bus *bus = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *s; int r; diff --git a/src/libsystemd/sd-bus/test-bus-proxy.c b/src/libsystemd/sd-bus/test-bus-proxy.c index 428e18576..45d0a5ffc 100644 --- a/src/libsystemd/sd-bus/test-bus-proxy.c +++ b/src/libsystemd/sd-bus/test-bus-proxy.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -53,7 +51,7 @@ static int test_proxy_acquired(sd_bus_message *m, void *userdata, sd_bus_error * } static void test_proxy_matched(void) { - _cleanup_bus_flush_close_unref_ sd_bus *a = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *a = NULL; _cleanup_free_ char *matchstr = NULL; TestProxyMatch match = {}; const char *me; diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c index 5bf2c1ecf..b6272efc3 100644 --- a/src/libsystemd/sd-bus/test-bus-server.c +++ b/src/libsystemd/sd-bus/test-bus-server.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -57,7 +55,7 @@ static void *server(void *p) { assert_se(sd_bus_start(bus) >= 0); while (!quit) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; r = sd_bus_process(bus, &m); if (r < 0) { @@ -124,8 +122,8 @@ fail: } static int client(struct context *c) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; int r; diff --git a/src/libsystemd/sd-bus/test-bus-signature.c b/src/libsystemd/sd-bus/test-bus-signature.c index 949d16e6e..4f4fd093b 100644 --- a/src/libsystemd/sd-bus/test-bus-signature.c +++ b/src/libsystemd/sd-bus/test-bus-signature.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-bus/test-bus-zero-copy.c b/src/libsystemd/sd-bus/test-bus-zero-copy.c index 1cf8416fa..3380e8500 100644 --- a/src/libsystemd/sd-bus/test-bus-zero-copy.c +++ b/src/libsystemd/sd-bus/test-bus-zero-copy.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index f1e9b7ed1..4e50b6197 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-device/device-enumerator-private.h b/src/libsystemd/sd-device/device-enumerator-private.h index 8d04640dc..eb06f9542 100644 --- a/src/libsystemd/sd-device/device-enumerator-private.h +++ b/src/libsystemd/sd-device/device-enumerator-private.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index ae3157ee5..4a7a8b1f9 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -59,7 +59,7 @@ struct sd_device_enumerator { }; _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) { - _cleanup_device_enumerator_unref_ sd_device_enumerator *enumerator = NULL; + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *enumerator = NULL; assert(ret); @@ -487,7 +487,7 @@ static int enumerator_scan_dir_and_add_devices(sd_device_enumerator *enumerator, return -errno; FOREACH_DIRENT_ALL(dent, dir, return -errno) { - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; char syspath[strlen(path) + 1 + strlen(dent->d_name) + 1]; dev_t devnum; int ifindex, initialized, k; @@ -640,7 +640,7 @@ static int enumerator_scan_devices_tag(sd_device_enumerator *enumerator, const c /* TODO: filter away subsystems? */ FOREACH_DIRENT_ALL(dent, dir, return -errno) { - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; const char *subsystem, *sysname; int k; @@ -710,7 +710,7 @@ static int enumerator_scan_devices_tags(sd_device_enumerator *enumerator) { } static int parent_add_child(sd_device_enumerator *enumerator, const char *path) { - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; const char *subsystem, *sysname; int r; diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index a13477e75..f2af3ab3a 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -553,7 +553,7 @@ static int device_verify(sd_device *device, DeviceAction action, uint64_t seqnum } int device_new_from_strv(sd_device **ret, char **strv) { - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; char **key; const char *major = NULL, *minor = NULL; DeviceAction action = _DEVICE_ACTION_INVALID; @@ -590,7 +590,7 @@ int device_new_from_strv(sd_device **ret, char **strv) { } int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) { - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; const char *major = NULL, *minor = NULL; DeviceAction action = _DEVICE_ACTION_INVALID; uint64_t seqnum; @@ -793,7 +793,7 @@ int device_rename(sd_device *device, const char *name) { } int device_shallow_clone(sd_device *old_device, sd_device **new_device) { - _cleanup_device_unref_ sd_device *ret = NULL; + _cleanup_(sd_device_unrefp) sd_device *ret = NULL; int r; assert(old_device); @@ -820,7 +820,7 @@ int device_shallow_clone(sd_device *old_device, sd_device **new_device) { } int device_clone_with_db(sd_device *old_device, sd_device **new_device) { - _cleanup_device_unref_ sd_device *ret = NULL; + _cleanup_(sd_device_unrefp) sd_device *ret = NULL; int r; assert(old_device); @@ -843,7 +843,7 @@ int device_clone_with_db(sd_device *old_device, sd_device **new_device) { } int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, const char *action) { - _cleanup_device_unref_ sd_device *ret = NULL; + _cleanup_(sd_device_unrefp) sd_device *ret = NULL; int r; assert(new_device); diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h index d1f34efc2..29b3e155f 100644 --- a/src/libsystemd/sd-device/device-private.h +++ b/src/libsystemd/sd-device/device-private.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-device/device-util.h b/src/libsystemd/sd-device/device-util.h index 9b05a2498..5b42e11de 100644 --- a/src/libsystemd/sd-device/device-util.h +++ b/src/libsystemd/sd-device/device-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,12 +21,6 @@ #include "util.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_device*, sd_device_unref); -#define _cleanup_device_unref_ _cleanup_(sd_device_unrefp) - -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_device_enumerator*, sd_device_enumerator_unref); -#define _cleanup_device_enumerator_unref_ _cleanup_(sd_device_enumerator_unrefp) - #define FOREACH_DEVICE_PROPERTY(device, key, value) \ for (key = sd_device_get_property_first(device, &(value)); \ key; \ diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index 0e4926208..9633e46ce 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -43,7 +43,7 @@ #include "util.h" int device_new_aux(sd_device **ret) { - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; assert(ret); @@ -222,7 +222,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { } _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) { - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; int r; assert_return(ret, -EINVAL); @@ -494,7 +494,7 @@ static int handle_uevent_line(sd_device *device, const char *key, const char *va int device_read_uevent_file(sd_device *device) { _cleanup_free_ char *uevent = NULL; - const char *syspath, *key, *value, *major = NULL, *minor = NULL; + const char *syspath, *key = NULL, *value = NULL, *major = NULL, *minor = NULL; char *path; size_t uevent_len; unsigned i; @@ -624,7 +624,7 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { } case 'n': { - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; _cleanup_close_ int sk = -1; struct ifreq ifr = {}; int ifindex; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 700ac691b..deef6ba9d 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -37,6 +35,7 @@ #include "process-util.h" #include "set.h" #include "signal-util.h" +#include "string-table.h" #include "string-util.h" #include "time-util.h" #include "util.h" @@ -60,6 +59,23 @@ typedef enum EventSourceType { _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1 } EventSourceType; +static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { + [SOURCE_IO] = "io", + [SOURCE_TIME_REALTIME] = "realtime", + [SOURCE_TIME_BOOTTIME] = "bootime", + [SOURCE_TIME_MONOTONIC] = "monotonic", + [SOURCE_TIME_REALTIME_ALARM] = "realtime-alarm", + [SOURCE_TIME_BOOTTIME_ALARM] = "boottime-alarm", + [SOURCE_SIGNAL] = "signal", + [SOURCE_CHILD] = "child", + [SOURCE_DEFER] = "defer", + [SOURCE_POST] = "post", + [SOURCE_EXIT] = "exit", + [SOURCE_WATCHDOG] = "watchdog", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int); + /* All objects we use in epoll events start with this value, so that * we know how to dispatch it */ typedef enum WakeupType { @@ -207,6 +223,7 @@ struct sd_event { bool exit_requested:1; bool need_process_child:1; bool watchdog:1; + bool profile_delays:1; int exit_code; @@ -218,6 +235,9 @@ struct sd_event { unsigned n_sources; LIST_HEAD(sd_event_source, sources); + + usec_t last_run, last_log; + unsigned delays[sizeof(usec_t) * 8]; }; static void source_disconnect(sd_event_source *s); @@ -305,6 +325,10 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { return 0; } +static usec_t time_event_source_latest(const sd_event_source *s) { + return usec_add(s->time.next, s->time.accuracy); +} + static int latest_time_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; @@ -324,9 +348,9 @@ static int latest_time_prioq_compare(const void *a, const void *b) { return 1; /* Order by time */ - if (x->time.next + x->time.accuracy < y->time.next + y->time.accuracy) + if (time_event_source_latest(x) < time_event_source_latest(y)) return -1; - if (x->time.next + x->time.accuracy > y->time.next + y->time.accuracy) + if (time_event_source_latest(x) > time_event_source_latest(y)) return 1; return 0; @@ -416,11 +440,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) { @@ -428,6 +450,11 @@ _public_ int sd_event_new(sd_event** ret) { goto fail; } + if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) { + log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 ... 2^63 us will be logged every 5s."); + e->profile_delays = true; + } + *ret = e; return 0; @@ -437,7 +464,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++; @@ -482,7 +511,8 @@ static void source_io_unregister(sd_event_source *s) { r = epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL); if (r < 0) - log_debug_errno(errno, "Failed to remove source %s from epoll: %m", strna(s->description)); + log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", + strna(s->description), event_source_type_to_string(s->type)); s->io.registered = false; } @@ -633,8 +663,10 @@ static int event_make_signal_data( d->priority = priority; r = hashmap_put(e->signal_data, &d->priority, d); - if (r < 0) + if (r < 0) { + free(d); return r; + } added = true; } @@ -1036,7 +1068,6 @@ _public_ int sd_event_add_time( int r; assert_return(e, -EINVAL); - assert_return(usec != (uint64_t) -1, -EINVAL); assert_return(accuracy != (uint64_t) -1, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -1050,17 +1081,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); @@ -1311,11 +1338,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) @@ -1339,7 +1364,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++; @@ -1730,7 +1757,6 @@ _public_ int sd_event_source_set_time(sd_event_source *s, uint64_t usec) { struct clock_data *d; assert_return(s, -EINVAL); - assert_return(usec != (uint64_t) -1, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(s->event), -ECHILD); @@ -1860,6 +1886,8 @@ static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { if (a <= 0) return 0; + if (a >= USEC_INFINITY) + return USEC_INFINITY; if (b <= a + 1) return a; @@ -1949,7 +1977,7 @@ static int event_arm_timer( d->needs_rearm = false; a = prioq_peek(d->earliest); - if (!a || a->enabled == SD_EVENT_OFF) { + if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) { if (d->fd < 0) return 0; @@ -1969,7 +1997,7 @@ static int event_arm_timer( b = prioq_peek(d->latest); assert_se(b && b->enabled != SD_EVENT_OFF); - t = sleep_between(e, a->time.next, b->time.next + b->time.accuracy); + t = sleep_between(e, a->time.next, time_event_source_latest(b)); if (d->next == t) return 0; @@ -2285,12 +2313,9 @@ static int source_dispatch(sd_event_source *s) { s->dispatching = false; - if (r < 0) { - if (s->description) - log_debug_errno(r, "Event source '%s' returned error, disabling: %m", s->description); - else - log_debug_errno(r, "Event source %p returned error, disabling: %m", s); - } + if (r < 0) + log_debug_errno(r, "Event source %s (type %s) returned error, disabling: %m", + strna(s->description), event_source_type_to_string(s->type)); if (s->n_ref == 0) source_free(s); @@ -2323,12 +2348,9 @@ static int event_prepare(sd_event *e) { r = s->prepare(s, s->userdata); s->dispatching = false; - if (r < 0) { - if (s->description) - log_debug_errno(r, "Prepare callback of event source '%s' returned error, disabling: %m", s->description); - else - log_debug_errno(r, "Prepare callback of event source %p returned error, disabling: %m", s); - } + if (r < 0) + log_debug_errno(r, "Prepare callback of event source %s (type %s) returned error, disabling: %m", + strna(s->description), event_source_type_to_string(s->type)); if (s->n_ref == 0) source_free(s); @@ -2433,7 +2455,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; @@ -2611,6 +2635,18 @@ _public_ int sd_event_dispatch(sd_event *e) { return 1; } +static void event_log_delays(sd_event *e) { + char b[ELEMENTSOF(e->delays) * DECIMAL_STR_MAX(unsigned) + 1]; + unsigned i; + int o; + + for (i = o = 0; i < ELEMENTSOF(e->delays); i++) { + o += snprintf(&b[o], sizeof(b) - o, "%u ", e->delays[i]); + e->delays[i] = 0; + } + log_debug("Event loop iterations: %.*s", o, b); +} + _public_ int sd_event_run(sd_event *e, uint64_t timeout) { int r; @@ -2619,11 +2655,30 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); + if (e->profile_delays && e->last_run) { + usec_t this_run; + unsigned l; + + this_run = now(CLOCK_MONOTONIC); + + l = u64log2(this_run - e->last_run); + assert(l < sizeof(e->delays)); + e->delays[l]++; + + if (this_run - e->last_log >= 5*USEC_PER_SEC) { + event_log_delays(e); + e->last_log = this_run; + } + } + r = sd_event_prepare(e); if (r == 0) /* There was nothing? Then wait... */ r = sd_event_wait(e, timeout); + if (e->profile_delays) + e->last_run = now(CLOCK_MONOTONIC); + if (r > 0) { /* There's something now, then let's dispatch it */ r = sd_event_dispatch(e); @@ -2700,6 +2755,12 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { assert_return(e, -EINVAL); assert_return(usec, -EINVAL); assert_return(!event_pid_changed(e), -ECHILD); + assert_return(IN_SET(clock, + CLOCK_REALTIME, + CLOCK_REALTIME_ALARM, + CLOCK_MONOTONIC, + CLOCK_BOOTTIME, + CLOCK_BOOTTIME_ALARM), -EOPNOTSUPP); if (!dual_timestamp_is_set(&e->timestamp)) { /* Implicitly fall back to now() if we never ran @@ -2719,8 +2780,7 @@ _public_ int sd_event_now(sd_event *e, clockid_t clock, uint64_t *usec) { *usec = e->timestamp.monotonic; break; - case CLOCK_BOOTTIME: - case CLOCK_BOOTTIME_ALARM: + default: *usec = e->timestamp_boottime; break; } diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index c1a3b4948..daea4126f 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -158,11 +156,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 +179,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 +240,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); @@ -248,6 +262,30 @@ static void test_basic(void) { safe_close_pair(k); } +static void test_sd_event_now(void) { + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + uint64_t event_now; + + assert_se(sd_event_new(&e) >= 0); + assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0); + assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0); + assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) > 0); + assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) > 0); + assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) > 0); + assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP); + assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP); + + assert_se(sd_event_run(e, 0) == 0); + + assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) == 0); + assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) == 0); + assert_se(sd_event_now(e, CLOCK_REALTIME_ALARM, &event_now) == 0); + assert_se(sd_event_now(e, CLOCK_BOOTTIME, &event_now) == 0); + assert_se(sd_event_now(e, CLOCK_BOOTTIME_ALARM, &event_now) == 0); + assert_se(sd_event_now(e, -1, &event_now) == -EOPNOTSUPP); + assert_se(sd_event_now(e, 900 /* arbitrary big number */, &event_now) == -EOPNOTSUPP); +} + static int last_rtqueue_sigval = 0; static int n_rtqueue = 0; @@ -308,7 +346,11 @@ static void test_rtqueue(void) { int main(int argc, char *argv[]) { + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + test_basic(); + test_sd_event_now(); test_rtqueue(); return 0; diff --git a/src/libsystemd/sd-hwdb/hwdb-util.h b/src/libsystemd/sd-hwdb/hwdb-util.h index d366c6fa4..5e21e5008 100644 --- a/src/libsystemd/sd-hwdb/hwdb-util.h +++ b/src/libsystemd/sd-hwdb/hwdb-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,7 +23,4 @@ #include "util.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_hwdb*, sd_hwdb_unref); -#define _cleanup_hwdb_unref_ _cleanup_(sd_hwdb_unrefp) - bool hwdb_validate(sd_hwdb *hwdb); diff --git a/src/libsystemd/sd-hwdb/sd-hwdb.c b/src/libsystemd/sd-hwdb/sd-hwdb.c index 0e034863d..062fa97b1 100644 --- a/src/libsystemd/sd-hwdb/sd-hwdb.c +++ b/src/libsystemd/sd-hwdb/sd-hwdb.c @@ -279,7 +279,7 @@ static const char hwdb_bin_paths[] = UDEVLIBEXECDIR "/hwdb.bin\0"; _public_ int sd_hwdb_new(sd_hwdb **ret) { - _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; const char *hwdb_bin_path; const char sig[] = HWDB_SIG; diff --git a/src/libsystemd/sd-id128/sd-id128.c b/src/libsystemd/sd-id128/sd-id128.c index c12bb1e20..d9c0116f6 100644 --- a/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libsystemd/sd-id128/sd-id128.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 3f2e45982..9d4f18750 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -810,7 +808,7 @@ _public_ int sd_get_uids(uid_t **users) { errno = 0; de = readdir(d); - if (!de && errno != 0) + if (!de && errno > 0) return -errno; if (!de) @@ -1017,7 +1015,8 @@ _public_ int sd_login_monitor_new(const char *category, sd_login_monitor **m) { _public_ sd_login_monitor* sd_login_monitor_unref(sd_login_monitor *m) { int fd; - assert_return(m, NULL); + if (!m) + return NULL; fd = MONITOR_TO_FD(m); close_nointr(fd); diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c index b0f94c952..c1fd7dd33 100644 --- a/src/libsystemd/sd-login/test-login.c +++ b/src/libsystemd/sd-login/test-login.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-netlink/local-addresses.c b/src/libsystemd/sd-netlink/local-addresses.c index d431ba4be..6abd8fd0c 100644 --- a/src/libsystemd/sd-netlink/local-addresses.c +++ b/src/libsystemd/sd-netlink/local-addresses.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -56,8 +54,8 @@ static int address_compare(const void *_a, const void *_b) { } int local_addresses(sd_netlink *context, int ifindex, int af, struct local_address **ret) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ struct local_address *list = NULL; size_t n_list = 0, n_allocated = 0; sd_netlink_message *m; @@ -167,8 +165,8 @@ int local_addresses(sd_netlink *context, int ifindex, int af, struct local_addre } int local_gateways(sd_netlink *context, int ifindex, int af, struct local_address **ret) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ struct local_address *list = NULL; sd_netlink_message *m = NULL; size_t n_list = 0, n_allocated = 0; diff --git a/src/libsystemd/sd-netlink/local-addresses.h b/src/libsystemd/sd-netlink/local-addresses.h index 5d0f11a2c..18d71e797 100644 --- a/src/libsystemd/sd-netlink/local-addresses.h +++ b/src/libsystemd/sd-netlink/local-addresses.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,6 +21,7 @@ #include "sd-netlink.h" + #include "in-addr-util.h" struct local_address { diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 8519a4d52..dcfb080ad 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -135,5 +133,5 @@ int rtnl_rqueue_make_room(sd_netlink *rtnl); int rtnl_rqueue_partial_make_room(sd_netlink *rtnl); /* Make sure callbacks don't destroy the rtnl connection */ -#define RTNL_DONT_DESTROY(rtnl) \ - _cleanup_netlink_unref_ _unused_ sd_netlink *_dont_destroy_##rtnl = sd_netlink_ref(rtnl) +#define NETLINK_DONT_DESTROY(rtnl) \ + _cleanup_(sd_netlink_unrefp) _unused_ sd_netlink *_dont_destroy_##rtnl = sd_netlink_ref(rtnl) diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index 03971b359..3a866fdaf 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -65,7 +63,7 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) { } int message_new(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t type) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; const NLType *nl_type; size_t size; int r; @@ -342,6 +340,19 @@ int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, ui return 0; } +int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len) { + int r; + + assert_return(m, -EINVAL); + assert_return(!m->sealed, -EPERM); + + r = add_rtattr(m, type, &data, len); + if (r < 0) + return r; + + return 0; +} + int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) { int r; diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 13945202e..590fc53fc 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -52,7 +50,7 @@ static int broadcast_groups_get(sd_netlink *nl) { int r; assert(nl); - assert(nl->fd > 0); + assert(nl->fd >= 0); r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len); if (r < 0) { @@ -323,7 +321,7 @@ static int socket_recv_message(int fd, struct iovec *iov, uint32_t *_group, bool * On failure, a negative error code is returned. */ int socket_read_message(sd_netlink *rtnl) { - _cleanup_netlink_message_unref_ sd_netlink_message *first = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *first = NULL; struct iovec iov = {}; uint32_t group = 0; bool multi_part = false, done = false; @@ -376,7 +374,7 @@ int socket_read_message(sd_netlink *rtnl) { } for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; const NLType *nl_type; if (!group && new_msg->nlmsg_pid != rtnl->sockaddr.nl.nl_pid) diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 135354e5f..a5758bb51 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -96,15 +94,6 @@ static const NLType rtnl_link_info_data_macvlan_types[] = { [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 }, }; -static const NLType rtnl_link_bridge_management_types[] = { - [IFLA_BRIDGE_FLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_BRIDGE_MODE] = { .type = NETLINK_TYPE_U16 }, -/* - [IFLA_BRIDGE_VLAN_INFO] = { .type = NETLINK_TYPE_BINARY, - .len = sizeof(struct bridge_vlan_info), }, -*/ -}; - static const NLType rtnl_link_info_data_bridge_types[] = { [IFLA_BR_FORWARD_DELAY] = { .type = NETLINK_TYPE_U32 }, [IFLA_BR_HELLO_TIME] = { .type = NETLINK_TYPE_U32 }, diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index 9e636a0b5..ecb20bfcd 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index 95690b7ff..73b9ac025 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -25,7 +23,7 @@ #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; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; int r; assert(rtnl); @@ -55,7 +53,7 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) { int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, unsigned mtu) { - _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; int r; assert(rtnl); diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index acc6c15ff..f49bf4eaa 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -39,9 +37,3 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, int rtnl_log_parse_error(int r); int rtnl_log_create_error(int r); - -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_netlink*, sd_netlink_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_netlink_message*, sd_netlink_message_unref); - -#define _cleanup_netlink_unref_ _cleanup_(sd_netlink_unrefp) -#define _cleanup_netlink_message_unref_ _cleanup_(sd_netlink_message_unrefp) diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 3e605db66..090552f57 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 7c24e053c..4833815b4 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -35,7 +33,7 @@ #include "util.h" static int sd_netlink_new(sd_netlink **ret) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; assert_return(ret, -EINVAL); @@ -44,11 +42,8 @@ static int sd_netlink_new(sd_netlink **ret) { return -ENOMEM; rtnl->n_ref = REFCNT_INIT; - rtnl->fd = -1; - rtnl->sockaddr.nl.nl_family = AF_NETLINK; - rtnl->original_pid = getpid(); LIST_HEAD_INIT(rtnl->match_callbacks); @@ -71,7 +66,7 @@ static int sd_netlink_new(sd_netlink **ret) { } int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; socklen_t addrlen; int r; @@ -87,6 +82,9 @@ int sd_netlink_new_from_netlink(sd_netlink **ret, int fd) { if (r < 0) return -errno; + if (rtnl->sockaddr.nl.nl_family != AF_NETLINK) + return -EINVAL; + rtnl->fd = fd; *ret = rtnl; @@ -105,7 +103,7 @@ static bool rtnl_pid_changed(sd_netlink *rtnl) { } int sd_netlink_open_fd(sd_netlink **ret, int fd) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int r; assert_return(ret, -EINVAL); @@ -118,8 +116,10 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) { rtnl->fd = fd; r = socket_bind(rtnl); - if (r < 0) + if (r < 0) { + rtnl->fd = -1; /* on failure, the caller remains owner of the fd, hence don't close it here */ return r; + } *ret = rtnl; rtnl = NULL; @@ -286,7 +286,7 @@ static int dispatch_rqueue(sd_netlink *rtnl, sd_netlink_message **message) { } static int process_timeout(sd_netlink *rtnl) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; struct reply_callback *c; usec_t n; int r; @@ -376,7 +376,7 @@ static int process_match(sd_netlink *rtnl, sd_netlink_message *m) { } static int process_running(sd_netlink *rtnl, sd_netlink_message **ret) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(rtnl); @@ -418,7 +418,7 @@ null_message: } int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) { - RTNL_DONT_DESTROY(rtnl); + NETLINK_DONT_DESTROY(rtnl); int r; assert_return(rtnl, -EINVAL); @@ -623,7 +623,7 @@ int sd_netlink_call(sd_netlink *rtnl, received_serial = rtnl_message_get_serial(rtnl->rqueue[i]); if (received_serial == serial) { - _cleanup_netlink_message_unref_ sd_netlink_message *incoming = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *incoming = NULL; uint16_t type; incoming = rtnl->rqueue[i]; diff --git a/src/libsystemd/sd-netlink/test-local-addresses.c b/src/libsystemd/sd-netlink/test-local-addresses.c index 0b53297ab..e0e28cc0c 100644 --- a/src/libsystemd/sd-netlink/test-local-addresses.c +++ b/src/libsystemd/sd-netlink/test-local-addresses.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-netlink/test-netlink.c b/src/libsystemd/sd-netlink/test-netlink.c index 58b774e0e..de5e0ffc8 100644 --- a/src/libsystemd/sd-netlink/test-netlink.c +++ b/src/libsystemd/sd-netlink/test-netlink.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -25,7 +23,6 @@ #include "sd-netlink.h" #include "ether-addr-util.h" -#include "event-util.h" #include "macro.h" #include "missing.h" #include "netlink-util.h" @@ -34,7 +31,7 @@ #include "util.h" static void test_message_link_bridge(sd_netlink *rtnl) { - _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; uint32_t cost; assert_se(sd_rtnl_message_new_link(rtnl, &message, RTM_NEWLINK, 1) >= 0); @@ -52,7 +49,7 @@ static void test_message_link_bridge(sd_netlink *rtnl) { } static void test_link_configure(sd_netlink *rtnl, int ifindex) { - _cleanup_netlink_message_unref_ sd_netlink_message *message = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; const char *mac = "98:fe:94:3f:c6:18", *name = "test"; char buffer[ETHER_ADDR_TO_STRING_MAX]; unsigned int mtu = 1450, mtu_out; @@ -146,7 +143,7 @@ static void test_address_get(sd_netlink *rtnl, int ifindex) { } static void test_route(void) { - _cleanup_netlink_message_unref_ sd_netlink_message *req; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req; struct in_addr addr, addr_data; uint32_t index = 2, u32_data; int r; @@ -209,9 +206,9 @@ static int link_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) } static void test_event_loop(int ifindex) { - _cleanup_event_unref_ sd_event *event = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; char *ifname; ifname = strdup("lo2"); @@ -249,8 +246,8 @@ static int pipe_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) } static void test_async(int ifindex) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL, *r = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *r = NULL; uint32_t serial; char *ifname; @@ -270,8 +267,8 @@ static void test_async(int ifindex) { } static void test_pipe(int ifindex) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - _cleanup_netlink_message_unref_ sd_netlink_message *m1 = NULL, *m2 = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m1 = NULL, *m2 = NULL; int counter = 0; assert_se(sd_netlink_open(&rtnl) >= 0); @@ -294,7 +291,7 @@ static void test_pipe(int ifindex) { } static void test_container(void) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; uint16_t u16_data; uint32_t u32_data; const char *string_data; @@ -329,7 +326,7 @@ static void test_container(void) { } static void test_match(void) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; assert_se(sd_netlink_open(&rtnl) >= 0); @@ -344,7 +341,7 @@ static void test_match(void) { } static void test_get_addresses(sd_netlink *rtnl) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *m; assert_se(sd_rtnl_message_new_addr(rtnl, &req, RTM_GETADDR, 0, AF_UNSPEC) >= 0); @@ -372,7 +369,7 @@ static void test_get_addresses(sd_netlink *rtnl) { } static void test_message(void) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; assert_se(rtnl_message_new_synthetic_error(-ETIMEDOUT, 1, &m) >= 0); assert_se(sd_netlink_message_get_errno(m) == -ETIMEDOUT); diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c index a2d6c5931..a0d9b5f1a 100644 --- a/src/libsystemd/sd-network/network-util.c +++ b/src/libsystemd/sd-network/network-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libsystemd/sd-network/network-util.h b/src/libsystemd/sd-network/network-util.h index 11a001234..26780dce2 100644 --- a/src/libsystemd/sd-network/network-util.h +++ b/src/libsystemd/sd-network/network-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,7 +21,4 @@ #include "sd-network.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_network_monitor*, sd_network_monitor_unref); -#define _cleanup_network_monitor_unref_ _cleanup_(sd_network_monitor_unrefp) - bool network_is_online(void); diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index efbceba83..62051992e 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -95,142 +93,25 @@ _public_ int sd_network_get_ntp(char ***ret) { return network_get_strv("NTP", ret); } -_public_ int sd_network_get_domains(char ***ret) { +_public_ int sd_network_get_search_domains(char ***ret) { return network_get_strv("DOMAINS", ret); } -_public_ int sd_network_link_get_setup_state(int ifindex, char **state) { - _cleanup_free_ char *s = NULL, *p = NULL; - int r; - - assert_return(ifindex > 0, -EINVAL); - assert_return(state, -EINVAL); - - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, "ADMIN_STATE", &s, NULL); - if (r == -ENOENT) - return -ENODATA; - if (r < 0) - return r; - if (isempty(s)) - return -ENODATA; - - *state = s; - s = NULL; - - return 0; +_public_ int sd_network_get_route_domains(char ***ret) { + return network_get_strv("ROUTE_DOMAINS", ret); } -_public_ int sd_network_link_get_network_file(int ifindex, char **filename) { - _cleanup_free_ char *s = NULL, *p = NULL; - int r; - - assert_return(ifindex > 0, -EINVAL); - assert_return(filename, -EINVAL); - - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, "NETWORK_FILE", &s, NULL); - if (r == -ENOENT) - return -ENODATA; - if (r < 0) - return r; - if (isempty(s)) - return -ENODATA; - - *filename = s; - s = NULL; - - return 0; -} - -_public_ int sd_network_link_get_operational_state(int ifindex, char **state) { - _cleanup_free_ char *s = NULL, *p = NULL; - int r; - - assert_return(ifindex > 0, -EINVAL); - assert_return(state, -EINVAL); - - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, "OPER_STATE", &s, NULL); - if (r == -ENOENT) - return -ENODATA; - if (r < 0) - return r; - if (isempty(s)) - return -ENODATA; - - *state = s; - s = NULL; - - return 0; -} - -_public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) { - _cleanup_free_ char *s = NULL, *p = NULL; - int r; - - assert_return(ifindex > 0, -EINVAL); - assert_return(llmnr, -EINVAL); - - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) - return -ENOMEM; - - r = parse_env_file(p, NEWLINE, "LLMNR", &s, NULL); - if (r == -ENOENT) - return -ENODATA; - if (r < 0) - return r; - if (isempty(s)) - return -ENODATA; - - *llmnr = s; - s = NULL; - - return 0; -} - -_public_ int sd_network_link_get_lldp(int ifindex, char **lldp) { - _cleanup_free_ char *s = NULL, *p = NULL; - size_t size; - int r; - - assert_return(ifindex > 0, -EINVAL); - assert_return(lldp, -EINVAL); - - if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0) - return -ENOMEM; - - r = read_full_file(p, &s, &size); - if (r == -ENOENT) - return -ENODATA; - if (r < 0) - return r; - if (size <= 0) - return -ENODATA; - - *lldp = s; - s = NULL; - - return 0; -} - -int sd_network_link_get_timezone(int ifindex, char **ret) { +static int network_link_get_string(int ifindex, const char *field, char **ret) { _cleanup_free_ char *s = NULL, *p = NULL; int r; assert_return(ifindex > 0, -EINVAL); assert_return(ret, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) + if (asprintf(&p, "/run/systemd/netif/links/%i", ifindex) < 0) return -ENOMEM; - r = parse_env_file(p, NEWLINE, "TIMEZONE", &s, NULL); + r = parse_env_file(p, NEWLINE, field, &s, NULL); if (r == -ENOENT) return -ENODATA; if (r < 0) @@ -240,10 +121,11 @@ int sd_network_link_get_timezone(int ifindex, char **ret) { *ret = s; s = NULL; + return 0; } -static int network_get_link_strv(const char *key, int ifindex, char ***ret) { +static int network_link_get_strv(int ifindex, const char *key, char ***ret) { _cleanup_free_ char *p = NULL, *s = NULL; _cleanup_strv_free_ char **a = NULL; int r; @@ -277,44 +159,85 @@ static int network_get_link_strv(const char *key, int ifindex, char ***ret) { return r; } -_public_ int sd_network_link_get_dns(int ifindex, char ***ret) { - return network_get_link_strv("DNS", ifindex, ret); +_public_ int sd_network_link_get_setup_state(int ifindex, char **state) { + return network_link_get_string(ifindex, "ADMIN_STATE", state); } -_public_ int sd_network_link_get_ntp(int ifindex, char ***ret) { - return network_get_link_strv("NTP", ifindex, ret); +_public_ int sd_network_link_get_network_file(int ifindex, char **filename) { + return network_link_get_string(ifindex, "NETWORK_FILE", filename); } -_public_ int sd_network_link_get_domains(int ifindex, char ***ret) { - return network_get_link_strv("DOMAINS", ifindex, ret); +_public_ int sd_network_link_get_operational_state(int ifindex, char **state) { + return network_link_get_string(ifindex, "OPER_STATE", state); } -_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) { - return network_get_link_strv("CARRIER_BOUND_TO", ifindex, ret); +_public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) { + return network_link_get_string(ifindex, "LLMNR", llmnr); } -_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) { - return network_get_link_strv("CARRIER_BOUND_BY", ifindex, ret); +_public_ int sd_network_link_get_mdns(int ifindex, char **mdns) { + return network_link_get_string(ifindex, "MDNS", mdns); } -_public_ int sd_network_link_get_wildcard_domain(int ifindex) { +_public_ int sd_network_link_get_dnssec(int ifindex, char **dnssec) { + return network_link_get_string(ifindex, "DNSSEC", dnssec); +} + +_public_ int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta) { + return network_link_get_strv(ifindex, "DNSSEC_NTA", nta); +} + +_public_ int sd_network_link_get_lldp(int ifindex, char **lldp) { + _cleanup_free_ char *s = NULL, *p = NULL; + size_t size; int r; - _cleanup_free_ char *p = NULL, *s = NULL; assert_return(ifindex > 0, -EINVAL); + assert_return(lldp, -EINVAL); - if (asprintf(&p, "/run/systemd/netif/links/%d", ifindex) < 0) + if (asprintf(&p, "/run/systemd/netif/lldp/%d", ifindex) < 0) return -ENOMEM; - r = parse_env_file(p, NEWLINE, "WILDCARD_DOMAIN", &s, NULL); + r = read_full_file(p, &s, &size); if (r == -ENOENT) return -ENODATA; if (r < 0) return r; - if (isempty(s)) + if (size <= 0) return -ENODATA; - return parse_boolean(s); + *lldp = s; + s = NULL; + + return 0; +} + +int sd_network_link_get_timezone(int ifindex, char **ret) { + return network_link_get_string(ifindex, "TIMEZONE", ret); +} + +_public_ int sd_network_link_get_dns(int ifindex, char ***ret) { + return network_link_get_strv(ifindex, "DNS", ret); +} + +_public_ int sd_network_link_get_ntp(int ifindex, char ***ret) { + return network_link_get_strv(ifindex, "NTP", ret); +} + +_public_ int sd_network_link_get_search_domains(int ifindex, char ***ret) { + return network_link_get_strv(ifindex, "DOMAINS", ret); +} + +_public_ int sd_network_link_get_route_domains(int ifindex, char ***ret) { + return network_link_get_strv(ifindex, "ROUTE_DOMAINS", ret); +} + +_public_ int sd_network_link_get_carrier_bound_to(int ifindex, char ***ret) { + return network_link_get_strv(ifindex, "CARRIER_BOUND_TO", ret); +} + +_public_ int sd_network_link_get_carrier_bound_by(int ifindex, char ***ret) { + return network_link_get_strv(ifindex, "CARRIER_BOUND_BY", ret); } static inline int MONITOR_TO_FD(sd_network_monitor *m) { diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 34a0b03f9..653dbfbe5 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -38,7 +36,6 @@ #include "io-util.h" #include "list.h" #include "missing.h" -#include "resolve-util.h" #include "socket-util.h" #include "util.h" @@ -179,7 +176,7 @@ static int getnameinfo_done(sd_resolve_query *q); static void resolve_query_disconnect(sd_resolve_query *q); #define RESOLVE_DONT_DESTROY(resolve) \ - _cleanup_resolve_unref_ _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve) + _cleanup_(sd_resolve_unrefp) _unused_ sd_resolve *_dont_destroy_##resolve = sd_resolve_ref(resolve) static int send_died(int out_fd) { diff --git a/src/libsystemd/sd-resolve/test-resolve.c b/src/libsystemd/sd-resolve/test-resolve.c index 05544a584..33ef6fc0f 100644 --- a/src/libsystemd/sd-resolve/test-resolve.c +++ b/src/libsystemd/sd-resolve/test-resolve.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -32,7 +30,6 @@ #include "alloc-util.h" #include "macro.h" -#include "resolve-util.h" #include "socket-util.h" #include "string-util.h" @@ -71,8 +68,8 @@ static int getnameinfo_handler(sd_resolve_query *q, int ret, const char *host, c } int main(int argc, char *argv[]) { - _cleanup_resolve_query_unref_ sd_resolve_query *q1 = NULL, *q2 = NULL; - _cleanup_resolve_unref_ sd_resolve *resolve = NULL; + _cleanup_(sd_resolve_query_unrefp) sd_resolve_query *q1 = NULL, *q2 = NULL; + _cleanup_(sd_resolve_unrefp) sd_resolve *resolve = NULL; int r = 0; struct addrinfo hints = { @@ -102,11 +99,11 @@ int main(int argc, char *argv[]) { if (r < 0) log_error_errno(r, "sd_resolve_getnameinfo(): %m"); - /* Wait until the two queries are completed */ - while (sd_resolve_query_is_done(q1) == 0 || - sd_resolve_query_is_done(q2) == 0) { - + /* Wait until all queries are completed */ + for (;;) { r = sd_resolve_wait(resolve, (uint64_t) -1); + if (r == 0) + break; if (r < 0) { log_error_errno(r, "sd_resolve_wait(): %m"); assert_not_reached("sd_resolve_wait() failed"); diff --git a/src/libsystemd/sd-utf8/sd-utf8.c b/src/libsystemd/sd-utf8/sd-utf8.c index 9e52db3b3..33a5a04ea 100644 --- a/src/libsystemd/sd-utf8/sd-utf8.c +++ b/src/libsystemd/sd-utf8/sd-utf8.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/libudev/libudev-device-private.c b/src/libudev/libudev-device-private.c index 2d3e62410..2aae0726c 100644 --- a/src/libudev/libudev-device-private.c +++ b/src/libudev/libudev-device-private.c @@ -137,14 +137,10 @@ gid_t udev_device_get_devnode_gid(struct udev_device *udev_device) { } void udev_device_ensure_usec_initialized(struct udev_device *udev_device, struct udev_device *udev_device_old) { - sd_device *device_old = NULL; - assert(udev_device); - if (udev_device_old) - device_old = udev_device_old->device; - - device_ensure_usec_initialized(udev_device->device, device_old); + device_ensure_usec_initialized(udev_device->device, + udev_device_old ? udev_device_old->device : NULL); } char **udev_device_get_properties_envp(struct udev_device *udev_device) { diff --git a/src/libudev/libudev-enumerate.c b/src/libudev/libudev-enumerate.c index 442f9615f..e416e178b 100644 --- a/src/libudev/libudev-enumerate.c +++ b/src/libudev/libudev-enumerate.c @@ -370,7 +370,7 @@ _public_ int udev_enumerate_add_match_sysname(struct udev_enumerate *udev_enumer * Returns: 0 on success, otherwise a negative error value. */ _public_ int udev_enumerate_add_syspath(struct udev_enumerate *udev_enumerate, const char *syspath) { - _cleanup_device_unref_ sd_device *device = NULL; + _cleanup_(sd_device_unrefp) sd_device *device = NULL; int r; assert_return(udev_enumerate, -EINVAL); diff --git a/src/libudev/libudev-hwdb.c b/src/libudev/libudev-hwdb.c index eba698d16..a53f00001 100644 --- a/src/libudev/libudev-hwdb.c +++ b/src/libudev/libudev-hwdb.c @@ -53,7 +53,7 @@ struct udev_hwdb { * Returns: a hwdb context. **/ _public_ struct udev_hwdb *udev_hwdb_new(struct udev *udev) { - _cleanup_hwdb_unref_ sd_hwdb *hwdb_internal = NULL; + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb_internal = NULL; struct udev_hwdb *hwdb; int r; diff --git a/src/libudev/libudev-private.h b/src/libudev/libudev-private.h index 5f5049629..52c507511 100644 --- a/src/libudev/libudev-private.h +++ b/src/libudev/libudev-private.h @@ -21,8 +21,8 @@ #define _LIBUDEV_PRIVATE_H_ #include -#include #include +#include #include "libudev.h" diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 4a339dcfd..365c79aa5 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -195,8 +193,8 @@ static int show_status(sd_bus *bus, char **args, unsigned n) { } static int set_locale(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -248,7 +246,7 @@ static int list_locales(sd_bus *bus, char **args, unsigned n) { } static int set_vconsole_keymap(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *map, *toggle_map; int r; @@ -351,7 +349,7 @@ static int list_vconsole_keymaps(sd_bus *bus, char **args, unsigned n) { } static int set_x11_keymap(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *layout, *model, *variant, *options; int r; @@ -666,7 +664,7 @@ static int localectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char*argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/locale/localed.c b/src/locale/localed.c index 720cbbaab..f0fe59cc6 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -36,7 +34,6 @@ #include "bus-util.h" #include "def.h" #include "env-util.h" -#include "event-util.h" #include "fd-util.h" #include "fileio-label.h" #include "fileio.h" @@ -327,7 +324,7 @@ static int locale_write_data(Context *c, char ***settings) { static int locale_update_system_manager(Context *c, sd_bus *bus) { _cleanup_free_ char **l_unset = NULL; _cleanup_strv_free_ char **l_set = NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; sd_bus_error error = SD_BUS_ERROR_NULL; unsigned c_set, c_unset, p; int r; @@ -500,7 +497,7 @@ fail: } static int vconsole_reload(sd_bus *bus) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -540,7 +537,7 @@ static int read_next_mapping(const char* filename, if (!fgets(line, sizeof(line), f)) { if (ferror(f)) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return 0; } @@ -1259,7 +1256,7 @@ static const sd_bus_vtable locale_vtable[] = { }; static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; assert(c); @@ -1290,8 +1287,8 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { int main(int argc, char *argv[]) { _cleanup_(context_free) Context context = {}; - _cleanup_event_unref_ sd_event *event = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; log_set_target(LOG_TARGET_AUTO); diff --git a/src/login/inhibit.c b/src/login/inhibit.c index 70fef332f..f2c37a862 100644 --- a/src/login/inhibit.c +++ b/src/login/inhibit.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -49,7 +47,7 @@ static enum { } arg_action = ACTION_INHIBIT; static int inhibit(sd_bus *bus, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; int fd; @@ -77,7 +75,7 @@ static int inhibit(sd_bus *bus, sd_bus_error *error) { } static int print_inhibitors(sd_bus *bus, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *what, *who, *why, *mode; unsigned int uid, pid; unsigned n = 0; @@ -223,8 +221,8 @@ static int parse_argv(int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; log_parse_environment(); diff --git a/src/login/loginctl.c b/src/login/loginctl.c index aff68a49f..6ad3d089b 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -88,12 +86,12 @@ static OutputFlags get_output_flags(void) { arg_all * OUTPUT_SHOW_ALL | arg_full * OUTPUT_FULL_WIDTH | (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | - on_tty() * OUTPUT_COLOR; + colors_enabled() * OUTPUT_COLOR; } static int list_sessions(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *id, *user, *seat, *object; sd_bus *bus = userdata; unsigned k = 0; @@ -139,8 +137,8 @@ static int list_sessions(int argc, char *argv[], void *userdata) { } static int list_users(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *user, *object; sd_bus *bus = userdata; unsigned k = 0; @@ -186,8 +184,8 @@ static int list_users(int argc, char *argv[], void *userdata) { } static int list_seats(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *seat, *object; sd_bus *bus = userdata; unsigned k = 0; @@ -232,8 +230,8 @@ static int list_seats(int argc, char *argv[], void *userdata) { } static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *path = NULL; const char *cgroup; int r; @@ -784,8 +782,8 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte } static int show_properties(sd_bus *bus, const char *path, bool *new_line) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -873,8 +871,8 @@ static int show_session(int argc, char *argv[], void *userdata) { } for (i = 1; i < argc; i++) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message * reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL; const char *path = NULL; r = sd_bus_call_method( @@ -928,8 +926,8 @@ static int show_user(int argc, char *argv[], void *userdata) { } for (i = 1; i < argc; i++) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message * reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL; const char *path = NULL; uid_t uid; @@ -988,8 +986,8 @@ static int show_seat(int argc, char *argv[], void *userdata) { } for (i = 1; i < argc; i++) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message * reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL; const char *path = NULL; r = sd_bus_call_method( @@ -1022,7 +1020,7 @@ static int show_seat(int argc, char *argv[], void *userdata) { } static int activate(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; char *short_argv[3]; int r, i; @@ -1068,7 +1066,7 @@ static int activate(int argc, char *argv[], void *userdata) { } static int kill_session(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -1100,7 +1098,7 @@ static int kill_session(int argc, char *argv[], void *userdata) { } static int enable_linger(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; char* short_argv[3]; bool b; @@ -1150,7 +1148,7 @@ static int enable_linger(int argc, char *argv[], void *userdata) { } static int terminate_user(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -1184,7 +1182,7 @@ static int terminate_user(int argc, char *argv[], void *userdata) { } static int kill_user(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -1221,7 +1219,7 @@ static int kill_user(int argc, char *argv[], void *userdata) { } static int attach(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -1251,7 +1249,7 @@ static int attach(int argc, char *argv[], void *userdata) { } static int flush_devices(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r; @@ -1275,7 +1273,7 @@ static int flush_devices(int argc, char *argv[], void *userdata) { } static int lock_sessions(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r; @@ -1299,7 +1297,7 @@ static int lock_sessions(int argc, char *argv[], void *userdata) { } static int terminate_seat(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -1534,7 +1532,7 @@ static int loginctl_main(int argc, char *argv[], sd_bus *bus) { } int main(int argc, char *argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/login/logind-acl.c b/src/login/logind-acl.c index d0dd569a0..0cef88a82 100644 --- a/src/login/logind-acl.c +++ b/src/login/logind-acl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/login/logind-acl.h b/src/login/logind-acl.h index 93e9ed02e..1286c6a3c 100644 --- a/src/login/logind-acl.h +++ b/src/login/logind-acl.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "libudev.h" diff --git a/src/login/logind-action.c b/src/login/logind-action.c index 185108f8f..9a8089f97 100644 --- a/src/login/logind-action.c +++ b/src/login/logind-action.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -61,7 +59,7 @@ int manager_handle_action( [HANDLE_HYBRID_SLEEP] = SPECIAL_HYBRID_SLEEP_TARGET }; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; InhibitWhat inhibit_operation; Inhibitor *offending = NULL; bool supported; diff --git a/src/login/logind-action.h b/src/login/logind-action.h index e9b424b5f..fb40ae48d 100644 --- a/src/login/logind-action.h +++ b/src/login/logind-action.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -35,8 +33,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-button.c b/src/login/logind-button.c index b08b69dbf..baa6b7113 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/login/logind-button.h b/src/login/logind-button.h index 80d93c7e6..f30cba295 100644 --- a/src/login/logind-button.h +++ b/src/login/logind-button.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 36cdbbe0f..8bdb3a9a3 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -139,7 +137,7 @@ int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) { errno = 0; p = getpwuid(uid); if (!p) - return errno ? -errno : -ENOENT; + return errno > 0 ? -errno : -ENOENT; return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user); } @@ -404,7 +402,7 @@ static int vt_is_busy(unsigned int vtnr) { } int manager_spawn_autovt(Manager *m, unsigned int vtnr) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)]; int r; diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index e507a19ae..1d3133ee2 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -53,7 +51,7 @@ #include "utmp-wtmp.h" int manager_get_session_from_creds(Manager *m, sd_bus_message *message, const char *name, sd_bus_error *error, Session **ret) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; Session *session; int r; @@ -88,7 +86,7 @@ int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, assert(ret); if (uid == UID_INVALID) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; /* Note that we get the owner UID of the session, not the actual client UID here! */ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); @@ -124,7 +122,6 @@ int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char return r; seat = session->seat; - if (!seat) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "Session has no seat."); } else { @@ -419,7 +416,7 @@ static int method_get_seat(sd_bus_message *message, void *userdata, sd_bus_error } static int method_list_sessions(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; Session *session; Iterator i; @@ -461,7 +458,7 @@ static int method_list_sessions(sd_bus_message *message, void *userdata, sd_bus_ } static int method_list_users(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; User *user; Iterator i; @@ -501,7 +498,7 @@ static int method_list_users(sd_bus_message *message, void *userdata, sd_bus_err } static int method_list_seats(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; Seat *seat; Iterator i; @@ -538,7 +535,7 @@ static int method_list_seats(sd_bus_message *message, void *userdata, sd_bus_err } static int method_list_inhibitors(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; Inhibitor *inhibitor; Iterator i; @@ -696,7 +693,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus } if (leader == 0) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); if (r < 0) @@ -1094,7 +1091,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu return r; if (uid == UID_INVALID) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; /* Note that we get the owner UID of the session, not the actual client UID here! */ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); @@ -1111,7 +1108,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu errno = 0; pw = getpwuid(uid); if (!pw) - return errno ? -errno : -ENOENT; + return errno > 0 ? -errno : -ENOENT; r = bus_verify_polkit_async( message, @@ -1229,7 +1226,6 @@ static int attach_device(Manager *m, const char *seat, const char *sysfs) { return -ENOMEM; mkdir_p_label("/etc/udev/rules.d", 0755); - mac_selinux_init("/etc"); r = write_string_file_atomic_label(file, rule); if (r < 0) return r; @@ -1465,7 +1461,7 @@ static int execute_shutdown_or_sleep( const char *unit_name, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; char *c = NULL; const char *p; int r; @@ -1515,7 +1511,7 @@ static int execute_shutdown_or_sleep( int manager_dispatch_delayed(Manager *manager, bool timeout) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; Inhibitor *offending = NULL; int r; @@ -1668,7 +1664,7 @@ static int verify_shutdown_creds( const char *action_ignore_inhibit, sd_bus_error *error) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; bool multiple_sessions, blocked; uid_t uid; int r; @@ -1820,7 +1816,7 @@ static int nologin_timeout_handler( log_info("Creating /run/nologin, blocking further logins..."); - r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); + r = write_string_file_atomic_label("/run/nologin", "System is going down."); if (r < 0) log_error_errno(r, "Failed to create /run/nologin: %m"); else @@ -1889,7 +1885,7 @@ static int manager_scheduled_shutdown_handler( uint64_t usec, void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; Manager *m = userdata; const char *target; int r; @@ -1915,7 +1911,7 @@ static int manager_scheduled_shutdown_handler( static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_bus_error *error) { Manager *m = userdata; - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; const char *action_multiple_sessions = NULL; const char *action_ignore_inhibit = NULL; const char *action = NULL; @@ -1944,9 +1940,9 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ action_multiple_sessions = "org.freedesktop.login1.halt-multiple-sessions"; action_ignore_inhibit = "org.freedesktop.login1.halt-ignore-inhibit"; } else if (streq(type, "poweroff")) { - action = "org.freedesktop.login1.poweroff"; - action_multiple_sessions = "org.freedesktop.login1.poweroff-multiple-sessions"; - action_ignore_inhibit = "org.freedesktop.login1.poweroff-ignore-inhibit"; + action = "org.freedesktop.login1.power-off"; + action_multiple_sessions = "org.freedesktop.login1.power-off-multiple-sessions"; + action_ignore_inhibit = "org.freedesktop.login1.power-off-ignore-inhibit"; } else return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type"); @@ -1995,7 +1991,7 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_AUGMENT|SD_BUS_CREDS_TTY|SD_BUS_CREDS_UID, &creds); if (r >= 0) { - const char *tty; + const char *tty = NULL; (void) sd_bus_creds_get_uid(creds, &m->scheduled_shutdown_uid); (void) sd_bus_creds_get_tty(creds, &tty); @@ -2032,7 +2028,7 @@ static int method_cancel_scheduled_shutdown(sd_bus_message *message, void *userd reset_scheduled_shutdown(m); if (cancelled) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; const char *tty = NULL; uid_t uid = 0; int r; @@ -2088,7 +2084,7 @@ static int method_can_shutdown_or_sleep( const char *sleep_verb, sd_bus_error *error) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; bool multiple_sessions, challenge, blocked; const char *result = NULL; uid_t uid; @@ -2374,7 +2370,7 @@ static int method_set_wall_message( } static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; const char *who, *why, *what, *mode; _cleanup_free_ char *id = NULL; _cleanup_close_ int fifo_fd = -1; @@ -2581,7 +2577,7 @@ static int session_jobs_reply(Session *s, const char *unit, const char *result) if (streq(result, "done")) r = session_send_create_reply(s, NULL); else { - _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result); r = session_send_create_reply(s, &e); @@ -2752,6 +2748,23 @@ int manager_send_changed(Manager *manager, const char *property, ...) { l); } +static int strdup_job(sd_bus_message *reply, char **job) { + const char *j; + char *copy; + int r; + + 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_slice( Manager *manager, const char *slice, @@ -2762,11 +2775,12 @@ int manager_start_slice( sd_bus_error *error, char **job) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; int r; assert(manager); assert(slice); + assert(job); r = sd_bus_message_new_method_call( manager->bus, @@ -2820,22 +2834,7 @@ int manager_start_slice( 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; + return strdup_job(reply, job); } int manager_start_scope( @@ -2850,12 +2849,13 @@ int manager_start_scope( sd_bus_error *error, char **job) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; int r; assert(manager); assert(scope); assert(pid > 1); + assert(job); r = sd_bus_message_new_method_call( manager->bus, @@ -2930,30 +2930,16 @@ int manager_start_scope( 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; + return strdup_job(reply, job); } int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; assert(manager); assert(unit); + assert(job); r = sd_bus_call_method( manager->bus, @@ -2967,30 +2953,16 @@ int manager_start_unit(Manager *manager, const char *unit, sd_bus_error *error, 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; + return strdup_job(reply, job); } int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; assert(manager); assert(unit); + assert(job); r = sd_bus_call_method( manager->bus, @@ -3005,9 +2977,7 @@ int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, c if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) || sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) { - if (job) - *job = NULL; - + *job = NULL; sd_bus_error_free(error); return 0; } @@ -3015,22 +2985,7 @@ int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, c 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; + return strdup_job(reply, job); } int manager_abandon_scope(Manager *manager, const char *scope, sd_bus_error *error) { @@ -3083,8 +3038,8 @@ int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo } int manager_unit_is_active(Manager *manager, const char *unit) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *path = NULL; const char *state; int r; @@ -3129,8 +3084,8 @@ int manager_unit_is_active(Manager *manager, const char *unit) { } int manager_job_is_active(Manager *manager, const char *path) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; assert(manager); diff --git a/src/login/logind-device.c b/src/login/logind-device.c index ffb9162e5..eb5edd1cd 100644 --- a/src/login/logind-device.c +++ b/src/login/logind-device.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/login/logind-device.h b/src/login/logind-device.h index 6b2728586..927068e00 100644 --- a/src/login/logind-device.h +++ b/src/login/logind-device.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/login/logind-inhibit.c b/src/login/logind-inhibit.c index 33fbdde55..a0e3ba2b7 100644 --- a/src/login/logind-inhibit.c +++ b/src/login/logind-inhibit.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/login/logind-inhibit.h b/src/login/logind-inhibit.h index 1b77fc1e9..70de199c6 100644 --- a/src/login/logind-inhibit.h +++ b/src/login/logind-inhibit.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index 43b578f36..3cee10d00 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -334,7 +332,7 @@ int seat_object_find(sd_bus *bus, const char *path, const char *interface, void assert(m); if (streq(path, "/org/freedesktop/login1/seat/self")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_bus_message *message; Session *session; const char *name; @@ -416,7 +414,7 @@ int seat_node_enumerator(sd_bus *bus, const char *path, void *userdata, char *** message = sd_bus_get_current_message(bus); if (message) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; const char *name; Session *session; diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index 1f4936ceb..b5192320e 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -34,6 +32,7 @@ #include "logind-seat.h" #include "mkdir.h" #include "parse-util.h" +#include "stdio-util.h" #include "string-util.h" #include "terminal-util.h" #include "util.h" @@ -181,7 +180,7 @@ static int vt_allocate(unsigned int vtnr) { assert(vtnr >= 1); - snprintf(p, sizeof(p), "/dev/tty%u", vtnr); + xsprintf(p, "/dev/tty%u", vtnr); fd = open_terminal(p, O_RDWR|O_NOCTTY|O_CLOEXEC); if (fd < 0) return -errno; diff --git a/src/login/logind-seat.h b/src/login/logind-seat.h index 248dbeb9d..9a4fbc5bc 100644 --- a/src/login/logind-seat.h +++ b/src/login/logind-seat.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 7810199a5..ff9170683 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -252,7 +250,7 @@ int bus_session_method_lock(sd_bus_message *message, void *userdata, sd_bus_erro } static int method_set_idle_hint(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; Session *s = userdata; uid_t uid; int r, b; @@ -327,7 +325,7 @@ int bus_session_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro } static int method_take_control(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; Session *s = userdata; int r, force; uid_t uid; @@ -521,7 +519,7 @@ int session_object_find(sd_bus *bus, const char *path, const char *interface, vo assert(m); if (streq(path, "/org/freedesktop/login1/session/self")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_bus_message *message; const char *name; @@ -598,7 +596,7 @@ int session_node_enumerator(sd_bus *bus, const char *path, void *userdata, char message = sd_bus_get_current_message(bus); if (message) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; const char *name; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_SESSION|SD_BUS_CREDS_AUGMENT, &creds); @@ -692,7 +690,7 @@ int session_send_lock_all(Manager *m, bool lock) { } int session_send_create_reply(Session *s, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *c = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL; _cleanup_close_ int fifo_fd = -1; _cleanup_free_ char *p = NULL; diff --git a/src/login/logind-session-device.c b/src/login/logind-session-device.c index 9bf3ca099..4055a2327 100644 --- a/src/login/logind-session-device.c +++ b/src/login/logind-session-device.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -42,7 +40,7 @@ enum SessionDeviceNotifications { }; static int session_device_notify(SessionDevice *sd, enum SessionDeviceNotifications type) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *path = NULL; const char *t = NULL; uint32_t major, minor; diff --git a/src/login/logind-session-device.h b/src/login/logind-session-device.h index 1c9f99837..7c8503583 100644 --- a/src/login/logind-session-device.h +++ b/src/login/logind-session-device.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 9f03a7b31..417b7f5d9 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -514,7 +512,7 @@ static int session_start_scope(Session *s) { assert(s->user); if (!s->scope) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *scope, *job = NULL; const char *description; @@ -611,7 +609,7 @@ int session_start(Session *s) { } static int session_stop_scope(Session *s, bool force) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *job = NULL; int r; diff --git a/src/login/logind-session.h b/src/login/logind-session.h index d054c33ce..e24b80847 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,8 +23,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-dbus.c b/src/login/logind-user-dbus.c index df901f655..fd98c7bec 100644 --- a/src/login/logind-user-dbus.c +++ b/src/login/logind-user-dbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -271,7 +269,7 @@ int user_object_find(sd_bus *bus, const char *path, const char *interface, void assert(m); if (streq(path, "/org/freedesktop/login1/user/self")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_bus_message *message; message = sd_bus_get_current_message(bus); @@ -340,7 +338,7 @@ int user_node_enumerator(sd_bus *bus, const char *path, void *userdata, char *** message = sd_bus_get_current_message(bus); if (message) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; uid_t uid; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_OWNER_UID|SD_BUS_CREDS_AUGMENT, &creds); diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 778f19b50..6b9c69cc4 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -393,7 +391,7 @@ fail: } static int user_start_slice(User *u) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *description; char *job; int r; @@ -412,19 +410,18 @@ static int user_start_slice(User *u) { 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 { + if (r >= 0) u->slice_job = job; - } + else if (!sd_bus_error_has_name(&error, BUS_ERROR_UNIT_EXISTS)) + /* we don't fail due to this, let's try to continue */ + log_error_errno(r, "Failed to start user slice %s, ignoring: %s (%s)", + u->slice, bus_error_message(&error, r), error.name); return 0; } static int user_start_service(User *u) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *job; int r; @@ -509,7 +506,7 @@ int user_start(User *u) { } static int user_stop_slice(User *u) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *job; int r; @@ -528,7 +525,7 @@ static int user_stop_slice(User *u) { } static int user_stop_service(User *u) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *job; int r; @@ -868,7 +865,7 @@ int config_parse_tmpfs_size( errno = 0; ul = strtoul(rvalue, &f, 10); - if (errno != 0 || f != e) { + if (errno > 0 || f != e) { log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse percentage value, ignoring: %s", rvalue); return 0; } diff --git a/src/login/logind-user.h b/src/login/logind-user.h index de99cf47b..4f0966dc7 100644 --- a/src/login/logind-user.h +++ b/src/login/logind-user.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/login/logind-utmp.c b/src/login/logind-utmp.c index 3bd61a81f..11a91c394 100644 --- a/src/login/logind-utmp.c +++ b/src/login/logind-utmp.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/login/logind.c b/src/login/logind.c index 7b41174c6..933602eb0 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -36,6 +34,7 @@ #include "fd-util.h" #include "formats-util.h" #include "logind.h" +#include "selinux-util.h" #include "signal-util.h" #include "strv.h" #include "udev-util.h" @@ -70,7 +69,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->user_tasks_max = UINT64_C(12288); m->devices = hashmap_new(&string_hash_ops); m->seats = hashmap_new(&string_hash_ops); @@ -579,7 +578,7 @@ static int manager_reserve_vt(Manager *m) { } static int manager_connect_bus(Manager *m) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(m); @@ -1127,6 +1126,12 @@ int main(int argc, char *argv[]) { goto finish; } + r = mac_selinux_init("/run"); + if (r < 0) { + log_error_errno(r, "Could not initialize labelling: %m"); + goto finish; + } + /* Always create the directories people can create inotify * watches in. Note that some applications might check for the * existence of /run/systemd/seats/ to determine whether diff --git a/src/login/logind.conf b/src/login/logind.conf index 81f669543..6095e482a 100644 --- a/src/login/logind.conf +++ b/src/login/logind.conf @@ -32,4 +32,4 @@ #IdleActionSec=30min #RuntimeDirectorySize=10% #RemoveIPC=yes -#UserTasksMax=4096 +#UserTasksMax=12288 diff --git a/src/login/logind.h b/src/login/logind.h index f34544e64..6748af3c0 100644 --- a/src/login/logind.h +++ b/src/login/logind.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index ed4f7c726..40e246bb0 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -220,8 +218,8 @@ _public_ PAM_EXTERN int pam_sm_open_session( int flags, int argc, const char **argv) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *username, *id, *object_path, *runtime_path, *service = NULL, @@ -230,7 +228,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( *seat = NULL, *type = NULL, *class = NULL, *class_pam = NULL, *type_pam = NULL, *cvtnr = NULL, *desktop = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int session_fd = -1, existing, r; bool debug = false, remote; struct passwd *pw; @@ -509,8 +507,8 @@ _public_ PAM_EXTERN int pam_sm_close_session( int flags, int argc, const char **argv) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; const void *existing = NULL; const char *id; int r; diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c index e9ca4bb03..bd603e297 100644 --- a/src/login/sysfs-show.c +++ b/src/login/sysfs-show.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/login/sysfs-show.h b/src/login/sysfs-show.h index 9ffd129c4..3e94bc3ed 100644 --- a/src/login/sysfs-show.h +++ b/src/login/sysfs-show.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/login/test-inhibit.c b/src/login/test-inhibit.c index d0727ff7c..a3cf9d293 100644 --- a/src/login/test-inhibit.c +++ b/src/login/test-inhibit.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -29,8 +27,8 @@ #include "util.h" static int inhibit(sd_bus *bus, const char *what) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *who = "Test Tool", *reason = "Just because!", *mode = "block"; int fd; int r; @@ -53,8 +51,8 @@ static int inhibit(sd_bus *bus, const char *what) { } static void print_inhibitors(sd_bus *bus) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *what, *who, *why, *mode; uint32_t uid, pid; unsigned n = 0; @@ -85,7 +83,7 @@ static void print_inhibitors(sd_bus *bus) { } int main(int argc, char*argv[]) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; int fd1, fd2; int r; diff --git a/src/login/test-login-shared.c b/src/login/test-login-shared.c index ac327f71f..3d233f017 100644 --- a/src/login/test-login-shared.c +++ b/src/login/test-login-shared.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index d805bcfdc..1d55fa04a 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -112,7 +110,7 @@ int main(int argc, char *argv[]) { if (arg_commit) r = machine_id_commit(arg_root); else - r = machine_id_setup(arg_root); + r = machine_id_setup(arg_root, SD_ID128_NULL); finish: free(arg_root); diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index 4ec176603..73f5112c4 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,6 +21,7 @@ #include "bus-label.h" #include "bus-util.h" #include "image-dbus.h" +#include "io-util.h" #include "machine-image.h" #include "strv.h" #include "user-util.h" @@ -195,6 +194,8 @@ int bus_image_method_set_limit( r = sd_bus_message_read(message, "t", &limit); if (r < 0) return r; + if (!FILE_SIZE_VALID_OR_INFINITY(limit)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range"); r = bus_verify_polkit_async( message, diff --git a/src/machine/image-dbus.h b/src/machine/image-dbus.h index d56d905c8..b62da996c 100644 --- a/src/machine/image-dbus.h +++ b/src/machine/image-dbus.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 452130a29..71f20b3f0 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -192,7 +190,7 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro } int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Machine *m = userdata; int r; @@ -375,7 +373,7 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd } int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_strv_free_ char **l = NULL; Machine *m = userdata; char **k, **v; @@ -481,7 +479,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s } int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *pty_name = NULL; _cleanup_close_ int master = -1; Machine *m = userdata; @@ -536,7 +534,7 @@ static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) { break; case MACHINE_CONTAINER: { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; char *address; r = sd_bus_new(&bus); @@ -570,9 +568,9 @@ static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) { } int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *pty_name = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL; _cleanup_close_ int master = -1; sd_bus *container_bus = NULL; Machine *m = userdata; @@ -639,9 +637,9 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu } int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *tm = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *tm = NULL; _cleanup_free_ char *pty_name = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL; sd_bus *container_bus = NULL; _cleanup_close_ int master = -1, slave = -1; _cleanup_strv_free_ char **env = NULL, **args = NULL; @@ -922,7 +920,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu First, we start by creating a private playground in /tmp, that we can mount MS_SLAVE. (Which is necessary, since - MS_MOUNT cannot be applied to mounts with MS_SHARED parent + MS_MOVE cannot be applied to mounts with MS_SHARED parent mounts.) */ if (!mkdtemp(mount_slave)) @@ -1086,7 +1084,7 @@ finish: } static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; MachineOperation *o = userdata; int r; @@ -1312,7 +1310,7 @@ int machine_object_find(sd_bus *bus, const char *path, const char *interface, vo assert(m); if (streq(path, "/org/freedesktop/machine1/machine/self")) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; sd_bus_message *message; pid_t pid; @@ -1411,7 +1409,7 @@ int machine_send_signal(Machine *m, bool new_machine) { } int machine_send_create_reply(Machine *m, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *c = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *c = NULL; _cleanup_free_ char *p = NULL; assert(m); diff --git a/src/machine/machine-dbus.h b/src/machine/machine-dbus.h index 194e680e0..3a8162b17 100644 --- a/src/machine/machine-dbus.h +++ b/src/machine/machine-dbus.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/machine/machine.c b/src/machine/machine.c index 6b1fae276..406d5a4b8 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -432,7 +430,7 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) { } static int machine_stop_scope(Machine *m) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *job = NULL; int r; diff --git a/src/machine/machine.h b/src/machine/machine.h index ad7f2a162..1d8cc5911 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 7e17c7a41..485313932 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -40,7 +38,6 @@ #include "cgroup-util.h" #include "copy.h" #include "env-util.h" -#include "event-util.h" #include "fd-util.h" #include "hostname-util.h" #include "import-util.h" @@ -79,7 +76,6 @@ static unsigned arg_lines = 10; static OutputMode arg_output = OUTPUT_SHORT; static bool arg_force = false; static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; -static const char* arg_dkr_index_url = NULL; static const char* arg_format = NULL; static const char *arg_uid = NULL; static char **arg_setenv = NULL; @@ -110,7 +106,7 @@ static OutputFlags get_output_flags(void) { arg_all * OUTPUT_SHOW_ALL | arg_full * OUTPUT_FULL_WIDTH | (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | - on_tty() * OUTPUT_COLOR | + colors_enabled() * OUTPUT_COLOR | !arg_quiet * OUTPUT_WARN_CUTOFF; } @@ -129,8 +125,8 @@ static int compare_machine_info(const void *a, const void *b) { static int list_machines(int argc, char *argv[], void *userdata) { size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE"); - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ MachineInfo *machines = NULL; const char *name, *class, *service, *object; size_t n_machines = 0, n_allocated = 0, j; @@ -230,9 +226,9 @@ static int compare_image_info(const void *a, const void *b) { static int list_images(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("USAGE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED"); - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ ImageInfo *images = NULL; size_t n_images = 0, n_allocated = 0, j; const char *name, *type, *object; @@ -344,8 +340,8 @@ static int list_images(int argc, char *argv[], void *userdata) { } static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *path = NULL; const char *cgroup; int r; @@ -393,7 +389,7 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { } static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; assert(bus); @@ -454,7 +450,7 @@ static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *p } static int print_os_release(sd_bus *bus, const char *name, const char *prefix) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *k, *v, *pretty = NULL; int r; @@ -701,8 +697,8 @@ static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line static int show_machine(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; bool properties, new_line = false; sd_bus *bus = userdata; int r = 0, i; @@ -950,8 +946,8 @@ static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) static int show_image(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; bool properties, new_line = false; sd_bus *bus = userdata; int r = 0, i; @@ -1006,7 +1002,7 @@ static int show_image(int argc, char *argv[], void *userdata) { } static int kill_machine(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -1051,7 +1047,7 @@ static int poweroff_machine(int argc, char *argv[], void *userdata) { } static int terminate_machine(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -1079,7 +1075,7 @@ static int terminate_machine(int argc, char *argv[], void *userdata) { } static int copy_files(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *abs_host_path = NULL; char *dest, *host_path, *container_path; sd_bus *bus = userdata; @@ -1122,7 +1118,7 @@ static int copy_files(int argc, char *argv[], void *userdata) { } static int bind_mount(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r; @@ -1226,11 +1222,11 @@ static int process_forward(sd_event *event, PTYForward **forward, int master, PT } static int login_machine(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(pty_forward_freep) PTYForward *forward = NULL; - _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; int master = -1, r; sd_bus *bus = userdata; const char *pty, *match, *machine; @@ -1293,11 +1289,11 @@ static int login_machine(int argc, char *argv[], void *userdata) { } static int shell_machine(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(pty_forward_freep) PTYForward *forward = NULL; - _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; int master = -1, r; sd_bus *bus = userdata; const char *pty, *match, *machine, *path, *uid = NULL; @@ -1397,7 +1393,7 @@ static int shell_machine(int argc, char *argv[], void *userdata) { } static int remove_image(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -1425,7 +1421,7 @@ static int remove_image(int argc, char *argv[], void *userdata) { } static int rename_image(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r; @@ -1449,7 +1445,7 @@ static int rename_image(int argc, char *argv[], void *userdata) { } static int clone_image(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r; @@ -1473,7 +1469,7 @@ static int clone_image(int argc, char *argv[], void *userdata) { } static int read_only_image(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int b = true, r; @@ -1528,7 +1524,7 @@ static int make_service_name(const char *name, char **ret) { } static int start_machine(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; sd_bus *bus = userdata; int r, i; @@ -1542,7 +1538,7 @@ static int start_machine(int argc, char *argv[], void *userdata) { return log_oom(); for (i = 1; i < argc; i++) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *unit = NULL; const char *object; @@ -1573,7 +1569,7 @@ static int start_machine(int argc, char *argv[], void *userdata) { return log_oom(); } - r = bus_wait_for_jobs(w, arg_quiet); + r = bus_wait_for_jobs(w, arg_quiet, NULL); if (r < 0) return r; @@ -1581,8 +1577,8 @@ static int start_machine(int argc, char *argv[], void *userdata) { } static int enable_machine(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int carries_install_info = 0; const char *method = NULL; sd_bus *bus = userdata; @@ -1721,10 +1717,10 @@ static int transfer_signal_handler(sd_event_source *s, const struct signalfd_sig } static int transfer_image_common(sd_bus *bus, sd_bus_message *m) { - _cleanup_bus_slot_unref_ sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_event_unref_ sd_event* event = NULL; + _cleanup_(sd_bus_slot_unrefp) sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_event_unrefp) sd_event* event = NULL; const char *path = NULL; uint32_t id; int r; @@ -1791,7 +1787,7 @@ static int transfer_image_common(sd_bus *bus, sd_bus_message *m) { } static int import_tar(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *ll = NULL; _cleanup_close_ int fd = -1; const char *local = NULL, *path = NULL; @@ -1858,7 +1854,7 @@ static int import_tar(int argc, char *argv[], void *userdata) { } static int import_raw(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *ll = NULL; _cleanup_close_ int fd = -1; const char *local = NULL, *path = NULL; @@ -1940,7 +1936,7 @@ static void determine_compression_from_filename(const char *p) { } static int export_tar(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_close_ int fd = -1; const char *local = NULL, *path = NULL; sd_bus *bus = userdata; @@ -1990,7 +1986,7 @@ static int export_tar(int argc, char *argv[], void *userdata) { } static int export_raw(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_close_ int fd = -1; const char *local = NULL, *path = NULL; sd_bus *bus = userdata; @@ -2040,7 +2036,7 @@ static int export_raw(int argc, char *argv[], void *userdata) { } static int pull_tar(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *l = NULL, *ll = NULL; const char *local, *remote; sd_bus *bus = userdata; @@ -2104,7 +2100,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) { } static int pull_raw(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *l = NULL, *ll = NULL; const char *local, *remote; sd_bus *bus = userdata; @@ -2167,78 +2163,6 @@ static int pull_raw(int argc, char *argv[], void *userdata) { return transfer_image_common(bus, m); } -static int pull_dkr(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - const char *local, *remote, *tag; - sd_bus *bus = userdata; - int r; - - if (arg_verify != IMPORT_VERIFY_NO) { - log_error("Imports from DKR do not support image verification, please pass --verify=no."); - return -EINVAL; - } - - remote = argv[1]; - tag = strchr(remote, ':'); - if (tag) { - remote = strndupa(remote, tag - remote); - tag++; - } - - if (!dkr_name_is_valid(remote)) { - log_error("DKR name '%s' is invalid.", remote); - return -EINVAL; - } - if (tag && !dkr_tag_is_valid(tag)) { - log_error("DKR tag '%s' is invalid.", remote); - return -EINVAL; - } - - if (argc >= 3) - local = argv[2]; - else { - local = strchr(remote, '/'); - if (local) - local++; - else - local = remote; - } - - if (isempty(local) || streq(local, "-")) - local = NULL; - - if (local) { - if (!machine_name_is_valid(local)) { - log_error("Local name %s is not a suitable machine name.", local); - return -EINVAL; - } - } - - r = sd_bus_message_new_method_call( - bus, - &m, - "org.freedesktop.import1", - "/org/freedesktop/import1", - "org.freedesktop.import1.Manager", - "PullDkr"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append( - m, - "sssssb", - arg_dkr_index_url, - remote, - tag, - local, - import_verify_to_string(arg_verify), - arg_force); - if (r < 0) - return bus_log_create_error(r); - - return transfer_image_common(bus, m); -} - typedef struct TransferInfo { uint32_t id; const char *type; @@ -2255,8 +2179,8 @@ static int compare_transfer_info(const void *a, const void *b) { static int list_transfers(int argc, char *argv[], void *userdata) { size_t max_type = strlen("TYPE"), max_local = strlen("LOCAL"), max_remote = strlen("REMOTE"); - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ TransferInfo *transfers = NULL; size_t n_transfers = 0, n_allocated = 0, j; const char *type, *remote, *local, *object; @@ -2346,7 +2270,7 @@ static int list_transfers(int argc, char *argv[], void *userdata) { } static int cancel_transfer(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; int r, i; @@ -2380,7 +2304,7 @@ static int cancel_transfer(int argc, char *argv[], void *userdata) { } static int set_limit(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus = userdata; uint64_t limit; int r; @@ -2453,9 +2377,7 @@ static int help(int argc, char *argv[], void *userdata) { " json-pretty, json-sse, cat)\n" " --verify=MODE Verification mode for downloaded images (no,\n" " checksum, signature)\n" - " --force Download image even if already exists\n" - " --dkr-index-url=URL Specify the index URL to use for DKR image\n" - " downloads\n\n" + " --force Download image even if already exists\n\n" "Machine Commands:\n" " list List running VMs and containers\n" " status NAME... Show VM/container details\n" @@ -2487,7 +2409,6 @@ static int help(int argc, char *argv[], void *userdata) { "Image Transfer Commands:\n" " pull-tar URL [NAME] Download a TAR container image\n" " pull-raw URL [NAME] Download a RAW container or VM image\n" - " pull-dkr REMOTE [NAME] Download a DKR container image\n" " import-tar FILE [NAME] Import a local TAR container image\n" " import-raw FILE [NAME] Import a local RAW container or VM image\n" " export-tar NAME [FILE] Export a TAR container image locally\n" @@ -2511,7 +2432,6 @@ static int parse_argv(int argc, char *argv[]) { ARG_NO_ASK_PASSWORD, ARG_VERIFY, ARG_FORCE, - ARG_DKR_INDEX_URL, ARG_FORMAT, ARG_UID, ARG_SETENV, @@ -2537,7 +2457,6 @@ static int parse_argv(int argc, char *argv[]) { { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD }, { "verify", required_argument, NULL, ARG_VERIFY }, { "force", no_argument, NULL, ARG_FORCE }, - { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL }, { "format", required_argument, NULL, ARG_FORMAT }, { "uid", required_argument, NULL, ARG_UID }, { "setenv", required_argument, NULL, ARG_SETENV }, @@ -2651,15 +2570,6 @@ static int parse_argv(int argc, char *argv[]) { arg_force = true; break; - case ARG_DKR_INDEX_URL: - if (!http_url_is_valid(optarg)) { - log_error("Index URL is invalid: %s", optarg); - return -EINVAL; - } - - arg_dkr_index_url = optarg; - break; - case ARG_FORMAT: if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2")) { log_error("Unknown format: %s", optarg); @@ -2726,7 +2636,6 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { { "export-raw", 2, 3, 0, export_raw }, { "pull-tar", 2, 3, 0, pull_tar }, { "pull-raw", 2, 3, 0, pull_raw }, - { "pull-dkr", 2, 3, 0, pull_dkr }, { "list-transfers", VERB_ANY, 1, 0, list_transfers }, { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer }, { "set-limit", 2, 3, 0, set_limit }, @@ -2737,7 +2646,7 @@ static int machinectl_main(int argc, char *argv[], sd_bus *bus) { } int main(int argc, char*argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 961767c4a..b93309933 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -34,6 +32,7 @@ #include "formats-util.h" #include "hostname-util.h" #include "image-dbus.h" +#include "io-util.h" #include "machine-dbus.h" #include "machine-image.h" #include "machine-pool.h" @@ -203,7 +202,7 @@ static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd return -EINVAL; if (pid == 0) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); if (r < 0) @@ -228,7 +227,7 @@ static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd } static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; Machine *machine; Iterator i; @@ -333,7 +332,7 @@ static int method_create_or_register_machine(Manager *manager, sd_bus_message *m return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path"); if (leader == 0) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds); if (r < 0) @@ -554,7 +553,7 @@ static int method_get_machine_os_release(sd_bus_message *message, void *userdata } static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(image_hashmap_freep) Hashmap *images = NULL; Manager *m = userdata; Image *image; @@ -813,6 +812,8 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus r = sd_bus_message_read(message, "t", &limit); if (r < 0) return r; + if (!FILE_SIZE_VALID_OR_INFINITY(limit)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range"); r = bus_verify_polkit_async( message, @@ -833,11 +834,14 @@ static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus if (r < 0) return r; - r = btrfs_resize_loopback("/var/lib/machines", limit, false); - if (r == -ENOTTY) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs."); - if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */ - return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m"); + /* Resize the backing loopback device, if there is one, except if we asked to drop any limit */ + if (limit != (uint64_t) -1) { + r = btrfs_resize_loopback("/var/lib/machines", limit, false); + if (r == -ENOTTY) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs."); + if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */ + return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m"); + } (void) btrfs_qgroup_set_limit("/var/lib/machines", 0, limit); @@ -910,7 +914,7 @@ static int method_map_from_machine_user(sd_bus_message *message, void *userdata, if (k < 0 && feof(f)) break; if (k != 3) { - if (ferror(f) && errno != 0) + if (ferror(f) && errno > 0) return -errno; return -EIO; @@ -968,7 +972,7 @@ static int method_map_to_machine_user(sd_bus_message *message, void *userdata, s if (k < 0 && feof(f)) break; if (k != 3) { - if (ferror(f) && errno != 0) + if (ferror(f) && errno > 0) return -errno; return -EIO; @@ -1028,7 +1032,7 @@ static int method_map_from_machine_group(sd_bus_message *message, void *groupdat if (k < 0 && feof(f)) break; if (k != 3) { - if (ferror(f) && errno != 0) + if (ferror(f) && errno > 0) return -errno; return -EIO; @@ -1086,7 +1090,7 @@ static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, if (k < 0 && feof(f)) break; if (k != 3) { - if (ferror(f) && errno != 0) + if (ferror(f) && errno > 0) return -errno; return -EIO; @@ -1176,7 +1180,7 @@ int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *err if (streq(result, "done")) machine_send_create_reply(machine, NULL); else { - _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result); @@ -1280,7 +1284,7 @@ int manager_start_scope( sd_bus_error *error, char **job) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; int r; assert(manager); @@ -1325,6 +1329,10 @@ int manager_start_scope( if (r < 0) return r; + r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", UINT64_C(16384)); + if (r < 0) + return bus_log_create_error(r); + if (more_properties) { r = sd_bus_message_copy(m, more_properties, true); if (r < 0) @@ -1362,7 +1370,7 @@ int manager_start_scope( } int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; assert(manager); @@ -1425,8 +1433,8 @@ int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_erro } int manager_unit_is_active(Manager *manager, const char *unit) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *path = NULL; const char *state; int r; @@ -1467,8 +1475,8 @@ int manager_unit_is_active(Manager *manager, const char *unit) { } int manager_job_is_active(Manager *manager, const char *path) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int r; assert(manager); diff --git a/src/machine/machined.c b/src/machine/machined.c index a099de9f3..f2c1966a6 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -184,7 +182,7 @@ int manager_enumerate_machines(Manager *m) { } static int manager_connect_bus(Manager *m) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(m); diff --git a/src/machine/machined.h b/src/machine/machined.h index dac7a29ed..e7d7dfdce 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -31,9 +29,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/modules-load/modules-load.c b/src/modules-load/modules-load.c index a7fdcb09c..f75015d8c 100644 --- a/src/modules-load/modules-load.c +++ b/src/modules-load/modules-load.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 6fcb3050c..60724fce8 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -40,6 +38,7 @@ #include "pager.h" #include "parse-util.h" #include "socket-util.h" +#include "stdio-util.h" #include "string-table.h" #include "string-util.h" #include "strv.h" @@ -196,8 +195,8 @@ static void setup_state_to_color(const char *state, const char **on, const char } static int list_links(int argc, char *argv[], void *userdata) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; int r, c, i; @@ -228,7 +227,7 @@ static int list_links(int argc, char *argv[], void *userdata) { for (i = 0; i < c; i++) { _cleanup_free_ char *setup_state = NULL, *operational_state = NULL; - _cleanup_device_unref_ sd_device *d = NULL; + _cleanup_(sd_device_unrefp) sd_device *d = NULL; const char *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup; char devid[2 + DECIMAL_STR_MAX(int)]; @@ -275,7 +274,8 @@ static int ieee_oui(sd_hwdb *hwdb, struct ether_addr *mac, char **ret) { if (memcmp(mac, "\0\0\0", 3) == 0) return -EINVAL; - snprintf(modalias, sizeof(modalias), "OUI:" ETHER_ADDR_FORMAT_STR, ETHER_ADDR_FORMAT_VAL(*mac)); + xsprintf(modalias, "OUI:" ETHER_ADDR_FORMAT_STR, + ETHER_ADDR_FORMAT_VAL(*mac)); r = sd_hwdb_get(hwdb, modalias, "ID_OUI_FROM_DATABASE", &description); if (r < 0) @@ -297,7 +297,7 @@ static int get_gateway_description( int family, union in_addr_union *gateway, char **gateway_description) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *m; int r; @@ -488,6 +488,9 @@ static int dump_addresses( static void dump_list(const char *prefix, char **l) { char **i; + if (strv_isempty(l)) + return; + STRV_FOREACH(i, l) { printf("%*s%s\n", (int) strlen(prefix), @@ -500,10 +503,10 @@ static int link_status_one( sd_netlink *rtnl, sd_hwdb *hwdb, const char *name) { - _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL; + _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains = NULL; _cleanup_free_ char *setup_state = NULL, *operational_state = NULL, *tz = NULL; - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_device_unref_ sd_device *d = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_device_unrefp) sd_device *d = NULL; char devid[2 + DECIMAL_STR_MAX(int)]; _cleanup_free_ char *t = NULL, *network = NULL; const char *driver = NULL, *path = NULL, *vendor = NULL, *model = NULL, *link = NULL; @@ -550,7 +553,6 @@ static int link_status_one( return rtnl_log_parse_error(r); have_mac = sd_netlink_message_read_ether_addr(reply, IFLA_ADDRESS, &e) >= 0; - if (have_mac) { const uint8_t *p; bool all_zeroes = true; @@ -565,44 +567,35 @@ static int link_status_one( have_mac = false; } - sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu); + (void) sd_netlink_message_read_u32(reply, IFLA_MTU, &mtu); - sd_network_link_get_operational_state(ifindex, &operational_state); + (void) sd_network_link_get_operational_state(ifindex, &operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - sd_network_link_get_setup_state(ifindex, &setup_state); + (void) sd_network_link_get_setup_state(ifindex, &setup_state); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); - sd_network_link_get_dns(ifindex, &dns); - sd_network_link_get_domains(ifindex, &domains); - r = sd_network_link_get_wildcard_domain(ifindex); - if (r > 0) { - char *wildcard; - - wildcard = strdup("*"); - if (!wildcard) - return log_oom(); - - if (strv_consume(&domains, wildcard) < 0) - return log_oom(); - } + (void) sd_network_link_get_dns(ifindex, &dns); + (void) sd_network_link_get_search_domains(ifindex, &search_domains); + (void) sd_network_link_get_route_domains(ifindex, &route_domains); + (void) sd_network_link_get_ntp(ifindex, &ntp); sprintf(devid, "n%i", ifindex); - (void)sd_device_new_from_device_id(&d, devid); + (void) sd_device_new_from_device_id(&d, devid); if (d) { - (void)sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link); - (void)sd_device_get_property_value(d, "ID_NET_DRIVER", &driver); - (void)sd_device_get_property_value(d, "ID_PATH", &path); + (void) sd_device_get_property_value(d, "ID_NET_LINK_FILE", &link); + (void) sd_device_get_property_value(d, "ID_NET_DRIVER", &driver); + (void) sd_device_get_property_value(d, "ID_PATH", &path); r = sd_device_get_property_value(d, "ID_VENDOR_FROM_DATABASE", &vendor); if (r < 0) - (void)sd_device_get_property_value(d, "ID_VENDOR", &vendor); + (void) sd_device_get_property_value(d, "ID_VENDOR", &vendor); r = sd_device_get_property_value(d, "ID_MODEL_FROM_DATABASE", &model); if (r < 0) - (void)sd_device_get_property_value(d, "ID_MODEL", &model); + (void) sd_device_get_property_value(d, "ID_MODEL", &model); } link_get_type_string(iftype, d, &t); @@ -651,20 +644,14 @@ static int link_status_one( dump_addresses(rtnl, " Address: ", ifindex); dump_gateways(rtnl, hwdb, " Gateway: ", ifindex); - if (!strv_isempty(dns)) - dump_list(" DNS: ", dns); - if (!strv_isempty(domains)) - dump_list(" Domain: ", domains); + dump_list(" DNS: ", dns); + dump_list(" Search Domains: ", search_domains); + dump_list(" Route Domains: ", route_domains); - (void) sd_network_link_get_ntp(ifindex, &ntp); - if (!strv_isempty(ntp)) - dump_list(" NTP: ", ntp); + dump_list(" NTP: ", ntp); - if (!strv_isempty(carrier_bound_to)) - dump_list("Carrier Bound To: ", carrier_bound_to); - - if (!strv_isempty(carrier_bound_by)) - dump_list("Carrier Bound By: ", carrier_bound_by); + dump_list("Carrier Bound To: ", carrier_bound_to); + dump_list("Carrier Bound By: ", carrier_bound_by); (void) sd_network_link_get_timezone(ifindex, &tz); if (tz) @@ -674,8 +661,8 @@ static int link_status_one( } static int link_status(int argc, char *argv[], void *userdata) { - _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; char **name; int r; @@ -689,30 +676,30 @@ static int link_status(int argc, char *argv[], void *userdata) { if (argc <= 1 && !arg_all) { _cleanup_free_ char *operational_state = NULL; - _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **domains = NULL; + _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **search_domains = NULL, **route_domains; const char *on_color_operational, *off_color_operational; sd_network_get_operational_state(&operational_state); operational_state_to_color(operational_state, &on_color_operational, &off_color_operational); - printf("%s%s%s State: %s%s%s\n", + printf("%s%s%s State: %s%s%s\n", on_color_operational, draw_special_char(DRAW_BLACK_CIRCLE), off_color_operational, on_color_operational, strna(operational_state), off_color_operational); - dump_addresses(rtnl, " Address: ", 0); - dump_gateways(rtnl, hwdb, " Gateway: ", 0); + dump_addresses(rtnl, " Address: ", 0); + dump_gateways(rtnl, hwdb, " Gateway: ", 0); sd_network_get_dns(&dns); - if (!strv_isempty(dns)) - dump_list(" DNS: ", dns); + dump_list(" DNS: ", dns); - sd_network_get_domains(&domains); - if (!strv_isempty(domains)) - dump_list(" Domain: ", domains); + sd_network_get_search_domains(&search_domains); + dump_list("Search Domains: ", search_domains); + + sd_network_get_route_domains(&route_domains); + dump_list(" Route Domains: ", route_domains); sd_network_get_ntp(&ntp); - if (!strv_isempty(ntp)) - dump_list(" NTP: ", ntp); + dump_list(" NTP: ", ntp); return 0; } @@ -720,7 +707,7 @@ static int link_status(int argc, char *argv[], void *userdata) { pager_open_if_enabled(); if (arg_all) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_free_ LinkInfo *links = NULL; int c, i; @@ -906,8 +893,8 @@ static char *lldp_system_caps(uint16_t cap) { } static int link_lldp_status(int argc, char *argv[], void *userdata) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_free_ LinkInfo *links = NULL; double ttl = -1; uint32_t capability; diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c index 889fe1e30..d9d487d80 100644 --- a/src/network/networkd-address-pool.c +++ b/src/network/networkd-address-pool.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-address-pool.h b/src/network/networkd-address-pool.h index e6207ccce..8e1378ff4 100644 --- a/src/network/networkd-address-pool.h +++ b/src/network/networkd-address-pool.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,6 +21,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 1ce1f4d8d..7f9a7268c 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -408,7 +406,7 @@ int address_get(Link *link, int family, const union in_addr_union *in_addr, unsi int address_remove(Address *address, Link *link, sd_netlink_message_handler_t callback) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(address); @@ -503,7 +501,7 @@ static int address_acquire(Link *link, Address *original, Address **ret) { } int address_configure(Address *address, Link *link, sd_netlink_message_handler_t callback, bool update) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(address); diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 4049a23bd..338f6eb9a 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -28,9 +26,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 b9c60a3c7..03c28bbcb 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -54,7 +52,7 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, static int link_set_dhcp_routes(Link *link) { struct in_addr gateway; - struct sd_dhcp_route *static_routes; + _cleanup_free_ sd_dhcp_route **static_routes = NULL; int r, n, i; assert(link); @@ -130,9 +128,9 @@ static int link_set_dhcp_routes(Link *link) { route->family = AF_INET; route->protocol = RTPROT_DHCP; - route->gw.in = static_routes[i].gw_addr; - route->dst.in = static_routes[i].dst_addr; - route->dst_prefixlen = static_routes[i].dst_prefixlen; + assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0); + assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0); + assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0); route->priority = link->network->dhcp_route_metric; r = route_configure(route, link, &dhcp4_route_handler); @@ -158,8 +156,8 @@ static int dhcp_lease_lost(Link *link) { log_link_warning(link, "DHCP lease lost"); - if (link->network->dhcp_routes) { - struct sd_dhcp_route *routes; + if (link->network->dhcp_use_routes) { + _cleanup_free_ sd_dhcp_route **routes = NULL; int n, i; n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes); @@ -170,9 +168,9 @@ static int dhcp_lease_lost(Link *link) { r = route_new(&route); if (r >= 0) { route->family = AF_INET; - route->gw.in = routes[i].gw_addr; - route->dst.in = routes[i].dst_addr; - route->dst_prefixlen = routes[i].dst_prefixlen; + assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0); + assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0); + assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0); route_remove(route, link, &link_route_remove_handler); @@ -223,7 +221,7 @@ static int dhcp_lease_lost(Link *link) { } } - if (link->network->dhcp_mtu) { + if (link->network->dhcp_use_mtu) { uint16_t mtu; r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu); @@ -238,11 +236,11 @@ static int dhcp_lease_lost(Link *link) { } } - if (link->network->dhcp_hostname) { + if (link->network->dhcp_use_hostname) { const char *hostname = NULL; - if (link->network->hostname) - hostname = link->network->hostname; + if (link->network->dhcp_hostname) + hostname = link->network->dhcp_hostname; else (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname); @@ -255,6 +253,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 +330,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,8 +408,9 @@ 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) { + if (link->network->dhcp_use_mtu) { uint16_t mtu; r = sd_dhcp_lease_get_mtu(lease, &mtu); @@ -420,11 +421,11 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { } } - if (link->network->dhcp_hostname) { + if (link->network->dhcp_use_hostname) { const char *hostname = NULL; - if (link->network->hostname) - hostname = link->network->hostname; + if (link->network->dhcp_hostname) + hostname = link->network->dhcp_hostname; else (void) sd_dhcp_lease_get_hostname(lease, &hostname); @@ -435,7 +436,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { } } - if (link->network->dhcp_timezone) { + if (link->network->dhcp_use_timezone) { const char *tz = NULL; (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz); @@ -568,45 +569,45 @@ int dhcp4_configure(Link *link) { return r; } - if (link->network->dhcp_mtu) { + if (link->network->dhcp_use_mtu) { r = sd_dhcp_client_set_request_option(link->dhcp_client, - DHCP_OPTION_INTERFACE_MTU); + SD_DHCP_OPTION_INTERFACE_MTU); if (r < 0) return r; } - if (link->network->dhcp_routes) { + if (link->network->dhcp_use_routes) { r = sd_dhcp_client_set_request_option(link->dhcp_client, - DHCP_OPTION_STATIC_ROUTE); + SD_DHCP_OPTION_STATIC_ROUTE); if (r < 0) return r; r = sd_dhcp_client_set_request_option(link->dhcp_client, - DHCP_OPTION_CLASSLESS_STATIC_ROUTE); + SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE); if (r < 0) return r; } - /* Always acquire the timezone and NTP*/ - r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NTP_SERVER); + /* Always acquire the timezone and NTP */ + r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER); if (r < 0) return r; - r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_NEW_TZDB_TIMEZONE); + r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE); if (r < 0) return r; - if (link->network->dhcp_sendhost) { + if (link->network->dhcp_send_hostname) { _cleanup_free_ char *hostname = NULL; const char *hn = NULL; - if (!link->network->hostname) { + if (!link->network->dhcp_hostname) { hostname = gethostname_malloc(); if (!hostname) return -ENOMEM; hn = hostname; } else - hn = link->network->hostname; + hn = link->network->dhcp_hostname; if (!is_localhost(hn)) { r = sd_dhcp_client_set_hostname(link->dhcp_client, hn); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index e67e51f7e..5f7a005c3 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 6e5480ee2..1538caa20 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -97,7 +95,7 @@ static int set_fdb_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda /* send a request to the kernel to add a FDB entry in its static MAC table. */ int fdb_entry_configure(Link *const link, FdbEntry *const fdb_entry) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; sd_netlink *rtnl; int r; diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h index f0efb902d..89b3e2940 100644 --- a/src/network/networkd-fdb.h +++ b/src/network/networkd-fdb.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,8 +21,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 f4aac4bb9..949c75337 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index d09a3c2d0..532557ed6 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -59,15 +57,19 @@ static char *link_bus_path(Link *link) { int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { _cleanup_strv_free_ char **l = NULL; Manager *m = userdata; + unsigned c = 0; Link *link; Iterator i; - int r; assert(bus); assert(path); assert(m); assert(nodes); + l = new0(char*, hashmap_size(m->links) + 1); + if (!l) + return -ENOMEM; + HASHMAP_FOREACH(link, m->links, i) { char *p; @@ -75,11 +77,10 @@ int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char *** if (!p) return -ENOMEM; - r = strv_consume(&l, p); - if (r < 0) - return r; + l[c++] = p; } + l[c] = NULL; *nodes = l; l = NULL; @@ -99,7 +100,7 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void assert(found); r = sd_bus_path_decode(path, "/org/freedesktop/network1/link", &identifier); - if (r < 0) + if (r <= 0) return 0; r = parse_ifindex(identifier, &ifindex); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 01d5942ce..692c0bf63 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -26,7 +24,6 @@ #include "alloc-util.h" #include "bus-util.h" #include "dhcp-lease-internal.h" -#include "event-util.h" #include "fd-util.h" #include "fileio.h" #include "netlink-util.h" @@ -404,7 +401,7 @@ static void link_free(Link *link) { free(link->lease_file); - sd_lldp_free(link->lldp); + sd_lldp_unref(link->lldp); free(link->lldp_file); @@ -768,7 +765,7 @@ static int link_push_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) { addresses[n_addresses++] = ia; } - if (link->network->dhcp_dns && + if (link->network->dhcp_use_dns && link->dhcp_lease) { const struct in_addr *da = NULL; int n; @@ -813,7 +810,7 @@ static int link_push_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) { addresses[n_addresses++] = ia; } - if (link->network->dhcp_ntp && + if (link->network->dhcp_use_ntp && link->dhcp_lease) { const struct in_addr *da = NULL; int n; @@ -1149,7 +1146,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda } int link_set_mtu(Link *link, uint32_t mtu) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(link); @@ -1176,7 +1173,7 @@ int link_set_mtu(Link *link, uint32_t mtu) { } static int link_set_bridge(Link *link) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(link); @@ -1360,7 +1357,7 @@ static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userda } static int link_up(Link *link) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; uint8_t ipv6ll_mode; int r; @@ -1447,7 +1444,7 @@ static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, void *user } static int link_down(Link *link) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(link); @@ -2040,9 +2037,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 or critical devices. + * We do not want to remove loopback address or addresses used for root NFS. */ + if (!(link->flags & IFF_LOOPBACK) && !(link->network->dhcp_critical)) { + r = link_drop_foreign_config(link); + if (r < 0) + return r; + } r = link_set_bridge_fdb(link); if (r < 0) @@ -2197,7 +2198,7 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m, } int link_initialized(Link *link, struct udev_device *device) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(link); @@ -2296,7 +2297,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, '/'); @@ -2326,10 +2328,12 @@ network_file_fail: } if (routes) { + p = routes; + for (;;) { Route *route; _cleanup_free_ char *route_str = NULL; - _cleanup_event_source_unref_ sd_event_source *expire = NULL; + _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL; usec_t lifetime; char *prefixlen_str; int family; @@ -2340,7 +2344,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, '/'); @@ -2488,7 +2493,7 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address) { link->ipv6ll_address = *address; link_check_ready(link); - if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { + if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { r = link_acquire_ipv6_conf(link); if (r < 0) { link_enter_failed(link); @@ -2504,7 +2509,7 @@ static int link_carrier_gained(Link *link) { assert(link); - if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { + if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_UNMANAGED, LINK_STATE_FAILED)) { r = link_acquire_conf(link); if (r < 0) { link_enter_failed(link); @@ -2722,9 +2727,10 @@ int link_save(Link *link) { admin_state, oper_state); if (link->network) { - char **address, **domain; bool space; sd_dhcp6_lease *dhcp6_lease = NULL; + const char *dhcp_domainname = NULL; + char **dhcp6_domains = NULL; if (link->dhcp6_client) { r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease); @@ -2736,14 +2742,9 @@ int link_save(Link *link) { fputs("DNS=", f); space = false; - STRV_FOREACH(address, link->network->dns) { - if (space) - fputc(' ', f); - fputs(*address, f); - space = true; - } + fputstrv(f, link->network->dns, NULL, &space); - if (link->network->dhcp_dns && + if (link->network->dhcp_use_dns && link->dhcp_lease) { const struct in_addr *addresses; @@ -2756,7 +2757,7 @@ int link_save(Link *link) { } } - if (link->network->dhcp_dns && dhcp6_lease) { + if (link->network->dhcp_use_dns && dhcp6_lease) { struct in6_addr *in6_addrs; r = sd_dhcp6_lease_get_dns(dhcp6_lease, &in6_addrs); @@ -2771,14 +2772,9 @@ int link_save(Link *link) { fputs("NTP=", f); space = false; - STRV_FOREACH(address, link->network->ntp) { - if (space) - fputc(' ', f); - fputs(*address, f); - space = true; - } + fputstrv(f, link->network->ntp, NULL, &space); - if (link->network->dhcp_ntp && + if (link->network->dhcp_use_ntp && link->dhcp_lease) { const struct in_addr *addresses; @@ -2791,10 +2787,9 @@ int link_save(Link *link) { } } - if (link->network->dhcp_ntp && dhcp6_lease) { + if (link->network->dhcp_use_ntp && dhcp6_lease) { struct in6_addr *in6_addrs; char **hosts; - char **hostname; r = sd_dhcp6_lease_get_ntp_addrs(dhcp6_lease, &in6_addrs); @@ -2806,61 +2801,60 @@ int link_save(Link *link) { } r = sd_dhcp6_lease_get_ntp_fqdn(dhcp6_lease, &hosts); - if (r > 0) { - STRV_FOREACH(hostname, hosts) { - if (space) - fputc(' ', f); - fputs(*hostname, f); - space = true; - } - } + if (r > 0) + fputstrv(f, hosts, NULL, &space); } fputc('\n', f); + if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { + if (link->dhcp_lease) + (void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname); + + if (dhcp6_lease) + (void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains); + } + fputs("DOMAINS=", f); - space = false; - STRV_FOREACH(domain, link->network->domains) { - if (space) - fputc(' ', f); - fputs(*domain, f); - space = true; - } + fputstrv(f, link->network->search_domains, NULL, &space); - if (link->network->dhcp_domains && - link->dhcp_lease) { - const char *domainname; + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp_domainname) + fputs_with_space(f, dhcp_domainname, NULL, &space); - r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); - if (r >= 0) { - if (space) - fputc(' ', f); - fputs(domainname, f); - space = true; - } - } - - if (link->network->dhcp_domains && dhcp6_lease) { - char **domains; - - r = sd_dhcp6_lease_get_domains(dhcp6_lease, &domains); - if (r >= 0) { - STRV_FOREACH(domain, domains) { - if (space) - fputc(' ', f); - fputs(*domain, f); - space = true; - } - } - } + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES && dhcp6_domains) + fputstrv(f, dhcp6_domains, NULL, &space); fputc('\n', f); - fprintf(f, "WILDCARD_DOMAIN=%s\n", - yes_no(link->network->wildcard_domain)); + fputs("ROUTE_DOMAINS=", f); + fputstrv(f, link->network->route_domains, NULL, NULL); + + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp_domainname) + fputs_with_space(f, dhcp_domainname, NULL, &space); + + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE && dhcp6_domains) + fputstrv(f, dhcp6_domains, NULL, &space); + + fputc('\n', f); fprintf(f, "LLMNR=%s\n", resolve_support_to_string(link->network->llmnr)); + fprintf(f, "MDNS=%s\n", + resolve_support_to_string(link->network->mdns)); + + if (link->network->dnssec_mode != _DNSSEC_MODE_INVALID) + fprintf(f, "DNSSEC=%s\n", + dnssec_mode_to_string(link->network->dnssec_mode)); + + if (!set_isempty(link->network->dnssec_negative_trust_anchors)) { + const char *n; + + fputs("DNSSEC_NTA=", f); + space = false; + SET_FOREACH(n, link->network->dnssec_negative_trust_anchors, i) + fputs_with_space(f, n, NULL, &space); + fputc('\n', f); + } fputs("ADDRESSES=", f); space = false; @@ -2874,7 +2868,6 @@ int link_save(Link *link) { fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen); space = true; } - fputc('\n', f); fputs("ROUTES=", f); @@ -2899,12 +2892,8 @@ int link_save(Link *link) { bool space = false; fputs("CARRIER_BOUND_TO=", f); - HASHMAP_FOREACH(carrier, link->bound_to_links, i) { - if (space) - fputc(' ', f); - fputs(carrier->ifname, f); - space = true; - } + HASHMAP_FOREACH(carrier, link->bound_to_links, i) + fputs_with_space(f, carrier->ifname, NULL, &space); fputc('\n', f); } @@ -2914,12 +2903,8 @@ int link_save(Link *link) { bool space = false; fputs("CARRIER_BOUND_BY=", f); - HASHMAP_FOREACH(carrier, link->bound_by_links, i) { - if (space) - fputc(' ', f); - fputs(carrier->ifname, f); - space = true; - } + HASHMAP_FOREACH(carrier, link->bound_by_links, i) + fputs_with_space(f, carrier->ifname, NULL, &space); fputc('\n', f); } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index aa2235b11..0e6a7b6f2 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -56,9 +54,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; diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index dafaf2dae..0c429b947 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 42f58fed1..b527191a5 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -29,12 +27,14 @@ #include "bus-util.h" #include "conf-parser.h" #include "def.h" +#include "dns-domain.h" #include "fd-util.h" #include "fileio.h" #include "libudev-private.h" #include "local-addresses.h" #include "netlink-util.h" #include "networkd.h" +#include "ordered-set.h" #include "path-util.h" #include "set.h" #include "udev-util.h" @@ -659,15 +659,16 @@ static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *messa } else if (ifindex <= 0) { log_warning("rtnl: received link message with invalid ifindex: %d", ifindex); return 0; - } else - link_get(m, ifindex, &link); + } r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name); if (r < 0) { log_warning_errno(r, "rtnl: Received link message without ifname: %m"); return 0; - } else - netdev_get(m, name, &netdev); + } + + (void) link_get(m, ifindex, &link); + (void) netdev_get(m, name, &netdev); switch (type) { case RTM_NEWLINK: @@ -775,7 +776,7 @@ static int manager_connect_rtnl(Manager *m) { return 0; } -static int set_put_in_addr(Set *s, const struct in_addr *address) { +static int ordered_set_put_in_addr(OrderedSet *s, const struct in_addr *address) { char *p; int r; @@ -785,21 +786,21 @@ static int set_put_in_addr(Set *s, const struct in_addr *address) { if (r < 0) return r; - r = set_consume(s, p); + r = ordered_set_consume(s, p); if (r == -EEXIST) return 0; return r; } -static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) { +static int ordered_set_put_in_addrv(OrderedSet *s, const struct in_addr *addresses, int n) { int r, i, c = 0; assert(s); assert(n <= 0 || addresses); for (i = 0; i < n; i++) { - r = set_put_in_addr(s, addresses+i); + r = ordered_set_put_in_addr(s, addresses+i); if (r < 0) return r; @@ -809,27 +810,24 @@ static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) { return c; } -static void print_string_set(FILE *f, const char *field, Set *s) { +static void print_string_set(FILE *f, const char *field, OrderedSet *s) { bool space = false; Iterator i; char *p; - if (set_isempty(s)) + if (ordered_set_isempty(s)) return; fputs(field, f); - SET_FOREACH(p, s, i) { - if (space) - fputc(' ', f); - fputs(p, f); - space = true; - } + ORDERED_SET_FOREACH(p, s, i) + fputs_with_space(f, p, NULL, &space); + fputc('\n', f); } static int manager_save(Manager *m) { - _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL; + _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL; Link *link; Iterator i; _cleanup_free_ char *temp_path = NULL; @@ -842,16 +840,20 @@ static int manager_save(Manager *m) { assert(m->state_file); /* We add all NTP and DNS server to a set, to filter out duplicates */ - dns = set_new(&string_hash_ops); + dns = ordered_set_new(&string_hash_ops); if (!dns) return -ENOMEM; - ntp = set_new(&string_hash_ops); + ntp = ordered_set_new(&string_hash_ops); if (!ntp) return -ENOMEM; - domains = set_new(&string_hash_ops); - if (!domains) + search_domains = ordered_set_new(&dns_name_hash_ops); + if (!search_domains) + return -ENOMEM; + + route_domains = ordered_set_new(&dns_name_hash_ops); + if (!route_domains) return -ENOMEM; HASHMAP_FOREACH(link, m->links, i) { @@ -865,15 +867,19 @@ static int manager_save(Manager *m) { continue; /* First add the static configured entries */ - r = set_put_strdupv(dns, link->network->dns); + r = ordered_set_put_strdupv(dns, link->network->dns); if (r < 0) return r; - r = set_put_strdupv(ntp, link->network->ntp); + r = ordered_set_put_strdupv(ntp, link->network->ntp); if (r < 0) return r; - r = set_put_strdupv(domains, link->network->domains); + r = ordered_set_put_strdupv(search_domains, link->network->search_domains); + if (r < 0) + return r; + + r = ordered_set_put_strdupv(route_domains, link->network->route_domains); if (r < 0) return r; @@ -881,36 +887,41 @@ static int manager_save(Manager *m) { continue; /* Secondly, add the entries acquired via DHCP */ - if (link->network->dhcp_dns) { + if (link->network->dhcp_use_dns) { const struct in_addr *addresses; r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); if (r > 0) { - r = set_put_in_addrv(dns, addresses, r); + r = ordered_set_put_in_addrv(dns, addresses, r); if (r < 0) return r; } else if (r < 0 && r != -ENODATA) return r; } - if (link->network->dhcp_ntp) { + if (link->network->dhcp_use_ntp) { const struct in_addr *addresses; r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); if (r > 0) { - r = set_put_in_addrv(ntp, addresses, r); + r = ordered_set_put_in_addrv(ntp, addresses, r); if (r < 0) return r; } else if (r < 0 && r != -ENODATA) return r; } - if (link->network->dhcp_domains) { + if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { const char *domainname; r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); if (r >= 0) { - r = set_put_strdup(domains, domainname); + + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) + r = ordered_set_put_strdup(search_domains, domainname); + else + r = ordered_set_put_strdup(route_domains, domainname); + if (r < 0) return r; } else if (r != -ENODATA) @@ -933,7 +944,8 @@ static int manager_save(Manager *m) { print_string_set(f, "DNS=", dns); print_string_set(f, "NTP=", ntp); - print_string_set(f, "DOMAINS=", domains); + print_string_set(f, "DOMAINS=", search_domains); + print_string_set(f, "ROUTE_DOMAINS=", route_domains); r = fflush_and_check(f); if (r < 0) @@ -1151,7 +1163,7 @@ bool manager_should_reload(Manager *m) { } int manager_rtnl_enumerate_links(Manager *m) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *link; int r; @@ -1186,7 +1198,7 @@ int manager_rtnl_enumerate_links(Manager *m) { } int manager_rtnl_enumerate_addresses(Manager *m) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *addr; int r; @@ -1221,7 +1233,7 @@ int manager_rtnl_enumerate_addresses(Manager *m) { } int manager_rtnl_enumerate_routes(Manager *m) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *route; int r; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index ce9e513ce..f2287be20 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -89,7 +87,7 @@ static void ndisc_prefix_autonomous_handler(sd_ndisc *nd, const struct in6_addr address->in_addr.in6.__in6_u.__u6_addr8[15] = link->mac.ether_addr_octet[5]; } address->prefixlen = prefixlen; - address->flags = IFA_F_NOPREFIXROUTE; + address->flags = IFA_F_NOPREFIXROUTE|IFA_F_MANAGETEMPADDR; address->cinfo.ifa_prefered = lifetime_preferred; address->cinfo.ifa_valid = lifetime_valid; diff --git a/src/network/networkd-netdev-bond.c b/src/network/networkd-netdev-bond.c index 50b9021d0..106f15fab 100644 --- a/src/network/networkd-netdev-bond.c +++ b/src/network/networkd-netdev-bond.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-bond.h b/src/network/networkd-netdev-bond.h index 0cdce1605..cb6baea24 100644 --- a/src/network/networkd-netdev-bond.h +++ b/src/network/networkd-netdev-bond.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c index a991bdb5f..cdcd08f05 100644 --- a/src/network/networkd-netdev-bridge.c +++ b/src/network/networkd-netdev-bridge.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -46,7 +44,7 @@ static int netdev_bridge_set_handler(sd_netlink *rtnl, sd_netlink_message *m, vo } static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; Bridge *b; int r; diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h index d3bd15e0d..b2bf7e15f 100644 --- a/src/network/networkd-netdev-bridge.h +++ b/src/network/networkd-netdev-bridge.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-dummy.c b/src/network/networkd-netdev-dummy.c index bb246a2be..6617a86c2 100644 --- a/src/network/networkd-netdev-dummy.c +++ b/src/network/networkd-netdev-dummy.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-dummy.h b/src/network/networkd-netdev-dummy.h index 0d321e5ae..29f75a149 100644 --- a/src/network/networkd-netdev-dummy.h +++ b/src/network/networkd-netdev-dummy.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf index 4a4b400e4..8f506af09 100644 --- a/src/network/networkd-netdev-gperf.gperf +++ b/src/network/networkd-netdev-gperf.gperf @@ -57,6 +57,8 @@ VXLAN.UDP6ZeroCheckSumTx, config_parse_bool, 0, VXLAN.FDBAgeingSec, config_parse_sec, 0, offsetof(VxLan, fdb_ageing) VXLAN.GroupPolicyExtension, config_parse_bool, 0, offsetof(VxLan, group_policy) VXLAN.MaximumFDBEntries, config_parse_unsigned, 0, offsetof(VxLan, max_fdb) +VXLAN.PortRange, config_parse_port_range, 0, 0 +VXLAN.DestinationPort, config_parse_destination_port, 0, offsetof(VxLan, dest_port) Tun.OneQueue, config_parse_bool, 0, offsetof(TunTap, one_queue) Tun.MultiQueue, config_parse_bool, 0, offsetof(TunTap, multi_queue) Tun.PacketInfo, config_parse_bool, 0, offsetof(TunTap, packet_info) diff --git a/src/network/networkd-netdev-ipvlan.c b/src/network/networkd-netdev-ipvlan.c index 27cb7d1bf..af4177e43 100644 --- a/src/network/networkd-netdev-ipvlan.c +++ b/src/network/networkd-netdev-ipvlan.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-ipvlan.h b/src/network/networkd-netdev-ipvlan.h index 408386f37..5b85ef215 100644 --- a/src/network/networkd-netdev-ipvlan.h +++ b/src/network/networkd-netdev-ipvlan.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-macvlan.c b/src/network/networkd-netdev-macvlan.c index 7144823b2..48e98aa51 100644 --- a/src/network/networkd-netdev-macvlan.c +++ b/src/network/networkd-netdev-macvlan.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-macvlan.h b/src/network/networkd-netdev-macvlan.h index c491bfa31..8b42684de 100644 --- a/src/network/networkd-netdev-macvlan.h +++ b/src/network/networkd-netdev-macvlan.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-tunnel.c b/src/network/networkd-netdev-tunnel.c index 385338849..46ff2974f 100644 --- a/src/network/networkd-netdev-tunnel.c +++ b/src/network/networkd-netdev-tunnel.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -56,7 +54,7 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin assert(link); assert(m); assert(t); - assert(t->family == AF_INET); + assert(t->family == AF_INET || t->family != -1); r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex); if (r < 0) @@ -89,7 +87,7 @@ static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink assert(link); assert(m); assert(t); - assert(t->family == AF_INET); + assert(t->family == AF_INET || t->family != -1); r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex); if (r < 0) @@ -126,7 +124,7 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink t = GRETAP(netdev); assert(t); - assert(t->family == AF_INET); + assert(t->family == AF_INET || t->family != -1); assert(link); assert(m); @@ -358,12 +356,7 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) { assert(t); - if (t->remote.in.s_addr == INADDR_ANY) { - log_warning("Tunnel without remote address configured in %s. Ignoring", filename); - return -EINVAL; - } - - if (t->family != AF_INET && t->family != AF_INET6) { + if (t->family != AF_INET && t->family != AF_INET6 && t->family != 0) { log_warning("Tunnel with invalid address family configured in %s. Ignoring", filename); return -EINVAL; } @@ -397,15 +390,21 @@ int config_parse_tunnel_address(const char *unit, assert(rvalue); assert(data); - r = in_addr_from_string_auto(rvalue, &f, &buffer); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue); + if (streq(rvalue, "any")) { + t->family = 0; return 0; - } + } else { - if (t->family != AF_UNSPEC && t->family != f) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue); - return 0; + r = in_addr_from_string_auto(rvalue, &f, &buffer); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel address is invalid, ignoring assignment: %s", rvalue); + return 0; + } + + if (t->family != AF_UNSPEC && t->family != f) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Tunnel addresses incompatible, ignoring assignment: %s", rvalue); + return 0; + } } t->family = f; @@ -498,6 +497,7 @@ static void ipip_init(NetDev *n) { assert(t); t->pmtudisc = true; + t->family = -1; } static void sit_init(NetDev *n) { @@ -507,6 +507,7 @@ static void sit_init(NetDev *n) { assert(t); t->pmtudisc = true; + t->family = -1; } static void vti_init(NetDev *n) { @@ -537,6 +538,7 @@ static void gre_init(NetDev *n) { assert(t); t->pmtudisc = true; + t->family = -1; } static void ip6gre_init(NetDev *n) { diff --git a/src/network/networkd-netdev-tunnel.h b/src/network/networkd-netdev-tunnel.h index fa7decce1..ea1d9a79e 100644 --- a/src/network/networkd-netdev-tunnel.h +++ b/src/network/networkd-netdev-tunnel.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-tuntap.c b/src/network/networkd-netdev-tuntap.c index 3d504a856..ab9a1b042 100644 --- a/src/network/networkd-netdev-tuntap.c +++ b/src/network/networkd-netdev-tuntap.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-tuntap.h b/src/network/networkd-netdev-tuntap.h index 29f8bb0ea..b970b0ce3 100644 --- a/src/network/networkd-netdev-tuntap.h +++ b/src/network/networkd-netdev-tuntap.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-veth.c b/src/network/networkd-netdev-veth.c index 773a1ee6d..b122a06c2 100644 --- a/src/network/networkd-netdev-veth.c +++ b/src/network/networkd-netdev-veth.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-veth.h b/src/network/networkd-netdev-veth.h index 85d8b49a7..f7fdf906a 100644 --- a/src/network/networkd-netdev-veth.h +++ b/src/network/networkd-netdev-veth.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-vlan.c b/src/network/networkd-netdev-vlan.c index 75fbdd355..b1f4714af 100644 --- a/src/network/networkd-netdev-vlan.c +++ b/src/network/networkd-netdev-vlan.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-vlan.h b/src/network/networkd-netdev-vlan.h index 0c0fbbe09..8701c4b78 100644 --- a/src/network/networkd-netdev-vlan.h +++ b/src/network/networkd-netdev-vlan.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-netdev-vxlan.c b/src/network/networkd-netdev-vxlan.c index 7932b9333..eb9a2c06b 100644 --- a/src/network/networkd-netdev-vxlan.c +++ b/src/network/networkd-netdev-vxlan.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -24,6 +22,8 @@ #include "sd-netlink.h" #include "conf-parser.h" +#include "alloc-util.h" +#include "parse-util.h" #include "missing.h" #include "networkd-link.h" #include "networkd-netdev-vxlan.h" @@ -110,6 +110,21 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_UDP_ZERO_CSUM6_RX attribute: %m"); + r = sd_netlink_message_append_u16(m, IFLA_VXLAN_PORT, htobe16(v->dest_port)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PORT attribute: %m"); + + if (v->port_range.low || v->port_range.high) { + struct ifla_vxlan_port_range port_range; + + port_range.low = htobe16(v->port_range.low); + port_range.high = htobe16(v->port_range.high); + + r = sd_netlink_message_append_data(m, IFLA_VXLAN_PORT_RANGE, &port_range, sizeof(port_range)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_PORT_RANGE attribute: %m"); + } + if (v->group_policy) { r = sd_netlink_message_append_flag(m, IFLA_VXLAN_GBP); if (r < 0) @@ -155,6 +170,89 @@ int config_parse_vxlan_group_address(const char *unit, return 0; } +int config_parse_port_range(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + _cleanup_free_ char *word = NULL; + VxLan *v = userdata; + unsigned low, high; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = extract_first_word(&rvalue, &word, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract VXLAN port range, ignoring: %s", rvalue); + return 0; + } + + if (r == 0) + return 0; + + r = parse_range(word, &low, &high); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VXLAN port range '%s'", word); + return 0; + } + + if (low <= 0 || low > 65535 || high <= 0 || high > 65535) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse VXLAN port range '%s'. Port should be greater than 0 and less than 65535.", word); + return 0; + } + + if (high < low) { + log_syntax(unit, LOG_ERR, filename, line, r, + "Failed to parse VXLAN port range '%s'. Port range %u .. %u not valid", word, low, high); + return 0; + } + + v->port_range.low = low; + v->port_range.high = high; + + return 0; +} + +int config_parse_destination_port(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) { + VxLan *v = userdata; + uint16_t port; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + r = safe_atou16(rvalue, &port); + if (r < 0 || port <= 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse VXLAN destination port '%s'.", rvalue); + return 0; + } + + v->dest_port = port; + + return 0; +} + static int netdev_vxlan_verify(NetDev *netdev, const char *filename) { VxLan *v = VXLAN(netdev); diff --git a/src/network/networkd-netdev-vxlan.h b/src/network/networkd-netdev-vxlan.h index d21f355f5..459ce53f5 100644 --- a/src/network/networkd-netdev-vxlan.h +++ b/src/network/networkd-netdev-vxlan.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,9 +21,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 @@ -41,6 +38,8 @@ struct VxLan { unsigned ttl; unsigned max_fdb; + uint16_t dest_port; + usec_t fdb_ageing; bool learning; @@ -52,6 +51,8 @@ struct VxLan { bool udp6zerocsumtx; bool udp6zerocsumrx; bool group_policy; + + struct ifla_vxlan_port_range port_range; }; extern const NetDevVTable vxlan_vtable; @@ -66,3 +67,24 @@ int config_parse_vxlan_group_address(const char *unit, const char *rvalue, void *data, void *userdata); +int config_parse_port_range(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_destination_port(const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata); diff --git a/src/network/networkd-netdev.c b/src/network/networkd-netdev.c index a86a6383d..d7d014f05 100644 --- a/src/network/networkd-netdev.c +++ b/src/network/networkd-netdev.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -86,7 +84,7 @@ DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind); DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind"); static void netdev_cancel_callbacks(NetDev *netdev) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; netdev_join_callback *callback; if (!netdev) @@ -193,7 +191,7 @@ static int netdev_enter_failed(NetDev *netdev) { } static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_handler_t callback) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(netdev); @@ -290,7 +288,7 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call if (r < 0) return r; } else if (IN_SET(netdev->state, NETDEV_STATE_LINGER, NETDEV_STATE_FAILED)) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; r = rtnl_message_new_synthetic_error(-ENODEV, 0, &m); if (r >= 0) @@ -470,7 +468,7 @@ static int netdev_create(NetDev *netdev, Link *link, log_netdev_debug(netdev, "Created"); } else { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; r = sd_rtnl_message_new_link(netdev->manager->rtnl, &m, RTM_NEWLINK, 0); if (r < 0) diff --git a/src/network/networkd-netdev.h b/src/network/networkd-netdev.h index 3b9ab27b6..3eacee824 100644 --- a/src/network/networkd-netdev.h +++ b/src/network/networkd-netdev.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -26,8 +24,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 +101,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-ipvlan.h" -#include "networkd-netdev-vxlan.h" -#include "networkd-netdev-veth.h" -#include "networkd-netdev-tunnel.h" +#include "networkd-netdev-bridge.h" #include "networkd-netdev-dummy.h" +#include "networkd-netdev-ipvlan.h" +#include "networkd-netdev-macvlan.h" +#include "networkd-netdev-tunnel.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-bus.c b/src/network/networkd-network-bus.c index 120760a98..d6b7448a4 100644 --- a/src/network/networkd-network-bus.c +++ b/src/network/networkd-network-bus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index de2c66d15..409df1709 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -43,9 +43,12 @@ Network.IPv6Token, config_parse_ipv6token, Network.LLDP, config_parse_bool, 0, offsetof(Network, lldp) Network.Address, config_parse_address, 0, 0 Network.Gateway, config_parse_gateway, 0, 0 -Network.Domains, config_parse_domains, 0, offsetof(Network, domains) +Network.Domains, config_parse_domains, 0, 0 Network.DNS, config_parse_strv, 0, offsetof(Network, dns) -Network.LLMNR, config_parse_resolve, 0, offsetof(Network, llmnr) +Network.LLMNR, config_parse_resolve_support, 0, offsetof(Network, llmnr) +Network.MulticastDNS, config_parse_resolve_support, 0, offsetof(Network, mdns) +Network.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Network, dnssec_mode) +Network.DNSSECNegativeTrustAnchors, config_parse_dnssec_negative_trust_anchors, 0, offsetof(Network, dnssec_negative_trust_anchors) Network.NTP, config_parse_strv, 0, offsetof(Network, ntp) Network.IPForward, config_parse_address_family_boolean_with_kernel,0, offsetof(Network, ip_forward) Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) @@ -65,19 +68,19 @@ Route.Metric, config_parse_route_priority, Route.Scope, config_parse_route_scope, 0, 0 Route.PreferredSource, config_parse_preferred_src, 0, 0 DHCP.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) -DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) -DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_ntp) -DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) -DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) -DHCP.UseDomains, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_routes) -DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_sendhost) -DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, hostname) +DHCP.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns) +DHCP.UseNTP, config_parse_bool, 0, offsetof(Network, dhcp_use_ntp) +DHCP.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu) +DHCP.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname) +DHCP.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains) +DHCP.UseRoutes, config_parse_bool, 0, offsetof(Network, dhcp_use_routes) +DHCP.SendHostname, config_parse_bool, 0, offsetof(Network, dhcp_send_hostname) +DHCP.Hostname, config_parse_hostname, 0, offsetof(Network, dhcp_hostname) DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) DHCP.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) DHCP.RouteMetric, config_parse_unsigned, 0, offsetof(Network, dhcp_route_metric) -DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_timezone) +DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit_dns) @@ -98,9 +101,9 @@ BridgeFDB.MACAddress, config_parse_fdb_hwaddr, BridgeFDB.VLANId, config_parse_fdb_vlan_id, 0, 0 /* backwards compatibility: do not add new entries to this section */ Network.IPv4LL, config_parse_ipv4ll, 0, offsetof(Network, link_local) -DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_dns) -DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_mtu) -DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_hostname) -DHCP.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) -DHCPv4.UseDomainName, config_parse_bool, 0, offsetof(Network, dhcp_domains) +DHCPv4.UseDNS, config_parse_bool, 0, offsetof(Network, dhcp_use_dns) +DHCPv4.UseMTU, config_parse_bool, 0, offsetof(Network, dhcp_use_mtu) +DHCPv4.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp_use_hostname) +DHCP.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains) +DHCPv4.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains) DHCPv4.CriticalConnection, config_parse_bool, 0, offsetof(Network, dhcp_critical) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 29723a852..431579009 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -32,6 +30,7 @@ #include "networkd-network.h" #include "networkd.h" #include "parse-util.h" +#include "set.h" #include "stat-util.h" #include "string-table.h" #include "string-util.h" @@ -104,11 +103,11 @@ static int network_load_one(Manager *manager, const char *filename) { *d = '\0'; network->dhcp = ADDRESS_FAMILY_NO; - network->dhcp_ntp = true; - network->dhcp_dns = true; - network->dhcp_hostname = true; - network->dhcp_routes = true; - network->dhcp_sendhost = true; + network->dhcp_use_ntp = true; + network->dhcp_use_dns = true; + network->dhcp_use_hostname = true; + network->dhcp_use_routes = true; + network->dhcp_send_hostname = true; network->dhcp_route_metric = DHCP_ROUTE_METRIC; network->dhcp_client_identifier = DHCP_CLIENT_ID_DUID; @@ -121,6 +120,8 @@ static int network_load_one(Manager *manager, const char *filename) { network->unicast_flood = true; network->llmnr = RESOLVE_SUPPORT_YES; + network->mdns = RESOLVE_SUPPORT_NO; + network->dnssec_mode = _DNSSEC_MODE_INVALID; network->link_local = ADDRESS_FAMILY_IPV6; @@ -224,13 +225,14 @@ void network_free(Network *network) { free(network->description); free(network->dhcp_vendor_class_identifier); - free(network->hostname); + free(network->dhcp_hostname); free(network->mac); strv_free(network->ntp); strv_free(network->dns); - strv_free(network->domains); + strv_free(network->search_domains); + strv_free(network->route_domains); strv_free(network->bind_carrier); netdev_unref(network->bridge); @@ -275,6 +277,8 @@ void network_free(Network *network) { free(network->dhcp_server_dns); free(network->dhcp_server_ntp); + set_free_free(network->dnssec_negative_trust_anchors); + free(network); } @@ -379,7 +383,10 @@ int network_apply(Manager *manager, Network *network, Link *link) { route->protocol = RTPROT_STATIC; } - if (network->dns || network->ntp || network->domains) { + if (!strv_isempty(network->dns) || + !strv_isempty(network->ntp) || + !strv_isempty(network->search_domains) || + !strv_isempty(network->route_domains)) { manager_dirty(manager); link_dirty(link); } @@ -464,49 +471,85 @@ int config_parse_netdev(const char *unit, return 0; } -int config_parse_domains(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - Network *network = userdata; - char ***domains = data; - char **domain; +int config_parse_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) { + + const char *p; + Network *n = data; int r; - r = config_parse_strv(unit, filename, line, section, section_line, - lvalue, ltype, rvalue, domains, userdata); - if (r < 0) - return r; + assert(n); + assert(lvalue); + assert(rvalue); - strv_uniq(*domains); - network->wildcard_domain = !!strv_find(*domains, "*"); + if (isempty(rvalue)) { + n->search_domains = strv_free(n->search_domains); + n->route_domains = strv_free(n->route_domains); + return 0; + } - STRV_FOREACH(domain, *domains) { - if (is_localhost(*domain)) - log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configured, ignoring assignment: %s", *domain); - else { - r = dns_name_is_valid(*domain); - if (r <= 0 && !streq(*domain, "*")) { - if (r < 0) - log_error_errno(r, "Failed to validate domain name: %s: %m", *domain); - if (r == 0) - log_warning("Domain name is not valid, ignoring assignment: %s", *domain); - } else + p = rvalue; + for (;;) { + _cleanup_free_ char *w = NULL, *normalized = NULL; + const char *domain; + bool is_route; + + r = extract_first_word(&p, &w, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract search or route domain, ignoring: %s", rvalue); + break; + } + if (r == 0) + break; + + is_route = w[0] == '~'; + domain = is_route ? w + 1 : w; + + if (dns_name_is_root(domain) || streq(domain, "*")) { + /* If the root domain appears as is, or the special token "*" is found, we'll consider this as + * routing domain, unconditionally. */ + is_route = true; + domain = "."; /* make sure we don't allow empty strings, thus write the root domain as "." */ + + } else { + r = dns_name_normalize(domain, &normalized); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain); continue; + } + + domain = normalized; + + if (is_localhost(domain)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "'localhost' domain names may not be configure as search or route domains, ignoring assignment: %s", domain); + continue; + } } - strv_remove(*domains, *domain); + if (is_route) { + r = strv_extend(&n->route_domains, domain); + if (r < 0) + return log_oom(); - /* We removed one entry, make sure we don't skip the next one */ - domain--; + } else { + r = strv_extend(&n->search_domains, domain); + if (r < 0) + return log_oom(); + } } + strv_uniq(n->route_domains); + strv_uniq(n->search_domains); + return 0; } @@ -908,3 +951,65 @@ int config_parse_dhcp_server_ntp( n->dhcp_server_ntp = m; } } + +int config_parse_dnssec_negative_trust_anchors( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + const char *p = rvalue; + Network *n = data; + int r; + + assert(n); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + n->dnssec_negative_trust_anchors = set_free_free(n->dnssec_negative_trust_anchors); + return 0; + } + + for (;;) { + _cleanup_free_ char *w = NULL; + + r = extract_first_word(&p, &w, NULL, 0); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract negative trust anchor domain, ignoring: %s", rvalue); + break; + } + if (r == 0) + break; + + r = dns_name_is_valid(w); + if (r <= 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name, ignoring.", w); + continue; + } + + r = set_put(n->dnssec_negative_trust_anchors, w); + if (r < 0) + return log_oom(); + if (r > 0) + w = NULL; + } + + return 0; +} + +DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting"); + +static const char* const dhcp_use_domains_table[_DHCP_USE_DOMAINS_MAX] = { + [DHCP_USE_DOMAINS_NO] = "no", + [DHCP_USE_DOMAINS_ROUTE] = "route", + [DHCP_USE_DOMAINS_YES] = "yes", +}; + +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dhcp_use_domains, DHCPUseDomains, DHCP_USE_DOMAINS_YES); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index a27c67eea..03c3f206c 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,15 +20,16 @@ ***/ #include "condition.h" +#include "resolve-util.h" 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 @@ -51,6 +50,14 @@ typedef enum IPv6PrivacyExtensions { _IPV6_PRIVACY_EXTENSIONS_INVALID = -1, } IPv6PrivacyExtensions; +typedef enum DHCPUseDomains { + DHCP_USE_DOMAINS_NO, + DHCP_USE_DOMAINS_YES, + DHCP_USE_DOMAINS_ROUTE, + _DHCP_USE_DOMAINS_MAX, + _DHCP_USE_DOMAINS_INVALID = -1, +} DHCPUseDomains; + struct Network { Manager *manager; @@ -78,17 +85,17 @@ struct Network { AddressFamilyBoolean dhcp; DCHPClientIdentifier dhcp_client_identifier; char *dhcp_vendor_class_identifier; - char *hostname; - bool dhcp_dns; - bool dhcp_ntp; - bool dhcp_mtu; - bool dhcp_hostname; - bool dhcp_domains; - bool dhcp_sendhost; + char *dhcp_hostname; + bool dhcp_use_dns; + bool dhcp_use_ntp; + bool dhcp_use_mtu; + bool dhcp_use_hostname; + DHCPUseDomains dhcp_use_domains; + bool dhcp_send_hostname; bool dhcp_broadcast; bool dhcp_critical; - bool dhcp_routes; - bool dhcp_timezone; + bool dhcp_use_routes; + bool dhcp_use_timezone; unsigned dhcp_route_metric; /* DHCP Server Support */ @@ -140,10 +147,12 @@ struct Network { Hashmap *routes_by_section; Hashmap *fdb_entries_by_section; - bool wildcard_domain; - char **domains, **dns, **ntp, **bind_carrier; + char **search_domains, **route_domains, **dns, **ntp, **bind_carrier; ResolveSupport llmnr; + ResolveSupport mdns; + DnssecMode dnssec_mode; + Set *dnssec_negative_trust_anchors; LIST_FIELDS(Network, networks); }; @@ -170,6 +179,8 @@ int config_parse_hostname(const char *unit, const char *filename, unsigned line, int config_parse_timezone(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_dhcp_server_dns(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_dhcp_server_ntp(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dnssec_negative_trust_anchors(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dhcp_use_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); /* Legacy IPv4LL support */ int config_parse_ipv4ll(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); @@ -183,3 +194,6 @@ int network_object_find(sd_bus *bus, const char *path, const char *interface, vo const char* ipv6_privacy_extensions_to_string(IPv6PrivacyExtensions i) _const_; IPv6PrivacyExtensions ipv6_privacy_extensions_from_string(const char *s) _pure_; + +const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_; +DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_; diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index ed06c2116..e065a5a5a 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,7 +19,6 @@ #include "alloc-util.h" #include "conf-parser.h" -#include "event-util.h" #include "in-addr-util.h" #include "netlink-util.h" #include "networkd-route.h" @@ -334,7 +331,7 @@ void route_drop(Route *route) { int route_remove(Route *route, Link *link, sd_netlink_message_handler_t callback) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; assert(link); @@ -429,8 +426,8 @@ int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) { int route_configure(Route *route, Link *link, sd_netlink_message_handler_t callback) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL; - _cleanup_event_source_unref_ sd_event_source *expire = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL; usec_t lifetime; int r; diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index b27675667..a4a4bf265 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,8 +21,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-util.c b/src/network/networkd-util.c index 2545621a9..555a7c68a 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -101,54 +99,3 @@ int config_parse_address_family_boolean_with_kernel( return 0; } - -static const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = { - [RESOLVE_SUPPORT_NO] = "no", - [RESOLVE_SUPPORT_YES] = "yes", - [RESOLVE_SUPPORT_RESOLVE] = "resolve", -}; - -DEFINE_STRING_TABLE_LOOKUP(resolve_support, ResolveSupport); - -int config_parse_resolve( - 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) { - - ResolveSupport *resolve = data; - int k; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(resolve); - - /* Our enum shall be a superset of booleans, hence first try - * to parse as boolean, and then as enum */ - - k = parse_boolean(rvalue); - if (k > 0) - *resolve = RESOLVE_SUPPORT_YES; - else if (k == 0) - *resolve = RESOLVE_SUPPORT_NO; - else { - ResolveSupport s; - - s = resolve_support_from_string(rvalue); - if (s < 0){ - log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse %s= option, ignoring: %s", lvalue, rvalue); - return 0; - } - - *resolve = s; - } - - return 0; -} diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h index cc41aae85..d5c385bea 100644 --- a/src/network/networkd-util.h +++ b/src/network/networkd-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -33,20 +31,8 @@ typedef enum AddressFamilyBoolean { _ADDRESS_FAMILY_BOOLEAN_INVALID = -1, } AddressFamilyBoolean; -typedef enum ResolveSupport { - RESOLVE_SUPPORT_NO, - RESOLVE_SUPPORT_YES, - RESOLVE_SUPPORT_RESOLVE, - _RESOLVE_SUPPORT_MAX, - _RESOLVE_SUPPORT_INVALID = -1, -} ResolveSupport; - -int config_parse_resolve(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_address_family_boolean(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); int config_parse_address_family_boolean_with_kernel(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); -const char* resolve_support_to_string(ResolveSupport i) _const_; -ResolveSupport resolve_support_from_string(const char *s) _pure_; - const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_; AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_; diff --git a/src/network/networkd-wait-online-link.c b/src/network/networkd-wait-online-link.c index c2779ff77..5727422e3 100644 --- a/src/network/networkd-wait-online-link.c +++ b/src/network/networkd-wait-online-link.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd-wait-online-link.h b/src/network/networkd-wait-online-link.h index 068196622..dc35085c5 100644 --- a/src/network/networkd-wait-online-link.h +++ b/src/network/networkd-wait-online-link.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/network/networkd-wait-online-manager.c b/src/network/networkd-wait-online-manager.c index 0c40ab2bb..2ff7ddb04 100644 --- a/src/network/networkd-wait-online-manager.c +++ b/src/network/networkd-wait-online-manager.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -175,7 +173,7 @@ static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdat } static int manager_rtnl_listen(Manager *m) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *i; int r; diff --git a/src/network/networkd-wait-online.h b/src/network/networkd-wait-online.h index 627c46be1..421c2bdf4 100644 --- a/src/network/networkd-wait-online.h +++ b/src/network/networkd-wait-online.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd.c b/src/network/networkd.c index ef394e0c0..3a2615e6f 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/network/networkd.h b/src/network/networkd.h index 97665fac7..7ee922621 100644 --- a/src/network/networkd.h +++ b/src/network/networkd.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,19 +21,19 @@ #include +#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.c b/src/network/test-network.c index a1a77b686..855646173 100644 --- a/src/network/test-network.c +++ b/src/network/test-network.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/notify/notify.c b/src/notify/notify.c index b14455470..49f97c61d 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/nspawn/nspawn-cgroup.c b/src/nspawn/nspawn-cgroup.c index 270bcf010..1db5ba711 100644 --- a/src/nspawn/nspawn-cgroup.c +++ b/src/nspawn/nspawn-cgroup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -54,6 +52,7 @@ int chown_cgroup(pid_t pid, uid_t uid_shift) { "tasks", "notify_on_release", "cgroup.procs", + "cgroup.events", "cgroup.clone_children", "cgroup.controllers", "cgroup.subtree_control", diff --git a/src/nspawn/nspawn-cgroup.h b/src/nspawn/nspawn-cgroup.h index 985fdfaad..1ff35a299 100644 --- a/src/nspawn/nspawn-cgroup.h +++ b/src/nspawn/nspawn-cgroup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#include #include +#include 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.c b/src/nspawn/nspawn-expose-ports.c index 38245434d..86124b877 100644 --- a/src/nspawn/nspawn-expose-ports.c +++ b/src/nspawn/nspawn-expose-ports.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -211,7 +209,7 @@ int expose_port_watch_rtnl( sd_netlink_message_handler_t handler, union in_addr_union *exposed, sd_netlink **ret) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int fd, r; assert(event); diff --git a/src/nspawn/nspawn-expose-ports.h b/src/nspawn/nspawn-expose-ports.h index 39cec2869..741ad9765 100644 --- a/src/nspawn/nspawn-expose-ports.h +++ b/src/nspawn/nspawn-expose-ports.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,8 +23,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-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 58f9f4c63..116655cdd 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -15,7 +15,8 @@ struct ConfigPerfItem; %struct-type %includes %% -Exec.Boot, config_parse_tristate, 0, offsetof(Settings, boot) +Exec.Boot, config_parse_boot, 0, 0 +Exec.ProcessTwo, config_parse_pid2, 0, 0, Exec.Parameters, config_parse_strv, 0, offsetof(Settings, parameters) Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment) Exec.User, config_parse_string, 0, offsetof(Settings, user) @@ -24,6 +25,7 @@ Exec.DropCapability, config_parse_capability, 0, offsetof(Settings, Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal) Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality) Exec.MachineID, config_parse_id128, 0, offsetof(Settings, machine_id) +Exec.WorkingDirectory, config_parse_path, 0, offsetof(Settings, working_directory) Files.ReadOnly, config_parse_tristate, 0, offsetof(Settings, read_only) Files.Volatile, config_parse_volatile_mode, 0, offsetof(Settings, volatile_mode) Files.Bind, config_parse_bind, 0, 0 diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index c8e627ac7..70cca1527 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h index bdab23bcc..0daf14541 100644 --- a/src/nspawn/nspawn-mount.h +++ b/src/nspawn/nspawn-mount.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 8f74c41c7..fcb1efaa7 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -94,7 +92,7 @@ static int add_veth( const char *ifname_container, const struct ether_addr *mac_container) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(rtnl); @@ -163,7 +161,7 @@ int setup_veth(const char *machine_name, char iface_name[IFNAMSIZ], bool bridge) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; struct ether_addr mac_host, mac_container; int r, i; @@ -204,7 +202,7 @@ int setup_veth_extra( pid_t pid, char **pairs) { - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; uint64_t idx = 0; char **a, **b; int r; @@ -241,8 +239,8 @@ int setup_veth_extra( } int setup_bridge(const char *veth_name, const char *bridge_name) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int r, bridge_ifi; assert(veth_name); @@ -303,7 +301,7 @@ static int parse_interface(struct udev *udev, const char *name) { int move_network_interfaces(pid_t pid, char **ifaces) { _cleanup_udev_unref_ struct udev *udev = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; char **i; int r; @@ -321,7 +319,7 @@ int move_network_interfaces(pid_t pid, char **ifaces) { } STRV_FOREACH(i, ifaces) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int ifi; ifi = parse_interface(udev, *i); @@ -346,7 +344,7 @@ int move_network_interfaces(pid_t pid, char **ifaces) { int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) { _cleanup_udev_unref_ struct udev *udev = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; unsigned idx = 0; char **i; int r; @@ -365,7 +363,7 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) { } STRV_FOREACH(i, ifaces) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_free_ char *n = NULL; struct ether_addr mac; int ifi; @@ -434,7 +432,7 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) { int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) { _cleanup_udev_unref_ struct udev *udev = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; char **i; int r; @@ -452,7 +450,7 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) { } STRV_FOREACH(i, ifaces) { - _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_free_ char *n = NULL; int ifi; diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h index b86effef4..9ab1606d1 100644 --- a/src/nspawn/nspawn-network.h +++ b/src/nspawn/nspawn-network.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,9 +20,8 @@ ***/ #include - -#include #include +#include 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 50871464c..760861089 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -42,8 +40,8 @@ int register_machine( bool keep_unit, const char *service) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; r = sd_bus_default_system(&bus); @@ -68,7 +66,7 @@ int register_machine( strempty(directory), local_ifindex > 0 ? 1 : 0, local_ifindex); } else { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; char **i; unsigned j; @@ -105,10 +103,6 @@ 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); @@ -170,17 +164,9 @@ int register_machine( } STRV_FOREACH(i, properties) { - r = sd_bus_message_open_container(m, 'r', "sv"); - if (r < 0) - return bus_log_create_error(r); - r = bus_append_unit_property_assignment(m, *i); if (r < 0) return r; - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); } r = sd_bus_message_close_container(m); @@ -199,9 +185,9 @@ int register_machine( } int terminate_machine(pid_t pid) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; const char *path; int r; diff --git a/src/nspawn/nspawn-register.h b/src/nspawn/nspawn-register.h index d3bfd84e5..304c5a485 100644 --- a/src/nspawn/nspawn-register.h +++ b/src/nspawn/nspawn-register.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index d6b64d8d5..4fb005469 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -24,6 +22,7 @@ #include "conf-parser.h" #include "nspawn-network.h" #include "nspawn-settings.h" +#include "parse-util.h" #include "process-util.h" #include "strv.h" #include "util.h" @@ -39,7 +38,7 @@ int settings_load(FILE *f, const char *path, Settings **ret) { if (!s) return -ENOMEM; - s->boot = -1; + s->start_mode = _START_MODE_INVALID; s->personality = PERSONALITY_INVALID; s->read_only = -1; @@ -74,6 +73,7 @@ Settings* settings_free(Settings *s) { strv_free(s->parameters); strv_free(s->environment); free(s->user); + free(s->working_directory); strv_free(s->network_interfaces); strv_free(s->network_macvlan); @@ -302,3 +302,93 @@ int config_parse_veth_extra( return 0; } + +int config_parse_boot( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Settings *settings = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Boot= parameter %s, ignoring: %m", rvalue); + return 0; + } + + if (r > 0) { + if (settings->start_mode == START_PID2) + goto conflict; + + settings->start_mode = START_BOOT; + } else { + if (settings->start_mode == START_BOOT) + goto conflict; + + if (settings->start_mode < 0) + settings->start_mode = START_PID1; + } + + return 0; + +conflict: + log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring."); + return 0; +} + +int config_parse_pid2( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Settings *settings = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse ProcessTwo= parameter %s, ignoring: %m", rvalue); + return 0; + } + + if (r > 0) { + if (settings->start_mode == START_BOOT) + goto conflict; + + settings->start_mode = START_PID2; + } else { + if (settings->start_mode == START_PID2) + goto conflict; + + if (settings->start_mode < 0) + settings->start_mode = START_PID1; + } + + return 0; + +conflict: + log_syntax(unit, LOG_ERR, filename, line, r, "Conflicting Boot= or ProcessTwo= setting found. Ignoring."); + return 0; +} diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index dde0d8bd4..a017405cd 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,29 +22,37 @@ #include #include "macro.h" - -#include "nspawn-mount.h" #include "nspawn-expose-ports.h" +#include "nspawn-mount.h" + +typedef enum StartMode { + START_PID1, /* Run parameters as command line as process 1 */ + START_PID2, /* Use stub init process as PID 1, run parameters as command line as process 2 */ + START_BOOT, /* Search for init system, pass arguments as parameters */ + _START_MODE_MAX, + _START_MODE_INVALID = -1 +} StartMode; typedef enum SettingsMask { - SETTING_BOOT = 1 << 0, - SETTING_ENVIRONMENT = 1 << 1, - SETTING_USER = 1 << 2, - SETTING_CAPABILITY = 1 << 3, - SETTING_KILL_SIGNAL = 1 << 4, - SETTING_PERSONALITY = 1 << 5, - SETTING_MACHINE_ID = 1 << 6, - SETTING_NETWORK = 1 << 7, - SETTING_EXPOSE_PORTS = 1 << 8, - SETTING_READ_ONLY = 1 << 9, - SETTING_VOLATILE_MODE = 1 << 10, - SETTING_CUSTOM_MOUNTS = 1 << 11, - _SETTINGS_MASK_ALL = (1 << 12) -1 + SETTING_START_MODE = 1 << 0, + SETTING_ENVIRONMENT = 1 << 1, + SETTING_USER = 1 << 2, + SETTING_CAPABILITY = 1 << 3, + SETTING_KILL_SIGNAL = 1 << 4, + SETTING_PERSONALITY = 1 << 5, + SETTING_MACHINE_ID = 1 << 6, + SETTING_NETWORK = 1 << 7, + SETTING_EXPOSE_PORTS = 1 << 8, + SETTING_READ_ONLY = 1 << 9, + SETTING_VOLATILE_MODE = 1 << 10, + SETTING_CUSTOM_MOUNTS = 1 << 11, + SETTING_WORKING_DIRECTORY = 1 << 12, + _SETTINGS_MASK_ALL = (1 << 13) -1 } SettingsMask; typedef struct Settings { /* [Run] */ - int boot; + StartMode start_mode; char **parameters; char **environment; char *user; @@ -55,6 +61,7 @@ typedef struct Settings { int kill_signal; unsigned long personality; sd_id128_t machine_id; + char *working_directory; /* [Image] */ int read_only; @@ -90,3 +97,5 @@ int config_parse_volatile_mode(const char *unit, const char *filename, unsigned int config_parse_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_tmpfs(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_veth_extra(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_boot(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_pid2(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/nspawn/nspawn-setuid.c b/src/nspawn/nspawn-setuid.c index aa6a16309..ee15a47e9 100644 --- a/src/nspawn/nspawn-setuid.c +++ b/src/nspawn/nspawn-setuid.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -261,10 +259,10 @@ int change_uid_gid(const char *user, char **_home) { return log_error_errno(errno, "Failed to set auxiliary groups: %m"); if (setresgid(gid, gid, gid) < 0) - return log_error_errno(errno, "setregid() failed: %m"); + return log_error_errno(errno, "setresgid() failed: %m"); if (setresuid(uid, uid, uid) < 0) - return log_error_errno(errno, "setreuid() failed: %m"); + return log_error_errno(errno, "setresuid() failed: %m"); if (_home) { *_home = home; diff --git a/src/nspawn/nspawn-setuid.h b/src/nspawn/nspawn-setuid.h index 33be44a94..b4968ba1f 100644 --- a/src/nspawn/nspawn-setuid.h +++ b/src/nspawn/nspawn-setuid.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/nspawn/nspawn-stub-pid1.c b/src/nspawn/nspawn-stub-pid1.c new file mode 100644 index 000000000..2de87e3c6 --- /dev/null +++ b/src/nspawn/nspawn-stub-pid1.c @@ -0,0 +1,170 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include +#include +#include + +#include "fd-util.h" +#include "log.h" +#include "nspawn-stub-pid1.h" +#include "process-util.h" +#include "signal-util.h" +#include "time-util.h" +#include "def.h" + +int stub_pid1(void) { + enum { + STATE_RUNNING, + STATE_REBOOT, + STATE_POWEROFF, + } state = STATE_RUNNING; + + sigset_t fullmask, oldmask, waitmask; + usec_t quit_usec = USEC_INFINITY; + pid_t pid; + int r; + + /* Implements a stub PID 1, that reaps all processes and processes a couple of standard signals. This is useful + * for allowing arbitrary processes run in a container, and still have all zombies reaped. */ + + assert_se(sigfillset(&fullmask) >= 0); + assert_se(sigprocmask(SIG_BLOCK, &fullmask, &oldmask) >= 0); + + pid = fork(); + if (pid < 0) + return log_error_errno(errno, "Failed to fork child pid: %m"); + + if (pid == 0) { + /* Return in the child */ + assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) >= 0); + setsid(); + return 0; + } + + reset_all_signal_handlers(); + + log_close(); + close_all_fds(NULL, 0); + log_open(); + + rename_process("STUBINIT"); + + assert_se(sigemptyset(&waitmask) >= 0); + assert_se(sigset_add_many(&waitmask, + SIGCHLD, /* posix: process died */ + SIGINT, /* sysv: ctrl-alt-del */ + SIGRTMIN+3, /* systemd: halt */ + SIGRTMIN+4, /* systemd: poweroff */ + SIGRTMIN+5, /* systemd: reboot */ + SIGRTMIN+6, /* systemd: kexec */ + SIGRTMIN+13, /* systemd: halt */ + SIGRTMIN+14, /* systemd: poweroff */ + SIGRTMIN+15, /* systemd: reboot */ + SIGRTMIN+16, /* systemd: kexec */ + -1) >= 0); + + /* Note that we ignore SIGTERM (sysv's reexec), SIGHUP (reload), and all other signals here, since we don't + * support reexec/reloading in this stub process. */ + + for (;;) { + siginfo_t si; + usec_t current_usec; + + si.si_pid = 0; + r = waitid(P_ALL, 0, &si, WEXITED|WNOHANG); + if (r < 0) { + r = log_error_errno(errno, "Failed to reap children: %m"); + goto finish; + } + + current_usec = now(CLOCK_MONOTONIC); + + if (si.si_pid == pid || current_usec >= quit_usec) { + + /* The child we started ourselves died or we reached a timeout. */ + + if (state == STATE_REBOOT) { /* dispatch a queued reboot */ + (void) reboot(RB_AUTOBOOT); + r = log_error_errno(errno, "Failed to reboot: %m"); + goto finish; + + } else if (state == STATE_POWEROFF) + (void) reboot(RB_POWER_OFF); /* if this fails, fall back to normal exit. */ + + if (si.si_pid == pid && si.si_code == CLD_EXITED) + r = si.si_status; /* pass on exit code */ + else + r = 255; /* signal, coredump, timeout, … */ + + goto finish; + } + if (si.si_pid != 0) + /* We reaped something. Retry until there's nothing more to reap. */ + continue; + + if (quit_usec == USEC_INFINITY) + r = sigwaitinfo(&waitmask, &si); + else { + struct timespec ts; + r = sigtimedwait(&waitmask, &si, timespec_store(&ts, quit_usec - current_usec)); + } + if (r < 0) { + if (errno == EINTR) /* strace -p attach can result in EINTR, let's handle this nicely. */ + continue; + if (errno == EAGAIN) /* timeout reached */ + continue; + + r = log_error_errno(errno, "Failed to wait for signal: %m"); + goto finish; + } + + if (si.si_signo == SIGCHLD) + continue; /* Let's reap this */ + + if (state != STATE_RUNNING) + continue; + + /* Would love to use a switch() statement here, but SIGRTMIN is actually a function call, not a + * constant… */ + + if (si.si_signo == SIGRTMIN+3 || + si.si_signo == SIGRTMIN+4 || + si.si_signo == SIGRTMIN+13 || + si.si_signo == SIGRTMIN+14) + + state = STATE_POWEROFF; + + else if (si.si_signo == SIGINT || + si.si_signo == SIGRTMIN+5 || + si.si_signo == SIGRTMIN+6 || + si.si_signo == SIGRTMIN+15 || + si.si_signo == SIGRTMIN+16) + + state = STATE_REBOOT; + else + assert_not_reached("Got unexpected signal"); + + /* (void) kill_and_sigcont(pid, SIGTERM); */ + quit_usec = now(CLOCK_MONOTONIC) + DEFAULT_TIMEOUT_USEC; + } + +finish: + _exit(r < 0 ? EXIT_FAILURE : r); +} diff --git a/src/nspawn/nspawn-stub-pid1.h b/src/nspawn/nspawn-stub-pid1.h new file mode 100644 index 000000000..36c1aaf5d --- /dev/null +++ b/src/nspawn/nspawn-stub-pid1.h @@ -0,0 +1,22 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +int stub_pid1(void); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index f6a2c0386..ef348c335 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -57,7 +55,6 @@ #include "copy.h" #include "dev-setup.h" #include "env-util.h" -#include "event-util.h" #include "fd-util.h" #include "fdset.h" #include "fileio.h" @@ -80,6 +77,7 @@ #include "nspawn-register.h" #include "nspawn-settings.h" #include "nspawn-setuid.h" +#include "nspawn-stub-pid1.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" @@ -115,6 +113,7 @@ typedef enum LinkJournal { static char *arg_directory = NULL; static char *arg_template = NULL; +static char *arg_chdir = NULL; static char *arg_user = NULL; static sd_id128_t arg_uuid = {}; static char *arg_machine = NULL; @@ -123,7 +122,7 @@ static const char *arg_selinux_apifs_context = NULL; static const char *arg_slice = NULL; static bool arg_private_network = false; static bool arg_read_only = false; -static bool arg_boot = false; +static StartMode arg_start_mode = START_PID1; static bool arg_ephemeral = false; static LinkJournal arg_link_journal = LINK_AUTO; static bool arg_link_journal_try = false; @@ -193,7 +192,9 @@ static void help(void) { " -x --ephemeral Run container with snapshot of root directory, and\n" " remove it after exit\n" " -i --image=PATH File system device or disk image for the container\n" + " -a --as-pid2 Maintain a stub init as PID1, invoke binary as PID2\n" " -b --boot Boot up full system (i.e. invoke init)\n" + " --chdir=PATH Set working directory in the container\n" " -u --user=USER Run the command under specified user or uid\n" " -M --machine=NAME Set the machine name for the container\n" " --uuid=UUID Set a specific machine UUID for the container\n" @@ -232,8 +233,8 @@ static void help(void) { " capability\n" " --drop-capability=CAP Drop the specified capability from the default set\n" " --kill-signal=SIGNAL Select signal to use for shutting down PID 1\n" - " --link-journal=MODE Link up guest journal, one of no, auto, guest, host,\n" - " try-guest, try-host\n" + " --link-journal=MODE Link up guest journal, one of no, auto, guest, \n" + " host, try-guest, try-host\n" " -j Equivalent to --link-journal=try-guest\n" " --read-only Mount the root directory read-only\n" " --bind=PATH[:PATH[:OPTIONS]]\n" @@ -346,6 +347,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_PRIVATE_USERS, ARG_KILL_SIGNAL, ARG_SETTINGS, + ARG_CHDIR, }; static const struct option options[] = { @@ -356,6 +358,7 @@ static int parse_argv(int argc, char *argv[]) { { "ephemeral", no_argument, NULL, 'x' }, { "user", required_argument, NULL, 'u' }, { "private-network", no_argument, NULL, ARG_PRIVATE_NETWORK }, + { "as-pid2", no_argument, NULL, 'a' }, { "boot", no_argument, NULL, 'b' }, { "uuid", required_argument, NULL, ARG_UUID }, { "read-only", no_argument, NULL, ARG_READ_ONLY }, @@ -390,6 +393,7 @@ static int parse_argv(int argc, char *argv[]) { { "private-users", optional_argument, NULL, ARG_PRIVATE_USERS }, { "kill-signal", required_argument, NULL, ARG_KILL_SIGNAL }, { "settings", required_argument, NULL, ARG_SETTINGS }, + { "chdir", required_argument, NULL, ARG_CHDIR }, {} }; @@ -401,7 +405,7 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "+hD:u:bL:M:jS:Z:qi:xp:n", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:n", options, NULL)) >= 0) switch (c) { @@ -492,8 +496,23 @@ static int parse_argv(int argc, char *argv[]) { break; case 'b': - arg_boot = true; - arg_settings_mask |= SETTING_BOOT; + if (arg_start_mode == START_PID2) { + log_error("--boot and --as-pid2 may not be combined."); + return -EINVAL; + } + + arg_start_mode = START_BOOT; + arg_settings_mask |= SETTING_START_MODE; + break; + + case 'a': + if (arg_start_mode == START_BOOT) { + log_error("--boot and --as-pid2 may not be combined."); + return -EINVAL; + } + + arg_start_mode = START_PID2; + arg_settings_mask |= SETTING_START_MODE; break; case ARG_UUID: @@ -850,6 +869,19 @@ static int parse_argv(int argc, char *argv[]) { break; + case ARG_CHDIR: + if (!path_is_absolute(optarg)) { + log_error("Working directory %s is not an absolute path.", optarg); + return -EINVAL; + } + + r = free_and_strdup(&arg_chdir, optarg); + if (r < 0) + return log_oom(); + + arg_settings_mask |= SETTING_WORKING_DIRECTORY; + break; + case '?': return -EINVAL; @@ -860,7 +892,7 @@ static int parse_argv(int argc, char *argv[]) { if (arg_share_system) arg_register = false; - if (arg_boot && arg_share_system) { + if (arg_start_mode != START_PID1 && arg_share_system) { log_error("--boot and --share-system may not be combined."); return -EINVAL; } @@ -908,7 +940,7 @@ static int parse_argv(int argc, char *argv[]) { if (!arg_parameters) return log_oom(); - arg_settings_mask |= SETTING_BOOT; + arg_settings_mask |= SETTING_START_MODE; } /* Load all settings from .nspawn files */ @@ -944,7 +976,7 @@ static int verify_arguments(void) { return -EINVAL; } - if (arg_boot && arg_kill_signal <= 0) + if (arg_start_mode == START_BOOT && arg_kill_signal <= 0) arg_kill_signal = SIGRTMIN+3; return 0; @@ -1028,7 +1060,7 @@ static int setup_timezone(const char *dest) { } check = strjoina("/usr/share/zoneinfo/", z); - check = prefix_root(dest, check); + check = prefix_roota(dest, check); if (laccess(check, F_OK) < 0) { log_warning("Timezone %s does not exist in container, not updating container timezone.", z); return 0; @@ -1338,6 +1370,7 @@ static int setup_journal(const char *directory) { sd_id128_t machine_id, this_id; _cleanup_free_ char *b = NULL, *d = NULL; const char *etc_machine_id, *p, *q; + bool try; char *id; int r; @@ -1345,16 +1378,21 @@ static int setup_journal(const char *directory) { if (arg_ephemeral) return 0; + if (arg_link_journal == LINK_NO) + return 0; + + try = arg_link_journal_try || arg_link_journal == LINK_AUTO; + etc_machine_id = prefix_roota(directory, "/etc/machine-id"); r = read_one_line_file(etc_machine_id, &b); - if (r == -ENOENT && arg_link_journal == LINK_AUTO) + if (r == -ENOENT && try) return 0; else if (r < 0) return log_error_errno(r, "Failed to read machine ID from %s: %m", etc_machine_id); id = strstrip(b); - if (isempty(id) && arg_link_journal == LINK_AUTO) + if (isempty(id) && try) return 0; /* Verify validity */ @@ -1367,16 +1405,13 @@ static int setup_journal(const char *directory) { return log_error_errno(r, "Failed to retrieve machine ID: %m"); if (sd_id128_equal(machine_id, this_id)) { - log_full(arg_link_journal == LINK_AUTO ? LOG_WARNING : LOG_ERR, + log_full(try ? LOG_WARNING : LOG_ERR, "Host and machine ids are equal (%s): refusing to link journals", id); - if (arg_link_journal == LINK_AUTO) + if (try) return 0; return -EEXIST; } - if (arg_link_journal == LINK_NO) - return 0; - r = userns_mkdir(directory, "/var", 0755, 0, 0); if (r < 0) return log_error_errno(r, "Failed to create /var: %m"); @@ -1393,21 +1428,19 @@ static int setup_journal(const char *directory) { q = prefix_roota(directory, p); if (path_is_mount_point(p, 0) > 0) { - if (arg_link_journal != LINK_AUTO) { - log_error("%s: already a mount point, refusing to use for journal", p); - return -EEXIST; - } + if (try) + return 0; - return 0; + log_error("%s: already a mount point, refusing to use for journal", p); + return -EEXIST; } if (path_is_mount_point(q, 0) > 0) { - if (arg_link_journal != LINK_AUTO) { - log_error("%s: already a mount point, refusing to use for journal", q); - return -EEXIST; - } + if (try) + return 0; - return 0; + log_error("%s: already a mount point, refusing to use for journal", q); + return -EEXIST; } r = readlink_and_make_absolute(p, &d); @@ -1441,7 +1474,7 @@ static int setup_journal(const char *directory) { if (arg_link_journal == LINK_GUEST) { if (symlink(q, p) < 0) { - if (arg_link_journal_try) { + if (try) { log_debug_errno(errno, "Failed to symlink %s to %s, skipping journal setup: %m", q, p); return 0; } else @@ -1457,9 +1490,9 @@ static int setup_journal(const char *directory) { if (arg_link_journal == LINK_HOST) { /* don't create parents here -- if the host doesn't have * permanent journal set up, don't force it here */ - r = mkdir(p, 0755); - if (r < 0) { - if (arg_link_journal_try) { + + if (mkdir(p, 0755) < 0 && errno != EEXIST) { + if (try) { log_debug_errno(errno, "Failed to create %s, skipping journal setup: %m", p); return 0; } else @@ -1483,7 +1516,7 @@ static int setup_journal(const char *directory) { } static int drop_capabilities(void) { - return capability_bounding_set_drop(~arg_retain, false); + return capability_bounding_set_drop(arg_retain, false); } static int reset_audit_loginuid(void) { @@ -2563,6 +2596,16 @@ static int inner_child( return -ESRCH; } + if (arg_chdir) + if (chdir(arg_chdir) < 0) + return log_error_errno(errno, "Failed to change to specified working directory %s: %m", arg_chdir); + + if (arg_start_mode == START_PID2) { + r = stub_pid1(); + if (r < 0) + return r; + } + /* Now, explicitly close the log, so that we * then can close all remaining fds. Closing * the log explicitly first has the benefit @@ -2574,7 +2617,7 @@ static int inner_child( log_close(); (void) fdset_close_others(fds); - if (arg_boot) { + if (arg_start_mode == START_BOOT) { char **a; size_t m; @@ -2598,7 +2641,9 @@ static int inner_child( } else if (!strv_isempty(arg_parameters)) execvpe(arg_parameters[0], arg_parameters, env_use); else { - chdir(home ?: "/root"); + if (!arg_chdir) + chdir(home ?: "/root"); + execle("/bin/bash", "-bash", NULL, env_use); execle("/bin/sh", "-sh", NULL, env_use); } @@ -2894,15 +2939,22 @@ static int load_settings(void) { /* Copy over bits from the settings, unless they have been * explicitly masked by command line switches. */ - if ((arg_settings_mask & SETTING_BOOT) == 0 && - settings->boot >= 0) { - arg_boot = settings->boot; + if ((arg_settings_mask & SETTING_START_MODE) == 0 && + settings->start_mode >= 0) { + arg_start_mode = settings->start_mode; strv_free(arg_parameters); arg_parameters = settings->parameters; settings->parameters = NULL; } + if ((arg_settings_mask & SETTING_WORKING_DIRECTORY) == 0 && + settings->working_directory) { + free(arg_chdir); + arg_chdir = settings->working_directory; + settings->working_directory = NULL; + } + if ((arg_settings_mask & SETTING_ENVIRONMENT) == 0 && settings->environment) { strv_free(arg_setenv); @@ -3044,6 +3096,10 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); + /* Make sure rename_process() in the stub init process can work */ + saved_argv = argv; + saved_argc = argc; + r = parse_argv(argc, argv); if (r <= 0) goto finish; @@ -3150,7 +3206,7 @@ int main(int argc, char *argv[]) { } } - if (arg_boot) { + if (arg_start_mode == START_BOOT) { if (path_is_os_tree(arg_directory) <= 0) { log_error("Directory %s doesn't look like an OS root directory (os-release file is missing). Refusing.", arg_directory); r = -EINVAL; @@ -3259,9 +3315,9 @@ int main(int argc, char *argv[]) { }; int ifi = 0; ssize_t l; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(pty_forward_freep) PTYForward *forward = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; char last_char = 0; r = barrier_create(&barrier); @@ -3629,6 +3685,7 @@ finish: free(arg_image); free(arg_machine); free(arg_user); + free(arg_chdir); strv_free(arg_setenv); free(arg_network_bridge); strv_free(arg_network_interfaces); diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index ee10b105e..2536ad289 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -31,6 +29,7 @@ #include "local-addresses.h" #include "macro.h" #include "nss-util.h" +#include "signal-util.h" #include "string-util.h" #include "util.h" @@ -63,6 +62,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r( char *r_name; unsigned n; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(name); assert(pat); assert(buffer); @@ -327,6 +328,8 @@ enum nss_status _nss_myhostname_gethostbyname3_r( uint32_t local_address_ipv4 = 0; int n_addresses = 0; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(name); assert(host); assert(buffer); @@ -409,6 +412,8 @@ enum nss_status _nss_myhostname_gethostbyaddr2_r( bool additional_from_hostname = false; unsigned n; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(addr); assert(host); assert(buffer); diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index 969fa9619..1582d702f 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -27,11 +25,11 @@ #include "alloc-util.h" #include "bus-common-errors.h" -#include "bus-util.h" #include "hostname-util.h" #include "in-addr-util.h" #include "macro.h" #include "nss-util.h" +#include "signal-util.h" #include "string-util.h" #include "user-util.h" #include "util.h" @@ -40,6 +38,9 @@ NSS_GETHOSTBYNAME_PROTOTYPES(mymachines); NSS_GETPW_PROTOTYPES(mymachines); NSS_GETGR_PROTOTYPES(mymachines); +#define HOST_UID_LIMIT ((uid_t) UINT32_C(0x10000)) +#define HOST_GID_LIMIT ((gid_t) UINT32_C(0x10000)) + static int count_addresses(sd_bus_message *m, int af, unsigned *ret) { unsigned c = 0; int r; @@ -86,8 +87,8 @@ enum nss_status _nss_mymachines_gethostbyname4_r( int32_t *ttlp) { struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; - _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ int *ifindices = NULL; _cleanup_free_ char *class = NULL; size_t l, ms, idx; @@ -95,6 +96,8 @@ enum nss_status _nss_mymachines_gethostbyname4_r( char *r_name; int n_ifindices, r; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(name); assert(pat); assert(buffer); @@ -235,14 +238,16 @@ enum nss_status _nss_mymachines_gethostbyname3_r( int32_t *ttlp, char **canonp) { - _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *class = NULL; unsigned c = 0, i = 0; char *r_name, *r_aliases, *r_addr, *r_addr_list; size_t l, idx, ms, alen; int r; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(name); assert(result); assert(buffer); @@ -396,15 +401,17 @@ enum nss_status _nss_mymachines_getpwnam_r( char *buffer, size_t buflen, int *errnop) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; const char *p, *e, *machine; uint32_t mapped; uid_t uid; size_t l; int r; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(name); assert(pwd); @@ -416,6 +423,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; @@ -448,6 +458,10 @@ enum nss_status _nss_mymachines_getpwnam_r( if (r < 0) goto fail; + /* Refuse to work if the mapped address is in the host UID range, or if there was no mapping at all. */ + if (mapped < HOST_UID_LIMIT || mapped == uid) + goto not_found; + l = strlen(name); if (buflen < l+1) { *errnop = ENOMEM; @@ -482,20 +496,22 @@ enum nss_status _nss_mymachines_getpwuid_r( char *buffer, size_t buflen, int *errnop) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; const char *machine, *object; uint32_t mapped; int r; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + if (!uid_is_valid(uid)) { r = -EINVAL; goto fail; } /* We consider all uids < 65536 host uids */ - if (uid < 0x10000) + if (uid < HOST_UID_LIMIT) goto not_found; r = sd_bus_open_system(&bus); @@ -522,6 +538,9 @@ enum nss_status _nss_mymachines_getpwuid_r( if (r < 0) goto fail; + if (mapped == uid) + goto not_found; + if (snprintf(buffer, buflen, "vu-%s-" UID_FMT, machine, (uid_t) mapped) >= (int) buflen) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; @@ -553,15 +572,17 @@ enum nss_status _nss_mymachines_getgrnam_r( char *buffer, size_t buflen, int *errnop) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; const char *p, *e, *machine; uint32_t mapped; uid_t gid; size_t l; int r; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(name); assert(gr); @@ -573,6 +594,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; @@ -605,6 +629,9 @@ enum nss_status _nss_mymachines_getgrnam_r( if (r < 0) goto fail; + if (mapped < HOST_GID_LIMIT || mapped == gid) + goto not_found; + l = sizeof(char*) + strlen(name) + 1; if (buflen < l) { *errnop = ENOMEM; @@ -637,20 +664,22 @@ enum nss_status _nss_mymachines_getgrgid_r( char *buffer, size_t buflen, int *errnop) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message* reply = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message* reply = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; const char *machine, *object; uint32_t mapped; int r; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + if (!gid_is_valid(gid)) { r = -EINVAL; goto fail; } /* We consider all gids < 65536 host gids */ - if (gid < 0x10000) + if (gid < HOST_GID_LIMIT) goto not_found; r = sd_bus_open_system(&bus); @@ -677,6 +706,9 @@ enum nss_status _nss_mymachines_getgrgid_r( if (r < 0) goto fail; + if (mapped == gid) + goto not_found; + if (buflen < sizeof(char*) + 1) { *errnop = ENOMEM; return NSS_STATUS_TRYAGAIN; diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index ed59a71e3..69c0d9bdc 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -29,12 +27,12 @@ #include "sd-bus.h" #include "bus-common-errors.h" -#include "bus-util.h" #include "in-addr-util.h" #include "macro.h" #include "nss-util.h" #include "string-util.h" #include "util.h" +#include "signal-util.h" NSS_GETHOSTBYNAME_PROTOTYPES(resolve); NSS_GETHOSTBYADDR_PROTOTYPES(resolve); @@ -119,15 +117,24 @@ enum nss_status _nss_resolve_gethostbyname4_r( int *errnop, int *h_errnop, int32_t *ttlp) { - _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + enum nss_status (*fallback)( + const char *name, + struct gaih_addrtuple **pat, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; const char *canonical = NULL; size_t l, ms, idx; char *r_name; int c, r, i = 0; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(name); assert(pat); assert(buffer); @@ -136,7 +143,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( r = sd_bus_open_system(&bus); if (r < 0) - goto fail; + goto fallback; r = sd_bus_message_new_method_call( bus, @@ -164,28 +171,10 @@ enum nss_status _nss_resolve_gethostbyname4_r( return NSS_STATUS_NOTFOUND; } - if (bus_error_shall_fallback(&error)) { + if (bus_error_shall_fallback(&error)) + goto fallback; - enum nss_status (*fallback)( - const char *name, - struct gaih_addrtuple **pat, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp); - - fallback = (enum nss_status (*)(const char *name, - struct gaih_addrtuple **pat, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp)) - find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r"); - if (fallback) - return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp); - } - - *errnop = -r; - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; + goto fail; } c = count_addresses(reply, AF_UNSPEC, &canonical); @@ -285,9 +274,20 @@ enum nss_status _nss_resolve_gethostbyname4_r( return NSS_STATUS_SUCCESS; +fallback: + fallback = (enum nss_status (*)(const char *name, + struct gaih_addrtuple **pat, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp)) + find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname4_r"); + + if (fallback) + return fallback(name, pat, buffer, buflen, errnop, h_errnop, ttlp); + fail: *errnop = -r; - *h_errnop = NO_DATA; + *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } @@ -300,14 +300,25 @@ enum nss_status _nss_resolve_gethostbyname3_r( int32_t *ttlp, char **canonp) { - _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + enum nss_status (*fallback)( + const char *name, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp); + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; size_t l, idx, ms, alen; const char *canonical; int c, r, i = 0; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(name); assert(result); assert(buffer); @@ -324,7 +335,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( r = sd_bus_open_system(&bus); if (r < 0) - goto fail; + goto fallback; r = sd_bus_message_new_method_call( bus, @@ -352,32 +363,10 @@ enum nss_status _nss_resolve_gethostbyname3_r( return NSS_STATUS_NOTFOUND; } - if (bus_error_shall_fallback(&error)) { + if (bus_error_shall_fallback(&error)) + goto fallback; - enum nss_status (*fallback)( - const char *name, - int af, - struct hostent *result, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp, - char **canonp); - - fallback = (enum nss_status (*)(const char *name, - int af, - struct hostent *result, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp, - char **canonp)) - find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r"); - if (fallback) - return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp); - } - - *errnop = -r; - *h_errnop = NO_RECOVERY; - return NSS_STATUS_UNAVAIL; + goto fail; } c = count_addresses(reply, af, &canonical); @@ -490,9 +479,21 @@ enum nss_status _nss_resolve_gethostbyname3_r( return NSS_STATUS_SUCCESS; +fallback: + fallback = (enum nss_status (*)(const char *name, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp, + char **canonp)) + find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyname3_r"); + if (fallback) + return fallback(name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp); + fail: *errnop = -r; - *h_errnop = NO_DATA; + *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } @@ -504,15 +505,26 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( int *errnop, int *h_errnop, int32_t *ttlp) { - _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + enum nss_status (*fallback)( + const void* addr, socklen_t len, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp); + + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *r_name, *r_aliases, *r_addr, *r_addr_list; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; unsigned c = 0, i = 0; size_t ms = 0, idx; const char *n; int r, ifindex; + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + assert(addr); assert(result); assert(buffer); @@ -533,7 +545,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( r = sd_bus_open_system(&bus); if (r < 0) - goto fail; + goto fallback; r = sd_bus_message_new_method_call( bus, @@ -569,28 +581,9 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( return NSS_STATUS_NOTFOUND; } - if (bus_error_shall_fallback(&error)) { + if (bus_error_shall_fallback(&error)) + goto fallback; - enum nss_status (*fallback)( - const void* addr, socklen_t len, - int af, - struct hostent *result, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp); - - fallback = (enum nss_status (*)( - const void* addr, socklen_t len, - int af, - struct hostent *result, - char *buffer, size_t buflen, - int *errnop, int *h_errnop, - int32_t *ttlp)) - find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r"); - - if (fallback) - return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp); - } *errnop = -r; *h_errnop = NO_RECOVERY; @@ -660,7 +653,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( p = buffer + idx; memcpy(p, n, l+1); - if (i > 1) + if (i > 0) ((char**) r_aliases)[i-1] = p; i++; @@ -688,9 +681,22 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( return NSS_STATUS_SUCCESS; +fallback: + fallback = (enum nss_status (*)( + const void* addr, socklen_t len, + int af, + struct hostent *result, + char *buffer, size_t buflen, + int *errnop, int *h_errnop, + int32_t *ttlp)) + find_fallback("libnss_dns.so.2", "_nss_dns_gethostbyaddr2_r"); + + if (fallback) + return fallback(addr, len, af, result, buffer, buflen, errnop, h_errnop, ttlp); + fail: *errnop = -r; - *h_errnop = NO_DATA; + *h_errnop = NO_RECOVERY; return NSS_STATUS_UNAVAIL; } diff --git a/src/path/path.c b/src/path/path.c index 0ece72f6f..61d877fcf 100644 --- a/src/path/path.c +++ b/src/path/path.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c index 883d96608..6d8c05f04 100644 --- a/src/quotacheck/quotacheck.c +++ b/src/quotacheck/quotacheck.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c index d857ade36..6748bb9dd 100644 --- a/src/random-seed/random-seed.c +++ b/src/random-seed/random-seed.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -40,7 +38,7 @@ int main(int argc, char *argv[]) { _cleanup_free_ void* buf = NULL; size_t buf_size = 0; ssize_t k; - int r; + int r, open_rw_error; FILE *f; bool refresh_seed_file = true; @@ -87,14 +85,23 @@ int main(int argc, char *argv[]) { if (streq(argv[1], "load")) { seed_fd = open(RANDOM_SEED, O_RDWR|O_CLOEXEC|O_NOCTTY|O_CREAT, 0600); + open_rw_error = -errno; if (seed_fd < 0) { + refresh_seed_file = false; + seed_fd = open(RANDOM_SEED, O_RDONLY|O_CLOEXEC|O_NOCTTY); if (seed_fd < 0) { - r = log_error_errno(errno, "Failed to open " RANDOM_SEED ": %m"); + bool missing = errno == ENOENT; + + log_full_errno(missing ? LOG_DEBUG : LOG_ERR, + open_rw_error, "Failed to open " RANDOM_SEED " for writing: %m"); + r = log_full_errno(missing ? LOG_DEBUG : LOG_ERR, + errno, "Failed to open " RANDOM_SEED " for reading: %m"); + if (missing) + r = 0; + goto finish; } - - refresh_seed_file = false; } random_fd = open("/dev/urandom", O_RDWR|O_CLOEXEC|O_NOCTTY, 0600); @@ -109,9 +116,10 @@ int main(int argc, char *argv[]) { k = loop_read(seed_fd, buf, buf_size, false); if (k < 0) r = log_error_errno(k, "Failed to read seed from " RANDOM_SEED ": %m"); - else if (k == 0) + else if (k == 0) { + r = 0; log_debug("Seed file " RANDOM_SEED " not yet initialized, proceeding."); - else { + } else { (void) lseek(seed_fd, 0, SEEK_SET); r = loop_write(random_fd, buf, (size_t) k, false); diff --git a/src/rc-local-generator/rc-local-generator.c b/src/rc-local-generator/rc-local-generator.c index 6ecadbf3e..9e9c16199 100644 --- a/src/rc-local-generator/rc-local-generator.c +++ b/src/rc-local-generator/rc-local-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c index 9fc56284d..6468d1eec 100644 --- a/src/remount-fs/remount-fs.c +++ b/src/remount-fs/remount-fs.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c index 166ab470e..e29175896 100644 --- a/src/reply-password/reply-password.c +++ b/src/reply-password/reply-password.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c deleted file mode 100644 index eb4e64684..000000000 --- a/src/resolve-host/resolve-host.c +++ /dev/null @@ -1,657 +0,0 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - -/*** - This file is part of systemd. - - Copyright 2014 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 . -***/ - -#include -#include - -#include "sd-bus.h" - -#include "af-list.h" -#include "alloc-util.h" -#include "bus-error.h" -#include "bus-util.h" -#include "in-addr-util.h" -#include "parse-util.h" -#include "resolved-def.h" -#include "resolved-dns-packet.h" - -#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC) - -static int arg_family = AF_UNSPEC; -static int arg_ifindex = 0; -static int arg_type = 0; -static uint16_t arg_class = 0; -static bool arg_legend = true; -static uint64_t arg_flags = 0; - -static void print_source(uint64_t flags, usec_t rtt) { - char rtt_str[FORMAT_TIMESTAMP_MAX]; - - if (!arg_legend) - return; - - if (flags == 0) - return; - - fputs("\n-- Information acquired via", stdout); - - if (flags != 0) - printf(" protocol%s%s%s", - flags & SD_RESOLVED_DNS ? " DNS" :"", - flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "", - flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : ""); - - assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100)); - - printf(" in %s", rtt_str); - - fputc('.', stdout); - fputc('\n', stdout); -} - -static int resolve_host(sd_bus *bus, const char *name) { - - _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - const char *canonical = NULL; - char ifname[IF_NAMESIZE] = ""; - unsigned c = 0; - int r; - uint64_t flags; - usec_t ts; - - assert(name); - - 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); - - log_debug("Resolving %s (family %s, interface %s).", name, 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", - "ResolveHostname"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(req, "isit", arg_ifindex, name, 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) { - log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r)); - return r; - } - - ts = now(CLOCK_MONOTONIC) - ts; - - 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) { - const void *a; - size_t sz; - _cleanup_free_ char *pretty = NULL; - int ifindex, family; - - 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"); - continue; - } - - 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%s\n", - (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ", - pretty, - isempty(ifname) ? "" : "%", ifname); - - 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, "st", &canonical, &flags); - if (r < 0) - return bus_log_parse_error(r); - - if (!streq(name, canonical)) - printf("%*s%s (%s)\n", - (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ", - canonical); - - if (c == 0) { - log_error("%s: no addresses found", name); - return -ESRCH; - } - - print_source(flags, ts); - - return 0; -} - -static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) { - _cleanup_bus_message_unref_ sd_bus_message *req = NULL, *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_free_ char *pretty = NULL; - char ifname[IF_NAMESIZE] = ""; - uint64_t flags; - unsigned c = 0; - usec_t ts; - int r; - - assert(bus); - assert(IN_SET(family, AF_INET, AF_INET6)); - assert(address); - - if (ifindex <= 0) - ifindex = arg_ifindex; - - r = in_addr_to_string(family, address, &pretty); - if (r < 0) - return log_oom(); - - if (ifindex > 0 && !if_indextoname(ifindex, ifname)) - return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); - - log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname); - - r = sd_bus_message_new_method_call( - bus, - &req, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "ResolveAddress"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(req, "ii", ifindex, family); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family)); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(req, "t", 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) { - log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r)); - return r; - } - - ts = now(CLOCK_MONOTONIC) - ts; - - r = sd_bus_message_enter_container(reply, 'a', "(is)"); - if (r < 0) - return bus_log_create_error(r); - - while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) { - const char *n; - - assert_cc(sizeof(int) == sizeof(int32_t)); - - r = sd_bus_message_read(reply, "is", &ifindex, &n); - if (r < 0) - return r; - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return r; - - ifname[0] = 0; - if (ifindex > 0 && !if_indextoname(ifindex, ifname)) - log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); - - printf("%*s%*s%*s%s %s\n", - (int) strlen(pretty), c == 0 ? pretty : "", - isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%", - (int) strlen(ifname), c == 0 ? ifname : "", - c == 0 ? ":" : " ", - n); - - 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, "t", &flags); - if (r < 0) - return bus_log_parse_error(r); - - if (c == 0) { - log_error("%s: no names found", pretty); - return -ESRCH; - } - - print_source(flags, ts); - - return 0; -} - -static int parse_address(const char *s, int *family, union in_addr_union *address, int *ifindex) { - const char *percent, *a; - int ifi = 0; - int r; - - percent = strchr(s, '%'); - if (percent) { - if (parse_ifindex(percent+1, &ifi) < 0) { - ifi = if_nametoindex(percent+1); - if (ifi <= 0) - return -EINVAL; - } - - a = strndupa(s, percent - s); - } else - a = s; - - r = in_addr_from_string_auto(a, family, address); - if (r < 0) - return r; - - *ifindex = ifi; - return 0; -} - -static int resolve_record(sd_bus *bus, const char *name) { - - _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] = ""; - unsigned n = 0; - uint64_t flags; - int r; - usec_t ts; - - assert(name); - - 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); - - log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(arg_class), dns_type_to_string(arg_type), isempty(ifname) ? "*" : ifname); - - r = sd_bus_message_new_method_call( - bus, - &req, - "org.freedesktop.resolve1", - "/org/freedesktop/resolve1", - "org.freedesktop.resolve1.Manager", - "ResolveRecord"); - if (r < 0) - return bus_log_create_error(r); - - assert((uint16_t) arg_type == arg_type); - r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, arg_class, arg_type, 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) { - log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r)); - return r; - } - - ts = now(CLOCK_MONOTONIC) - ts; - - r = sd_bus_message_enter_container(reply, 'a', "(iqqay)"); - if (r < 0) - return bus_log_parse_error(r); - - while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - _cleanup_free_ char *s = NULL; - uint16_t c, t; - int ifindex; - const void *d; - size_t l; - - assert_cc(sizeof(int) == sizeof(int32_t)); - - r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t); - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_read_array(reply, 'y', &d, &l); - 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 = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); - if (r < 0) - return log_oom(); - - p->refuse_compression = true; - - r = dns_packet_append_blob(p, d, l, NULL); - if (r < 0) - return log_oom(); - - r = dns_packet_read_rr(p, &rr, NULL); - if (r < 0) { - log_error("Failed to parse RR."); - return r; - } - - r = dns_resource_record_to_string(rr, &s); - if (r < 0) { - log_error("Failed to format RR."); - return r; - } - - ifname[0] = 0; - if (ifindex > 0 && !if_indextoname(ifindex, ifname)) - log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); - - printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname); - n++; - } - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_exit_container(reply); - if (r < 0) - return bus_log_parse_error(r); - - r = sd_bus_message_read(reply, "t", &flags); - if (r < 0) - return bus_log_parse_error(r); - - if (n == 0) { - log_error("%s: no records found", name); - return -ESRCH; - } - - print_source(flags, ts); - - return 0; -} - -static void help_dns_types(void) { - int i; - const char *t; - - if (arg_legend) - puts("Known DNS RR types:"); - for (i = 0; i < _DNS_TYPE_MAX; i++) { - t = dns_type_to_string(i); - if (t) - puts(t); - } -} - -static void help_dns_classes(void) { - int i; - const char *t; - - if (arg_legend) - puts("Known DNS RR classes:"); - for (i = 0; i < _DNS_CLASS_MAX; i++) { - t = dns_class_to_string(i); - if (t) - puts(t); - } -} - -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); -} - -static int parse_argv(int argc, char *argv[]) { - enum { - ARG_VERSION = 0x100, - ARG_LEGEND, - }; - - 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' }, - {} - }; - - int c, r; - - assert(argc >= 0); - assert(argv); - - while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0) - switch(c) { - - case 'h': - help(); - return 0; /* done */; - - case ARG_VERSION: - return version(); - - case '4': - arg_family = AF_INET; - break; - - case '6': - arg_family = AF_INET6; - break; - - case 'i': { - int ifi; - - if (parse_ifindex(optarg, &ifi) >= 0) - arg_ifindex = ifi; - else { - ifi = if_nametoindex(optarg); - if (ifi <= 0) - return log_error_errno(errno, "Unknown interface %s: %m", optarg); - - arg_ifindex = ifi; - } - - break; - } - - case 't': - if (streq(optarg, "help")) { - help_dns_types(); - return 0; - } - - arg_type = dns_type_from_string(optarg); - if (arg_type < 0) { - log_error("Failed to parse RR record type %s", optarg); - return arg_type; - } - assert(arg_type > 0 && (uint16_t) arg_type == arg_type); - - break; - - case 'c': - if (streq(optarg, "help")) { - help_dns_classes(); - return 0; - } - - r = dns_class_from_string(optarg, &arg_class); - if (r < 0) { - log_error("Failed to parse RR record class %s", optarg); - return r; - } - - 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; - break; - - case 'p': - if (streq(optarg, "dns")) - arg_flags |= SD_RESOLVED_DNS; - else if (streq(optarg, "llmnr")) - arg_flags |= SD_RESOLVED_LLMNR; - else if (streq(optarg, "llmnr-ipv4")) - arg_flags |= SD_RESOLVED_LLMNR_IPV4; - else if (streq(optarg, "llmnr-ipv6")) - arg_flags |= SD_RESOLVED_LLMNR_IPV6; - else { - log_error("Unknown protocol specifier: %s", optarg); - return -EINVAL; - } - - break; - - case '?': - return -EINVAL; - - default: - assert_not_reached("Unhandled option"); - } - - if (arg_type == 0 && arg_class != 0) { - log_error("--class= may only be used in conjunction with --type="); - return -EINVAL; - } - - if (arg_type != 0 && arg_class == 0) - arg_class = DNS_CLASS_IN; - - return 1 /* work to do */; -} - -int main(int argc, char **argv) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; - int r; - - log_parse_environment(); - log_open(); - - r = parse_argv(argc, argv); - if (r <= 0) - goto finish; - - if (optind >= argc) { - log_error("No arguments passed"); - r = -EINVAL; - goto finish; - } - - r = sd_bus_open_system(&bus); - if (r < 0) { - log_error_errno(r, "sd_bus_open_system: %m"); - goto finish; - } - - while (argv[optind]) { - int family, ifindex, k; - union in_addr_union a; - - if (arg_type != 0) - k = resolve_record(bus, argv[optind]); - else { - k = parse_address(argv[optind], &family, &a, &ifindex); - if (k >= 0) - k = resolve_address(bus, family, &a, ifindex); - else - k = resolve_host(bus, argv[optind]); - } - - if (r == 0) - r = k; - - optind++; - } - -finish: - return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/src/resolve/RFCs b/src/resolve/RFCs new file mode 100644 index 000000000..22004a00c --- /dev/null +++ b/src/resolve/RFCs @@ -0,0 +1,59 @@ +Y = Comprehensively Implemented, to the point appropriate for resolved +D = Comprehensively Implemented, by a dependency of resolved +! = Missing and something we might want to implement +~ = Needs no explicit support or doesn't apply +? = Is this relevant today? + = We are working on this + +Y https://tools.ietf.org/html/rfc1034 → DOMAIN NAMES - CONCEPTS AND FACILITIES +Y https://tools.ietf.org/html/rfc1035 → DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION +? https://tools.ietf.org/html/rfc1101 → DNS Encoding of Network Names and Other Types +Y https://tools.ietf.org/html/rfc1123 → Requirements for Internet Hosts -- Application and Support +~ https://tools.ietf.org/html/rfc1464 → Using the Domain Name System To Store Arbitrary String Attributes +Y https://tools.ietf.org/html/rfc1536 → Common DNS Implementation Errors and Suggested Fixes +Y https://tools.ietf.org/html/rfc1876 → A Means for Expressing Location Information in the Domain Name System +Y https://tools.ietf.org/html/rfc2181 → Clarifications to the DNS Specification +Y https://tools.ietf.org/html/rfc2308 → Negative Caching of DNS Queries (DNS NCACHE) +Y https://tools.ietf.org/html/rfc2782 → A DNS RR for specifying the location of services (DNS SRV) +D https://tools.ietf.org/html/rfc3492 → Punycode: A Bootstring encoding of Unicode for Internationalized Domain Names in Applications (IDNA) +Y https://tools.ietf.org/html/rfc3596 → DNS Extensions to Support IP Version 6 +Y https://tools.ietf.org/html/rfc3597 → Handling of Unknown DNS Resource Record (RR) Types +Y https://tools.ietf.org/html/rfc4033 → DNS Security Introduction and Requirements +Y https://tools.ietf.org/html/rfc4034 → Resource Records for the DNS Security Extensions +Y https://tools.ietf.org/html/rfc4035 → Protocol Modifications for the DNS Security Extensions +! https://tools.ietf.org/html/rfc4183 → A Suggested Scheme for DNS Resolution of Networks and Gateways +Y https://tools.ietf.org/html/rfc4255 → Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints +Y https://tools.ietf.org/html/rfc4343 → Domain Name System (DNS) Case Insensitivity Clarification +~ https://tools.ietf.org/html/rfc4470 → Minimally Covering NSEC Records and DNSSEC On-line Signing +Y https://tools.ietf.org/html/rfc4501 → Domain Name System Uniform Resource Identifiers +Y https://tools.ietf.org/html/rfc4509 → Use of SHA-256 in DNSSEC Delegation Signer (DS) Resource Records (RRs) +~ https://tools.ietf.org/html/rfc4592 → The Role of Wildcards in the Domain Name System +~ https://tools.ietf.org/html/rfc4697 → Observed DNS Resolution Misbehavior +Y https://tools.ietf.org/html/rfc4795 → Link-Local Multicast Name Resolution (LLMNR) +Y https://tools.ietf.org/html/rfc5011 → Automated Updates of DNS Security (DNSSEC) Trust Anchors +Y https://tools.ietf.org/html/rfc5155 → DNS Security (DNSSEC) Hashed Authenticated Denial of Existence +Y https://tools.ietf.org/html/rfc5452 → Measures for Making DNS More Resilient against Forged Answers +Y https://tools.ietf.org/html/rfc5702 → Use of SHA-2 Algorithms with RSA in DNSKEY and RRSIG Resource Records for DNSSEC +Y https://tools.ietf.org/html/rfc5890 → Internationalized Domain Names for Applications (IDNA): Definitions and Document Framework +Y https://tools.ietf.org/html/rfc5891 → Internationalized Domain Names in Applications (IDNA): Protocol +Y https://tools.ietf.org/html/rfc5966 → DNS Transport over TCP - Implementation Requirements +Y https://tools.ietf.org/html/rfc6303 → Locally Served DNS Zones +Y https://tools.ietf.org/html/rfc6604 → xNAME RCODE and Status Bits Clarification +Y https://tools.ietf.org/html/rfc6605 → Elliptic Curve Digital Signature Algorithm (DSA) for DNSSEC + https://tools.ietf.org/html/rfc6672 → DNAME Redirection in the DNS +! https://tools.ietf.org/html/rfc6731 → Improved Recursive DNS Server Selection for Multi-Interfaced Nodes +Y https://tools.ietf.org/html/rfc6761 → Special-Use Domain Names + https://tools.ietf.org/html/rfc6762 → Multicast DNS + https://tools.ietf.org/html/rfc6763 → DNS-Based Service Discovery +~ https://tools.ietf.org/html/rfc6781 → DNSSEC Operational Practices, Version 2 +Y https://tools.ietf.org/html/rfc6840 → Clarifications and Implementation Notes for DNS Security (DNSSEC) +Y https://tools.ietf.org/html/rfc6891 → Extension Mechanisms for DNS (EDNS(0)) +Y https://tools.ietf.org/html/rfc6944 → Applicability Statement: DNS Security (DNSSEC) DNSKEY Algorithm Implementation Status +Y https://tools.ietf.org/html/rfc6975 → Signaling Cryptographic Algorithm Understanding in DNS Security Extensions (DNSSEC) +Y https://tools.ietf.org/html/rfc7129 → Authenticated Denial of Existence in the DNS +Y https://tools.ietf.org/html/rfc7646 → Definition and Use of DNSSEC Negative Trust Anchors +~ https://tools.ietf.org/html/rfc7719 → DNS Terminology + +Also relevant: + + https://www.iab.org/documents/correspondence-reports-documents/2013-2/iab-statement-dotless-domains-considered-harmful/ diff --git a/src/resolve/dns-type.c b/src/resolve/dns-type.c index 63b4b36e8..b2f479cae 100644 --- a/src/resolve/dns-type.c +++ b/src/resolve/dns-type.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,11 @@ along with systemd; If not, see . ***/ +#include + #include "dns-type.h" +#include "parse-util.h" +#include "string-util.h" typedef const struct { uint16_t type; @@ -38,13 +40,267 @@ int dns_type_from_string(const char *s) { assert(s); sc = lookup_dns_type(s, strlen(s)); - if (!sc) - return _DNS_TYPE_INVALID; + if (sc) + return sc->id; - return sc->id; + s = startswith_no_case(s, "TYPE"); + if (s) { + unsigned x; + + if (safe_atou(s, &x) >= 0 && + x <= UINT16_MAX) + return (int) x; + } + + return _DNS_TYPE_INVALID; } -/* XXX: find an authoritative list of all pseudo types? */ -bool dns_type_is_pseudo(int n) { - return IN_SET(n, DNS_TYPE_ANY, DNS_TYPE_AXFR, DNS_TYPE_IXFR, DNS_TYPE_OPT); +bool dns_type_is_pseudo(uint16_t type) { + + /* Checks whether the specified type is a "pseudo-type". What + * a "pseudo-type" precisely is, is defined only very weakly, + * but apparently entails all RR types that are not actually + * stored as RRs on the server and should hence also not be + * cached. We use this list primarily to validate NSEC type + * bitfields, and to verify what to cache. */ + + return IN_SET(type, + 0, /* A Pseudo RR type, according to RFC 2931 */ + DNS_TYPE_ANY, + DNS_TYPE_AXFR, + DNS_TYPE_IXFR, + DNS_TYPE_OPT, + DNS_TYPE_TSIG, + DNS_TYPE_TKEY + ); +} + +bool dns_class_is_pseudo(uint16_t class) { + return class == DNS_TYPE_ANY; +} + +bool dns_type_is_valid_query(uint16_t type) { + + /* The types valid as questions in packets */ + + return !IN_SET(type, + 0, + DNS_TYPE_OPT, + DNS_TYPE_TSIG, + DNS_TYPE_TKEY, + + /* RRSIG are technically valid as questions, but we refuse doing explicit queries for them, as + * they aren't really payload, but signatures for payload, and cannot be validated on their + * own. After all they are the signatures, and have no signatures of their own validating + * them. */ + DNS_TYPE_RRSIG); +} + +bool dns_type_is_valid_rr(uint16_t type) { + + /* The types valid as RR in packets (but not necessarily + * stored on servers). */ + + return !IN_SET(type, + DNS_TYPE_ANY, + DNS_TYPE_AXFR, + DNS_TYPE_IXFR); +} + +bool dns_class_is_valid_rr(uint16_t class) { + return class != DNS_CLASS_ANY; +} + +bool dns_type_may_redirect(uint16_t type) { + /* The following record types should never be redirected using + * CNAME/DNAME RRs. See + * . */ + + if (dns_type_is_pseudo(type)) + return false; + + return !IN_SET(type, + DNS_TYPE_CNAME, + DNS_TYPE_DNAME, + DNS_TYPE_NSEC3, + DNS_TYPE_NSEC, + DNS_TYPE_RRSIG, + DNS_TYPE_NXT, + DNS_TYPE_SIG, + DNS_TYPE_KEY); +} + +bool dns_type_may_wildcard(uint16_t type) { + + /* The following records may not be expanded from wildcard RRsets */ + + if (dns_type_is_pseudo(type)) + return false; + + return !IN_SET(type, + DNS_TYPE_NSEC3, + DNS_TYPE_SOA, + + /* Prohibited by https://tools.ietf.org/html/rfc4592#section-4.4 */ + DNS_TYPE_DNAME); +} + +bool dns_type_apex_only(uint16_t type) { + + /* Returns true for all RR types that may only appear signed in a zone apex */ + + return IN_SET(type, + DNS_TYPE_SOA, + DNS_TYPE_NS, /* this one can appear elsewhere, too, but not signed */ + DNS_TYPE_DNSKEY, + DNS_TYPE_NSEC3PARAM); +} + +bool dns_type_is_dnssec(uint16_t type) { + return IN_SET(type, + DNS_TYPE_DS, + DNS_TYPE_DNSKEY, + DNS_TYPE_RRSIG, + DNS_TYPE_NSEC, + DNS_TYPE_NSEC3, + DNS_TYPE_NSEC3PARAM); +} + +bool dns_type_is_obsolete(uint16_t type) { + return IN_SET(type, + /* Obsoleted by RFC 973 */ + DNS_TYPE_MD, + DNS_TYPE_MF, + DNS_TYPE_MAILA, + + /* Kinda obsoleted by RFC 2505 */ + DNS_TYPE_MB, + DNS_TYPE_MG, + DNS_TYPE_MR, + DNS_TYPE_MINFO, + DNS_TYPE_MAILB, + + /* RFC1127 kinda obsoleted this by recommending against its use */ + DNS_TYPE_WKS, + + /* Declared historical by RFC 6563 */ + DNS_TYPE_A6, + + /* Obsoleted by DNSSEC-bis */ + DNS_TYPE_NXT, + + /* RFC 1035 removed support for concepts that needed this from RFC 883 */ + DNS_TYPE_NULL); +} + +int dns_type_to_af(uint16_t t) { + switch (t) { + + case DNS_TYPE_A: + return AF_INET; + + case DNS_TYPE_AAAA: + return AF_INET6; + + case DNS_TYPE_ANY: + return AF_UNSPEC; + + default: + return -EINVAL; + } +} + +const char *dns_class_to_string(uint16_t class) { + + switch (class) { + + case DNS_CLASS_IN: + return "IN"; + + case DNS_CLASS_ANY: + return "ANY"; + } + + return NULL; +} + +int dns_class_from_string(const char *s) { + + if (!s) + return _DNS_CLASS_INVALID; + + if (strcaseeq(s, "IN")) + return DNS_CLASS_IN; + else if (strcaseeq(s, "ANY")) + return DNS_CLASS_ANY; + + return _DNS_CLASS_INVALID; +} + +const char* tlsa_cert_usage_to_string(uint8_t cert_usage) { + + switch (cert_usage) { + + case 0: + return "CA constraint"; + + case 1: + return "Service certificate constraint"; + + case 2: + return "Trust anchor assertion"; + + case 3: + return "Domain-issued certificate"; + + case 4 ... 254: + return "Unassigned"; + + case 255: + return "Private use"; + } + + return NULL; /* clang cannot count that we covered everything */ +} + +const char* tlsa_selector_to_string(uint8_t selector) { + switch (selector) { + + case 0: + return "Full Certificate"; + + case 1: + return "SubjectPublicKeyInfo"; + + case 2 ... 254: + return "Unassigned"; + + case 255: + return "Private use"; + } + + return NULL; +} + +const char* tlsa_matching_type_to_string(uint8_t selector) { + + switch (selector) { + + case 0: + return "No hash used"; + + case 1: + return "SHA-256"; + + case 2: + return "SHA-512"; + + case 3 ... 254: + return "Unassigned"; + + case 255: + return "Private use"; + } + + return NULL; } diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index 950af36ee..a6c163002 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,10 +21,6 @@ #include "macro.h" -const char *dns_type_to_string(int type); -int dns_type_from_string(const char *s); -bool dns_type_is_pseudo(int n); - /* DNS record types, taken from * http://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml. */ @@ -91,6 +85,7 @@ enum { DNS_TYPE_TALINK, DNS_TYPE_CDS, DNS_TYPE_CDNSKEY, + DNS_TYPE_OPENPGPKEY, DNS_TYPE_SPF = 0x63, DNS_TYPE_NID, @@ -119,3 +114,41 @@ enum { assert_cc(DNS_TYPE_SSHFP == 44); assert_cc(DNS_TYPE_TLSA == 52); assert_cc(DNS_TYPE_ANY == 255); + +/* DNS record classes, see RFC 1035 */ +enum { + DNS_CLASS_IN = 0x01, + DNS_CLASS_ANY = 0xFF, + + _DNS_CLASS_MAX, + _DNS_CLASS_INVALID = -1 +}; + +bool dns_type_is_pseudo(uint16_t type); +bool dns_type_is_valid_query(uint16_t type); +bool dns_type_is_valid_rr(uint16_t type); +bool dns_type_may_redirect(uint16_t type); +bool dns_type_is_dnssec(uint16_t type); +bool dns_type_is_obsolete(uint16_t type); +bool dns_type_may_wildcard(uint16_t type); +bool dns_type_apex_only(uint16_t type); +int dns_type_to_af(uint16_t t); + +bool dns_class_is_pseudo(uint16_t class); +bool dns_class_is_valid_rr(uint16_t class); + +/* TYPE?? follows http://tools.ietf.org/html/rfc3597#section-5 */ +const char *dns_type_to_string(int type); +int dns_type_from_string(const char *s); + +const char *dns_class_to_string(uint16_t type); +int dns_class_from_string(const char *name); + +/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.2 */ +const char *tlsa_cert_usage_to_string(uint8_t cert_usage); + +/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.3 */ +const char *tlsa_selector_to_string(uint8_t selector); + +/* https://tools.ietf.org/html/draft-ietf-dane-protocol-23#section-7.4 */ +const char *tlsa_matching_type_to_string(uint8_t selector); diff --git a/src/resolve/resolve-tool.c b/src/resolve/resolve-tool.c new file mode 100644 index 000000000..824cb267b --- /dev/null +++ b/src/resolve/resolve-tool.c @@ -0,0 +1,1272 @@ +/*** + This file is part of systemd. + + Copyright 2014 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 . +***/ + +#include +#include + +#include "sd-bus.h" + +#include "af-list.h" +#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" +#include "resolved-dns-packet.h" +#include "terminal-util.h" + +#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC) + +static int arg_family = AF_UNSPEC; +static int arg_ifindex = 0; +static uint16_t arg_type = 0; +static uint16_t arg_class = 0; +static bool arg_legend = true; +static uint64_t arg_flags = 0; + +static enum { + MODE_RESOLVE_HOST, + MODE_RESOLVE_RECORD, + MODE_RESOLVE_SERVICE, + MODE_STATISTICS, + MODE_RESET_STATISTICS, +} arg_mode = MODE_RESOLVE_HOST; + +static void print_source(uint64_t flags, usec_t rtt) { + char rtt_str[FORMAT_TIMESTAMP_MAX]; + + if (!arg_legend) + return; + + if (flags == 0) + return; + + fputs("\n-- Information acquired via", stdout); + + if (flags != 0) + printf(" protocol%s%s%s%s%s", + flags & SD_RESOLVED_DNS ? " DNS" :"", + flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "", + flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "", + flags & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4" : "", + flags & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6" : ""); + + assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100)); + + printf(" in %s", rtt_str); + + fputc('.', stdout); + fputc('\n', stdout); + + printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED)); +} + +static int resolve_host(sd_bus *bus, const char *name) { + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + const char *canonical = NULL; + char ifname[IF_NAMESIZE] = ""; + unsigned c = 0; + int r; + uint64_t flags; + usec_t ts; + + assert(name); + + 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); + + log_debug("Resolving %s (family %s, interface %s).", name, 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", + "ResolveHostname"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(req, "isit", arg_ifindex, name, 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, "%s: resolve call failed: %s", name, bus_error_message(&error, r)); + + ts = now(CLOCK_MONOTONIC) - ts; + + 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; + size_t sz; + + 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%s\n", + (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ", + pretty, + isempty(ifname) ? "" : "%", ifname); + + 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, "st", &canonical, &flags); + if (r < 0) + return bus_log_parse_error(r); + + if (!streq(name, canonical)) + printf("%*s%s (%s)\n", + (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ", + canonical); + + if (c == 0) { + log_error("%s: no addresses found", name); + return -ESRCH; + } + + print_source(flags, ts); + + return 0; +} + +static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *pretty = NULL; + char ifname[IF_NAMESIZE] = ""; + uint64_t flags; + unsigned c = 0; + usec_t ts; + int r; + + assert(bus); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(address); + + if (ifindex <= 0) + ifindex = arg_ifindex; + + r = in_addr_to_string(family, address, &pretty); + if (r < 0) + return log_oom(); + + if (ifindex > 0 && !if_indextoname(ifindex, ifname)) + return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); + + log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname); + + r = sd_bus_message_new_method_call( + bus, + &req, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "ResolveAddress"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(req, "ii", ifindex, family); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family)); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(req, "t", 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) { + log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r)); + return r; + } + + ts = now(CLOCK_MONOTONIC) - ts; + + r = sd_bus_message_enter_container(reply, 'a', "(is)"); + if (r < 0) + return bus_log_create_error(r); + + while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) { + const char *n; + + assert_cc(sizeof(int) == sizeof(int32_t)); + + r = sd_bus_message_read(reply, "is", &ifindex, &n); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + ifname[0] = 0; + if (ifindex > 0 && !if_indextoname(ifindex, ifname)) + log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); + + printf("%*s%*s%*s%s %s\n", + (int) strlen(pretty), c == 0 ? pretty : "", + isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%", + (int) strlen(ifname), c == 0 ? ifname : "", + c == 0 ? ":" : " ", + n); + + 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, "t", &flags); + if (r < 0) + return bus_log_parse_error(r); + + if (c == 0) { + log_error("%s: no names found", pretty); + return -ESRCH; + } + + print_source(flags, ts); + + return 0; +} + +static int parse_address(const char *s, int *family, union in_addr_union *address, int *ifindex) { + const char *percent, *a; + int ifi = 0; + int r; + + percent = strchr(s, '%'); + if (percent) { + if (parse_ifindex(percent+1, &ifi) < 0) { + ifi = if_nametoindex(percent+1); + if (ifi <= 0) + return -EINVAL; + } + + a = strndupa(s, percent - s); + } else + a = s; + + r = in_addr_from_string_auto(a, family, address); + if (r < 0) + return r; + + *ifindex = ifi; + return 0; +} + +static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + char ifname[IF_NAMESIZE] = ""; + unsigned n = 0; + uint64_t flags; + int r; + usec_t ts; + + assert(name); + + 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); + + log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(ifname) ? "*" : ifname); + + r = sd_bus_message_new_method_call( + bus, + &req, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "ResolveRecord"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, 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) { + log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r)); + return r; + } + + ts = now(CLOCK_MONOTONIC) - ts; + + r = sd_bus_message_enter_container(reply, 'a', "(iqqay)"); + if (r < 0) + return bus_log_parse_error(r); + + while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + const char *s; + uint16_t c, t; + int ifindex; + const void *d; + size_t l; + + assert_cc(sizeof(int) == sizeof(int32_t)); + + r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_read_array(reply, 'y', &d, &l); + 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 = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); + if (r < 0) + return log_oom(); + + p->refuse_compression = true; + + r = dns_packet_append_blob(p, d, l, NULL); + if (r < 0) + return log_oom(); + + r = dns_packet_read_rr(p, &rr, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to parse RR: %m"); + + s = dns_resource_record_to_string(rr); + if (!s) + return log_oom(); + + ifname[0] = 0; + if (ifindex > 0 && !if_indextoname(ifindex, ifname)) + log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex); + + printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname); + n++; + } + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_message_read(reply, "t", &flags); + if (r < 0) + return bus_log_parse_error(r); + + if (n == 0) { + log_error("%s: no records found", name); + return -ESRCH; + } + + print_source(flags, ts); + + return 0; +} + +static int resolve_rfc4501(sd_bus *bus, const char *name) { + uint16_t type = 0, class = 0; + const char *p, *q, *n; + int r; + + assert(bus); + assert(name); + assert(startswith(name, "dns:")); + + /* Parse RFC 4501 dns: URIs */ + + p = name + 4; + + if (p[0] == '/') { + const char *e; + + if (p[1] != '/') + goto invalid; + + e = strchr(p + 2, '/'); + if (!e) + goto invalid; + + if (e != p + 2) + log_warning("DNS authority specification not supported; ignoring specified authority."); + + p = e + 1; + } + + q = strchr(p, '?'); + if (q) { + n = strndupa(p, q - p); + q++; + + for (;;) { + const char *f; + + f = startswith_no_case(q, "class="); + if (f) { + _cleanup_free_ char *t = NULL; + const char *e; + + if (class != 0) { + log_error("DNS class specified twice."); + return -EINVAL; + } + + e = strchrnul(f, ';'); + t = strndup(f, e - f); + if (!t) + return log_oom(); + + r = dns_class_from_string(t); + if (r < 0) { + log_error("Unknown DNS class %s.", t); + return -EINVAL; + } + + class = r; + + if (*e == ';') { + q = e + 1; + continue; + } + + break; + } + + f = startswith_no_case(q, "type="); + if (f) { + _cleanup_free_ char *t = NULL; + const char *e; + + if (type != 0) { + log_error("DNS type specified twice."); + return -EINVAL; + } + + e = strchrnul(f, ';'); + t = strndup(f, e - f); + if (!t) + return log_oom(); + + r = dns_type_from_string(t); + if (r < 0) { + log_error("Unknown DNS type %s.", t); + return -EINVAL; + } + + type = r; + + if (*e == ';') { + q = e + 1; + continue; + } + + break; + } + + goto invalid; + } + } else + n = p; + + if (type == 0) + type = arg_type; + if (type == 0) + type = DNS_TYPE_A; + + if (class == 0) + class = arg_class; + if (class == 0) + class = DNS_CLASS_IN; + + return resolve_record(bus, n, class, type); + +invalid: + log_error("Invalid DNS URI: %s", name); + return -EINVAL; +} + +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_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; + _cleanup_(sd_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 int show_statistics(sd_bus *bus) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + uint64_t n_current_transactions, n_total_transactions, + cache_size, n_cache_hit, n_cache_miss, + n_dnssec_secure, n_dnssec_insecure, n_dnssec_bogus, n_dnssec_indeterminate; + int r, dnssec_supported; + + assert(bus); + + r = sd_bus_get_property_trivial(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "DNSSECSupported", + &error, + 'b', + &dnssec_supported); + if (r < 0) + return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r)); + + printf("DNSSEC supported by current servers: %s%s%s\n\n", + ansi_highlight(), + yes_no(dnssec_supported), + ansi_normal()); + + r = sd_bus_get_property(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "TransactionStatistics", + &error, + &reply, + "(tt)"); + if (r < 0) + return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r)); + + r = sd_bus_message_read(reply, "(tt)", + &n_current_transactions, + &n_total_transactions); + if (r < 0) + return bus_log_parse_error(r); + + printf("%sTransactions%s\n" + "Current Transactions: %" PRIu64 "\n" + " Total Transactions: %" PRIu64 "\n", + ansi_highlight(), + ansi_normal(), + n_current_transactions, + n_total_transactions); + + reply = sd_bus_message_unref(reply); + + r = sd_bus_get_property(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "CacheStatistics", + &error, + &reply, + "(ttt)"); + if (r < 0) + return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r)); + + r = sd_bus_message_read(reply, "(ttt)", + &cache_size, + &n_cache_hit, + &n_cache_miss); + if (r < 0) + return bus_log_parse_error(r); + + printf("\n%sCache%s\n" + " Current Cache Size: %" PRIu64 "\n" + " Cache Hits: %" PRIu64 "\n" + " Cache Misses: %" PRIu64 "\n", + ansi_highlight(), + ansi_normal(), + cache_size, + n_cache_hit, + n_cache_miss); + + reply = sd_bus_message_unref(reply); + + r = sd_bus_get_property(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "DNSSECStatistics", + &error, + &reply, + "(tttt)"); + if (r < 0) + return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r)); + + r = sd_bus_message_read(reply, "(tttt)", + &n_dnssec_secure, + &n_dnssec_insecure, + &n_dnssec_bogus, + &n_dnssec_indeterminate); + if (r < 0) + return bus_log_parse_error(r); + + printf("\n%sDNSSEC Verdicts%s\n" + " Secure: %" PRIu64 "\n" + " Insecure: %" PRIu64 "\n" + " Bogus: %" PRIu64 "\n" + " Indeterminate: %" PRIu64 "\n", + ansi_highlight(), + ansi_normal(), + n_dnssec_secure, + n_dnssec_insecure, + n_dnssec_bogus, + n_dnssec_indeterminate); + + return 0; +} + +static int reset_statistics(sd_bus *bus) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + r = sd_bus_call_method(bus, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "ResetStatistics", + &error, + NULL, + NULL); + if (r < 0) + return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r)); + + return 0; +} + +static void help_protocol_types(void) { + if (arg_legend) + puts("Known protocol types:"); + puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6"); +} + +static void help_dns_types(void) { + int i; + const char *t; + + if (arg_legend) + puts("Known DNS RR types:"); + for (i = 0; i < _DNS_TYPE_MAX; i++) { + t = dns_type_to_string(i); + if (t) + puts(t); + } +} + +static void help_dns_classes(void) { + int i; + const char *t; + + if (arg_legend) + puts("Known DNS RR classes:"); + for (i = 0; i < _DNS_CLASS_MAX; i++) { + t = dns_class_to_string(i); + if (t) + puts(t); + } +} + +static void help(void) { + printf("%s [OPTIONS...] NAME...\n" + "%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n" + "Resolve domain names, IPv4 and IPv6 addresses, DNS 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=INTERFACE Look on interface\n" + " -p --protocol=PROTOCOL|help Look via protocol\n" + " -t --type=TYPE|help Query RR with DNS type\n" + " -c --class=CLASS|help 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 and meta information\n" + " --statistics Show resolver statistics\n" + " --reset-statistics Reset resolver statistics\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, + ARG_STATISTICS, + ARG_RESET_STATISTICS, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "type", required_argument, NULL, 't' }, + { "class", required_argument, NULL, 'c' }, + { "legend", required_argument, NULL, ARG_LEGEND }, + { "interface", required_argument, NULL, 'i' }, + { "protocol", required_argument, NULL, 'p' }, + { "cname", required_argument, NULL, ARG_CNAME }, + { "service", no_argument, NULL, ARG_SERVICE }, + { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, + { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, + { "search", required_argument, NULL, ARG_SEARCH }, + { "statistics", no_argument, NULL, ARG_STATISTICS, }, + { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS }, + {} + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0) + switch(c) { + + case 'h': + help(); + return 0; /* done */; + + case ARG_VERSION: + return version(); + + case '4': + arg_family = AF_INET; + break; + + case '6': + arg_family = AF_INET6; + break; + + case 'i': { + int ifi; + + if (parse_ifindex(optarg, &ifi) >= 0) + arg_ifindex = ifi; + else { + ifi = if_nametoindex(optarg); + if (ifi <= 0) + return log_error_errno(errno, "Unknown interface %s: %m", optarg); + + arg_ifindex = ifi; + } + + break; + } + + case 't': + if (streq(optarg, "help")) { + help_dns_types(); + return 0; + } + + r = dns_type_from_string(optarg); + if (r < 0) { + log_error("Failed to parse RR record type %s", optarg); + return r; + } + arg_type = (uint16_t) r; + assert((int) arg_type == r); + + arg_mode = MODE_RESOLVE_RECORD; + break; + + case 'c': + if (streq(optarg, "help")) { + help_dns_classes(); + return 0; + } + + r = dns_class_from_string(optarg); + if (r < 0) { + log_error("Failed to parse RR record class %s", optarg); + return r; + } + arg_class = (uint16_t) r; + assert((int) arg_class == r); + + break; + + case ARG_LEGEND: + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --legend= argument"); + + arg_legend = r; + break; + + case 'p': + if (streq(optarg, "help")) { + help_protocol_types(); + return 0; + } else if (streq(optarg, "dns")) + arg_flags |= SD_RESOLVED_DNS; + else if (streq(optarg, "llmnr")) + arg_flags |= SD_RESOLVED_LLMNR; + else if (streq(optarg, "llmnr-ipv4")) + arg_flags |= SD_RESOLVED_LLMNR_IPV4; + else if (streq(optarg, "llmnr-ipv6")) + arg_flags |= SD_RESOLVED_LLMNR_IPV6; + else { + log_error("Unknown protocol specifier: %s", optarg); + return -EINVAL; + } + + break; + + case ARG_SERVICE: + arg_mode = MODE_RESOLVE_SERVICE; + 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 ARG_STATISTICS: + arg_mode = MODE_STATISTICS; + break; + + case ARG_RESET_STATISTICS: + arg_mode = MODE_RESET_STATISTICS; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + + if (arg_type == 0 && arg_class != 0) { + log_error("--class= may only be used in conjunction with --type=."); + return -EINVAL; + } + + if (arg_type != 0 && arg_mode != MODE_RESOLVE_RECORD) { + log_error("--service and --type= may not be combined."); + return -EINVAL; + } + + if (arg_type != 0 && arg_class == 0) + arg_class = DNS_CLASS_IN; + + if (arg_class != 0 && arg_type == 0) + arg_type = DNS_TYPE_A; + + return 1 /* work to do */; +} + +int main(int argc, char **argv) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + int r; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + r = sd_bus_open_system(&bus); + if (r < 0) { + log_error_errno(r, "sd_bus_open_system: %m"); + goto finish; + } + + switch (arg_mode) { + + case MODE_RESOLVE_HOST: + if (optind >= argc) { + log_error("No arguments passed."); + r = -EINVAL; + goto finish; + } + + while (argv[optind]) { + int family, ifindex, k; + union in_addr_union a; + + if (startswith(argv[optind], "dns:")) + k = resolve_rfc4501(bus, argv[optind]); + else { + k = parse_address(argv[optind], &family, &a, &ifindex); + if (k >= 0) + k = resolve_address(bus, family, &a, ifindex); + else + k = resolve_host(bus, argv[optind]); + } + + if (r == 0) + r = k; + + optind++; + } + break; + + case MODE_RESOLVE_RECORD: + if (optind >= argc) { + log_error("No arguments passed."); + r = -EINVAL; + goto finish; + } + + while (argv[optind]) { + int k; + + k = resolve_record(bus, argv[optind], arg_class, arg_type); + if (r == 0) + r = k; + + optind++; + } + break; + + case MODE_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; + } + + break; + + case MODE_STATISTICS: + if (argc > optind) { + log_error("Too many arguments."); + r = -EINVAL; + goto finish; + } + + r = show_statistics(bus); + break; + + case MODE_RESET_STATISTICS: + if (argc > optind) { + log_error("Too many arguments."); + r = -EINVAL; + goto finish; + } + + r = reset_statistics(bus); + break; + } + +finish: + return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index f0a3b607d..fc5e6beca 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -25,21 +23,9 @@ #include "dns-domain.h" #include "resolved-bus.h" #include "resolved-def.h" +#include "resolved-link-bus.h" static int reply_query_state(DnsQuery *q) { - _cleanup_free_ char *ip = NULL; - const char *name; - int r; - - if (q->request_hostname) - name = q->request_hostname; - else { - r = in_addr_to_string(q->request_family, &q->request_address, &ip); - if (r < 0) - return r; - - name = ip; - } switch (q->state) { @@ -55,20 +41,38 @@ static int reply_query_state(DnsQuery *q) { case DNS_TRANSACTION_INVALID_REPLY: return sd_bus_reply_method_errorf(q->request, BUS_ERROR_INVALID_REPLY, "Received invalid reply"); - case DNS_TRANSACTION_RESOURCES: - return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_RESOURCES, "Not enough resources"); + case DNS_TRANSACTION_ERRNO: + return sd_bus_reply_method_errnof(q->request, q->answer_errno, "Lookup failed due to system error: %m"); case DNS_TRANSACTION_ABORTED: return sd_bus_reply_method_errorf(q->request, BUS_ERROR_ABORTED, "Query aborted"); - case DNS_TRANSACTION_FAILURE: { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + case DNS_TRANSACTION_DNSSEC_FAILED: + return sd_bus_reply_method_errorf(q->request, BUS_ERROR_DNSSEC_FAILED, "DNSSEC validation failed: %s", + dnssec_result_to_string(q->answer_dnssec_result)); + + case DNS_TRANSACTION_NO_TRUST_ANCHOR: + return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_TRUST_ANCHOR, "No suitable trust anchor known"); + + case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED: + return sd_bus_reply_method_errorf(q->request, BUS_ERROR_RR_TYPE_UNSUPPORTED, "Server does not support requested resource record type"); + + case DNS_TRANSACTION_NETWORK_DOWN: + return sd_bus_reply_method_errorf(q->request, BUS_ERROR_NETWORK_DOWN, "Network is down"); + + case DNS_TRANSACTION_NOT_FOUND: + /* We return this as NXDOMAIN. This is only generated when a host doesn't implement LLMNR/TCP, and we + * thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */ + return sd_bus_reply_method_errorf(q->request, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q)); + + case DNS_TRANSACTION_RCODE_FAILURE: { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (q->answer_rcode == DNS_RCODE_NXDOMAIN) - sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", name); + sd_bus_error_setf(&error, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q)); else { const char *rc, *n; - char p[3]; /* the rcode is 4 bits long */ + char p[DECIMAL_STR_MAX(q->answer_rcode)]; rc = dns_rcode_to_string(q->answer_rcode); if (!rc) { @@ -77,7 +81,7 @@ static int reply_query_state(DnsQuery *q) { } n = strjoina(_BUS_ERROR_DNS, rc); - sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", name, rc); + sd_bus_error_setf(&error, n, "Could not resolve '%s', server or network returned error %s", dns_query_string(q), rc); } return sd_bus_reply_method_error(q->request, &error); @@ -85,6 +89,7 @@ static int reply_query_state(DnsQuery *q) { case DNS_TRANSACTION_NULL: case DNS_TRANSACTION_PENDING: + case DNS_TRANSACTION_VALIDATING: case DNS_TRANSACTION_SUCCESS: default: assert_not_reached("Impossible state"); @@ -132,11 +137,11 @@ 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_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - unsigned added = 0, i; - int r; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *canonical = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + DnsResourceRecord *rr; + unsigned added = 0; + int ifindex, r; assert(q); @@ -145,6 +150,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_query_string(q)); + goto finish; + } + if (r < 0) + goto finish; + if (r == DNS_QUERY_RESTARTED) /* 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; @@ -153,93 +168,42 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { if (r < 0) goto finish; - if (q->answer) { - answer = dns_answer_ref(q->answer); + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + DnsQuestion *question; - 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) { - /* 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); + question = dns_query_question_for_protocol(q, q->answer_protocol); - continue; - } + r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); + 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; + r = append_address(reply, rr, ifindex); + if (r < 0) + goto finish; - if (!canonical) - canonical = dns_resource_record_ref(answer->items[i].rr); + if (!canonical) + canonical = dns_resource_record_ref(rr); - added ++; - } + 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_query_string(q)); + 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, q->answer_authenticated)); if (r < 0) goto finish; @@ -248,29 +212,29 @@ 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; } static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; + _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL; Manager *m = userdata; const char *hostname; int family, ifindex; @@ -281,6 +245,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,69 +254,54 @@ 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; + r = dns_question_new_address(&question_utf8, family, hostname, false); + if (r < 0) + return r; - if (family != AF_INET6) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + r = dns_question_new_address(&question_idna, family, hostname, true); + if (r < 0) + return r; - 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_query_new(m, &q, question, ifindex, flags); + r = dns_query_new(m, &q, question_utf8, question_idna, ifindex, flags); if (r < 0) return r; q->request = sd_bus_message_ref(message); q->request_family = family; - q->request_hostname = hostname; q->complete = bus_method_resolve_hostname_complete; + q->suppress_unroutable_family = family == AF_UNSPEC; 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; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + DnsQuestion *question; + DnsResourceRecord *rr; + unsigned added = 0; + int ifindex, r; assert(q); @@ -359,6 +310,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_query_string(q)); + goto finish; + } + if (r < 0) + goto finish; + if (r == DNS_QUERY_RESTARTED) /* 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; @@ -367,30 +328,27 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { if (r < 0) goto finish; - if (q->answer) { - answer = dns_answer_ref(q->answer); + question = dns_query_question_for_protocol(q, q->answer_protocol); - 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; + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + r = dns_question_matches_rr(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); - if (r < 0) - goto finish; + r = sd_bus_message_append(reply, "(is)", ifindex, rr->ptr.name); + if (r < 0) + goto finish; - added ++; - } + added ++; } - 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; } @@ -398,7 +356,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { if (r < 0) goto finish; - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); + r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated)); if (r < 0) goto finish; @@ -407,16 +365,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 +384,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,29 +404,15 @@ 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; - - key = dns_resource_key_new_consume(DNS_CLASS_IN, DNS_TYPE_PTR, reverse); - if (!key) - return -ENOMEM; - - reverse = NULL; - - r = dns_question_add(question, key); - if (r < 0) - return r; - - r = dns_query_new(m, &q, question, ifindex, flags); + r = dns_query_new(m, &q, question, question, ifindex, flags|SD_RESOLVED_NO_SEARCH); if (r < 0) return r; @@ -479,21 +423,53 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s 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 int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int ifindex) { + int r; + + assert(m); + assert(rr); + + r = sd_bus_message_open_container(m, 'r', "iqqay"); + if (r < 0) + return r; + + r = sd_bus_message_append(m, "iqq", + ifindex, + rr->key->class, + rr->key->type); + if (r < 0) + return r; + + r = dns_resource_record_to_wire_format(rr, false); + if (r < 0) + return r; + + r = sd_bus_message_append_array(m, 'y', rr->wire_format, rr->wire_format_size); + if (r < 0) + return r; + + 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; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + DnsResourceRecord *rr; + DnsQuestion *question; + unsigned added = 0; + int ifindex; int r; assert(q); @@ -503,6 +479,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_query_string(q)); + goto finish; + } + if (r < 0) + goto finish; + if (r == DNS_QUERY_RESTARTED) /* 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; @@ -511,54 +497,24 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { if (r < 0) goto finish; - if (q->answer) { - answer = dns_answer_ref(q->answer); + question = dns_query_question_for_protocol(q, q->answer_protocol); - for (i = 0; i < answer->n_rrs; i++) { - _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; - size_t start; + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + r = dns_question_matches_rr(question, rr, NULL); + if (r < 0) + goto finish; + if (r == 0) + continue; - r = dns_question_matches_rr(q->question, answer->items[i].rr); - if (r < 0) - goto finish; - if (r == 0) - continue; + r = bus_message_append_rr(reply, rr, ifindex); + if (r < 0) + goto finish; - 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); - if (r < 0) - goto finish; - - added ++; - } + added ++; } 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_query_string(q)); goto finish; } @@ -566,7 +522,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { if (r < 0) goto finish; - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); + r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated)); if (r < 0) goto finish; @@ -575,7 +531,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 +550,24 @@ 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); + if (!dns_type_is_valid_query(type)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified resource record type %" PRIu16 " may not be used in a query.", type); + if (dns_type_is_obsolete(type)) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Specified DNS resource record type %" PRIu16 " is obsolete.", type); + + r = check_ifindex_flags(ifindex, &flags, 0, error); if (r < 0) return r; @@ -618,32 +583,892 @@ 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, 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) { - dns_query_free(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; + DnsQuestion *question; + + if (aux->state != DNS_TRANSACTION_SUCCESS) + continue; + if (aux->auxiliary_result != 0) + continue; + + question = dns_query_question_for_protocol(aux, aux->answer_protocol); + + r = dns_name_equal(dns_question_first_name(question), rr->srv.name); + if (r < 0) + return r; + if (r == 0) + continue; + + DNS_ANSWER_FOREACH(zz, aux->answer) { + + r = dns_question_matches_rr(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; + DnsQuestion *question; + int ifindex; + + if (aux->state != DNS_TRANSACTION_SUCCESS) + continue; + if (aux->auxiliary_result != 0) + continue; + + question = dns_query_question_for_protocol(aux, aux->answer_protocol); + + r = dns_name_equal(dns_question_first_name(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(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; + DnsQuestion *question; + DnsResourceRecord *rr; + unsigned added = 0; + DnsQuery *aux; + 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_query_string(bad)); + 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; + + question = dns_query_question_for_protocol(q, q->answer_protocol); + DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_question_matches_rr(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_query_string(q)); + 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; + + DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_question_matches_rr(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, q->answer_authenticated)); + if (r < 0) + goto finish; + + r = sd_bus_send(q->manager->bus, reply, NULL); + +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 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 == DNS_QUERY_RESTARTED) /* 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, false); + if (r < 0) + return r; + + r = dns_query_new(q->manager, &aux, question, 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) { + bool has_root_domain = false; + DnsResourceRecord *rr; + DnsQuestion *question; + unsigned found = 0; + int ifindex, 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_query_string(q)); + goto finish; + } + if (r < 0) + goto finish; + if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */ + return; + + question = dns_query_question_for_protocol(q, q->answer_protocol); + + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, q->answer) { + r = dns_question_matches_rr(question, rr, NULL); + if (r < 0) + goto finish; + if (r == 0) + continue; + + if (rr->key->type != DNS_TYPE_SRV) + continue; + + if (dns_name_is_root(rr->srv.name)) { + has_root_domain = true; + 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 (has_root_domain && found <= 0) { + /* If there's exactly one SRV RR and it uses + * the root domain as host name, then the + * service is explicitly not offered on the + * domain. Report this as a recognizable + * error. See RFC 2782, Section "Usage + * Rules". */ + r = sd_bus_reply_method_errorf(q->request, BUS_ERROR_NO_SUCH_SERVICE, "'%s' does not provide the requested service", dns_query_string(q)); + goto finish; + } + + 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_query_string(q)); + 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_idna = NULL, *question_utf8 = NULL; + const char *name, *type, *domain; + _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; + + r = dns_question_new_service(&question_utf8, name, type, domain, !(flags & SD_RESOLVED_NO_TXT), false); + if (r < 0) + return r; + + r = dns_question_new_service(&question_idna, name, type, domain, !(flags & SD_RESOLVED_NO_TXT), true); + if (r < 0) + return r; + + r = dns_query_new(m, &q, question_utf8, question_idna, 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; +} + +int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex) { + int r; + + assert(reply); + assert(s); + + r = sd_bus_message_open_container(reply, 'r', with_ifindex ? "iiay" : "iay"); + if (r < 0) + return r; + + if (with_ifindex) { + r = sd_bus_message_append(reply, "i", s->link ? s->link->ifindex : 0); + if (r < 0) + return r; + } + + r = sd_bus_message_append(reply, "i", 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 = bus_dns_server_append(reply, s, true); + if (r < 0) + return r; + + c++; + } + + HASHMAP_FOREACH(l, m->links, i) { + LIST_FOREACH(servers, s, l->dns_servers) { + r = bus_dns_server_append(reply, s, true); + if (r < 0) + return r; + c++; + } + } + + if (c == 0) { + LIST_FOREACH(servers, s, m->fallback_dns_servers) { + r = bus_dns_server_append(reply, s, true); + 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', "(isb)"); + if (r < 0) + return r; + + LIST_FOREACH(domains, d, m->search_domains) { + r = sd_bus_message_append(reply, "(isb)", 0, d->name, d->route_only); + if (r < 0) + return r; + } + + HASHMAP_FOREACH(l, m->links, i) { + LIST_FOREACH(domains, d, l->search_domains) { + r = sd_bus_message_append(reply, "(isb)", l->ifindex, d->name, d->route_only); + if (r < 0) + return r; + } + } + + return sd_bus_message_close_container(reply); +} + +static int bus_property_get_transaction_statistics( + 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; + + assert(reply); + assert(m); + + return sd_bus_message_append(reply, "(tt)", + (uint64_t) hashmap_size(m->dns_transactions), + (uint64_t) m->n_transactions_total); +} + +static int bus_property_get_cache_statistics( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + uint64_t size = 0, hit = 0, miss = 0; + Manager *m = userdata; + DnsScope *s; + + assert(reply); + assert(m); + + LIST_FOREACH(scopes, s, m->dns_scopes) { + size += dns_cache_size(&s->cache); + hit += s->cache.n_hit; + miss += s->cache.n_miss; + } + + return sd_bus_message_append(reply, "(ttt)", size, hit, miss); +} + +static int bus_property_get_dnssec_statistics( + 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; + + assert(reply); + assert(m); + + return sd_bus_message_append(reply, "(tttt)", + (uint64_t) m->n_dnssec_verdict[DNSSEC_SECURE], + (uint64_t) m->n_dnssec_verdict[DNSSEC_INSECURE], + (uint64_t) m->n_dnssec_verdict[DNSSEC_BOGUS], + (uint64_t) m->n_dnssec_verdict[DNSSEC_INDETERMINATE]); +} + +static int bus_property_get_dnssec_supported( + 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; + + assert(reply); + assert(m); + + return sd_bus_message_append(reply, "b", manager_dnssec_supported(m)); +} + +static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + DnsScope *s; + + assert(message); + assert(m); + + LIST_FOREACH(scopes, s, m->dns_scopes) + s->cache.n_hit = s->cache.n_miss = 0; + + m->n_transactions_total = 0; + zero(m->n_dnssec_verdict); + + return sd_bus_reply_method_return(message, NULL); +} + +static int get_any_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) { + Link *l; + + assert(m); + assert(ret); + + if (ifindex <= 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index"); + + l = hashmap_get(m->links, INT_TO_PTR(ifindex)); + if (!l) + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex); + + *ret = l; + return 0; +} + +static int get_unmanaged_link(Manager *m, int ifindex, Link **ret, sd_bus_error *error) { + Link *l; + int r; + + assert(m); + assert(ret); + + r = get_any_link(m, ifindex, &l, error); + if (r < 0) + return r; + + if (l->flags & IFF_LOOPBACK) + return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name); + if (l->is_managed) + return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name); + + *ret = l; + return 0; +} + +static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) { + int ifindex, r; + Link *l; + + assert(m); + assert(message); + assert(handler); + + assert_cc(sizeof(int) == sizeof(int32_t)); + r = sd_bus_message_read(message, "i", &ifindex); + if (r < 0) + return r; + + r = get_unmanaged_link(m, ifindex, &l, error); + if (r < 0) + return r; + + return handler(message, l, error); +} + +static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_dns_servers, error); +} + +static int bus_method_set_link_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_search_domains, error); +} + +static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_llmnr, error); +} + +static int bus_method_set_link_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_mdns, error); +} + +static int bus_method_set_link_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_dnssec, error); +} + +static int bus_method_set_link_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_set_dnssec_negative_trust_anchors, error); +} + +static int bus_method_revert_link(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return call_link_method(userdata, message, bus_link_method_revert, error); +} + +static int bus_method_get_link(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *p = NULL; + Manager *m = userdata; + int r, ifindex; + Link *l; + + assert(message); + assert(m); + + assert_cc(sizeof(int) == sizeof(int32_t)); + r = sd_bus_message_read(message, "i", &ifindex); + if (r < 0) + return r; + + r = get_any_link(m, ifindex, &l, error); + if (r < 0) + return r; + + p = link_bus_path(l); + if (!p) + return -ENOMEM; + + return sd_bus_reply_method_return(message, "o", p); +} + 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("DNS", "a(iiay)", bus_property_get_dns_servers, 0, 0), + SD_BUS_PROPERTY("SearchDomains", "a(isb)", bus_property_get_search_domains, 0, 0), + SD_BUS_PROPERTY("TransactionStatistics", "(tt)", bus_property_get_transaction_statistics, 0, 0), + SD_BUS_PROPERTY("CacheStatistics", "(ttt)", bus_property_get_cache_statistics, 0, 0), + SD_BUS_PROPERTY("DNSSECStatistics", "(tttt)", bus_property_get_dnssec_statistics, 0, 0), + SD_BUS_PROPERTY("DNSSECSupported", "b", bus_property_get_dnssec_supported, 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_METHOD("ResetStatistics", NULL, NULL, bus_method_reset_statistics, 0), + SD_BUS_METHOD("GetLink", "i", "o", bus_method_get_link, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, 0), + SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_search_domains, 0), + SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, 0), + SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, 0), + SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, 0), + SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, 0), + SD_BUS_METHOD("RevertLink", "i", NULL, bus_method_revert_link, 0), + SD_BUS_VTABLE_END, }; @@ -701,6 +1526,7 @@ int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to install bus reconnect time event: %m"); + (void) sd_event_source_set_description(m->bus_retry_event_source, "bus-retry"); return 0; } @@ -708,6 +1534,14 @@ int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to register object: %m"); + r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/resolve1/link", "org.freedesktop.resolve1.Link", link_vtable, link_object_find, m); + if (r < 0) + return log_error_errno(r, "Failed to register link objects: %m"); + + r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/resolve1/link", link_node_enumerator, m); + if (r < 0) + return log_error_errno(r, "Failed to register link enumerator: %m"); + r = sd_bus_request_name(m->bus, "org.freedesktop.resolve1", 0); if (r < 0) return log_error_errno(r, "Failed to register name: %m"); diff --git a/src/resolve/resolved-bus.h b/src/resolve/resolved-bus.h index 1e7289117..f49e1337d 100644 --- a/src/resolve/resolved-bus.h +++ b/src/resolve/resolved-bus.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,3 +22,4 @@ #include "resolved-manager.h" int manager_connect_bus(Manager *m); +int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex); diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 920771955..bb93fbfda 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -27,53 +25,113 @@ #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; - } - - /* Filter out duplicates */ - LIST_FOREACH(servers, s, first) - if (s->family == family && in_addr_equal(family, &s->address, &addr)) { - found = true; - break; - } - - if (found) - continue; - - r = dns_server_new(m, NULL, type, NULL, family, &addr); + r = manager_add_dns_server_by_string(m, type, word); if (r < 0) - return r; + log_warning_errno(r, "Failed to add DNS server address '%s', ignoring.", word); } return 0; } -int config_parse_dnsv( +int manager_add_search_domain_by_string(Manager *m, const char *domain) { + DnsSearchDomain *d; + bool route_only; + int r; + + assert(m); + assert(domain); + + route_only = *domain == '~'; + if (route_only) + domain++; + + if (dns_name_is_root(domain) || streq(domain, "*")) { + route_only = true; + domain = "."; + } + + 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); + else { + r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain); + if (r < 0) + return r; + } + + d->route_only = route_only; + return 0; +} + +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_dns_servers( const char *unit, const char *filename, unsigned line, @@ -95,10 +153,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,11 +167,13 @@ 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_support( +int config_parse_search_domains( const char *unit, const char *filename, unsigned line, @@ -125,34 +185,52 @@ int config_parse_support( void *data, void *userdata) { - Support support, *v = data; + Manager *m = userdata; int r; assert(filename); assert(lvalue); assert(rvalue); + assert(m); - support = support_from_string(rvalue); - if (support < 0) { - r = parse_boolean(rvalue); + 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 support level '%s'. Ignoring.", rvalue); + log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse search domains string '%s'. Ignoring.", rvalue); return 0; } - - support = r ? SUPPORT_YES : SUPPORT_NO; } - *v = support; + /* If we have a manual setting, then we stop reading + * /etc/resolv.conf */ + m->read_resolv_conf = false; + return 0; } 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 b3dbea7b6..e1fd2ccee 100644 --- a/src/resolve/resolved-conf.h +++ b/src/resolve/resolved-conf.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,10 +21,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_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); +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_dnssec(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 086d11120..c4c1915b1 100644 --- a/src/resolve/resolved-def.h +++ b/src/resolve/resolved-def.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,10 +19,20 @@ along with systemd; If not, see . ***/ -#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) +#include -#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_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_MDNS_IPV4 (UINT64_C(1) << 3) +#define SD_RESOLVED_MDNS_IPV6 (UINT64_C(1) << 4) +#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_AUTHENTICATED (UINT64_C(1) << 9) + +#define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6) +#define SD_RESOLVED_MDNS (SD_RESOLVED_MDNS_IPV4|SD_RESOLVED_MDNS_IPV6) + +#define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_MDNS|SD_RESOLVED_LLMNR|SD_RESOLVED_DNS) diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 3cf9c6807..7eb303ab9 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,6 +20,7 @@ #include "alloc-util.h" #include "dns-domain.h" #include "resolved-dns-answer.h" +#include "resolved-dns-dnssec.h" #include "string-util.h" DnsAnswer *dns_answer_new(unsigned n) { @@ -46,6 +45,18 @@ DnsAnswer *dns_answer_ref(DnsAnswer *a) { return a; } +static void dns_answer_flush(DnsAnswer *a) { + DnsResourceRecord *rr; + + if (!a) + return; + + DNS_ANSWER_FOREACH(rr, a) + dns_resource_record_unref(rr); + + a->n_rrs = 0; +} + DnsAnswer *dns_answer_unref(DnsAnswer *a) { if (!a) return NULL; @@ -53,11 +64,7 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a) { assert(a->n_ref > 0); if (a->n_ref == 1) { - unsigned i; - - for (i = 0; i < a->n_rrs; i++) - dns_resource_record_unref(a->items[i].rr); - + dns_answer_flush(a); free(a); } else a->n_ref--; @@ -65,7 +72,39 @@ DnsAnswer *dns_answer_unref(DnsAnswer *a) { return NULL; } -int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex) { +static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) { + assert(rr); + + if (!a) + return -ENOSPC; + + if (a->n_rrs >= a->n_allocated) + return -ENOSPC; + + a->items[a->n_rrs++] = (DnsAnswerItem) { + .rr = dns_resource_record_ref(rr), + .ifindex = ifindex, + .flags = flags, + }; + + return 1; +} + +static int dns_answer_add_raw_all(DnsAnswer *a, DnsAnswer *source) { + DnsResourceRecord *rr; + DnsAnswerFlags flags; + int ifindex, r; + + DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, source) { + r = dns_answer_add_raw(a, rr, ifindex, flags); + if (r < 0) + return r; + } + + return 0; +} + +int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) { unsigned i; int r; @@ -73,6 +112,8 @@ int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex) { if (!a) return -ENOSPC; + if (a->n_ref > 1) + return -EBUSY; for (i = 0; i < a->n_rrs; i++) { if (a->items[i].ifindex != ifindex) @@ -82,27 +123,66 @@ int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex) { if (r < 0) return r; if (r > 0) { - /* Entry already exists, keep the entry with - * the higher RR, or the one with TTL 0 */ + /* Don't mix contradicting TTLs (see below) */ + if ((rr->ttl == 0) != (a->items[i].rr->ttl == 0)) + return -EINVAL; - if (rr->ttl == 0 || (rr->ttl > a->items[i].rr->ttl && a->items[i].rr->ttl != 0)) { + /* Entry already exists, keep the entry with + * the higher RR. */ + if (rr->ttl > a->items[i].rr->ttl) { dns_resource_record_ref(rr); dns_resource_record_unref(a->items[i].rr); a->items[i].rr = rr; } + a->items[i].flags |= flags; return 0; } + + r = dns_resource_key_equal(a->items[i].rr->key, rr->key); + if (r < 0) + return r; + if (r > 0) { + /* There's already an RR of the same RRset in + * place! Let's see if the TTLs more or less + * match. We don't really care if they match + * precisely, but we do care whether one is 0 + * and the other is not. See RFC 2181, Section + * 5.2.*/ + + if ((rr->ttl == 0) != (a->items[i].rr->ttl == 0)) + return -EINVAL; + } } - if (a->n_rrs >= a->n_allocated) - return -ENOSPC; + return dns_answer_add_raw(a, rr, ifindex, flags); +} - a->items[a->n_rrs].rr = dns_resource_record_ref(rr); - a->items[a->n_rrs].ifindex = ifindex; - a->n_rrs++; +static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) { + DnsResourceRecord *rr; + DnsAnswerFlags flags; + int ifindex, r; - return 1; + DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, b) { + r = dns_answer_add(a, rr, ifindex, flags); + if (r < 0) + return r; + } + + return 0; +} + +int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) { + int r; + + assert(a); + assert(rr); + + r = dns_answer_reserve_or_clone(a, 1); + if (r < 0) + return r; + + return dns_answer_add(*a, rr, ifindex, flags); } int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl) { @@ -128,59 +208,204 @@ int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl) { soa->soa.expire = 1; soa->soa.minimum = ttl; - return dns_answer_add(a, soa, 0); + return dns_answer_add(a, soa, 0, DNS_ANSWER_AUTHENTICATED); } -int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key) { - unsigned i; +int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) { + DnsAnswerFlags flags = 0, i_flags; + DnsResourceRecord *i; + bool found = false; int r; assert(key); - if (!a) - return 0; - - for (i = 0; i < a->n_rrs; i++) { - r = dns_resource_key_match_rr(key, a->items[i].rr); + DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) { + r = dns_resource_key_match_rr(key, i, NULL); if (r < 0) return r; - if (r > 0) + if (r == 0) + continue; + + if (!ret_flags) return 1; + + if (found) + flags &= i_flags; + else { + flags = i_flags; + found = true; + } } - return 0; + if (ret_flags) + *ret_flags = flags; + + return found; } -int dns_answer_match_soa(DnsResourceKey *key, DnsResourceKey *soa) { - if (soa->class != DNS_CLASS_IN) - return 0; +int dns_answer_contains_rr(DnsAnswer *a, DnsResourceRecord *rr, DnsAnswerFlags *ret_flags) { + DnsAnswerFlags flags = 0, i_flags; + DnsResourceRecord *i; + bool found = false; + int r; - if (soa->type != DNS_TYPE_SOA) - return 0; + assert(rr); - if (!dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa))) - return 0; + DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) { + r = dns_resource_record_equal(i, rr); + if (r < 0) + return r; + if (r == 0) + continue; - return 1; + if (!ret_flags) + return 1; + + if (found) + flags &= i_flags; + else { + flags = i_flags; + found = true; + } + } + + if (ret_flags) + *ret_flags = flags; + + return found; } -int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret) { - unsigned i; +int dns_answer_contains_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) { + DnsAnswerFlags flags = 0, i_flags; + DnsResourceRecord *i; + bool found = false; + int r; assert(key); - assert(ret); - if (!a) - return 0; + DNS_ANSWER_FOREACH_FLAGS(i, i_flags, a) { + r = dns_resource_key_equal(i->key, key); + if (r < 0) + return r; + if (r == 0) + continue; + + if (!ret_flags) + return true; + + if (found) + flags &= i_flags; + else { + flags = i_flags; + found = true; + } + } + + if (ret_flags) + *ret_flags = flags; + + return found; +} + +int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a) { + DnsResourceRecord *i; + + DNS_ANSWER_FOREACH(i, a) { + if (IN_SET(i->key->type, DNS_TYPE_NSEC, DNS_TYPE_NSEC3)) + return true; + } + + return false; +} + +int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) { + DnsResourceRecord *rr; + int r; + + /* Checks whether the specified answer contains at least one NSEC3 RR in the specified zone */ + + DNS_ANSWER_FOREACH(rr, answer) { + const char *p; + + if (rr->key->type != DNS_TYPE_NSEC3) + continue; + + p = DNS_RESOURCE_KEY_NAME(rr->key); + r = dns_name_parent(&p); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dns_name_equal(p, zone); + if (r != 0) + return r; + } + + return false; +} + +int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) { + DnsResourceRecord *rr, *soa = NULL; + DnsAnswerFlags rr_flags, soa_flags = 0; + int r; + + assert(key); /* For a SOA record we can never find a matching SOA record */ if (key->type == DNS_TYPE_SOA) return 0; - for (i = 0; i < a->n_rrs; i++) { + DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) { + r = dns_resource_key_match_soa(key, rr->key); + if (r < 0) + return r; + if (r > 0) { - if (dns_answer_match_soa(key, a->items[i].rr->key)) { - *ret = a->items[i].rr; + if (soa) { + r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(rr->key), DNS_RESOURCE_KEY_NAME(soa->key)); + if (r < 0) + return r; + if (r > 0) + continue; + } + + soa = rr; + soa_flags = rr_flags; + } + } + + if (!soa) + return 0; + + if (ret) + *ret = soa; + if (flags) + *flags = soa_flags; + + return 1; +} + +int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) { + DnsResourceRecord *rr; + DnsAnswerFlags rr_flags; + int r; + + assert(key); + + /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */ + if (!dns_type_may_redirect(key->type)) + return 0; + + DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) { + r = dns_resource_key_match_cname_or_dname(key, rr->key, NULL); + if (r < 0) + return r; + if (r > 0) { + if (ret) + *ret = rr; + if (flags) + *flags = rr_flags; return 1; } } @@ -188,41 +413,271 @@ int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **r return 0; } -DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b) { - _cleanup_(dns_answer_unrefp) DnsAnswer *ret = NULL; - DnsAnswer *k; +int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret) { + _cleanup_(dns_answer_unrefp) DnsAnswer *k = NULL; + int r; + + assert(ret); + + if (dns_answer_size(a) <= 0) { + *ret = dns_answer_ref(b); + return 0; + } + + if (dns_answer_size(b) <= 0) { + *ret = dns_answer_ref(a); + return 0; + } + + k = dns_answer_new(a->n_rrs + b->n_rrs); + if (!k) + return -ENOMEM; + + r = dns_answer_add_raw_all(k, a); + if (r < 0) + return r; + + r = dns_answer_add_all(k, b); + if (r < 0) + return r; + + *ret = k; + k = NULL; + + return 0; +} + +int dns_answer_extend(DnsAnswer **a, DnsAnswer *b) { + DnsAnswer *merged; + int r; + + assert(a); + + r = dns_answer_merge(*a, b, &merged); + if (r < 0) + return r; + + dns_answer_unref(*a); + *a = merged; + + return 0; +} + +int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) { + bool found = false, other = false; + DnsResourceRecord *rr; unsigned i; int r; - if (a && (!b || b->n_rrs <= 0)) - return dns_answer_ref(a); - if ((!a || a->n_rrs <= 0) && b) - return dns_answer_ref(b); + assert(a); + assert(key); - ret = dns_answer_new((a ? a->n_rrs : 0) + (b ? b->n_rrs : 0)); - if (!ret) - return NULL; + /* Remove all entries matching the specified key from *a */ - if (a) { - for (i = 0; i < a->n_rrs; i++) { - r = dns_answer_add(ret, a->items[i].rr, a->items[i].ifindex); - if (r < 0) - return NULL; - } + DNS_ANSWER_FOREACH(rr, *a) { + r = dns_resource_key_equal(rr->key, key); + if (r < 0) + return r; + if (r > 0) + found = true; + else + other = true; + + if (found && other) + break; } - if (b) { - for (i = 0; i < b->n_rrs; i++) { - r = dns_answer_add(ret, b->items[i].rr, b->items[i].ifindex); - if (r < 0) - return NULL; - } + if (!found) + return 0; + + if (!other) { + *a = dns_answer_unref(*a); /* Return NULL for the empty answer */ + return 1; } - k = ret; - ret = NULL; + if ((*a)->n_ref > 1) { + _cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL; + DnsAnswerFlags flags; + int ifindex; - return k; + copy = dns_answer_new((*a)->n_rrs); + if (!copy) + return -ENOMEM; + + DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) { + r = dns_resource_key_equal(rr->key, key); + if (r < 0) + return r; + if (r > 0) + continue; + + r = dns_answer_add_raw(copy, rr, ifindex, flags); + if (r < 0) + return r; + } + + dns_answer_unref(*a); + *a = copy; + copy = NULL; + + return 1; + } + + /* Only a single reference, edit in-place */ + + i = 0; + for (;;) { + if (i >= (*a)->n_rrs) + break; + + r = dns_resource_key_equal((*a)->items[i].rr->key, key); + if (r < 0) + return r; + if (r > 0) { + /* Kill this entry */ + + dns_resource_record_unref((*a)->items[i].rr); + memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1)); + (*a)->n_rrs --; + continue; + + } else + /* Keep this entry */ + i++; + } + + return 1; +} + +int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) { + bool found = false, other = false; + DnsResourceRecord *rr; + unsigned i; + int r; + + assert(a); + assert(rm); + + /* Remove all entries matching the specified RR from *a */ + + DNS_ANSWER_FOREACH(rr, *a) { + r = dns_resource_record_equal(rr, rm); + if (r < 0) + return r; + if (r > 0) + found = true; + else + other = true; + + if (found && other) + break; + } + + if (!found) + return 0; + + if (!other) { + *a = dns_answer_unref(*a); /* Return NULL for the empty answer */ + return 1; + } + + if ((*a)->n_ref > 1) { + _cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL; + DnsAnswerFlags flags; + int ifindex; + + copy = dns_answer_new((*a)->n_rrs); + if (!copy) + return -ENOMEM; + + DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) { + r = dns_resource_record_equal(rr, rm); + if (r < 0) + return r; + if (r > 0) + continue; + + r = dns_answer_add_raw(copy, rr, ifindex, flags); + if (r < 0) + return r; + } + + dns_answer_unref(*a); + *a = copy; + copy = NULL; + + return 1; + } + + /* Only a single reference, edit in-place */ + + i = 0; + for (;;) { + if (i >= (*a)->n_rrs) + break; + + r = dns_resource_record_equal((*a)->items[i].rr, rm); + if (r < 0) + return r; + if (r > 0) { + /* Kill this entry */ + + dns_resource_record_unref((*a)->items[i].rr); + memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1)); + (*a)->n_rrs --; + continue; + + } else + /* Keep this entry */ + i++; + } + + return 1; +} + +int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags) { + DnsResourceRecord *rr_source; + int ifindex_source, r; + DnsAnswerFlags flags_source; + + assert(a); + assert(key); + + /* Copy all RRs matching the specified key from source into *a */ + + DNS_ANSWER_FOREACH_FULL(rr_source, ifindex_source, flags_source, source) { + + r = dns_resource_key_equal(rr_source->key, key); + if (r < 0) + return r; + if (r == 0) + continue; + + /* Make space for at least one entry */ + r = dns_answer_reserve_or_clone(a, 1); + if (r < 0) + return r; + + r = dns_answer_add(*a, rr_source, ifindex_source, flags_source|or_flags); + if (r < 0) + return r; + } + + return 0; +} + +int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags) { + int r; + + assert(to); + assert(from); + assert(key); + + r = dns_answer_copy_by_key(to, *from, key, or_flags); + if (r < 0) + return r; + + return dns_answer_remove_by_key(from, key); } void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) { @@ -261,6 +716,8 @@ void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) { int dns_answer_reserve(DnsAnswer **a, unsigned n_free) { DnsAnswer *n; + assert(a); + if (n_free <= 0) return 0; @@ -275,6 +732,9 @@ int dns_answer_reserve(DnsAnswer **a, unsigned n_free) { if ((*a)->n_allocated >= ns) return 0; + /* Allocate more than we need */ + ns *= 2; + n = realloc(*a, offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * ns); if (!n) return -ENOMEM; @@ -289,3 +749,110 @@ int dns_answer_reserve(DnsAnswer **a, unsigned n_free) { *a = n; return 0; } + +int dns_answer_reserve_or_clone(DnsAnswer **a, unsigned n_free) { + _cleanup_(dns_answer_unrefp) DnsAnswer *n = NULL; + int r; + + assert(a); + + /* Tries to extend the DnsAnswer object. And if that's not + * possibly, since we are not the sole owner, then allocate a + * new, appropriately sized one. Either way, after this call + * the object will only have a single reference, and has room + * for at least the specified number of RRs. */ + + r = dns_answer_reserve(a, n_free); + if (r != -EBUSY) + return r; + + assert(*a); + + n = dns_answer_new(((*a)->n_rrs + n_free) * 2); + if (!n) + return -ENOMEM; + + r = dns_answer_add_raw_all(n, *a); + if (r < 0) + return r; + + dns_answer_unref(*a); + *a = n; + n = NULL; + + return 0; +} + +void dns_answer_dump(DnsAnswer *answer, FILE *f) { + DnsResourceRecord *rr; + DnsAnswerFlags flags; + int ifindex; + + if (!f) + f = stdout; + + DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) { + const char *t; + + fputc('\t', f); + + t = dns_resource_record_to_string(rr); + if (!t) { + log_oom(); + continue; + } + + fputs(t, f); + + if (ifindex != 0 || flags & (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE|DNS_ANSWER_SHARED_OWNER)) + fputs("\t;", f); + + if (ifindex != 0) + printf(" ifindex=%i", ifindex); + if (flags & DNS_ANSWER_AUTHENTICATED) + fputs(" authenticated", f); + if (flags & DNS_ANSWER_CACHEABLE) + fputs(" cachable", f); + if (flags & DNS_ANSWER_SHARED_OWNER) + fputs(" shared-owner", f); + + fputc('\n', f); + } +} + +bool dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) { + DnsResourceRecord *rr; + int r; + + assert(cname); + + /* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is + * synthesized from it */ + + if (cname->key->type != DNS_TYPE_CNAME) + return 0; + + DNS_ANSWER_FOREACH(rr, a) { + _cleanup_free_ char *n = NULL; + + if (rr->key->type != DNS_TYPE_DNAME) + continue; + if (rr->key->class != cname->key->class) + continue; + + r = dns_name_change_suffix(cname->cname.name, rr->dname.name, DNS_RESOURCE_KEY_NAME(rr->key), &n); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dns_name_equal(n, DNS_RESOURCE_KEY_NAME(cname->key)); + if (r < 0) + return r; + if (r > 0) + return 1; + + } + + return 0; +} diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 044d73b19..8f9c15eab 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,16 +22,26 @@ typedef struct DnsAnswer DnsAnswer; typedef struct DnsAnswerItem DnsAnswerItem; +#include "macro.h" #include "resolved-dns-rr.h" /* A simple array of resource records. We keep track of the * originating ifindex for each RR where that makes sense, so that we * can qualify A and AAAA RRs referring to a local link with the - * right ifindex. */ + * right ifindex. + * + * Note that we usually encode the the empty DnsAnswer object as a simple NULL. */ + +typedef enum DnsAnswerFlags { + DNS_ANSWER_AUTHENTICATED = 1, /* Item has been authenticated */ + DNS_ANSWER_CACHEABLE = 2, /* Item is subject to caching */ + DNS_ANSWER_SHARED_OWNER = 4, /* For mDNS: RRset may be owner by multiple peers */ +} DnsAnswerFlags; struct DnsAnswerItem { DnsResourceRecord *rr; int ifindex; + DnsAnswerFlags flags; }; struct DnsAnswer { @@ -46,15 +54,90 @@ DnsAnswer *dns_answer_new(unsigned n); DnsAnswer *dns_answer_ref(DnsAnswer *a); DnsAnswer *dns_answer_unref(DnsAnswer *a); -int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex); +int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags); +int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags); int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl); -int dns_answer_contains(DnsAnswer *a, DnsResourceKey *key); -int dns_answer_match_soa(DnsResourceKey *key, DnsResourceKey *soa); -int dns_answer_find_soa(DnsAnswer *a, DnsResourceKey *key, DnsResourceRecord **ret); -DnsAnswer *dns_answer_merge(DnsAnswer *a, DnsAnswer *b); +int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *combined_flags); +int dns_answer_contains_rr(DnsAnswer *a, DnsResourceRecord *rr, DnsAnswerFlags *combined_flags); +int dns_answer_contains_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *combined_flags); +int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a); +int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone); + +int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags); +int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags); + +int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret); +int dns_answer_extend(DnsAnswer **a, DnsAnswer *b); + void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local); int dns_answer_reserve(DnsAnswer **a, unsigned n_free); +int dns_answer_reserve_or_clone(DnsAnswer **a, unsigned n_free); + +int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key); +int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rr); + +int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags); +int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags); + +bool dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname); + +static inline unsigned dns_answer_size(DnsAnswer *a) { + return a ? a->n_rrs : 0; +} + +void dns_answer_dump(DnsAnswer *answer, FILE *f); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref); + +#define _DNS_ANSWER_FOREACH(q, kk, a) \ + for (unsigned UNIQ_T(i, q) = ({ \ + (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \ + 0; \ + }); \ + (a) && (UNIQ_T(i, q) < (a)->n_rrs); \ + UNIQ_T(i, q)++, (kk) = (UNIQ_T(i, q) < (a)->n_rrs ? (a)->items[UNIQ_T(i, q)].rr : NULL)) + +#define DNS_ANSWER_FOREACH(kk, a) _DNS_ANSWER_FOREACH(UNIQ, kk, a) + +#define _DNS_ANSWER_FOREACH_IFINDEX(q, kk, ifi, a) \ + for (unsigned UNIQ_T(i, q) = ({ \ + (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \ + (ifi) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].ifindex : 0; \ + 0; \ + }); \ + (a) && (UNIQ_T(i, q) < (a)->n_rrs); \ + UNIQ_T(i, q)++, \ + (kk) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].rr : NULL), \ + (ifi) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].ifindex : 0)) + +#define DNS_ANSWER_FOREACH_IFINDEX(kk, ifindex, a) _DNS_ANSWER_FOREACH_IFINDEX(UNIQ, kk, ifindex, a) + +#define _DNS_ANSWER_FOREACH_FLAGS(q, kk, fl, a) \ + for (unsigned UNIQ_T(i, q) = ({ \ + (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \ + (fl) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].flags : 0; \ + 0; \ + }); \ + (a) && (UNIQ_T(i, q) < (a)->n_rrs); \ + UNIQ_T(i, q)++, \ + (kk) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].rr : NULL), \ + (fl) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].flags : 0)) + +#define DNS_ANSWER_FOREACH_FLAGS(kk, flags, a) _DNS_ANSWER_FOREACH_FLAGS(UNIQ, kk, flags, a) + +#define _DNS_ANSWER_FOREACH_FULL(q, kk, ifi, fl, a) \ + for (unsigned UNIQ_T(i, q) = ({ \ + (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \ + (ifi) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].ifindex : 0; \ + (fl) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].flags : 0; \ + 0; \ + }); \ + (a) && (UNIQ_T(i, q) < (a)->n_rrs); \ + UNIQ_T(i, q)++, \ + (kk) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].rr : NULL), \ + (ifi) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].ifindex : 0), \ + (fl) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].flags : 0)) + +#define DNS_ANSWER_FOREACH_FULL(kk, ifindex, flags, a) _DNS_ANSWER_FOREACH_FULL(UNIQ, kk, ifindex, flags, a) diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 04f64022e..9bcc71724 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,14 +18,18 @@ ***/ #include "alloc-util.h" +#include "dns-domain.h" +#include "resolved-dns-answer.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 +/* Never cache more than 4K entries. RFC 1536, Section 5 suggests to + * leave DNS caches unbounded, but that's crazy. */ +#define CACHE_MAX 4096 -/* We never keep any item longer than 10min in our cache */ -#define CACHE_TTL_MAX_USEC (10 * USEC_PER_MINUTE) +/* We never keep any item longer than 2h in our cache */ +#define CACHE_TTL_MAX_USEC (2 * USEC_PER_HOUR) typedef enum DnsCacheItemType DnsCacheItemType; typedef struct DnsCacheItem DnsCacheItem; @@ -39,13 +41,19 @@ enum DnsCacheItemType { }; struct DnsCacheItem { + DnsCacheItemType type; DnsResourceKey *key; DnsResourceRecord *rr; + usec_t until; - DnsCacheItemType type; - unsigned prioq_idx; + bool authenticated:1; + bool shared_owner:1; + + int ifindex; int owner_family; union in_addr_union owner_address; + + unsigned prioq_idx; LIST_FIELDS(DnsCacheItem, by_key); }; @@ -60,7 +68,7 @@ static void dns_cache_item_free(DnsCacheItem *i) { DEFINE_TRIVIAL_CLEANUP_FUNC(DnsCacheItem*, dns_cache_item_free); -static void dns_cache_item_remove_and_free(DnsCache *c, DnsCacheItem *i) { +static void dns_cache_item_unlink_and_free(DnsCache *c, DnsCacheItem *i) { DnsCacheItem *first; assert(c); @@ -81,13 +89,49 @@ static void dns_cache_item_remove_and_free(DnsCache *c, DnsCacheItem *i) { dns_cache_item_free(i); } +static bool dns_cache_remove_by_rr(DnsCache *c, DnsResourceRecord *rr) { + DnsCacheItem *first, *i; + int r; + + first = hashmap_get(c->by_key, rr->key); + LIST_FOREACH(by_key, i, first) { + r = dns_resource_record_equal(i->rr, rr); + if (r < 0) + return r; + if (r > 0) { + dns_cache_item_unlink_and_free(c, i); + return true; + } + } + + return false; +} + +static bool dns_cache_remove_by_key(DnsCache *c, DnsResourceKey *key) { + DnsCacheItem *first, *i, *n; + + assert(c); + assert(key); + + first = hashmap_remove(c->by_key, key); + if (!first) + return false; + + LIST_FOREACH_SAFE(by_key, i, n, first) { + prioq_remove(c->by_expiry, i, &i->prioq_idx); + dns_cache_item_free(i); + } + + return true; +} + void dns_cache_flush(DnsCache *c) { - DnsCacheItem *i; + DnsResourceKey *key; assert(c); - while ((i = hashmap_first(c->by_key))) - dns_cache_item_remove_and_free(c, i); + while ((key = hashmap_first_key(c->by_key))) + dns_cache_remove_by_key(c, key); assert(hashmap_size(c->by_key) == 0); assert(prioq_size(c->by_expiry) == 0); @@ -96,21 +140,6 @@ void dns_cache_flush(DnsCache *c) { c->by_expiry = prioq_free(c->by_expiry); } -static bool dns_cache_remove(DnsCache *c, DnsResourceKey *key) { - DnsCacheItem *i; - bool exist = false; - - assert(c); - assert(key); - - while ((i = hashmap_get(c->by_key, key))) { - dns_cache_item_remove_and_free(c, i); - exist = true; - } - - return exist; -} - static void dns_cache_make_space(DnsCache *c, unsigned add) { assert(c); @@ -138,7 +167,7 @@ static void dns_cache_make_space(DnsCache *c, unsigned add) { /* Take an extra reference to the key so that it * doesn't go away in the middle of the remove call */ key = dns_resource_key_ref(i->key); - dns_cache_remove(c, key); + dns_cache_remove_by_key(c, key); } } @@ -150,7 +179,6 @@ void dns_cache_prune(DnsCache *c) { /* Remove all entries that are past their TTL */ for (;;) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; DnsCacheItem *i; i = prioq_peek(c->by_expiry); @@ -163,10 +191,19 @@ void dns_cache_prune(DnsCache *c) { if (i->until > t) break; - /* Take an extra reference to the key so that it - * doesn't go away in the middle of the remove call */ - key = dns_resource_key_ref(i->key); - dns_cache_remove(c, key); + /* Depending whether this is an mDNS shared entry + * either remove only this one RR or the whole + * RRset */ + if (i->shared_owner) + dns_cache_item_unlink_and_free(c, i); + else { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + /* Take an extra reference to the key so that it + * doesn't go away in the middle of the remove call */ + key = dns_resource_key_ref(i->key); + dns_cache_remove_by_key(c, key); + } } } @@ -209,6 +246,19 @@ static int dns_cache_link_item(DnsCache *c, DnsCacheItem *i) { first = hashmap_get(c->by_key, i->key); if (first) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL; + + /* Keep a reference to the original key, while we manipulate the list. */ + k = dns_resource_key_ref(first->key); + + /* Now, try to reduce the number of keys we keep */ + dns_resource_key_reduce(&first->key, &i->key); + + if (first->rr) + dns_resource_key_reduce(&first->rr->key, &i->key); + if (i->rr) + dns_resource_key_reduce(&i->rr->key, &i->key); + LIST_PREPEND(by_key, first, i); assert_se(hashmap_replace(c->by_key, first->key, first) >= 0); } else { @@ -235,10 +285,57 @@ static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) { return NULL; } -static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsResourceRecord *rr, usec_t timestamp) { +static usec_t calculate_until(DnsResourceRecord *rr, uint32_t nsec_ttl, usec_t timestamp, bool use_soa_minimum) { + uint32_t ttl; + usec_t u; + + assert(rr); + + ttl = MIN(rr->ttl, nsec_ttl); + if (rr->key->type == DNS_TYPE_SOA && use_soa_minimum) { + /* If this is a SOA RR, and it is requested, clamp to + * the SOA's minimum field. This is used when we do + * negative caching, to determine the TTL for the + * negative caching entry. See RFC 2308, Section + * 5. */ + + if (ttl > rr->soa.minimum) + ttl = rr->soa.minimum; + } + + u = ttl * USEC_PER_SEC; + if (u > CACHE_TTL_MAX_USEC) + u = CACHE_TTL_MAX_USEC; + + if (rr->expiry != USEC_INFINITY) { + usec_t left; + + /* Make use of the DNSSEC RRSIG expiry info, if we + * have it */ + + left = LESS_BY(rr->expiry, now(CLOCK_REALTIME)); + if (u > left) + u = left; + } + + return timestamp + u; +} + +static void dns_cache_item_update_positive( + DnsCache *c, + DnsCacheItem *i, + DnsResourceRecord *rr, + bool authenticated, + bool shared_owner, + usec_t timestamp, + int ifindex, + int owner_family, + const union in_addr_union *owner_address) { + assert(c); assert(i); assert(rr); + assert(owner_address); i->type = DNS_CACHE_POSITIVE; @@ -255,7 +352,14 @@ static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsReso dns_resource_key_unref(i->key); i->key = dns_resource_key_ref(rr->key); - i->until = timestamp + MIN(rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC); + i->until = calculate_until(rr, (uint32_t) -1, timestamp, false); + i->authenticated = authenticated; + i->shared_owner = shared_owner; + + i->ifindex = ifindex; + + i->owner_family = owner_family; + i->owner_address = *owner_address; prioq_reshuffle(c->by_expiry, i, &i->prioq_idx); } @@ -263,42 +367,59 @@ static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsReso static int dns_cache_put_positive( DnsCache *c, DnsResourceRecord *rr, + bool authenticated, + bool shared_owner, usec_t timestamp, + int ifindex, int owner_family, const union in_addr_union *owner_address) { _cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL; _cleanup_free_ char *key_str = NULL; DnsCacheItem *existing; - int r; + int r, k; assert(c); assert(rr); assert(owner_address); - /* New TTL is 0? Delete the entry... */ - if (rr->ttl <= 0) { - r = dns_resource_key_to_string(rr->key, &key_str); - if (r < 0) - return r; + /* Never cache pseudo RRs */ + if (dns_class_is_pseudo(rr->key->class)) + return 0; + if (dns_type_is_pseudo(rr->key->type)) + return 0; - if (dns_cache_remove(c, rr->key)) - log_debug("Removed zero TTL entry from cache: %s", key_str); - else - log_debug("Not caching zero TTL cache entry: %s", key_str); + /* New TTL is 0? Delete this specific entry... */ + if (rr->ttl <= 0) { + k = dns_cache_remove_by_rr(c, rr); + + if (log_get_max_level() >= LOG_DEBUG) { + r = dns_resource_key_to_string(rr->key, &key_str); + if (r < 0) + return r; + + if (k > 0) + log_debug("Removed zero TTL entry from cache: %s", key_str); + else + log_debug("Not caching zero TTL cache entry: %s", key_str); + } return 0; } - if (rr->key->class == DNS_CLASS_ANY) - return 0; - if (rr->key->type == DNS_TYPE_ANY) - return 0; - - /* Entry exists already? Update TTL and timestamp */ + /* Entry exists already? Update TTL, timestamp and owner*/ existing = dns_cache_get(c, rr); if (existing) { - dns_cache_item_update_positive(c, existing, rr, timestamp); + dns_cache_item_update_positive( + c, + existing, + rr, + authenticated, + shared_owner, + timestamp, + ifindex, + owner_family, + owner_address); return 0; } @@ -316,20 +437,25 @@ static int dns_cache_put_positive( i->type = DNS_CACHE_POSITIVE; i->key = dns_resource_key_ref(rr->key); i->rr = dns_resource_record_ref(rr); - i->until = timestamp + MIN(i->rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC); - i->prioq_idx = PRIOQ_IDX_NULL; + i->until = calculate_until(rr, (uint32_t) -1, timestamp, false); + i->authenticated = authenticated; + i->shared_owner = shared_owner; + i->ifindex = ifindex; i->owner_family = owner_family; i->owner_address = *owner_address; + i->prioq_idx = PRIOQ_IDX_NULL; r = dns_cache_link_item(c, i); if (r < 0) return r; - r = dns_resource_key_to_string(i->key, &key_str); - if (r < 0) - return r; + if (log_get_max_level() >= LOG_DEBUG) { + r = dns_resource_key_to_string(i->key, &key_str); + if (r < 0) + return r; - log_debug("Added cache entry for %s", key_str); + log_debug("Added positive cache entry for %s", key_str); + } i = NULL; return 0; @@ -339,8 +465,10 @@ static int dns_cache_put_negative( DnsCache *c, DnsResourceKey *key, int rcode, + bool authenticated, + uint32_t nsec_ttl, usec_t timestamp, - uint32_t soa_ttl, + DnsResourceRecord *soa, int owner_family, const union in_addr_union *owner_address) { @@ -350,20 +478,25 @@ static int dns_cache_put_negative( assert(c); assert(key); + assert(soa); assert(owner_address); - dns_cache_remove(c, key); - - if (key->class == DNS_CLASS_ANY) + /* Never cache pseudo RR keys. DNS_TYPE_ANY is particularly + * important to filter out as we use this as a pseudo-type for + * NXDOMAIN entries */ + if (dns_class_is_pseudo(key->class)) return 0; - if (key->type == DNS_TYPE_ANY) + if (dns_type_is_pseudo(key->type)) return 0; - if (soa_ttl <= 0) { - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; - log_debug("Not caching negative entry with zero SOA TTL: %s", key_str); + if (nsec_ttl <= 0 || soa->soa.minimum <= 0 || soa->ttl <= 0) { + if (log_get_max_level() >= LOG_DEBUG) { + r = dns_resource_key_to_string(key, &key_str); + if (r < 0) + return r; + + log_debug("Not caching negative entry with zero SOA/NSEC/NSEC3 TTL: %s", key_str); + } return 0; } @@ -382,63 +515,139 @@ static int dns_cache_put_negative( return -ENOMEM; i->type = rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA : DNS_CACHE_NXDOMAIN; - i->key = dns_resource_key_ref(key); - i->until = timestamp + MIN(soa_ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC); - i->prioq_idx = PRIOQ_IDX_NULL; + i->until = calculate_until(soa, nsec_ttl, timestamp, true); + i->authenticated = authenticated; i->owner_family = owner_family; i->owner_address = *owner_address; + i->prioq_idx = PRIOQ_IDX_NULL; + + if (i->type == DNS_CACHE_NXDOMAIN) { + /* NXDOMAIN entries should apply equally to all types, so we use ANY as + * a pseudo type for this purpose here. */ + i->key = dns_resource_key_new(key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(key)); + if (!i->key) + return -ENOMEM; + + /* Make sure to remove any previous entry for this + * specific ANY key. (For non-ANY keys the cache data + * is already cleared by the caller.) Note that we + * don't bother removing positive or NODATA cache + * items in this case, because it would either be slow + * or require explicit indexing by name */ + dns_cache_remove_by_key(c, key); + } else + i->key = dns_resource_key_ref(key); r = dns_cache_link_item(c, i); if (r < 0) return r; - r = dns_resource_key_to_string(i->key, &key_str); - if (r < 0) - return r; + if (log_get_max_level() >= LOG_DEBUG) { + r = dns_resource_key_to_string(i->key, &key_str); + if (r < 0) + return r; - log_debug("Added %s cache entry for %s", i->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", key_str); + log_debug("Added %s cache entry for %s", i->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", key_str); + } i = NULL; return 0; } +static void dns_cache_remove_previous( + DnsCache *c, + DnsResourceKey *key, + DnsAnswer *answer) { + + DnsResourceRecord *rr; + DnsAnswerFlags flags; + + assert(c); + + /* First, if we were passed a key (i.e. on LLMNR/DNS, but + * not on mDNS), delete all matching old RRs, so that we only + * keep complete by_key in place. */ + if (key) + dns_cache_remove_by_key(c, key); + + /* Second, flush all entries matching the answer, unless this + * is an RR that is explicitly marked to be "shared" between + * peers (i.e. mDNS RRs without the flush-cache bit set). */ + DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) { + if ((flags & DNS_ANSWER_CACHEABLE) == 0) + continue; + + if (flags & DNS_ANSWER_SHARED_OWNER) + continue; + + dns_cache_remove_by_key(c, rr->key); + } +} + +static bool rr_eligible(DnsResourceRecord *rr) { + assert(rr); + + /* When we see an NSEC/NSEC3 RR, we'll only cache it if it is from the lower zone, not the upper zone, since + * that's where the interesting bits are (with exception of DS RRs). Of course, this way we cannot derive DS + * existence from any cached NSEC/NSEC3, but that should be fine. */ + + switch (rr->key->type) { + + case DNS_TYPE_NSEC: + return !bitmap_isset(rr->nsec.types, DNS_TYPE_NS) || + bitmap_isset(rr->nsec.types, DNS_TYPE_SOA); + + case DNS_TYPE_NSEC3: + return !bitmap_isset(rr->nsec3.types, DNS_TYPE_NS) || + bitmap_isset(rr->nsec3.types, DNS_TYPE_SOA); + + default: + return true; + } +} + int dns_cache_put( DnsCache *c, DnsResourceKey *key, int rcode, DnsAnswer *answer, - unsigned max_rrs, + bool authenticated, + uint32_t nsec_ttl, usec_t timestamp, int owner_family, const union in_addr_union *owner_address) { - DnsResourceRecord *soa = NULL; - unsigned cache_keys, i; - int r; + DnsResourceRecord *soa = NULL, *rr; + DnsAnswerFlags flags; + unsigned cache_keys; + int r, ifindex; assert(c); + assert(owner_address); - if (key) { - /* First, if we were passed a key, delete all matching old RRs, - * so that we only keep complete by_key in place. */ - dns_cache_remove(c, key); - } + dns_cache_remove_previous(c, key, answer); + + if (dns_answer_size(answer) <= 0) { + if (log_get_max_level() >= LOG_DEBUG) { + _cleanup_free_ char *key_str = NULL; + + r = dns_resource_key_to_string(key, &key_str); + if (r < 0) + return r; + + log_debug("Not caching negative entry without a SOA record: %s", key_str); + } - if (!answer) return 0; - - for (i = 0; i < answer->n_rrs; i++) - dns_cache_remove(c, answer->items[i].rr->key); + } /* We only care for positive replies and NXDOMAINs, on all * other replies we will simply flush the respective entries, * and that's it */ - if (!IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)) return 0; - cache_keys = answer->n_rrs; - + cache_keys = dns_answer_size(answer); if (key) cache_keys ++; @@ -449,58 +658,70 @@ int dns_cache_put( timestamp = now(clock_boottime_or_monotonic()); /* Second, add in positive entries for all contained RRs */ - for (i = 0; i < MIN(max_rrs, answer->n_rrs); i++) { - r = dns_cache_put_positive(c, answer->items[i].rr, timestamp, owner_family, owner_address); + DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) { + if ((flags & DNS_ANSWER_CACHEABLE) == 0) + continue; + + r = rr_eligible(rr); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dns_cache_put_positive( + c, + rr, + flags & DNS_ANSWER_AUTHENTICATED, + flags & DNS_ANSWER_SHARED_OWNER, + timestamp, + ifindex, + owner_family, owner_address); if (r < 0) goto fail; } - if (!key) + if (!key) /* mDNS doesn't know negative caching, really */ return 0; /* Third, add in negative entries if the key has no RR */ - r = dns_answer_contains(answer, key); + r = dns_answer_match_key(answer, key, NULL); if (r < 0) goto fail; if (r > 0) return 0; - /* See https://tools.ietf.org/html/rfc2308, which - * say that a matching SOA record in the packet - * is used to to enable negative caching. */ + /* But not if it has a matching CNAME/DNAME (the negative + * caching will be done on the canonical name, not on the + * alias) */ + r = dns_answer_find_cname_or_dname(answer, key, NULL, NULL); + if (r < 0) + goto fail; + if (r > 0) + return 0; - r = dns_answer_find_soa(answer, key, &soa); + /* See https://tools.ietf.org/html/rfc2308, which say that a + * matching SOA record in the packet is used to to enable + * negative caching. */ + r = dns_answer_find_soa(answer, key, &soa, &flags); if (r < 0) goto fail; if (r == 0) return 0; - /* Also, if the requested key is an alias, the negative response should - be cached for each name in the redirect chain. Any CNAME record in - the response is from the redirection chain, though only the final one - is guaranteed to be included. This means that we cannot verify the - chain and that we need to cache them all as it may be incomplete. */ - for (i = 0; i < answer->n_rrs; i++) { - DnsResourceRecord *answer_rr = answer->items[i].rr; + /* Refuse using the SOA data if it is unsigned, but the key is + * signed */ + if (authenticated && (flags & DNS_ANSWER_AUTHENTICATED) == 0) + return 0; - if (answer_rr->key->type == DNS_TYPE_CNAME) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *canonical_key = NULL; - - canonical_key = dns_resource_key_new_redirect(key, answer_rr); - if (!canonical_key) - goto fail; - - /* Let's not add negative cache entries for records outside the current zone. */ - if (!dns_answer_match_soa(canonical_key, soa->key)) - continue; - - r = dns_cache_put_negative(c, canonical_key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address); - if (r < 0) - goto fail; - } - } - - r = dns_cache_put_negative(c, key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address); + r = dns_cache_put_negative( + c, + key, + rcode, + authenticated, + nsec_ttl, + timestamp, + soa, + owner_family, owner_address); if (r < 0) goto fail; @@ -511,75 +732,122 @@ fail: * added, just in case */ if (key) - dns_cache_remove(c, key); + dns_cache_remove_by_key(c, key); - for (i = 0; i < answer->n_rrs; i++) - dns_cache_remove(c, answer->items[i].rr->key); + DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) { + if ((flags & DNS_ANSWER_CACHEABLE) == 0) + continue; + + dns_cache_remove_by_key(c, rr->key); + } return r; } -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; +static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, DnsResourceKey *k) { + 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) return i; - /* check if we have a CNAME record instead */ - cname_key = dns_resource_key_new_cname(k); - if (!cname_key) - return NULL; + n = DNS_RESOURCE_KEY_NAME(k); - j = hashmap_get(c->by_key, cname_key); - if (j) - return j; + /* Check if we have an NXDOMAIN cache item for the name, notice that we use + * the pseudo-type ANY for NXDOMAIN cache items. */ + i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_ANY, n)); + if (i && i->type == DNS_CACHE_NXDOMAIN) + return i; - return i; + if (dns_type_may_redirect(k->type)) { + /* Check if we have a CNAME record instead */ + i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_CNAME, n)); + if (i) + return i; + + /* OK, let's look for cached DNAME records. */ + for (;;) { + if (isempty(n)) + return NULL; + + i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_DNAME, n)); + if (i) + return i; + + /* Jump one label ahead */ + r = dns_name_parent(&n); + if (r <= 0) + return NULL; + } + } + + if (k->type != DNS_TYPE_NSEC) { + /* Check if we have an NSEC record instead for the name. */ + i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_NSEC, n)); + if (i) + return i; + } + + return NULL; } -int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret) { +int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret, bool *authenticated) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; unsigned n = 0; int r; bool nxdomain = false; _cleanup_free_ char *key_str = NULL; - DnsCacheItem *j, *first; + DnsCacheItem *j, *first, *nsec = NULL; + bool have_authenticated = false, have_non_authenticated = false; assert(c); assert(key); assert(rcode); assert(ret); + assert(authenticated); if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) { - /* If we have ANY lookups we simply refresh */ + /* If we have ANY lookups we don't use the cache, so + * that the caller refreshes via the network. */ - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; + if (log_get_max_level() >= LOG_DEBUG) { + r = dns_resource_key_to_string(key, &key_str); + if (r < 0) + return r; - log_debug("Ignoring cache for ANY lookup: %s", key_str); + log_debug("Ignoring cache for ANY lookup: %s", key_str); + } + + c->n_miss++; *ret = NULL; *rcode = DNS_RCODE_SUCCESS; return 0; } - first = dns_cache_get_by_key_follow_cname(c, key); + first = dns_cache_get_by_key_follow_cname_dname_nsec(c, key); if (!first) { /* If one question cannot be answered we need to refresh */ - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; + if (log_get_max_level() >= LOG_DEBUG) { + r = dns_resource_key_to_string(key, &key_str); + if (r < 0) + return r; - log_debug("Cache miss for %s", key_str); + log_debug("Cache miss for %s", key_str); + } + + c->n_miss++; *ret = NULL; *rcode = DNS_RCODE_SUCCESS; @@ -587,24 +855,68 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r } LIST_FOREACH(by_key, j, first) { - if (j->rr) + if (j->rr) { + if (j->rr->key->type == DNS_TYPE_NSEC) + nsec = j; + n++; - else if (j->type == DNS_CACHE_NXDOMAIN) + } else if (j->type == DNS_CACHE_NXDOMAIN) nxdomain = true; + + if (j->authenticated) + have_authenticated = true; + else + have_non_authenticated = true; } - r = dns_resource_key_to_string(key, &key_str); - if (r < 0) - return r; + if (nsec && !IN_SET(key->type, DNS_TYPE_NSEC, DNS_TYPE_DS)) { + /* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC RRs from + * the lower-zone of a zone cut, but the DS RRs are on the upper zone. */ - log_debug("%s cache hit for %s", - nxdomain ? "NXDOMAIN" : - n > 0 ? "Positive" : "NODATA", - key_str); + if (log_get_max_level() >= LOG_DEBUG) { + r = dns_resource_key_to_string(key, &key_str); + if (r < 0) + return r; + + log_debug("NSEC NODATA cache hit for %s", key_str); + } + + /* We only found an NSEC record that matches our name. + * If it says the type doesn't exist report + * NODATA. Otherwise report a cache miss. */ + + *ret = NULL; + *rcode = DNS_RCODE_SUCCESS; + *authenticated = nsec->authenticated; + + if (!bitmap_isset(nsec->rr->nsec.types, key->type) && + !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_CNAME) && + !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_DNAME)) { + c->n_hit++; + return 1; + } + + c->n_miss++; + return 0; + } + + if (log_get_max_level() >= LOG_DEBUG) { + r = dns_resource_key_to_string(key, &key_str); + if (r < 0) + return r; + + log_debug("%s cache hit for %s", + n > 0 ? "Positive" : + nxdomain ? "NXDOMAIN" : "NODATA", + key_str); + } if (n <= 0) { + c->n_hit++; + *ret = NULL; *rcode = nxdomain ? DNS_RCODE_NXDOMAIN : DNS_RCODE_SUCCESS; + *authenticated = have_authenticated && !have_non_authenticated; return 1; } @@ -616,13 +928,16 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r if (!j->rr) continue; - r = dns_answer_add(answer, j->rr, 0); + r = dns_answer_add(answer, j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0); if (r < 0) return r; } + c->n_hit++; + *ret = answer; *rcode = DNS_RCODE_SUCCESS; + *authenticated = have_authenticated && !have_non_authenticated; answer = NULL; return n; @@ -664,6 +979,55 @@ int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_ return 1; } +int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { + unsigned ancount = 0; + Iterator iterator; + DnsCacheItem *i; + int r; + + assert(cache); + assert(p); + + HASHMAP_FOREACH(i, cache->by_key, iterator) { + DnsCacheItem *j; + + LIST_FOREACH(by_key, j, i) { + if (!j->rr) + continue; + + if (!j->shared_owner) + continue; + + r = dns_packet_append_rr(p, j->rr, NULL, NULL); + if (r == -EMSGSIZE && p->protocol == DNS_PROTOCOL_MDNS) { + /* For mDNS, if we're unable to stuff all known answers into the given packet, + * allocate a new one, push the RR into that one and link it to the current one. + */ + + DNS_PACKET_HEADER(p)->ancount = htobe16(ancount); + ancount = 0; + + r = dns_packet_new_query(&p->more, p->protocol, 0, true); + if (r < 0) + return r; + + /* continue with new packet */ + p = p->more; + r = dns_packet_append_rr(p, j->rr, NULL, NULL); + } + + if (r < 0) + return r; + + ancount ++; + } + } + + DNS_PACKET_HEADER(p)->ancount = htobe16(ancount); + + return 0; +} + void dns_cache_dump(DnsCache *cache, FILE *f) { Iterator iterator; DnsCacheItem *i; @@ -679,13 +1043,13 @@ void dns_cache_dump(DnsCache *cache, FILE *f) { DnsCacheItem *j; LIST_FOREACH(by_key, j, i) { - _cleanup_free_ char *t = NULL; fputc('\t', f); if (j->rr) { - r = dns_resource_record_to_string(j->rr, &t); - if (r < 0) { + const char *t; + t = dns_resource_record_to_string(j->rr); + if (!t) { log_oom(); continue; } @@ -693,13 +1057,14 @@ void dns_cache_dump(DnsCache *cache, FILE *f) { fputs(t, f); fputc('\n', f); } else { - r = dns_resource_key_to_string(j->key, &t); + _cleanup_free_ char *z = NULL; + r = dns_resource_key_to_string(j->key, &z); if (r < 0) { log_oom(); continue; } - fputs(t, f); + fputs(z, f); fputs(" -- ", f); fputs(j->type == DNS_CACHE_NODATA ? "NODATA" : "NXDOMAIN", f); fputc('\n', f); @@ -714,3 +1079,10 @@ bool dns_cache_is_empty(DnsCache *cache) { return hashmap_isempty(cache->by_key); } + +unsigned dns_cache_size(DnsCache *cache) { + if (!cache) + return 0; + + return hashmap_size(cache->by_key); +} diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index 60cf6a478..2293718e8 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,28 +19,34 @@ along with systemd; If not, see . ***/ - #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; + unsigned n_hit; + unsigned n_miss; } DnsCache; -#include "resolved-dns-rr.h" -#include "resolved-dns-question.h" #include "resolved-dns-answer.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-question.h" +#include "resolved-dns-rr.h" void dns_cache_flush(DnsCache *c); void dns_cache_prune(DnsCache *c); -int dns_cache_put(DnsCache *c, DnsResourceKey *key, int rcode, DnsAnswer *answer, unsigned max_rrs, usec_t timestamp, int owner_family, const union in_addr_union *owner_address); -int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **answer); +int dns_cache_put(DnsCache *c, DnsResourceKey *key, int rcode, DnsAnswer *answer, bool authenticated, uint32_t nsec_ttl, usec_t timestamp, int owner_family, const union in_addr_union *owner_address); +int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **answer, bool *authenticated); int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address); void dns_cache_dump(DnsCache *cache, FILE *f); bool dns_cache_is_empty(DnsCache *cache); + +unsigned dns_cache_size(DnsCache *cache); + +int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p); diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c new file mode 100644 index 000000000..7123d2d3a --- /dev/null +++ b/src/resolve/resolved-dns-dnssec.c @@ -0,0 +1,2211 @@ +/*** + 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 . +***/ + +#ifdef HAVE_GCRYPT +#include +#endif + +#include "alloc-util.h" +#include "dns-domain.h" +#include "hexdecoct.h" +#include "resolved-dns-dnssec.h" +#include "resolved-dns-packet.h" +#include "string-table.h" + +#define VERIFY_RRS_MAX 256 +#define MAX_KEY_SIZE (32*1024) + +/* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */ +#define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE) + +/* Maximum number of NSEC3 iterations we'll do. RFC5155 says 2500 shall be the maximum useful value */ +#define NSEC3_ITERATIONS_MAX 2500 + +/* + * The DNSSEC Chain of trust: + * + * Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone + * DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree + * DS RRs are protected like normal RRs + * + * Example chain: + * Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS + */ + +uint16_t dnssec_keytag(DnsResourceRecord *dnskey, bool mask_revoke) { + const uint8_t *p; + uint32_t sum, f; + size_t i; + + /* The algorithm from RFC 4034, Appendix B. */ + + assert(dnskey); + assert(dnskey->key->type == DNS_TYPE_DNSKEY); + + f = (uint32_t) dnskey->dnskey.flags; + + if (mask_revoke) + f &= ~DNSKEY_FLAG_REVOKE; + + sum = f + ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm); + + p = dnskey->dnskey.key; + + for (i = 0; i < dnskey->dnskey.key_size; i++) + sum += (i & 1) == 0 ? (uint32_t) p[i] << 8 : (uint32_t) p[i]; + + sum += (sum >> 16) & UINT32_C(0xFFFF); + + return sum & UINT32_C(0xFFFF); +} + +int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) { + size_t c = 0; + int r; + + /* Converts the specified hostname into DNSSEC canonicalized + * form. */ + + if (buffer_max < 2) + return -ENOBUFS; + + for (;;) { + r = dns_label_unescape(&n, buffer, buffer_max); + if (r < 0) + return r; + if (r == 0) + break; + + if (buffer_max < (size_t) r + 2) + return -ENOBUFS; + + /* The DNSSEC canonical form is not clear on what to + * do with dots appearing in labels, the way DNS-SD + * does it. Refuse it for now. */ + + if (memchr(buffer, '.', r)) + return -EINVAL; + + ascii_strlower_n(buffer, (size_t) r); + buffer[r] = '.'; + + buffer += r + 1; + c += r + 1; + + buffer_max -= r + 1; + } + + if (c <= 0) { + /* Not even a single label: this is the root domain name */ + + assert(buffer_max > 2); + buffer[0] = '.'; + buffer[1] = 0; + + return 1; + } + + return (int) c; +} + +#ifdef HAVE_GCRYPT + +static void initialize_libgcrypt(void) { + const char *p; + + if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) + return; + + p = gcry_check_version("1.4.5"); + assert(p); + + gcry_control(GCRYCTL_DISABLE_SECMEM); + gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); +} + +static int rr_compare(const void *a, const void *b) { + DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b; + size_t m; + int r; + + /* Let's order the RRs according to RFC 4034, Section 6.3 */ + + assert(x); + assert(*x); + assert((*x)->wire_format); + assert(y); + assert(*y); + assert((*y)->wire_format); + + m = MIN(DNS_RESOURCE_RECORD_RDATA_SIZE(*x), DNS_RESOURCE_RECORD_RDATA_SIZE(*y)); + + r = memcmp(DNS_RESOURCE_RECORD_RDATA(*x), DNS_RESOURCE_RECORD_RDATA(*y), m); + if (r != 0) + return r; + + if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) < DNS_RESOURCE_RECORD_RDATA_SIZE(*y)) + return -1; + else if (DNS_RESOURCE_RECORD_RDATA_SIZE(*x) > DNS_RESOURCE_RECORD_RDATA_SIZE(*y)) + return 1; + + return 0; +} + +static int dnssec_rsa_verify_raw( + const char *hash_algorithm, + const void *signature, size_t signature_size, + const void *data, size_t data_size, + const void *exponent, size_t exponent_size, + const void *modulus, size_t modulus_size) { + + gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL; + gcry_mpi_t n = NULL, e = NULL, s = NULL; + gcry_error_t ge; + int r; + + assert(hash_algorithm); + + ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL); + if (ge != 0) { + r = -EIO; + goto finish; + } + + ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL); + if (ge != 0) { + r = -EIO; + goto finish; + } + + ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL); + if (ge != 0) { + r = -EIO; + goto finish; + } + + ge = gcry_sexp_build(&signature_sexp, + NULL, + "(sig-val (rsa (s %m)))", + s); + + if (ge != 0) { + r = -EIO; + goto finish; + } + + ge = gcry_sexp_build(&data_sexp, + NULL, + "(data (flags pkcs1) (hash %s %b))", + hash_algorithm, + (int) data_size, + data); + if (ge != 0) { + r = -EIO; + goto finish; + } + + ge = gcry_sexp_build(&public_key_sexp, + NULL, + "(public-key (rsa (n %m) (e %m)))", + n, + e); + if (ge != 0) { + r = -EIO; + goto finish; + } + + ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp); + if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE) + r = 0; + else if (ge != 0) { + log_debug("RSA signature check failed: %s", gpg_strerror(ge)); + r = -EIO; + } else + r = 1; + +finish: + if (e) + gcry_mpi_release(e); + if (n) + gcry_mpi_release(n); + if (s) + gcry_mpi_release(s); + + if (public_key_sexp) + gcry_sexp_release(public_key_sexp); + if (signature_sexp) + gcry_sexp_release(signature_sexp); + if (data_sexp) + gcry_sexp_release(data_sexp); + + return r; +} + +static int dnssec_rsa_verify( + const char *hash_algorithm, + const void *hash, size_t hash_size, + DnsResourceRecord *rrsig, + DnsResourceRecord *dnskey) { + + size_t exponent_size, modulus_size; + void *exponent, *modulus; + + assert(hash_algorithm); + assert(hash); + assert(hash_size > 0); + assert(rrsig); + assert(dnskey); + + if (*(uint8_t*) dnskey->dnskey.key == 0) { + /* exponent is > 255 bytes long */ + + exponent = (uint8_t*) dnskey->dnskey.key + 3; + exponent_size = + ((size_t) (((uint8_t*) dnskey->dnskey.key)[1]) << 8) | + ((size_t) ((uint8_t*) dnskey->dnskey.key)[2]); + + if (exponent_size < 256) + return -EINVAL; + + if (3 + exponent_size >= dnskey->dnskey.key_size) + return -EINVAL; + + modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size; + modulus_size = dnskey->dnskey.key_size - 3 - exponent_size; + + } else { + /* exponent is <= 255 bytes long */ + + exponent = (uint8_t*) dnskey->dnskey.key + 1; + exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0]; + + if (exponent_size <= 0) + return -EINVAL; + + if (1 + exponent_size >= dnskey->dnskey.key_size) + return -EINVAL; + + modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size; + modulus_size = dnskey->dnskey.key_size - 1 - exponent_size; + } + + return dnssec_rsa_verify_raw( + hash_algorithm, + rrsig->rrsig.signature, rrsig->rrsig.signature_size, + hash, hash_size, + exponent, exponent_size, + modulus, modulus_size); +} + +static int dnssec_ecdsa_verify_raw( + const char *hash_algorithm, + const char *curve, + const void *signature_r, size_t signature_r_size, + const void *signature_s, size_t signature_s_size, + const void *data, size_t data_size, + const void *key, size_t key_size) { + + gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL; + gcry_mpi_t q = NULL, r = NULL, s = NULL; + gcry_error_t ge; + int k; + + assert(hash_algorithm); + + ge = gcry_mpi_scan(&r, GCRYMPI_FMT_USG, signature_r, signature_r_size, NULL); + if (ge != 0) { + k = -EIO; + goto finish; + } + + ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature_s, signature_s_size, NULL); + if (ge != 0) { + k = -EIO; + goto finish; + } + + ge = gcry_mpi_scan(&q, GCRYMPI_FMT_USG, key, key_size, NULL); + if (ge != 0) { + k = -EIO; + goto finish; + } + + ge = gcry_sexp_build(&signature_sexp, + NULL, + "(sig-val (ecdsa (r %m) (s %m)))", + r, + s); + if (ge != 0) { + k = -EIO; + goto finish; + } + + ge = gcry_sexp_build(&data_sexp, + NULL, + "(data (flags rfc6979) (hash %s %b))", + hash_algorithm, + (int) data_size, + data); + if (ge != 0) { + k = -EIO; + goto finish; + } + + ge = gcry_sexp_build(&public_key_sexp, + NULL, + "(public-key (ecc (curve %s) (q %m)))", + curve, + q); + if (ge != 0) { + k = -EIO; + goto finish; + } + + ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp); + if (gpg_err_code(ge) == GPG_ERR_BAD_SIGNATURE) + k = 0; + else if (ge != 0) { + log_debug("ECDSA signature check failed: %s", gpg_strerror(ge)); + k = -EIO; + } else + k = 1; +finish: + if (r) + gcry_mpi_release(r); + if (s) + gcry_mpi_release(s); + if (q) + gcry_mpi_release(q); + + if (public_key_sexp) + gcry_sexp_release(public_key_sexp); + if (signature_sexp) + gcry_sexp_release(signature_sexp); + if (data_sexp) + gcry_sexp_release(data_sexp); + + return k; +} + +static int dnssec_ecdsa_verify( + const char *hash_algorithm, + int algorithm, + const void *hash, size_t hash_size, + DnsResourceRecord *rrsig, + DnsResourceRecord *dnskey) { + + const char *curve; + size_t key_size; + uint8_t *q; + + assert(hash); + assert(hash_size); + assert(rrsig); + assert(dnskey); + + if (algorithm == DNSSEC_ALGORITHM_ECDSAP256SHA256) { + key_size = 32; + curve = "NIST P-256"; + } else if (algorithm == DNSSEC_ALGORITHM_ECDSAP384SHA384) { + key_size = 48; + curve = "NIST P-384"; + } else + return -EOPNOTSUPP; + + if (dnskey->dnskey.key_size != key_size * 2) + return -EINVAL; + + if (rrsig->rrsig.signature_size != key_size * 2) + return -EINVAL; + + q = alloca(key_size*2 + 1); + q[0] = 0x04; /* Prepend 0x04 to indicate an uncompressed key */ + memcpy(q+1, dnskey->dnskey.key, key_size*2); + + return dnssec_ecdsa_verify_raw( + hash_algorithm, + curve, + rrsig->rrsig.signature, key_size, + (uint8_t*) rrsig->rrsig.signature + key_size, key_size, + hash, hash_size, + q, key_size*2+1); +} + +static void md_add_uint8(gcry_md_hd_t md, uint8_t v) { + gcry_md_write(md, &v, sizeof(v)); +} + +static void md_add_uint16(gcry_md_hd_t md, uint16_t v) { + v = htobe16(v); + gcry_md_write(md, &v, sizeof(v)); +} + +static void md_add_uint32(gcry_md_hd_t md, uint32_t v) { + v = htobe32(v); + gcry_md_write(md, &v, sizeof(v)); +} + +static int dnssec_rrsig_prepare(DnsResourceRecord *rrsig) { + int n_key_labels, n_signer_labels; + const char *name; + int r; + + /* Checks whether the specified RRSIG RR is somewhat valid, and initializes the .n_skip_labels_source and + * .n_skip_labels_signer fields so that we can use them later on. */ + + assert(rrsig); + assert(rrsig->key->type == DNS_TYPE_RRSIG); + + /* Check if this RRSIG RR is already prepared */ + if (rrsig->n_skip_labels_source != (unsigned) -1) + return 0; + + if (rrsig->rrsig.inception > rrsig->rrsig.expiration) + return -EINVAL; + + name = DNS_RESOURCE_KEY_NAME(rrsig->key); + + n_key_labels = dns_name_count_labels(name); + if (n_key_labels < 0) + return n_key_labels; + if (rrsig->rrsig.labels > n_key_labels) + return -EINVAL; + + n_signer_labels = dns_name_count_labels(rrsig->rrsig.signer); + if (n_signer_labels < 0) + return n_signer_labels; + if (n_signer_labels > rrsig->rrsig.labels) + return -EINVAL; + + r = dns_name_skip(name, n_key_labels - n_signer_labels, &name); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + /* Check if the signer is really a suffix of us */ + r = dns_name_equal(name, rrsig->rrsig.signer); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + rrsig->n_skip_labels_source = n_key_labels - rrsig->rrsig.labels; + rrsig->n_skip_labels_signer = n_key_labels - n_signer_labels; + + return 0; +} + +static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) { + usec_t expiration, inception, skew; + + assert(rrsig); + assert(rrsig->key->type == DNS_TYPE_RRSIG); + + if (realtime == USEC_INFINITY) + realtime = now(CLOCK_REALTIME); + + expiration = rrsig->rrsig.expiration * USEC_PER_SEC; + inception = rrsig->rrsig.inception * USEC_PER_SEC; + + /* Consider inverted validity intervals as expired */ + if (inception > expiration) + return true; + + /* Permit a certain amount of clock skew of 10% of the valid + * time range. This takes inspiration from unbound's + * resolver. */ + skew = (expiration - inception) / 10; + if (skew > SKEW_MAX) + skew = SKEW_MAX; + + if (inception < skew) + inception = 0; + else + inception -= skew; + + if (expiration + skew < expiration) + expiration = USEC_INFINITY; + else + expiration += skew; + + return realtime < inception || realtime > expiration; +} + +static int algorithm_to_gcrypt_md(uint8_t algorithm) { + + /* Translates a DNSSEC signature algorithm into a gcrypt + * digest identifier. + * + * Note that we implement all algorithms listed as "Must + * implement" and "Recommended to Implement" in RFC6944. We + * don't implement any algorithms that are listed as + * "Optional" or "Must Not Implement". Specifically, we do not + * implement RSAMD5, DSASHA1, DH, DSA-NSEC3-SHA1, and + * GOST-ECC. */ + + switch (algorithm) { + + case DNSSEC_ALGORITHM_RSASHA1: + case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1: + return GCRY_MD_SHA1; + + case DNSSEC_ALGORITHM_RSASHA256: + case DNSSEC_ALGORITHM_ECDSAP256SHA256: + return GCRY_MD_SHA256; + + case DNSSEC_ALGORITHM_ECDSAP384SHA384: + return GCRY_MD_SHA384; + + case DNSSEC_ALGORITHM_RSASHA512: + return GCRY_MD_SHA512; + + default: + return -EOPNOTSUPP; + } +} + +static void dnssec_fix_rrset_ttl( + DnsResourceRecord *list[], + unsigned n, + DnsResourceRecord *rrsig, + usec_t realtime) { + + unsigned k; + + assert(list); + assert(n > 0); + assert(rrsig); + + for (k = 0; k < n; k++) { + DnsResourceRecord *rr = list[k]; + + /* Pick the TTL as the minimum of the RR's TTL, the + * RR's original TTL according to the RRSIG and the + * RRSIG's own TTL, see RFC 4035, Section 5.3.3 */ + rr->ttl = MIN3(rr->ttl, rrsig->rrsig.original_ttl, rrsig->ttl); + rr->expiry = rrsig->rrsig.expiration * USEC_PER_SEC; + + /* Copy over information about the signer and wildcard source of synthesis */ + rr->n_skip_labels_source = rrsig->n_skip_labels_source; + rr->n_skip_labels_signer = rrsig->n_skip_labels_signer; + } + + rrsig->expiry = rrsig->rrsig.expiration * USEC_PER_SEC; +} + +int dnssec_verify_rrset( + DnsAnswer *a, + const DnsResourceKey *key, + DnsResourceRecord *rrsig, + DnsResourceRecord *dnskey, + usec_t realtime, + DnssecResult *result) { + + uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX]; + DnsResourceRecord **list, *rr; + const char *source, *name; + gcry_md_hd_t md = NULL; + int r, md_algorithm; + size_t k, n = 0; + size_t hash_size; + void *hash; + bool wildcard; + + assert(key); + assert(rrsig); + assert(dnskey); + assert(result); + assert(rrsig->key->type == DNS_TYPE_RRSIG); + assert(dnskey->key->type == DNS_TYPE_DNSKEY); + + /* Verifies the the RRSet matching the specified "key" in "a", + * using the signature "rrsig" and the key "dnskey". It's + * assumed the RRSIG and DNSKEY match. */ + + md_algorithm = algorithm_to_gcrypt_md(rrsig->rrsig.algorithm); + if (md_algorithm == -EOPNOTSUPP) { + *result = DNSSEC_UNSUPPORTED_ALGORITHM; + return 0; + } + if (md_algorithm < 0) + return md_algorithm; + + r = dnssec_rrsig_prepare(rrsig); + if (r == -EINVAL) { + *result = DNSSEC_INVALID; + return r; + } + if (r < 0) + return r; + + r = dnssec_rrsig_expired(rrsig, realtime); + if (r < 0) + return r; + if (r > 0) { + *result = DNSSEC_SIGNATURE_EXPIRED; + return 0; + } + + name = DNS_RESOURCE_KEY_NAME(key); + + /* Some keys may only appear signed in the zone apex, and are invalid anywhere else. (SOA, NS...) */ + if (dns_type_apex_only(rrsig->rrsig.type_covered)) { + r = dns_name_equal(rrsig->rrsig.signer, name); + if (r < 0) + return r; + if (r == 0) { + *result = DNSSEC_INVALID; + return 0; + } + } + + /* OTOH DS RRs may not appear in the zone apex, but are valid everywhere else. */ + if (rrsig->rrsig.type_covered == DNS_TYPE_DS) { + r = dns_name_equal(rrsig->rrsig.signer, name); + if (r < 0) + return r; + if (r > 0) { + *result = DNSSEC_INVALID; + return 0; + } + } + + /* Determine the "Source of Synthesis" and whether this is a wildcard RRSIG */ + r = dns_name_suffix(name, rrsig->rrsig.labels, &source); + if (r < 0) + return r; + if (r > 0 && !dns_type_may_wildcard(rrsig->rrsig.type_covered)) { + /* We refuse to validate NSEC3 or SOA RRs that are synthesized from wildcards */ + *result = DNSSEC_INVALID; + return 0; + } + if (r == 1) { + /* If we stripped a single label, then let's see if that maybe was "*". If so, we are not really + * synthesized from a wildcard, we are the wildcard itself. Treat that like a normal name. */ + r = dns_name_startswith(name, "*"); + if (r < 0) + return r; + if (r > 0) + source = name; + + wildcard = r == 0; + } else + wildcard = r > 0; + + /* Collect all relevant RRs in a single array, so that we can look at the RRset */ + list = newa(DnsResourceRecord *, dns_answer_size(a)); + + DNS_ANSWER_FOREACH(rr, a) { + r = dns_resource_key_equal(key, rr->key); + if (r < 0) + return r; + if (r == 0) + continue; + + /* We need the wire format for ordering, and digest calculation */ + r = dns_resource_record_to_wire_format(rr, true); + if (r < 0) + return r; + + list[n++] = rr; + + if (n > VERIFY_RRS_MAX) + return -E2BIG; + } + + if (n <= 0) + return -ENODATA; + + /* Bring the RRs into canonical order */ + qsort_safe(list, n, sizeof(DnsResourceRecord*), rr_compare); + + /* OK, the RRs are now in canonical order. Let's calculate the digest */ + initialize_libgcrypt(); + + hash_size = gcry_md_get_algo_dlen(md_algorithm); + assert(hash_size > 0); + + gcry_md_open(&md, md_algorithm, 0); + if (!md) + return -EIO; + + md_add_uint16(md, rrsig->rrsig.type_covered); + md_add_uint8(md, rrsig->rrsig.algorithm); + md_add_uint8(md, rrsig->rrsig.labels); + md_add_uint32(md, rrsig->rrsig.original_ttl); + md_add_uint32(md, rrsig->rrsig.expiration); + md_add_uint32(md, rrsig->rrsig.inception); + md_add_uint16(md, rrsig->rrsig.key_tag); + + r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true); + if (r < 0) + goto finish; + gcry_md_write(md, wire_format_name, r); + + /* Convert the source of synthesis into wire format */ + r = dns_name_to_wire_format(source, wire_format_name, sizeof(wire_format_name), true); + if (r < 0) + goto finish; + + for (k = 0; k < n; k++) { + size_t l; + + rr = list[k]; + + /* Hash the source of synthesis. If this is a wildcard, then prefix it with the *. label */ + if (wildcard) + gcry_md_write(md, (uint8_t[]) { 1, '*'}, 2); + gcry_md_write(md, wire_format_name, r); + + md_add_uint16(md, rr->key->type); + md_add_uint16(md, rr->key->class); + md_add_uint32(md, rrsig->rrsig.original_ttl); + + l = DNS_RESOURCE_RECORD_RDATA_SIZE(rr); + assert(l <= 0xFFFF); + + md_add_uint16(md, (uint16_t) l); + gcry_md_write(md, DNS_RESOURCE_RECORD_RDATA(rr), l); + } + + hash = gcry_md_read(md, 0); + if (!hash) { + r = -EIO; + goto finish; + } + + switch (rrsig->rrsig.algorithm) { + + case DNSSEC_ALGORITHM_RSASHA1: + case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1: + case DNSSEC_ALGORITHM_RSASHA256: + case DNSSEC_ALGORITHM_RSASHA512: + r = dnssec_rsa_verify( + gcry_md_algo_name(md_algorithm), + hash, hash_size, + rrsig, + dnskey); + break; + + case DNSSEC_ALGORITHM_ECDSAP256SHA256: + case DNSSEC_ALGORITHM_ECDSAP384SHA384: + r = dnssec_ecdsa_verify( + gcry_md_algo_name(md_algorithm), + rrsig->rrsig.algorithm, + hash, hash_size, + rrsig, + dnskey); + break; + } + + if (r < 0) + goto finish; + + /* Now, fix the ttl, expiry, and remember the synthesizing source and the signer */ + if (r > 0) + dnssec_fix_rrset_ttl(list, n, rrsig, realtime); + + if (r == 0) + *result = DNSSEC_INVALID; + else if (wildcard) + *result = DNSSEC_VALIDATED_WILDCARD; + else + *result = DNSSEC_VALIDATED; + + r = 0; + +finish: + gcry_md_close(md); + return r; +} + +int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok) { + + assert(rrsig); + assert(dnskey); + + /* Checks if the specified DNSKEY RR matches the key used for + * the signature in the specified RRSIG RR */ + + if (rrsig->key->type != DNS_TYPE_RRSIG) + return -EINVAL; + + if (dnskey->key->type != DNS_TYPE_DNSKEY) + return 0; + if (dnskey->key->class != rrsig->key->class) + return 0; + if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0) + return 0; + if (!revoked_ok && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE)) + return 0; + if (dnskey->dnskey.protocol != 3) + return 0; + if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm) + return 0; + + if (dnssec_keytag(dnskey, false) != rrsig->rrsig.key_tag) + return 0; + + return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), rrsig->rrsig.signer); +} + +int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) { + assert(key); + assert(rrsig); + + /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */ + + if (rrsig->key->type != DNS_TYPE_RRSIG) + return 0; + if (rrsig->key->class != key->class) + return 0; + if (rrsig->rrsig.type_covered != key->type) + return 0; + + return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key)); +} + +int dnssec_verify_rrset_search( + DnsAnswer *a, + const DnsResourceKey *key, + DnsAnswer *validated_dnskeys, + usec_t realtime, + DnssecResult *result, + DnsResourceRecord **ret_rrsig) { + + bool found_rrsig = false, found_invalid = false, found_expired_rrsig = false, found_unsupported_algorithm = false; + DnsResourceRecord *rrsig; + int r; + + assert(key); + assert(result); + + /* Verifies all RRs from "a" that match the key "key" against DNSKEYs in "validated_dnskeys" */ + + if (!a || a->n_rrs <= 0) + return -ENODATA; + + /* Iterate through each RRSIG RR. */ + DNS_ANSWER_FOREACH(rrsig, a) { + DnsResourceRecord *dnskey; + DnsAnswerFlags flags; + + /* Is this an RRSIG RR that applies to RRs matching our key? */ + r = dnssec_key_match_rrsig(key, rrsig); + if (r < 0) + return r; + if (r == 0) + continue; + + found_rrsig = true; + + /* Look for a matching key */ + DNS_ANSWER_FOREACH_FLAGS(dnskey, flags, validated_dnskeys) { + DnssecResult one_result; + + if ((flags & DNS_ANSWER_AUTHENTICATED) == 0) + continue; + + /* Is this a DNSKEY RR that matches they key of our RRSIG? */ + r = dnssec_rrsig_match_dnskey(rrsig, dnskey, false); + if (r < 0) + return r; + if (r == 0) + continue; + + /* Take the time here, if it isn't set yet, so + * that we do all validations with the same + * time. */ + if (realtime == USEC_INFINITY) + realtime = now(CLOCK_REALTIME); + + /* Yay, we found a matching RRSIG with a matching + * DNSKEY, awesome. Now let's verify all entries of + * the RRSet against the RRSIG and DNSKEY + * combination. */ + + r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime, &one_result); + if (r < 0) + return r; + + switch (one_result) { + + case DNSSEC_VALIDATED: + case DNSSEC_VALIDATED_WILDCARD: + /* Yay, the RR has been validated, + * return immediately, but fix up the expiry */ + if (ret_rrsig) + *ret_rrsig = rrsig; + + *result = one_result; + return 0; + + case DNSSEC_INVALID: + /* If the signature is invalid, let's try another + key and/or signature. After all they + key_tags and stuff are not unique, and + might be shared by multiple keys. */ + found_invalid = true; + continue; + + case DNSSEC_UNSUPPORTED_ALGORITHM: + /* If the key algorithm is + unsupported, try another + RRSIG/DNSKEY pair, but remember we + encountered this, so that we can + return a proper error when we + encounter nothing better. */ + found_unsupported_algorithm = true; + continue; + + case DNSSEC_SIGNATURE_EXPIRED: + /* If the signature is expired, try + another one, but remember it, so + that we can return this */ + found_expired_rrsig = true; + continue; + + default: + assert_not_reached("Unexpected DNSSEC validation result"); + } + } + } + + if (found_expired_rrsig) + *result = DNSSEC_SIGNATURE_EXPIRED; + else if (found_unsupported_algorithm) + *result = DNSSEC_UNSUPPORTED_ALGORITHM; + else if (found_invalid) + *result = DNSSEC_INVALID; + else if (found_rrsig) + *result = DNSSEC_MISSING_KEY; + else + *result = DNSSEC_NO_SIGNATURE; + + if (ret_rrsig) + *ret_rrsig = NULL; + + return 0; +} + +int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) { + DnsResourceRecord *rr; + int r; + + /* Checks whether there's at least one RRSIG in 'a' that proctects RRs of the specified key */ + + DNS_ANSWER_FOREACH(rr, a) { + r = dnssec_key_match_rrsig(key, rr); + if (r < 0) + return r; + if (r > 0) + return 1; + } + + return 0; +} + +static int digest_to_gcrypt_md(uint8_t algorithm) { + + /* Translates a DNSSEC digest algorithm into a gcrypt digest identifier */ + + switch (algorithm) { + + case DNSSEC_DIGEST_SHA1: + return GCRY_MD_SHA1; + + case DNSSEC_DIGEST_SHA256: + return GCRY_MD_SHA256; + + case DNSSEC_DIGEST_SHA384: + return GCRY_MD_SHA384; + + default: + return -EOPNOTSUPP; + } +} + +int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) { + char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX]; + gcry_md_hd_t md = NULL; + size_t hash_size; + int md_algorithm, r; + void *result; + + assert(dnskey); + assert(ds); + + /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */ + + if (dnskey->key->type != DNS_TYPE_DNSKEY) + return -EINVAL; + if (ds->key->type != DNS_TYPE_DS) + return -EINVAL; + if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0) + return -EKEYREJECTED; + if (!mask_revoke && (dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE)) + return -EKEYREJECTED; + if (dnskey->dnskey.protocol != 3) + return -EKEYREJECTED; + + if (dnskey->dnskey.algorithm != ds->ds.algorithm) + return 0; + if (dnssec_keytag(dnskey, mask_revoke) != ds->ds.key_tag) + return 0; + + initialize_libgcrypt(); + + md_algorithm = digest_to_gcrypt_md(ds->ds.digest_type); + if (md_algorithm < 0) + return md_algorithm; + + hash_size = gcry_md_get_algo_dlen(md_algorithm); + assert(hash_size > 0); + + if (ds->ds.digest_size != hash_size) + return 0; + + r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name)); + if (r < 0) + return r; + + gcry_md_open(&md, md_algorithm, 0); + if (!md) + return -EIO; + + gcry_md_write(md, owner_name, r); + if (mask_revoke) + md_add_uint16(md, dnskey->dnskey.flags & ~DNSKEY_FLAG_REVOKE); + else + md_add_uint16(md, dnskey->dnskey.flags); + md_add_uint8(md, dnskey->dnskey.protocol); + md_add_uint8(md, dnskey->dnskey.algorithm); + gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size); + + result = gcry_md_read(md, 0); + if (!result) { + r = -EIO; + goto finish; + } + + r = memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0; + +finish: + gcry_md_close(md); + return r; +} + +int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) { + DnsResourceRecord *ds; + DnsAnswerFlags flags; + int r; + + assert(dnskey); + + if (dnskey->key->type != DNS_TYPE_DNSKEY) + return 0; + + DNS_ANSWER_FOREACH_FLAGS(ds, flags, validated_ds) { + + if ((flags & DNS_ANSWER_AUTHENTICATED) == 0) + continue; + + if (ds->key->type != DNS_TYPE_DS) + continue; + if (ds->key->class != dnskey->key->class) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(ds->key)); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dnssec_verify_dnskey_by_ds(dnskey, ds, false); + if (IN_SET(r, -EKEYREJECTED, -EOPNOTSUPP)) + return 0; /* The DNSKEY is revoked or otherwise invalid, or we don't support the digest algorithm */ + if (r < 0) + return r; + if (r > 0) + return 1; + } + + return 0; +} + +static int nsec3_hash_to_gcrypt_md(uint8_t algorithm) { + + /* Translates a DNSSEC NSEC3 hash algorithm into a gcrypt digest identifier */ + + switch (algorithm) { + + case NSEC3_ALGORITHM_SHA1: + return GCRY_MD_SHA1; + + default: + return -EOPNOTSUPP; + } +} + +int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) { + uint8_t wire_format[DNS_WIRE_FOMAT_HOSTNAME_MAX]; + gcry_md_hd_t md = NULL; + size_t hash_size; + int algorithm; + void *result; + unsigned k; + int r; + + assert(nsec3); + assert(name); + assert(ret); + + if (nsec3->key->type != DNS_TYPE_NSEC3) + return -EINVAL; + + if (nsec3->nsec3.iterations > NSEC3_ITERATIONS_MAX) { + log_debug("Ignoring NSEC3 RR %s with excessive number of iterations.", dns_resource_record_to_string(nsec3)); + return -EOPNOTSUPP; + } + + algorithm = nsec3_hash_to_gcrypt_md(nsec3->nsec3.algorithm); + if (algorithm < 0) + return algorithm; + + initialize_libgcrypt(); + + hash_size = gcry_md_get_algo_dlen(algorithm); + assert(hash_size > 0); + + if (nsec3->nsec3.next_hashed_name_size != hash_size) + return -EINVAL; + + r = dns_name_to_wire_format(name, wire_format, sizeof(wire_format), true); + if (r < 0) + return r; + + gcry_md_open(&md, algorithm, 0); + if (!md) + return -EIO; + + gcry_md_write(md, wire_format, r); + gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size); + + result = gcry_md_read(md, 0); + if (!result) { + r = -EIO; + goto finish; + } + + for (k = 0; k < nsec3->nsec3.iterations; k++) { + uint8_t tmp[hash_size]; + memcpy(tmp, result, hash_size); + + gcry_md_reset(md); + gcry_md_write(md, tmp, hash_size); + gcry_md_write(md, nsec3->nsec3.salt, nsec3->nsec3.salt_size); + + result = gcry_md_read(md, 0); + if (!result) { + r = -EIO; + goto finish; + } + } + + memcpy(ret, result, hash_size); + r = (int) hash_size; + +finish: + gcry_md_close(md); + return r; +} + +static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) { + const char *a, *b; + int r; + + assert(rr); + + if (rr->key->type != DNS_TYPE_NSEC3) + return 0; + + /* RFC 5155, Section 8.2 says we MUST ignore NSEC3 RRs with flags != 0 or 1 */ + if (!IN_SET(rr->nsec3.flags, 0, 1)) + return 0; + + /* Ignore NSEC3 RRs whose algorithm we don't know */ + if (nsec3_hash_to_gcrypt_md(rr->nsec3.algorithm) < 0) + return 0; + /* Ignore NSEC3 RRs with an excessive number of required iterations */ + if (rr->nsec3.iterations > NSEC3_ITERATIONS_MAX) + return 0; + + /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this + * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */ + if (rr->n_skip_labels_source != 0 && rr->n_skip_labels_source != (unsigned) -1) + return 0; + /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */ + if (rr->n_skip_labels_signer != 1 && rr->n_skip_labels_signer != (unsigned) -1) + return 0; + + if (!nsec3) + return 1; + + /* If a second NSEC3 RR is specified, also check if they are from the same zone. */ + + if (nsec3 == rr) /* Shortcut */ + return 1; + + if (rr->key->class != nsec3->key->class) + return 0; + if (rr->nsec3.algorithm != nsec3->nsec3.algorithm) + return 0; + if (rr->nsec3.iterations != nsec3->nsec3.iterations) + return 0; + if (rr->nsec3.salt_size != nsec3->nsec3.salt_size) + return 0; + if (memcmp(rr->nsec3.salt, nsec3->nsec3.salt, rr->nsec3.salt_size) != 0) + return 0; + + a = DNS_RESOURCE_KEY_NAME(rr->key); + r = dns_name_parent(&a); /* strip off hash */ + if (r < 0) + return r; + if (r == 0) + return 0; + + b = DNS_RESOURCE_KEY_NAME(nsec3->key); + r = dns_name_parent(&b); /* strip off hash */ + if (r < 0) + return r; + if (r == 0) + return 0; + + /* Make sure both have the same parent */ + return dns_name_equal(a, b); +} + +static int nsec3_hashed_domain_format(const uint8_t *hashed, size_t hashed_size, const char *zone, char **ret) { + _cleanup_free_ char *l = NULL; + char *j; + + assert(hashed); + assert(hashed_size > 0); + assert(zone); + assert(ret); + + l = base32hexmem(hashed, hashed_size, false); + if (!l) + return -ENOMEM; + + j = strjoin(l, ".", zone, NULL); + if (!j) + return -ENOMEM; + + *ret = j; + return (int) hashed_size; +} + +static int nsec3_hashed_domain_make(DnsResourceRecord *nsec3, const char *domain, const char *zone, char **ret) { + uint8_t hashed[DNSSEC_HASH_SIZE_MAX]; + int hashed_size; + + assert(nsec3); + assert(domain); + assert(zone); + assert(ret); + + hashed_size = dnssec_nsec3_hash(nsec3, domain, hashed); + if (hashed_size < 0) + return hashed_size; + + return nsec3_hashed_domain_format(hashed, (size_t) hashed_size, zone, ret); +} + +/* See RFC 5155, Section 8 + * First try to find a NSEC3 record that matches our query precisely, if that fails, find the closest + * enclosure. Secondly, find a proof that there is no closer enclosure and either a proof that there + * is no wildcard domain as a direct descendant of the closest enclosure, or find an NSEC3 record that + * matches the wildcard domain. + * + * Based on this we can prove either the existence of the record in @key, or NXDOMAIN or NODATA, or + * that there is no proof either way. The latter is the case if a the proof of non-existence of a given + * name uses an NSEC3 record with the opt-out bit set. Lastly, if we are given insufficient NSEC3 records + * to conclude anything we indicate this by returning NO_RR. */ +static int dnssec_test_nsec3(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) { + _cleanup_free_ char *next_closer_domain = NULL, *wildcard_domain = NULL; + const char *zone, *p, *pp = NULL, *wildcard; + DnsResourceRecord *rr, *enclosure_rr, *zone_rr, *wildcard_rr = NULL; + DnsAnswerFlags flags; + int hashed_size, r; + bool a, no_closer = false, no_wildcard = false, optout = false; + + assert(key); + assert(result); + + /* First step, find the zone name and the NSEC3 parameters of the zone. + * it is sufficient to look for the longest common suffix we find with + * any NSEC3 RR in the response. Any NSEC3 record will do as all NSEC3 + * records from a given zone in a response must use the same + * parameters. */ + zone = DNS_RESOURCE_KEY_NAME(key); + for (;;) { + DNS_ANSWER_FOREACH_FLAGS(zone_rr, flags, answer) { + r = nsec3_is_good(zone_rr, NULL); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dns_name_equal_skip(DNS_RESOURCE_KEY_NAME(zone_rr->key), 1, zone); + if (r < 0) + return r; + if (r > 0) + goto found_zone; + } + + /* Strip one label from the front */ + r = dns_name_parent(&zone); + if (r < 0) + return r; + if (r == 0) + break; + } + + *result = DNSSEC_NSEC_NO_RR; + return 0; + +found_zone: + /* Second step, find the closest encloser NSEC3 RR in 'answer' that matches 'key' */ + p = DNS_RESOURCE_KEY_NAME(key); + for (;;) { + _cleanup_free_ char *hashed_domain = NULL; + + hashed_size = nsec3_hashed_domain_make(zone_rr, p, zone, &hashed_domain); + if (hashed_size == -EOPNOTSUPP) { + *result = DNSSEC_NSEC_UNSUPPORTED_ALGORITHM; + return 0; + } + if (hashed_size < 0) + return hashed_size; + + DNS_ANSWER_FOREACH_FLAGS(enclosure_rr, flags, answer) { + + r = nsec3_is_good(enclosure_rr, zone_rr); + if (r < 0) + return r; + if (r == 0) + continue; + + if (enclosure_rr->nsec3.next_hashed_name_size != (size_t) hashed_size) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(enclosure_rr->key), hashed_domain); + if (r < 0) + return r; + if (r > 0) { + a = flags & DNS_ANSWER_AUTHENTICATED; + goto found_closest_encloser; + } + } + + /* We didn't find the closest encloser with this name, + * but let's remember this domain name, it might be + * the next closer name */ + + pp = p; + + /* Strip one label from the front */ + r = dns_name_parent(&p); + if (r < 0) + return r; + if (r == 0) + break; + } + + *result = DNSSEC_NSEC_NO_RR; + return 0; + +found_closest_encloser: + /* We found a closest encloser in 'p'; next closer is 'pp' */ + + if (!pp) { + /* We have an exact match! If we area looking for a DS RR, then we must insist that we got the NSEC3 RR + * from the parent. Otherwise the one from the child. Do so, by checking whether SOA and NS are + * appropriately set. */ + + if (key->type == DNS_TYPE_DS) { + if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA)) + return -EBADMSG; + } else { + if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_NS) && + !bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA)) + return -EBADMSG; + } + + /* No next closer NSEC3 RR. That means there's a direct NSEC3 RR for our key. */ + if (bitmap_isset(enclosure_rr->nsec3.types, key->type)) + *result = DNSSEC_NSEC_FOUND; + else if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_CNAME)) + *result = DNSSEC_NSEC_CNAME; + else + *result = DNSSEC_NSEC_NODATA; + + if (authenticated) + *authenticated = a; + if (ttl) + *ttl = enclosure_rr->ttl; + + return 0; + } + + /* Ensure this is not a DNAME domain, see RFC5155, section 8.3. */ + if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_DNAME)) + return -EBADMSG; + + /* Ensure that this data is from the delegated domain + * (i.e. originates from the "lower" DNS server), and isn't + * just glue records (i.e. doesn't originate from the "upper" + * DNS server). */ + if (bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_NS) && + !bitmap_isset(enclosure_rr->nsec3.types, DNS_TYPE_SOA)) + return -EBADMSG; + + /* Prove that there is no next closer and whether or not there is a wildcard domain. */ + + wildcard = strjoina("*.", p); + r = nsec3_hashed_domain_make(enclosure_rr, wildcard, zone, &wildcard_domain); + if (r < 0) + return r; + if (r != hashed_size) + return -EBADMSG; + + r = nsec3_hashed_domain_make(enclosure_rr, pp, zone, &next_closer_domain); + if (r < 0) + return r; + if (r != hashed_size) + return -EBADMSG; + + DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) { + _cleanup_free_ char *next_hashed_domain = NULL; + + r = nsec3_is_good(rr, zone_rr); + if (r < 0) + return r; + if (r == 0) + continue; + + r = nsec3_hashed_domain_format(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, zone, &next_hashed_domain); + if (r < 0) + return r; + + r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), next_closer_domain, next_hashed_domain); + if (r < 0) + return r; + if (r > 0) { + if (rr->nsec3.flags & 1) + optout = true; + + a = a && (flags & DNS_ANSWER_AUTHENTICATED); + + no_closer = true; + } + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain); + if (r < 0) + return r; + if (r > 0) { + a = a && (flags & DNS_ANSWER_AUTHENTICATED); + + wildcard_rr = rr; + } + + r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wildcard_domain, next_hashed_domain); + if (r < 0) + return r; + if (r > 0) { + if (rr->nsec3.flags & 1) + /* This only makes sense if we have a wildcard delegation, which is + * very unlikely, see RFC 4592, Section 4.2, but we cannot rely on + * this not happening, so hence cannot simply conclude NXDOMAIN as + * we would wish */ + optout = true; + + a = a && (flags & DNS_ANSWER_AUTHENTICATED); + + no_wildcard = true; + } + } + + if (wildcard_rr && no_wildcard) + return -EBADMSG; + + if (!no_closer) { + *result = DNSSEC_NSEC_NO_RR; + return 0; + } + + if (wildcard_rr) { + /* A wildcard exists that matches our query. */ + if (optout) + /* This is not specified in any RFC to the best of my knowledge, but + * if the next closer enclosure is covered by an opt-out NSEC3 RR + * it means that we cannot prove that the source of synthesis is + * correct, as there may be a closer match. */ + *result = DNSSEC_NSEC_OPTOUT; + else if (bitmap_isset(wildcard_rr->nsec3.types, key->type)) + *result = DNSSEC_NSEC_FOUND; + else if (bitmap_isset(wildcard_rr->nsec3.types, DNS_TYPE_CNAME)) + *result = DNSSEC_NSEC_CNAME; + else + *result = DNSSEC_NSEC_NODATA; + } else { + if (optout) + /* The RFC only specifies that we have to care for optout for NODATA for + * DS records. However, children of an insecure opt-out delegation should + * also be considered opt-out, rather than verified NXDOMAIN. + * Note that we do not require a proof of wildcard non-existence if the + * next closer domain is covered by an opt-out, as that would not provide + * any additional information. */ + *result = DNSSEC_NSEC_OPTOUT; + else if (no_wildcard) + *result = DNSSEC_NSEC_NXDOMAIN; + else { + *result = DNSSEC_NSEC_NO_RR; + + return 0; + } + } + + if (authenticated) + *authenticated = a; + + if (ttl) + *ttl = enclosure_rr->ttl; + + return 0; +} + +static int dnssec_nsec_wildcard_equal(DnsResourceRecord *rr, const char *name) { + char label[DNS_LABEL_MAX]; + const char *n; + int r; + + assert(rr); + assert(rr->key->type == DNS_TYPE_NSEC); + + /* Checks whether the specified RR has a name beginning in "*.", and if the rest is a suffix of our name */ + + if (rr->n_skip_labels_source != 1) + return 0; + + n = DNS_RESOURCE_KEY_NAME(rr->key); + r = dns_label_unescape(&n, label, sizeof(label)); + if (r <= 0) + return r; + if (r != 1 || label[0] != '*') + return 0; + + return dns_name_endswith(name, n); +} + +static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) { + const char *nn, *common_suffix; + int r; + + assert(rr); + assert(rr->key->type == DNS_TYPE_NSEC); + + /* Checks whether the specified nsec RR indicates that name is an empty non-terminal (ENT) + * + * A couple of examples: + * + * NSEC bar → waldo.foo.bar: indicates that foo.bar exists and is an ENT + * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that xoo.bar and zzz.xoo.bar exist and are ENTs + * NSEC yyy.zzz.xoo.bar → bar: indicates pretty much nothing about ENTs + */ + + /* First, determine parent of next domain. */ + nn = rr->nsec.next_domain_name; + r = dns_name_parent(&nn); + if (r <= 0) + return r; + + /* If the name we just determined is not equal or child of the name we are interested in, then we can't say + * anything at all. */ + r = dns_name_endswith(nn, name); + if (r <= 0) + return r; + + /* If the name we we are interested in is not a prefix of the common suffix of the NSEC RR's owner and next domain names, then we can't say anything either. */ + r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix); + if (r < 0) + return r; + + return dns_name_endswith(name, common_suffix); +} + +static int dnssec_nsec_from_parent_zone(DnsResourceRecord *rr, const char *name) { + int r; + + assert(rr); + assert(rr->key->type == DNS_TYPE_NSEC); + + /* Checks whether this NSEC originates to the parent zone or the child zone. */ + + r = dns_name_parent(&name); + if (r <= 0) + return r; + + r = dns_name_equal(name, DNS_RESOURCE_KEY_NAME(rr->key)); + if (r <= 0) + return r; + + /* DNAME, and NS without SOA is an indication for a delegation. */ + if (bitmap_isset(rr->nsec.types, DNS_TYPE_DNAME)) + return 1; + + if (bitmap_isset(rr->nsec.types, DNS_TYPE_NS) && !bitmap_isset(rr->nsec.types, DNS_TYPE_SOA)) + return 1; + + return 0; +} + +static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) { + const char *common_suffix, *p; + int r; + + assert(rr); + assert(rr->key->type == DNS_TYPE_NSEC); + + /* Checks whether the "Next Closer" is witin the space covered by the specified RR. */ + + r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix); + if (r < 0) + return r; + + for (;;) { + p = name; + r = dns_name_parent(&name); + if (r < 0) + return r; + if (r == 0) + return 0; + + r = dns_name_equal(name, common_suffix); + if (r < 0) + return r; + if (r > 0) + break; + } + + /* p is now the "Next Closer". */ + + return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), p, rr->nsec.next_domain_name); +} + +static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) { + const char *common_suffix, *wc; + int r; + + assert(rr); + assert(rr->key->type == DNS_TYPE_NSEC); + + /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified + * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as + * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label. + * + * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist + * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...) + * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either... + */ + + r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix); + if (r < 0) + return r; + + /* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */ + r = dns_name_endswith(name, common_suffix); + if (r <= 0) + return r; + + wc = strjoina("*.", common_suffix, NULL); + return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wc, rr->nsec.next_domain_name); +} + +int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) { + bool have_nsec3 = false, covering_rr_authenticated = false, wildcard_rr_authenticated = false; + DnsResourceRecord *rr, *covering_rr = NULL, *wildcard_rr = NULL; + DnsAnswerFlags flags; + const char *name; + int r; + + assert(key); + assert(result); + + /* Look for any NSEC/NSEC3 RRs that say something about the specified key. */ + + name = DNS_RESOURCE_KEY_NAME(key); + + DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) { + + if (rr->key->class != key->class) + continue; + + have_nsec3 = have_nsec3 || (rr->key->type == DNS_TYPE_NSEC3); + + if (rr->key->type != DNS_TYPE_NSEC) + continue; + + /* The following checks only make sense for NSEC RRs that are not expanded from a wildcard */ + r = dns_resource_record_is_synthetic(rr); + if (r < 0) + return r; + if (r > 0) + continue; + + /* Check if this is a direct match. If so, we have encountered a NODATA case */ + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(rr->key), name); + if (r < 0) + return r; + if (r == 0) { + /* If it's not a direct match, maybe it's a wild card match? */ + r = dnssec_nsec_wildcard_equal(rr, name); + if (r < 0) + return r; + } + if (r > 0) { + if (key->type == DNS_TYPE_DS) { + /* If we look for a DS RR and the server sent us the NSEC RR of the child zone + * we have a problem. For DS RRs we want the NSEC RR from the parent */ + if (bitmap_isset(rr->nsec.types, DNS_TYPE_SOA)) + continue; + } else { + /* For all RR types, ensure that if NS is set SOA is set too, so that we know + * we got the child's NSEC. */ + if (bitmap_isset(rr->nsec.types, DNS_TYPE_NS) && + !bitmap_isset(rr->nsec.types, DNS_TYPE_SOA)) + continue; + } + + if (bitmap_isset(rr->nsec.types, key->type)) + *result = DNSSEC_NSEC_FOUND; + else if (bitmap_isset(rr->nsec.types, DNS_TYPE_CNAME)) + *result = DNSSEC_NSEC_CNAME; + else + *result = DNSSEC_NSEC_NODATA; + + if (authenticated) + *authenticated = flags & DNS_ANSWER_AUTHENTICATED; + if (ttl) + *ttl = rr->ttl; + + return 0; + } + + /* Check if the name we are looking for is an empty non-terminal within the owner or next name + * of the NSEC RR. */ + r = dnssec_nsec_in_path(rr, name); + if (r < 0) + return r; + if (r > 0) { + *result = DNSSEC_NSEC_NODATA; + + if (authenticated) + *authenticated = flags & DNS_ANSWER_AUTHENTICATED; + if (ttl) + *ttl = rr->ttl; + + return 0; + } + + /* The following two "covering" checks, are not useful if the NSEC is from the parent */ + r = dnssec_nsec_from_parent_zone(rr, name); + if (r < 0) + return r; + if (r > 0) + continue; + + /* Check if this NSEC RR proves the absence of an explicit RR under this name */ + r = dnssec_nsec_covers(rr, name); + if (r < 0) + return r; + if (r > 0 && (!covering_rr || !covering_rr_authenticated)) { + covering_rr = rr; + covering_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED; + } + + /* Check if this NSEC RR proves the absence of a wildcard RR under this name */ + r = dnssec_nsec_covers_wildcard(rr, name); + if (r < 0) + return r; + if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) { + wildcard_rr = rr; + wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED; + } + } + + if (covering_rr && wildcard_rr) { + /* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we + * proved the NXDOMAIN case. */ + *result = DNSSEC_NSEC_NXDOMAIN; + + if (authenticated) + *authenticated = covering_rr_authenticated && wildcard_rr_authenticated; + if (ttl) + *ttl = MIN(covering_rr->ttl, wildcard_rr->ttl); + + return 0; + } + + /* OK, this was not sufficient. Let's see if NSEC3 can help. */ + if (have_nsec3) + return dnssec_test_nsec3(answer, key, result, authenticated, ttl); + + /* No approproate NSEC RR found, report this. */ + *result = DNSSEC_NSEC_NO_RR; + return 0; +} + +static int dnssec_nsec_test_enclosed(DnsAnswer *answer, uint16_t type, const char *name, const char *zone, bool *authenticated) { + DnsResourceRecord *rr; + DnsAnswerFlags flags; + int r; + + assert(name); + assert(zone); + + /* Checks whether there's an NSEC/NSEC3 that proves that the specified 'name' is non-existing in the specified + * 'zone'. The 'zone' must be a suffix of the 'name'. */ + + DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) { + bool found = false; + + if (rr->key->type != type && type != DNS_TYPE_ANY) + continue; + + switch (rr->key->type) { + + case DNS_TYPE_NSEC: + + /* We only care for NSEC RRs from the indicated zone */ + r = dns_resource_record_is_signer(rr, zone); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), name, rr->nsec.next_domain_name); + if (r < 0) + return r; + + found = r > 0; + break; + + case DNS_TYPE_NSEC3: { + _cleanup_free_ char *hashed_domain = NULL, *next_hashed_domain = NULL; + + /* We only care for NSEC3 RRs from the indicated zone */ + r = dns_resource_record_is_signer(rr, zone); + if (r < 0) + return r; + if (r == 0) + continue; + + r = nsec3_is_good(rr, NULL); + if (r < 0) + return r; + if (r == 0) + break; + + /* Format the domain we are testing with the NSEC3 RR's hash function */ + r = nsec3_hashed_domain_make( + rr, + name, + zone, + &hashed_domain); + if (r < 0) + return r; + if ((size_t) r != rr->nsec3.next_hashed_name_size) + break; + + /* Format the NSEC3's next hashed name as proper domain name */ + r = nsec3_hashed_domain_format( + rr->nsec3.next_hashed_name, + rr->nsec3.next_hashed_name_size, + zone, + &next_hashed_domain); + if (r < 0) + return r; + + r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), hashed_domain, next_hashed_domain); + if (r < 0) + return r; + + found = r > 0; + break; + } + + default: + continue; + } + + if (found) { + if (authenticated) + *authenticated = flags & DNS_ANSWER_AUTHENTICATED; + return 1; + } + } + + return 0; +} + +static int dnssec_test_positive_wildcard_nsec3( + DnsAnswer *answer, + const char *name, + const char *source, + const char *zone, + bool *authenticated) { + + const char *next_closer = NULL; + int r; + + /* Run a positive NSEC3 wildcard proof. Specifically: + * + * A proof that the the "next closer" of the generating wildcard does not exist. + * + * Note a key difference between the NSEC3 and NSEC versions of the proof. NSEC RRs don't have to exist for + * empty non-transients. NSEC3 RRs however have to. This means it's sufficient to check if the next closer name + * exists for the NSEC3 RR and we are done. + * + * To prove that a.b.c.d.e.f is rightfully synthesized from a wildcard *.d.e.f all we have to check is that + * c.d.e.f does not exist. */ + + for (;;) { + next_closer = name; + r = dns_name_parent(&name); + if (r < 0) + return r; + if (r == 0) + return 0; + + r = dns_name_equal(name, source); + if (r < 0) + return r; + if (r > 0) + break; + } + + return dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC3, next_closer, zone, authenticated); +} + +static int dnssec_test_positive_wildcard_nsec( + DnsAnswer *answer, + const char *name, + const char *source, + const char *zone, + bool *_authenticated) { + + bool authenticated = true; + int r; + + /* Run a positive NSEC wildcard proof. Specifically: + * + * A proof that there's neither a wildcard name nor a non-wildcard name that is a suffix of the name "name" and + * a prefix of the synthesizing source "source" in the zone "zone". + * + * See RFC 5155, Section 8.8 and RFC 4035, Section 5.3.4 + * + * Note that if we want to prove that a.b.c.d.e.f is rightfully synthesized from a wildcard *.d.e.f, then we + * have to prove that none of the following exist: + * + * 1) a.b.c.d.e.f + * 2) *.b.c.d.e.f + * 3) b.c.d.e.f + * 4) *.c.d.e.f + * 5) c.d.e.f + * + */ + + for (;;) { + _cleanup_free_ char *wc = NULL; + bool a = false; + + /* Check if there's an NSEC or NSEC3 RR that proves that the mame we determined is really non-existing, + * i.e between the owner name and the next name of an NSEC RR. */ + r = dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC, name, zone, &a); + if (r <= 0) + return r; + + authenticated = authenticated && a; + + /* Strip one label off */ + r = dns_name_parent(&name); + if (r <= 0) + return r; + + /* Did we reach the source of synthesis? */ + r = dns_name_equal(name, source); + if (r < 0) + return r; + if (r > 0) { + /* Successful exit */ + *_authenticated = authenticated; + return 1; + } + + /* Safety check, that the source of synthesis is still our suffix */ + r = dns_name_endswith(name, source); + if (r < 0) + return r; + if (r == 0) + return -EBADMSG; + + /* Replace the label we stripped off with an asterisk */ + wc = strappend("*.", name); + if (!wc) + return -ENOMEM; + + /* And check if the proof holds for the asterisk name, too */ + r = dnssec_nsec_test_enclosed(answer, DNS_TYPE_NSEC, wc, zone, &a); + if (r <= 0) + return r; + + authenticated = authenticated && a; + /* In the next iteration we'll check the non-asterisk-prefixed version */ + } +} + +int dnssec_test_positive_wildcard( + DnsAnswer *answer, + const char *name, + const char *source, + const char *zone, + bool *authenticated) { + + int r; + + assert(name); + assert(source); + assert(zone); + assert(authenticated); + + r = dns_answer_contains_zone_nsec3(answer, zone); + if (r < 0) + return r; + if (r > 0) + return dnssec_test_positive_wildcard_nsec3(answer, name, source, zone, authenticated); + else + return dnssec_test_positive_wildcard_nsec(answer, name, source, zone, authenticated); +} + +#else + +int dnssec_verify_rrset( + DnsAnswer *a, + const DnsResourceKey *key, + DnsResourceRecord *rrsig, + DnsResourceRecord *dnskey, + usec_t realtime, + DnssecResult *result) { + + return -EOPNOTSUPP; +} + +int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok) { + + return -EOPNOTSUPP; +} + +int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig) { + + return -EOPNOTSUPP; +} + +int dnssec_verify_rrset_search( + DnsAnswer *a, + const DnsResourceKey *key, + DnsAnswer *validated_dnskeys, + usec_t realtime, + DnssecResult *result, + DnsResourceRecord **ret_rrsig) { + + return -EOPNOTSUPP; +} + +int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key) { + + return -EOPNOTSUPP; +} + +int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke) { + + return -EOPNOTSUPP; +} + +int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds) { + + return -EOPNOTSUPP; +} + +int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret) { + + return -EOPNOTSUPP; +} + +int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) { + + return -EOPNOTSUPP; +} + +int dnssec_test_positive_wildcard( + DnsAnswer *answer, + const char *name, + const char *source, + const char *zone, + bool *authenticated) { + + return -EOPNOTSUPP; +} + +#endif + +static const char* const dnssec_result_table[_DNSSEC_RESULT_MAX] = { + [DNSSEC_VALIDATED] = "validated", + [DNSSEC_VALIDATED_WILDCARD] = "validated-wildcard", + [DNSSEC_INVALID] = "invalid", + [DNSSEC_SIGNATURE_EXPIRED] = "signature-expired", + [DNSSEC_UNSUPPORTED_ALGORITHM] = "unsupported-algorithm", + [DNSSEC_NO_SIGNATURE] = "no-signature", + [DNSSEC_MISSING_KEY] = "missing-key", + [DNSSEC_UNSIGNED] = "unsigned", + [DNSSEC_FAILED_AUXILIARY] = "failed-auxiliary", + [DNSSEC_NSEC_MISMATCH] = "nsec-mismatch", + [DNSSEC_INCOMPATIBLE_SERVER] = "incompatible-server", +}; +DEFINE_STRING_TABLE_LOOKUP(dnssec_result, DnssecResult); + +static const char* const dnssec_verdict_table[_DNSSEC_VERDICT_MAX] = { + [DNSSEC_SECURE] = "secure", + [DNSSEC_INSECURE] = "insecure", + [DNSSEC_BOGUS] = "bogus", + [DNSSEC_INDETERMINATE] = "indeterminate", +}; +DEFINE_STRING_TABLE_LOOKUP(dnssec_verdict, DnssecVerdict); diff --git a/src/resolve/resolved-dns-dnssec.h b/src/resolve/resolved-dns-dnssec.h new file mode 100644 index 000000000..77bd4d71b --- /dev/null +++ b/src/resolve/resolved-dns-dnssec.h @@ -0,0 +1,102 @@ +#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 . +***/ + +typedef enum DnssecResult DnssecResult; +typedef enum DnssecVerdict DnssecVerdict; + +#include "dns-domain.h" +#include "resolved-dns-answer.h" +#include "resolved-dns-rr.h" + +enum DnssecResult { + /* These five are returned by dnssec_verify_rrset() */ + DNSSEC_VALIDATED, + DNSSEC_VALIDATED_WILDCARD, /* Validated via a wildcard RRSIG, further NSEC/NSEC3 checks necessary */ + DNSSEC_INVALID, + DNSSEC_SIGNATURE_EXPIRED, + DNSSEC_UNSUPPORTED_ALGORITHM, + + /* These two are added by dnssec_verify_rrset_search() */ + DNSSEC_NO_SIGNATURE, + DNSSEC_MISSING_KEY, + + /* These two are added by the DnsTransaction logic */ + DNSSEC_UNSIGNED, + DNSSEC_FAILED_AUXILIARY, + DNSSEC_NSEC_MISMATCH, + DNSSEC_INCOMPATIBLE_SERVER, + + _DNSSEC_RESULT_MAX, + _DNSSEC_RESULT_INVALID = -1 +}; + +enum DnssecVerdict { + DNSSEC_SECURE, + DNSSEC_INSECURE, + DNSSEC_BOGUS, + DNSSEC_INDETERMINATE, + + _DNSSEC_VERDICT_MAX, + _DNSSEC_VERDICT_INVALID = -1 +}; + +#define DNSSEC_CANONICAL_HOSTNAME_MAX (DNS_HOSTNAME_MAX + 2) + +/* The longest digest we'll ever generate, of all digest algorithms we support */ +#define DNSSEC_HASH_SIZE_MAX (MAX(20, 32)) + +int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, bool revoked_ok); +int dnssec_key_match_rrsig(const DnsResourceKey *key, DnsResourceRecord *rrsig); + +int dnssec_verify_rrset(DnsAnswer *answer, const DnsResourceKey *key, DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, usec_t realtime, DnssecResult *result); +int dnssec_verify_rrset_search(DnsAnswer *answer, const DnsResourceKey *key, DnsAnswer *validated_dnskeys, usec_t realtime, DnssecResult *result, DnsResourceRecord **rrsig); + +int dnssec_verify_dnskey_by_ds(DnsResourceRecord *dnskey, DnsResourceRecord *ds, bool mask_revoke); +int dnssec_verify_dnskey_by_ds_search(DnsResourceRecord *dnskey, DnsAnswer *validated_ds); + +int dnssec_has_rrsig(DnsAnswer *a, const DnsResourceKey *key); + +uint16_t dnssec_keytag(DnsResourceRecord *dnskey, bool mask_revoke); + +int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max); + +int dnssec_nsec3_hash(DnsResourceRecord *nsec3, const char *name, void *ret); + +typedef enum DnssecNsecResult { + DNSSEC_NSEC_NO_RR, /* No suitable NSEC/NSEC3 RR found */ + DNSSEC_NSEC_CNAME, /* Didn't find what was asked for, but did find CNAME */ + DNSSEC_NSEC_UNSUPPORTED_ALGORITHM, + DNSSEC_NSEC_NXDOMAIN, + DNSSEC_NSEC_NODATA, + DNSSEC_NSEC_FOUND, + DNSSEC_NSEC_OPTOUT, +} DnssecNsecResult; + +int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl); + + +int dnssec_test_positive_wildcard(DnsAnswer *a, const char *name, const char *source, const char *zone, bool *authenticated); + +const char* dnssec_result_to_string(DnssecResult m) _const_; +DnssecResult dnssec_result_from_string(const char *s) _pure_; + +const char* dnssec_verdict_to_string(DnssecVerdict m) _const_; +DnssecVerdict dnssec_verdict_from_string(const char *s) _pure_; diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index f23b3cf89..c940dd892 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -28,6 +26,8 @@ #include "utf8.h" #include "util.h" +#define EDNS0_OPT_DO (1<<15) + int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { DnsPacket *p; size_t a; @@ -56,6 +56,7 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { p->size = p->rindex = DNS_PACKET_HEADER_SIZE; p->allocated = a; p->protocol = protocol; + p->opt_start = p->opt_size = (size_t) -1; p->n_ref = 1; *ret = p; @@ -63,20 +64,18 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { return 0; } -int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { - DnsPacket *p; +void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated) { + DnsPacketHeader *h; - int r; - assert(ret); - - r = dns_packet_new(&p, protocol, mtu); - if (r < 0) - return r; + assert(p); h = DNS_PACKET_HEADER(p); - if (protocol == DNS_PROTOCOL_LLMNR) + switch(p->protocol) { + case DNS_PROTOCOL_LLMNR: + assert(!truncated); + h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */, 0 /* opcode */, 0 /* c */, @@ -86,7 +85,23 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { 0 /* ad */, 0 /* cd */, 0 /* rcode */)); - else + break; + + case DNS_PROTOCOL_MDNS: + h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */, + 0 /* opcode */, + 0 /* aa */, + truncated /* tc */, + 0 /* rd (ask for recursion) */, + 0 /* ra */, + 0 /* ad */, + 0 /* cd */, + 0 /* rcode */)); + break; + + default: + assert(!truncated); + h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */, 0 /* opcode */, 0 /* aa */, @@ -94,8 +109,25 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { 1 /* rd (ask for recursion) */, 0 /* ra */, 0 /* ad */, - 0 /* cd */, + dnssec_checking_disabled /* cd */, 0 /* rcode */)); + } +} + +int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu, bool dnssec_checking_disabled) { + DnsPacket *p; + int r; + + assert(ret); + + r = dns_packet_new(&p, protocol, mtu); + if (r < 0) + return r; + + /* Always set the TC bit to 0 initially. + * If there are multiple packets later, we'll update the bit shortly before sending. + */ + dns_packet_set_flags(p, dnssec_checking_disabled, false); *ret = p; return 0; @@ -106,6 +138,8 @@ DnsPacket *dns_packet_ref(DnsPacket *p) { if (!p) return NULL; + assert(!p->on_stack); + assert(p->n_ref > 0); p->n_ref++; return p; @@ -118,13 +152,16 @@ static void dns_packet_free(DnsPacket *p) { dns_question_unref(p->question); dns_answer_unref(p->answer); + dns_resource_record_unref(p->opt); while ((s = hashmap_steal_first_key(p->names))) free(s); hashmap_free(p->names); free(p->_data); - free(p); + + if (!p->on_stack) + free(p); } DnsPacket *dns_packet_unref(DnsPacket *p) { @@ -133,6 +170,8 @@ DnsPacket *dns_packet_unref(DnsPacket *p) { assert(p->n_ref > 0); + dns_packet_unref(p->more); + if (p->n_ref == 1) dns_packet_free(p); else @@ -169,6 +208,7 @@ int dns_packet_validate_reply(DnsPacket *p) { return -EBADMSG; switch (p->protocol) { + case DNS_PROTOCOL_LLMNR: /* RFC 4795, Section 2.1.1. says to discard all replies with QDCOUNT != 1 */ if (DNS_PACKET_QDCOUNT(p) != 1) @@ -176,6 +216,13 @@ int dns_packet_validate_reply(DnsPacket *p) { break; + case DNS_PROTOCOL_MDNS: + /* RFC 6762, Section 18 */ + if (DNS_PACKET_RCODE(p) != 0) + return -EBADMSG; + + break; + default: break; } @@ -202,6 +249,7 @@ int dns_packet_validate_query(DnsPacket *p) { return -EBADMSG; switch (p->protocol) { + case DNS_PROTOCOL_LLMNR: /* RFC 4795, Section 2.1.1. says to discard all queries with QDCOUNT != 1 */ if (DNS_PACKET_QDCOUNT(p) != 1) @@ -217,6 +265,18 @@ int dns_packet_validate_query(DnsPacket *p) { break; + case DNS_PROTOCOL_MDNS: + /* RFC 6762, Section 18 */ + if (DNS_PACKET_AA(p) != 0 || + DNS_PACKET_RD(p) != 0 || + DNS_PACKET_RA(p) != 0 || + DNS_PACKET_AD(p) != 0 || + DNS_PACKET_CD(p) != 0 || + DNS_PACKET_RCODE(p) != 0) + return -EBADMSG; + + break; + default: break; } @@ -267,7 +327,7 @@ static int dns_packet_extend(DnsPacket *p, size_t add, void **ret, size_t *start return 0; } -static void dns_packet_truncate(DnsPacket *p, size_t sz) { +void dns_packet_truncate(DnsPacket *p, size_t sz) { Iterator i; char *s; void *n; @@ -349,43 +409,68 @@ 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) { - void *d; - size_t l; - int r; - assert(p); assert(s); - l = strlen(s); - if (l > 255) + return dns_packet_append_raw_string(p, s, strlen(s), start); +} + +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 + l, &d, start); + r = dns_packet_extend(p, 1 + size, &d, start); if (r < 0) return r; - ((uint8_t*) d)[0] = (uint8_t) l; - memcpy(((uint8_t*) d) + 1, s, l); + ((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 dns_packet_append_label(DnsPacket *p, const char *d, size_t l, bool canonical_candidate, size_t *start) { + uint8_t *w; int r; + /* Append a label to a packet. Optionally, does this in DNSSEC + * canonical form, if this label is marked as a candidate for + * it, and the canonical form logic is enabled for the + * packet */ + assert(p); assert(d); if (l > DNS_LABEL_MAX) return -E2BIG; - r = dns_packet_extend(p, 1 + l, &w, start); + r = dns_packet_extend(p, 1 + l, (void**) &w, start); if (r < 0) return r; - ((uint8_t*) w)[0] = (uint8_t) l; - memcpy(((uint8_t*) w) + 1, d, l); + *(w++) = (uint8_t) l; + + if (p->canonical_form && canonical_candidate) { + size_t i; + + /* Generate in canonical form, as defined by DNSSEC + * RFC 4034, Section 6.2, i.e. all lower-case. */ + + for (i = 0; i < l; i++) + w[i] = (uint8_t) ascii_tolower(d[i]); + } else + /* Otherwise, just copy the string unaltered. This is + * essential for DNS-SD, where the casing of labels + * matters and needs to be retained. */ + memcpy(w, d, l); return 0; } @@ -394,6 +479,7 @@ int dns_packet_append_name( DnsPacket *p, const char *name, bool allow_compression, + bool canonical_candidate, size_t *start) { size_t saved_size; @@ -407,11 +493,10 @@ int dns_packet_append_name( saved_size = p->size; - while (*name) { - _cleanup_free_ char *s = NULL; + while (!dns_name_is_root(name)) { + const char *z = name; char label[DNS_LABEL_MAX]; size_t n = 0; - int k; if (allow_compression) n = PTR_TO_SIZE(hashmap_get(p->names, name)); @@ -427,32 +512,23 @@ int dns_packet_append_name( } } - s = strdup(name); - if (!s) { - r = -ENOMEM; - goto fail; - } - r = dns_label_unescape(&name, label, sizeof(label)); if (r < 0) goto fail; - if (p->protocol == DNS_PROTOCOL_DNS) - k = dns_label_apply_idna(label, r, label, sizeof(label)); - else - k = dns_label_undo_idna(label, r, label, sizeof(label)); - if (k < 0) { - r = k; - goto fail; - } - if (k > 0) - r = k; - - r = dns_packet_append_label(p, label, r, &n); + r = dns_packet_append_label(p, label, r, canonical_candidate, &n); if (r < 0) goto fail; if (allow_compression) { + _cleanup_free_ char *s = NULL; + + s = strdup(z); + if (!s) { + r = -ENOMEM; + goto fail; + } + r = hashmap_ensure_allocated(&p->names, &dns_name_hash_ops); if (r < 0) goto fail; @@ -489,7 +565,7 @@ int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *k, size_t *start) saved_size = p->size; - r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, NULL); + r = dns_packet_append_name(p, DNS_RESOURCE_KEY_NAME(k), true, true, NULL); if (r < 0) goto fail; @@ -511,7 +587,7 @@ fail: return r; } -static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, uint8_t *types, size_t *start) { +static int dns_packet_append_type_window(DnsPacket *p, uint8_t window, uint8_t length, const uint8_t *types, size_t *start) { size_t saved_size; int r; @@ -552,7 +628,6 @@ static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) { int r; assert(p); - assert(types); saved_size = p->size; @@ -568,15 +643,16 @@ static int dns_packet_append_types(DnsPacket *p, Bitmap *types, size_t *start) { } window = n >> 8; - entry = n & 255; bitmaps[entry / 8] |= 1 << (7 - (entry % 8)); } - r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL); - if (r < 0) - goto fail; + if (bitmaps[entry / 8] != 0) { + r = dns_packet_append_type_window(p, window, entry / 8 + 1, bitmaps, NULL); + if (r < 0) + goto fail; + } if (start) *start = saved_size; @@ -587,8 +663,123 @@ fail: return r; } -int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) { - size_t saved_size, rdlength_offset, end, rdlength; +/* Append the OPT pseudo-RR described in RFC6891 */ +int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start) { + size_t saved_size; + int r; + + assert(p); + /* we must never advertise supported packet size smaller than the legacy max */ + assert(max_udp_size >= DNS_PACKET_UNICAST_SIZE_MAX); + + if (p->opt_start != (size_t) -1) + return -EBUSY; + + assert(p->opt_size == (size_t) -1); + + saved_size = p->size; + + /* empty name */ + r = dns_packet_append_uint8(p, 0, NULL); + if (r < 0) + return r; + + /* type */ + r = dns_packet_append_uint16(p, DNS_TYPE_OPT, NULL); + if (r < 0) + goto fail; + + /* maximum udp packet that can be received */ + r = dns_packet_append_uint16(p, max_udp_size, NULL); + if (r < 0) + goto fail; + + /* extended RCODE and VERSION */ + r = dns_packet_append_uint16(p, 0, NULL); + if (r < 0) + goto fail; + + /* flags: DNSSEC OK (DO), see RFC3225 */ + r = dns_packet_append_uint16(p, edns0_do ? EDNS0_OPT_DO : 0, NULL); + if (r < 0) + goto fail; + + /* RDLENGTH */ + + if (edns0_do) { + /* If DO is on, also append RFC6975 Algorithm data */ + + static const uint8_t rfc6975[] = { + + 0, 5, /* OPTION_CODE: DAU */ + 0, 6, /* LIST_LENGTH */ + DNSSEC_ALGORITHM_RSASHA1, + DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1, + DNSSEC_ALGORITHM_RSASHA256, + DNSSEC_ALGORITHM_RSASHA512, + DNSSEC_ALGORITHM_ECDSAP256SHA256, + DNSSEC_ALGORITHM_ECDSAP384SHA384, + + 0, 6, /* OPTION_CODE: DHU */ + 0, 3, /* LIST_LENGTH */ + DNSSEC_DIGEST_SHA1, + DNSSEC_DIGEST_SHA256, + DNSSEC_DIGEST_SHA384, + + 0, 7, /* OPTION_CODE: N3U */ + 0, 1, /* LIST_LENGTH */ + NSEC3_ALGORITHM_SHA1, + }; + + r = dns_packet_append_uint16(p, sizeof(rfc6975), NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_blob(p, rfc6975, sizeof(rfc6975), NULL); + } else + r = dns_packet_append_uint16(p, 0, NULL); + + if (r < 0) + goto fail; + + DNS_PACKET_HEADER(p)->arcount = htobe16(DNS_PACKET_ARCOUNT(p) + 1); + + p->opt_start = saved_size; + p->opt_size = p->size - saved_size; + + if (start) + *start = saved_size; + + return 0; + +fail: + dns_packet_truncate(p, saved_size); + return r; +} + +int dns_packet_truncate_opt(DnsPacket *p) { + assert(p); + + if (p->opt_start == (size_t) -1) { + assert(p->opt_size == (size_t) -1); + return 0; + } + + assert(p->opt_size != (size_t) -1); + assert(DNS_PACKET_ARCOUNT(p) > 0); + + if (p->opt_start + p->opt_size != p->size) + return -EBUSY; + + dns_packet_truncate(p, p->opt_start); + DNS_PACKET_HEADER(p)->arcount = htobe16(DNS_PACKET_ARCOUNT(p) - 1); + p->opt_start = p->opt_size = (size_t) -1; + + return 1; +} + +int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start) { + size_t saved_size, rdlength_offset, end, rdlength, rds; int r; assert(p); @@ -609,6 +800,8 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; + rds = p->size - saved_size; + switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { case DNS_TYPE_SRV: @@ -624,14 +817,14 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; - r = dns_packet_append_name(p, rr->srv.name, true, NULL); + r = dns_packet_append_name(p, rr->srv.name, true, false, NULL); break; case DNS_TYPE_PTR: case DNS_TYPE_NS: case DNS_TYPE_CNAME: case DNS_TYPE_DNAME: - r = dns_packet_append_name(p, rr->ptr.name, true, NULL); + r = dns_packet_append_name(p, rr->ptr.name, true, false, NULL); break; case DNS_TYPE_HINFO: @@ -643,19 +836,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 +857,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); @@ -674,11 +867,11 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star break; case DNS_TYPE_SOA: - r = dns_packet_append_name(p, rr->soa.mname, true, NULL); + r = dns_packet_append_name(p, rr->soa.mname, true, false, NULL); if (r < 0) goto fail; - r = dns_packet_append_name(p, rr->soa.rname, true, NULL); + r = dns_packet_append_name(p, rr->soa.rname, true, false, NULL); if (r < 0) goto fail; @@ -706,7 +899,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; - r = dns_packet_append_name(p, rr->mx.exchange, true, NULL); + r = dns_packet_append_name(p, rr->mx.exchange, true, false, NULL); break; case DNS_TYPE_LOC: @@ -766,11 +959,11 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star break; case DNS_TYPE_DNSKEY: - r = dns_packet_append_uint16(p, dnskey_to_flags(rr), NULL); + r = dns_packet_append_uint16(p, rr->dnskey.flags, NULL); if (r < 0) goto fail; - r = dns_packet_append_uint8(p, 3u, NULL); + r = dns_packet_append_uint8(p, rr->dnskey.protocol, NULL); if (r < 0) goto fail; @@ -810,7 +1003,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (r < 0) goto fail; - r = dns_packet_append_name(p, rr->rrsig.signer, false, NULL); + r = dns_packet_append_name(p, rr->rrsig.signer, false, true, NULL); if (r < 0) goto fail; @@ -818,7 +1011,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star break; case DNS_TYPE_NSEC: - r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, NULL); + r = dns_packet_append_name(p, rr->nsec.next_domain_name, false, false, NULL); if (r < 0) goto fail; @@ -827,6 +1020,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star goto fail; break; + case DNS_TYPE_NSEC3: r = dns_packet_append_uint8(p, rr->nsec3.algorithm, NULL); if (r < 0) @@ -861,10 +1055,29 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star goto fail; break; + + case DNS_TYPE_TLSA: + r = dns_packet_append_uint8(p, rr->tlsa.cert_usage, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint8(p, rr->tlsa.selector, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_uint8(p, rr->tlsa.matching_type, NULL); + if (r < 0) + goto fail; + + r = dns_packet_append_blob(p, rr->tlsa.data, rr->tlsa.data_size, NULL); + break; + + case DNS_TYPE_OPT: + case DNS_TYPE_OPENPGPKEY: case _DNS_TYPE_INVALID: /* unparseable */ default: - r = dns_packet_append_blob(p, rr->generic.data, rr->generic.size, NULL); + r = dns_packet_append_blob(p, rr->generic.data, rr->generic.data_size, NULL); break; } if (r < 0) @@ -873,7 +1086,7 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star /* Let's calculate the actual data size and update the field */ rdlength = p->size - rdlength_offset - sizeof(uint16_t); if (rdlength > 0xFFFF) { - r = ENOSPC; + r = -ENOSPC; goto fail; } @@ -887,6 +1100,9 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star if (start) *start = saved_size; + if (rdata_start) + *rdata_start = rds; + return 0; fail: @@ -894,7 +1110,6 @@ fail: return r; } - int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start) { assert(p); @@ -1062,6 +1277,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 +1338,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 +1345,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) { @@ -1277,8 +1519,9 @@ fail: return r; } -int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) { +int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flush, size_t *start) { _cleanup_free_ char *name = NULL; + bool cache_flush = false; uint16_t class, type; DnsResourceKey *key; size_t saved_rindex; @@ -1301,6 +1544,15 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) { if (r < 0) goto fail; + if (p->protocol == DNS_PROTOCOL_MDNS) { + /* See RFC6762, Section 10.2 */ + + if (type != DNS_TYPE_OPT && (class & MDNS_RR_CACHE_FLUSH)) { + class &= ~MDNS_RR_CACHE_FLUSH; + cache_flush = true; + } + } + key = dns_resource_key_new_consume(class, type, name); if (!key) { r = -ENOMEM; @@ -1310,6 +1562,8 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) { name = NULL; *ret = key; + if (ret_cache_flush) + *ret_cache_flush = cache_flush; if (start) *start = saved_rindex; @@ -1325,22 +1579,12 @@ static bool loc_size_ok(uint8_t size) { return m <= 9 && e <= 9 && (m > 0 || e == 0); } -static int dnskey_parse_flags(DnsResourceRecord *rr, uint16_t flags) { - assert(rr); - - if (flags & ~(DNSKEY_FLAG_SEP | DNSKEY_FLAG_ZONE_KEY)) - return -EBADMSG; - - rr->dnskey.zone_key_flag = flags & DNSKEY_FLAG_ZONE_KEY; - rr->dnskey.sep_flag = flags & DNSKEY_FLAG_SEP; - return 0; -} - -int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { +int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; size_t saved_rindex, offset; uint16_t rdlength; + bool cache_flush; int r; assert(p); @@ -1348,12 +1592,12 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { saved_rindex = p->rindex; - r = dns_packet_read_key(p, &key, NULL); + r = dns_packet_read_key(p, &key, &cache_flush, NULL); if (r < 0) goto fail; - if (key->class == DNS_CLASS_ANY || - key->type == DNS_TYPE_ANY) { + if (!dns_class_is_valid_rr(key->class)|| + !dns_type_is_valid_rr(key->type)) { r = -EBADMSG; goto fail; } @@ -1368,6 +1612,11 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { if (r < 0) goto fail; + /* RFC 2181, Section 8, suggests to + * treat a TTL with the MSB set as a zero TTL. */ + if (rr->ttl & UINT32_C(0x80000000)) + rr->ttl = 0; + r = dns_packet_read_uint16(p, &rdlength, NULL); if (r < 0) goto fail; @@ -1412,24 +1661,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; } } @@ -1565,6 +1827,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { } break; + case DNS_TYPE_SSHFP: r = dns_packet_read_uint8(p, &rr->sshfp.algorithm, NULL); if (r < 0) @@ -1587,28 +1850,15 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { break; - case DNS_TYPE_DNSKEY: { - uint16_t flags; - uint8_t proto; - - r = dns_packet_read_uint16(p, &flags, NULL); + case DNS_TYPE_DNSKEY: + r = dns_packet_read_uint16(p, &rr->dnskey.flags, NULL); if (r < 0) goto fail; - r = dnskey_parse_flags(rr, flags); + r = dns_packet_read_uint8(p, &rr->dnskey.protocol, NULL); if (r < 0) goto fail; - r = dns_packet_read_uint8(p, &proto, NULL); - if (r < 0) - goto fail; - - /* protocol is required to be always 3 */ - if (proto != 3) { - r = -EBADMSG; - goto fail; - } - r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL); if (r < 0) goto fail; @@ -1625,7 +1875,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { } break; - } case DNS_TYPE_RRSIG: r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL); @@ -1673,8 +1922,16 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { break; - case DNS_TYPE_NSEC: - r = dns_packet_read_name(p, &rr->nsec.next_domain_name, false, NULL); + case DNS_TYPE_NSEC: { + + /* + * RFC6762, section 18.14 explictly states mDNS should use name compression. + * This contradicts RFC3845, section 2.1.1 + */ + + bool allow_compressed = p->protocol == DNS_PROTOCOL_MDNS; + + r = dns_packet_read_name(p, &rr->nsec.next_domain_name, allow_compressed, NULL); if (r < 0) goto fail; @@ -1682,15 +1939,12 @@ 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; - + } case DNS_TYPE_NSEC3: { uint8_t size; @@ -1736,9 +1990,37 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { break; } + + case DNS_TYPE_TLSA: + r = dns_packet_read_uint8(p, &rr->tlsa.cert_usage, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint8(p, &rr->tlsa.selector, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_uint8(p, &rr->tlsa.matching_type, NULL); + if (r < 0) + goto fail; + + r = dns_packet_read_memdup(p, rdlength - 3, + &rr->tlsa.data, &rr->tlsa.data_size, + NULL); + if (rr->tlsa.data_size <= 0) { + /* the accepted size depends on the algorithm, but for now + just ensure that the value is greater than zero */ + r = -EBADMSG; + goto fail; + } + + break; + + case DNS_TYPE_OPT: /* we only care about the header of OPT for now. */ + case DNS_TYPE_OPENPGPKEY: default: unparseable: - r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.size, NULL); + r = dns_packet_read_memdup(p, rdlength, &rr->generic.data, &rr->generic.data_size, NULL); if (r < 0) goto fail; break; @@ -1753,6 +2035,8 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) { *ret = rr; rr = NULL; + if (ret_cache_flush) + *ret_cache_flush = cache_flush; if (start) *start = saved_rindex; @@ -1762,6 +2046,48 @@ fail: return r; } +static bool opt_is_good(DnsResourceRecord *rr, bool *rfc6975) { + const uint8_t* p; + bool found_dau_dhu_n3u = false; + size_t l; + + /* Checks whether the specified OPT RR is well-formed and whether it contains RFC6975 data (which is not OK in + * a reply). */ + + assert(rr); + assert(rr->key->type == DNS_TYPE_OPT); + + /* Check that the version is 0 */ + if (((rr->ttl >> 16) & UINT32_C(0xFF)) != 0) + return false; + + p = rr->opt.data; + l = rr->opt.data_size; + while (l > 0) { + uint16_t option_code, option_length; + + /* At least four bytes for OPTION-CODE and OPTION-LENGTH are required */ + if (l < 4U) + return false; + + option_code = unaligned_read_be16(p); + option_length = unaligned_read_be16(p + 2); + + if (l < option_length + 4U) + return false; + + /* RFC 6975 DAU, DHU or N3U fields found. */ + if (IN_SET(option_code, 5, 6, 7)) + found_dau_dhu_n3u = true; + + p += option_length + 4U; + l -= option_length + 4U; + } + + *rfc6975 = found_dau_dhu_n3u; + return true; +} + int dns_packet_extract(DnsPacket *p) { _cleanup_(dns_question_unrefp) DnsQuestion *question = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; @@ -1785,11 +2111,22 @@ int dns_packet_extract(DnsPacket *p) { for (i = 0; i < n; i++) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + bool cache_flush; - r = dns_packet_read_key(p, &key, NULL); + r = dns_packet_read_key(p, &key, &cache_flush, NULL); if (r < 0) goto finish; + if (cache_flush) { + r = -EBADMSG; + goto finish; + } + + if (!dns_type_is_valid_query(key->type)) { + r = -EBADMSG; + goto finish; + } + r = dns_question_add(question, key); if (r < 0) goto finish; @@ -1798,6 +2135,9 @@ int dns_packet_extract(DnsPacket *p) { n = DNS_PACKET_RRCOUNT(p); if (n > 0) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *previous = NULL; + bool bad_opt = false; + answer = dns_answer_new(n); if (!answer) { r = -ENOMEM; @@ -1806,15 +2146,84 @@ int dns_packet_extract(DnsPacket *p) { for (i = 0; i < n; i++) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + bool cache_flush; - r = dns_packet_read_rr(p, &rr, NULL); + r = dns_packet_read_rr(p, &rr, &cache_flush, NULL); if (r < 0) goto finish; - r = dns_answer_add(answer, rr, p->ifindex); - if (r < 0) - goto finish; + /* Try to reduce memory usage a bit */ + if (previous) + dns_resource_key_reduce(&rr->key, &previous->key); + + if (rr->key->type == DNS_TYPE_OPT) { + bool has_rfc6975; + + if (p->opt || bad_opt) { + /* Multiple OPT RRs? if so, let's ignore all, because there's something wrong + * with the server, and if one is valid we wouldn't know which one. */ + log_debug("Multiple OPT RRs detected, ignoring all."); + bad_opt = true; + continue; + } + + if (!dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key))) { + /* If the OPT RR is not owned by the root domain, then it is bad, let's ignore + * it. */ + log_debug("OPT RR is not owned by root domain, ignoring."); + bad_opt = true; + continue; + } + + if (i < DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)) { + /* OPT RR is in the wrong section? Some Belkin routers do this. This is a hint + * the EDNS implementation is borked, like the Belkin one is, hence ignore + * it. */ + log_debug("OPT RR in wrong section, ignoring."); + bad_opt = true; + continue; + } + + if (!opt_is_good(rr, &has_rfc6975)) { + log_debug("Malformed OPT RR, ignoring."); + bad_opt = true; + continue; + } + + if (has_rfc6975) { + /* If the OPT RR contains RFC6975 algorithm data, then this is indication that + * the server just copied the OPT it got from us (which contained that data) + * back into the reply. If so, then it doesn't properly support EDNS, as + * RFC6975 makes it very clear that the algorithm data should only be contained + * in questions, never in replies. Crappy Belkin routers copy the OPT data for + * example, hence let's detect this so that we downgrade early. */ + log_debug("OPT RR contained RFC6975 data, ignoring."); + bad_opt = true; + continue; + } + + p->opt = dns_resource_record_ref(rr); + } else { + + /* According to RFC 4795, section 2.9. only the RRs from the Answer section shall be + * cached. Hence mark only those RRs as cacheable by default, but not the ones from the + * Additional or Authority sections. */ + + r = dns_answer_add(answer, rr, p->ifindex, + (i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) | + (p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0)); + if (r < 0) + goto finish; + } + + /* Remember this RR, so that we potentically can merge it's ->key object with the next RR. Note + * that we only do this if we actually decided to keep the RR around. */ + dns_resource_record_unref(previous); + previous = dns_resource_record_ref(rr); } + + if (bad_opt) + p->opt = dns_resource_record_unref(p->opt); } p->question = question; @@ -1832,6 +2241,30 @@ finish: return r; } +int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) { + int r; + + assert(p); + assert(key); + + /* Checks if the specified packet is a reply for the specified + * key and the specified key is the only one in the question + * section. */ + + if (DNS_PACKET_QR(p) != 1) + return 0; + + /* Let's unpack the packet, if that hasn't happened yet. */ + r = dns_packet_extract(p); + if (r < 0) + return r; + + if (p->question->n_keys != 1) + return 0; + + return dns_resource_key_equal(p->question->keys[0], key); +} + static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = { [DNS_RCODE_SUCCESS] = "SUCCESS", [DNS_RCODE_FORMERR] = "FORMERR", @@ -1860,17 +2293,3 @@ static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = { [DNS_PROTOCOL_LLMNR] = "llmnr", }; DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol); - -static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = { - [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5", - [DNSSEC_ALGORITHM_DH] = "DH", - [DNSSEC_ALGORITHM_DSA] = "DSA", - [DNSSEC_ALGORITHM_ECC] = "ECC", - [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1", - [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1", - [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1", - [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT", - [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS", - [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID", -}; -DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int); diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index fbbabaf23..0bf34d270 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,21 +19,21 @@ along with systemd; If not, see . ***/ -#include #include +#include -#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, @@ -65,6 +63,9 @@ struct DnsPacketHeader { /* RFC 1035 say 512 is the maximum, for classic unicast DNS */ #define DNS_PACKET_UNICAST_SIZE_MAX 512 +/* With EDNS0 we can use larger packets, default to 4096, which is what is commonly used */ +#define DNS_PACKET_UNICAST_SIZE_LARGE_MAX 4096 + #define DNS_PACKET_SIZE_START 512 struct DnsPacket { @@ -73,10 +74,12 @@ struct DnsPacket { size_t size, allocated, rindex; void *_data; /* don't access directly, use DNS_PACKET_DATA()! */ Hashmap *names; /* For name compression */ + size_t opt_start, opt_size; /* Parsed data */ DnsQuestion *question; DnsAnswer *answer; + DnsResourceRecord *opt; /* Packet reception metadata */ int ifindex; @@ -85,8 +88,13 @@ struct DnsPacket { uint16_t sender_port, destination_port; uint32_t ttl; - bool extracted; - bool refuse_compression; + /* For support of truncated packets */ + DnsPacket *more; + + bool on_stack:1; + bool extracted:1; + bool refuse_compression:1; + bool canonical_form:1; }; static inline uint8_t* DNS_PACKET_DATA(DnsPacket *p) { @@ -109,7 +117,17 @@ static inline uint8_t* DNS_PACKET_DATA(DnsPacket *p) { #define DNS_PACKET_RA(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 7) & 1) #define DNS_PACKET_AD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 5) & 1) #define DNS_PACKET_CD(p) ((be16toh(DNS_PACKET_HEADER(p)->flags) >> 4) & 1) -#define DNS_PACKET_RCODE(p) (be16toh(DNS_PACKET_HEADER(p)->flags) & 15) + +static inline uint16_t DNS_PACKET_RCODE(DnsPacket *p) { + uint16_t rcode; + + if (p->opt) + rcode = (uint16_t) (p->opt->ttl >> 24); + else + rcode = 0; + + return rcode | (be16toh(DNS_PACKET_HEADER(p)->flags) & 15); +} /* LLMNR defines some bits differently */ #define DNS_PACKET_LLMNR_C(p) DNS_PACKET_AA(p) @@ -139,7 +157,9 @@ static inline unsigned DNS_PACKET_RRCOUNT(DnsPacket *p) { } int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t mtu); -int dns_packet_new_query(DnsPacket **p, DnsProtocol protocol, size_t mtu); +int dns_packet_new_query(DnsPacket **p, DnsProtocol protocol, size_t mtu, bool dnssec_checking_disabled); + +void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated); DnsPacket *dns_packet_ref(DnsPacket *p); DnsPacket *dns_packet_unref(DnsPacket *p); @@ -150,16 +170,22 @@ int dns_packet_validate(DnsPacket *p); int dns_packet_validate_reply(DnsPacket *p); int dns_packet_validate_query(DnsPacket *p); +int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key); + int dns_packet_append_blob(DnsPacket *p, const void *d, size_t sz, size_t *start); 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_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_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, bool canonical_candidate, size_t *start); +int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, bool canonical_candidate, size_t *start); int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start); -int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start); +int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start); +int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start); + +void dns_packet_truncate(DnsPacket *p, size_t sz); +int dns_packet_truncate_opt(DnsPacket *p); int dns_packet_read(DnsPacket *p, size_t sz, const void **ret, size_t *start); int dns_packet_read_blob(DnsPacket *p, void *d, size_t sz, size_t *start); @@ -167,16 +193,25 @@ 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_key(DnsPacket *p, DnsResourceKey **ret, size_t *start); -int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, 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, bool *ret_cache_flush, size_t *start); +int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start); 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; +} + +/* https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6 */ enum { DNS_RCODE_SUCCESS = 0, DNS_RCODE_FORMERR = 1, @@ -209,42 +244,25 @@ DnsProtocol dns_protocol_from_string(const char *s) _pure_; #define LLMNR_MULTICAST_IPV4_ADDRESS ((struct in_addr) { .s_addr = htobe32(224U << 24 | 252U) }) #define LLMNR_MULTICAST_IPV6_ADDRESS ((struct in6_addr) { .s6_addr = { 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03 } }) -#define DNSKEY_FLAG_ZONE_KEY (1u << 8) -#define DNSKEY_FLAG_SEP (1u << 0) +#define MDNS_MULTICAST_IPV4_ADDRESS ((struct in_addr) { .s_addr = htobe32(224U << 24 | 251U) }) +#define MDNS_MULTICAST_IPV6_ADDRESS ((struct in6_addr) { .s6_addr = { 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb } }) -static inline uint16_t dnskey_to_flags(const DnsResourceRecord *rr) { - return (rr->dnskey.zone_key_flag * DNSKEY_FLAG_ZONE_KEY | - rr->dnskey.sep_flag * DNSKEY_FLAG_SEP); -} +static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family, bool authenticated) { + uint64_t f; -/* http://tools.ietf.org/html/rfc4034#appendix-A.1 */ -enum { - DNSSEC_ALGORITHM_RSAMD5 = 1, - DNSSEC_ALGORITHM_DH, - DNSSEC_ALGORITHM_DSA, - DNSSEC_ALGORITHM_ECC, - DNSSEC_ALGORITHM_RSASHA1, - DNSSEC_ALGORITHM_DSA_NSEC3_SHA1, - DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1, - DNSSEC_ALGORITHM_INDIRECT = 252, - DNSSEC_ALGORITHM_PRIVATEDNS, - DNSSEC_ALGORITHM_PRIVATEOID, - _DNSSEC_ALGORITHM_MAX_DEFINED -}; + /* Converts a protocol + family into a flags field as used in queries and responses */ -const char* dnssec_algorithm_to_string(int i) _const_; -int dnssec_algorithm_from_string(const char *s) _pure_; - -static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family) { - - /* Converts a protocol + family into a flags field as used in queries */ + f = authenticated ? SD_RESOLVED_AUTHENTICATED : 0; switch (protocol) { case DNS_PROTOCOL_DNS: - return SD_RESOLVED_DNS; + return f|SD_RESOLVED_DNS; case DNS_PROTOCOL_LLMNR: - return family == AF_INET6 ? SD_RESOLVED_LLMNR_IPV6 : SD_RESOLVED_LLMNR_IPV4; + return f|(family == AF_INET6 ? SD_RESOLVED_LLMNR_IPV6 : SD_RESOLVED_LLMNR_IPV4); + + case DNS_PROTOCOL_MDNS: + return family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4; default: break; diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index f7cb84e2a..a378b2b7f 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,42 +19,387 @@ #include "alloc-util.h" #include "dns-domain.h" +#include "dns-type.h" #include "hostname-util.h" #include "local-addresses.h" #include "resolved-dns-query.h" +#include "resolved-dns-synthesize.h" +#include "resolved-etc-hosts.h" +#include "string-util.h" /* How long to wait for the query in total */ #define QUERY_TIMEOUT_USEC (30 * USEC_PER_SEC) #define CNAME_MAX 8 #define QUERIES_MAX 2048 +#define AUXILIARY_QUERIES_MAX 64 + +static int dns_query_candidate_new(DnsQueryCandidate **ret, DnsQuery *q, DnsScope *s) { + DnsQueryCandidate *c; + + assert(ret); + assert(q); + assert(s); + + 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; +} + +static void dns_query_candidate_stop(DnsQueryCandidate *c) { + DnsTransaction *t; + + assert(c); + + while ((t = set_steal_first(c->transactions))) { + set_remove(t->notify_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) { + DnsSearchDomain *next = NULL; + + assert(c); + + if (c->search_domain && c->search_domain->linked) + next = c->search_domain->domains_next; + else + next = dns_scope_get_search_domains(c->scope); + + for (;;) { + if (!next) /* We hit the end of the list */ + return 0; + + if (!next->route_only) + break; + + /* Skip over route-only domains */ + next = next->domains_next; + } + + 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); + + t = dns_scope_find_transaction(c->scope, key, true); + if (!t) { + r = dns_transaction_new(&t, c->scope, key); + if (r < 0) + return r; + } else { + if (set_contains(c->transactions, t)) + return 0; + } + + r = set_ensure_allocated(&c->transactions, NULL); + if (r < 0) + goto gc; + + r = set_ensure_allocated(&t->notify_query_candidates, NULL); + if (r < 0) + goto gc; + + r = set_put(t->notify_query_candidates, c); + if (r < 0) + goto gc; + + r = set_put(c->transactions, t); + if (r < 0) { + (void) set_remove(t->notify_query_candidates, c); + goto gc; + } + + return 1; + +gc: + dns_transaction_gc(t); + return r; +} + +static int dns_query_candidate_go(DnsQueryCandidate *c) { + DnsTransaction *t; + Iterator i; + int r; + unsigned n = 0; + + 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; + + n++; + } + + /* If there was nothing to start, then let's proceed immediately */ + if (n == 0) + dns_query_candidate_notify(c); + + 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_ERRNO; + + SET_FOREACH(t, c->transactions, i) { + + switch (t->state) { + + case DNS_TRANSACTION_NULL: + /* If there's a NULL transaction pending, then + * this means not all transactions where + * started yet, and we were called from within + * the stackframe that is supposed to start + * remaining transactions. In this case, + * simply claim the candidate is pending. */ + + case DNS_TRANSACTION_PENDING: + case DNS_TRANSACTION_VALIDATING: + /* If there's one transaction currently in + * VALIDATING state, then this means there's + * also one in PENDING state, hence we can + * return PENDING immediately. */ + return DNS_TRANSACTION_PENDING; + + case DNS_TRANSACTION_SUCCESS: + state = t->state; + break; + + default: + if (state != DNS_TRANSACTION_SUCCESS) + state = t->state; + + break; + } + } + + return state; +} + +static bool dns_query_candidate_is_routable(DnsQueryCandidate *c, uint16_t type) { + int family; + + assert(c); + + /* Checks whether the specified RR type matches an address family that is routable on the link(s) the scope of + * this candidate belongs to. Specifically, whether there's a routable IPv4 address on it if we query an A RR, + * or a routable IPv6 address if we query an AAAA RR. */ + + if (!c->query->suppress_unroutable_family) + return true; + + if (c->scope->protocol != DNS_PROTOCOL_DNS) + return true; + + family = dns_type_to_af(type); + if (family < 0) + return true; + + if (c->scope->link) + return link_relevant(c->scope->link, family, false); + else + return manager_routable(c->scope->manager, family); +} + +static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) { + DnsQuestion *question; + DnsResourceKey *key; + int n = 0, r; + + assert(c); + + dns_query_candidate_stop(c); + + question = dns_query_question_for_protocol(c->query, c->scope->protocol); + + /* Create one transaction per question key */ + DNS_QUESTION_FOREACH(key, question) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *new_key = NULL; + DnsResourceKey *qkey; + + if (!dns_query_candidate_is_routable(c, key->type)) + continue; + + if (c->search_domain) { + r = dns_resource_key_new_append_suffix(&new_key, key, c->search_domain->name); + if (r < 0) + goto fail; + + qkey = new_key; + } else + qkey = key; + + if (!dns_scope_good_key(c->scope, qkey)) + continue; + + r = dns_query_candidate_add_transaction(c, qkey); + if (r < 0) + goto fail; + + n++; + } + + return n; + +fail: + dns_query_candidate_stop(c); + return r; +} + +void dns_query_candidate_notify(DnsQueryCandidate *c) { + DnsTransactionState state; + int r; + + assert(c); + + state = dns_query_candidate_state(c); + + if (DNS_TRANSACTION_IS_LIVE(state)) + 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) { - DnsTransaction *t; + DnsQueryCandidate *c; assert(q); q->timeout_event_source = sd_event_source_unref(q->timeout_event_source); - while ((t = set_steal_first(q->transactions))) { - set_remove(t->queries, q); - dns_transaction_gc(t); - } + LIST_FOREACH(candidates_by_query, c, q->candidates) + dns_query_candidate_stop(c); +} + +static void dns_query_free_candidates(DnsQuery *q) { + assert(q); + + while (q->candidates) + dns_query_candidate_free(q->candidates); +} + +static void dns_query_reset_answer(DnsQuery *q) { + assert(q); + + q->answer = dns_answer_unref(q->answer); + q->answer_rcode = 0; + q->answer_dnssec_result = _DNSSEC_RESULT_INVALID; + q->answer_errno = 0; + q->answer_authenticated = false; + q->answer_protocol = _DNS_PROTOCOL_INVALID; + q->answer_family = AF_UNSPEC; + q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain); } 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); - dns_question_unref(q->question); - dns_answer_unref(q->answer); + 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); + } + + dns_query_free_candidates(q); + + dns_question_unref(q->question_idna); + dns_question_unref(q->question_utf8); + + dns_query_reset_answer(q); sd_bus_message_unref(q->request); sd_bus_track_unref(q->bus_track); + free(q->request_address_string); + if (q->manager) { LIST_REMOVE(queries, q->manager->dns_queries, q); q->manager->n_dns_queries--; @@ -67,17 +410,50 @@ DnsQuery *dns_query_free(DnsQuery *q) { return NULL; } -int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex, uint64_t flags) { +int dns_query_new( + Manager *m, + DnsQuery **ret, + DnsQuestion *question_utf8, + DnsQuestion *question_idna, + int ifindex, uint64_t flags) { + _cleanup_(dns_query_freep) DnsQuery *q = NULL; - unsigned i; + DnsResourceKey *key; + bool good = false; int r; assert(m); - assert(question); - r = dns_question_is_valid(question); + if (dns_question_size(question_utf8) > 0) { + r = dns_question_is_valid_for_query(question_utf8); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + good = true; + } + + /* If the IDNA and UTF8 questions are the same, merge their references */ + r = dns_question_is_equal(question_idna, question_utf8); if (r < 0) return r; + if (r > 0) + question_idna = question_utf8; + else { + if (dns_question_size(question_idna) > 0) { + r = dns_question_is_valid_for_query(question_idna); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + good = true; + } + } + + if (!good) /* don't allow empty queries */ + return -EINVAL; if (m->n_dns_queries >= QUERIES_MAX) return -EBUSY; @@ -86,18 +462,40 @@ int dns_query_new(Manager *m, DnsQuery **ret, DnsQuestion *question, int ifindex if (!q) return -ENOMEM; - q->question = dns_question_ref(question); + q->question_utf8 = dns_question_ref(question_utf8); + q->question_idna = dns_question_ref(question_idna); q->ifindex = ifindex; q->flags = flags; + q->answer_dnssec_result = _DNSSEC_RESULT_INVALID; + q->answer_protocol = _DNS_PROTOCOL_INVALID; + q->answer_family = AF_UNSPEC; - for (i = 0; i < question->n_keys; i++) { - _cleanup_free_ char *p; + /* First dump UTF8 question */ + DNS_QUESTION_FOREACH(key, question_utf8) { + _cleanup_free_ char *p = NULL; - r = dns_resource_key_to_string(question->keys[i], &p); + r = dns_resource_key_to_string(key, &p); if (r < 0) return r; - log_debug("Looking up RR for %s", p); + log_debug("Looking up RR for %s.", strstrip(p)); + } + + /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */ + DNS_QUESTION_FOREACH(key, question_idna) { + _cleanup_free_ char *p = NULL; + + r = dns_question_contains(question_utf8, key); + if (r < 0) + return r; + if (r > 0) + continue; + + r = dns_resource_key_to_string(key, &p); + if (r < 0) + return r; + + log_debug("Looking up IDNA RR for %s.", strstrip(p)); } LIST_PREPEND(queries, m->dns_queries, q); @@ -111,10 +509,33 @@ 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)); - assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)); + assert(!DNS_TRANSACTION_IS_LIVE(state)); + assert(DNS_TRANSACTION_IS_LIVE(q->state)); /* Note that this call might invalidate the query. Callers * should hence not attempt to access the query or transaction @@ -137,481 +558,117 @@ 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 this a single-label domain on DNS, we might append a suitable search domain first. */ + if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0) { + r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question_idna)); if (r < 0) - return r; + goto fail; + if (r > 0) { + /* OK, we need a search domain now. Let's find one for this scope */ + + 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 = set_ensure_allocated(&t->queries, NULL); + r = dns_query_candidate_setup_transactions(c); if (r < 0) - goto gc; - - r = set_put(t->queries, q); - if (r < 0) - goto gc; - - r = set_put(q->transactions, t); - if (r < 0) { - set_remove(t->queries, q); - goto gc; - } + 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 - * interface, we synthesize the answer for that - * interface. However, if nothing specific was claimed and we - * only return localhost RRs, we synthesize the answer for - * localhost. */ - - if (ifindex > 0) - return ifindex; - - return LOOPBACK_IFINDEX; -} - -static int SYNTHESIZE_FAMILY(uint64_t flags) { - - /* Picks an address family depending on set flags. This is - * purely for synthesized answers, where the family we return - * for the reply should match what was requested in the - * question, even though we are synthesizing the answer - * here. */ - - if (!(flags & SD_RESOLVED_DNS)) { - if (flags & SD_RESOLVED_LLMNR_IPV4) - return AF_INET; - if (flags & SD_RESOLVED_LLMNR_IPV6) - return AF_INET6; - } - - return AF_UNSPEC; -} - -static DnsProtocol SYNTHESIZE_PROTOCOL(uint64_t flags) { - - /* Similar as SYNTHESIZE_FAMILY() but does this for the - * protocol. If resolving via DNS was requested, we claim it - * was DNS. Similar, if nothing specific was - * requested. However, if only resolving via LLMNR was - * requested we return that. */ - - if (flags & SD_RESOLVED_DNS) - return DNS_PROTOCOL_DNS; - if (flags & SD_RESOLVED_LLMNR) - return DNS_PROTOCOL_LLMNR; - - return DNS_PROTOCOL_DNS; -} - -static int dns_type_to_af(uint16_t t) { - switch (t) { - - case DNS_TYPE_A: - return AF_INET; - - case DNS_TYPE_AAAA: - return AF_INET6; - - case DNS_TYPE_ANY: - return AF_UNSPEC; - - default: - return -EINVAL; - } -} - -static int synthesize_localhost_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) { - int r; - - assert(q); - assert(key); - assert(answer); - - r = dns_answer_reserve(answer, 2); - if (r < 0) - return r; - - if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - - rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key)); - if (!rr) - return -ENOMEM; - - rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK); - - r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex)); - if (r < 0) - return r; - } - - if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - - rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key)); - if (!rr) - return -ENOMEM; - - rr->aaaa.in6_addr = in6addr_loopback; - - r = dns_answer_add(*answer, rr, SYNTHESIZE_IFINDEX(q->ifindex)); - if (r < 0) - return r; - } - - return 0; -} - -static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - - rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from); - if (!rr) - return -ENOMEM; - - rr->ptr.name = strdup(to); - if (!rr->ptr.name) - return -ENOMEM; - - return dns_answer_add(*answer, rr, ifindex); -} - -static int synthesize_localhost_ptr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) { - int r; - - assert(q); - assert(key); - assert(answer); - - r = dns_answer_reserve(answer, 1); - if (r < 0) - return r; - - if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) { - r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", SYNTHESIZE_IFINDEX(q->ifindex)); - if (r < 0) - return r; - } - - return 0; -} - -static int answer_add_addresses_rr( - DnsAnswer **answer, - const char *name, - struct local_address *addresses, - unsigned n_addresses) { - - unsigned j; - int r; - - assert(answer); - assert(name); - - r = dns_answer_reserve(answer, n_addresses); - if (r < 0) - return r; - - for (j = 0; j < n_addresses; j++) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - - r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name); - if (r < 0) - return r; - - r = dns_answer_add(*answer, rr, addresses[j].ifindex); - if (r < 0) - return r; - } - - return 0; -} - -static int answer_add_addresses_ptr( - DnsAnswer **answer, - const char *name, - struct local_address *addresses, - unsigned n_addresses, - int af, const union in_addr_union *match) { - - unsigned j; - int r; - - assert(answer); - assert(name); - - for (j = 0; j < n_addresses; j++) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - - if (af != AF_UNSPEC) { - - if (addresses[j].family != af) - continue; - - if (match && !in_addr_equal(af, match, &addresses[j].address)) - continue; - } - - r = dns_answer_reserve(answer, 1); - if (r < 0) - return r; - - r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name); - if (r < 0) - return r; - - r = dns_answer_add(*answer, rr, addresses[j].ifindex); - if (r < 0) - return r; - } - - return 0; -} - -static int synthesize_system_hostname_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) { - _cleanup_free_ struct local_address *addresses = NULL; - int n = 0, af; - - assert(q); - assert(key); - assert(answer); - - af = dns_type_to_af(key->type); - if (af >= 0) { - n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses); - if (n < 0) - return n; - - if (n == 0) { - struct local_address buffer[2]; - - /* If we have no local addresses then use ::1 - * and 127.0.0.2 as local ones. */ - - if (af == AF_INET || af == AF_UNSPEC) - buffer[n++] = (struct local_address) { - .family = AF_INET, - .ifindex = SYNTHESIZE_IFINDEX(q->ifindex), - .address.in.s_addr = htobe32(0x7F000002), - }; - - if (af == AF_INET6 || af == AF_UNSPEC) - buffer[n++] = (struct local_address) { - .family = AF_INET6, - .ifindex = SYNTHESIZE_IFINDEX(q->ifindex), - .address.in6 = in6addr_loopback, - }; - - return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n); - } - } - - return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n); -} - -static int synthesize_system_hostname_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) { - _cleanup_free_ struct local_address *addresses = NULL; - int n, r; - - assert(q); - assert(address); - assert(answer); - - if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) { - - /* Always map the IPv4 address 127.0.0.2 to the local - * hostname, in addition to "localhost": */ - - r = dns_answer_reserve(answer, 3); - if (r < 0) - return r; - - r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->llmnr_hostname, SYNTHESIZE_IFINDEX(q->ifindex)); - if (r < 0) - return r; - - r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", q->manager->mdns_hostname, SYNTHESIZE_IFINDEX(q->ifindex)); - if (r < 0) - return r; - - r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", SYNTHESIZE_IFINDEX(q->ifindex)); - if (r < 0) - return r; - - return 0; - } - - n = local_addresses(q->manager->rtnl, q->ifindex, af, &addresses); - if (n < 0) - return n; - - r = answer_add_addresses_ptr(answer, q->manager->llmnr_hostname, addresses, n, af, address); - if (r < 0) - return r; - - return answer_add_addresses_ptr(answer, q->manager->mdns_hostname, addresses, n, af, address); -} - -static int synthesize_gateway_rr(DnsQuery *q, DnsResourceKey *key, DnsAnswer **answer) { - _cleanup_free_ struct local_address *addresses = NULL; - int n = 0, af; - - assert(q); - assert(key); - assert(answer); - - af = dns_type_to_af(key->type); - if (af >= 0) { - n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses); - if (n < 0) - return n; - } - - return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n); -} - -static int synthesize_gateway_ptr(DnsQuery *q, int af, const union in_addr_union *address, DnsAnswer **answer) { - _cleanup_free_ struct local_address *addresses = NULL; - int n; - - assert(q); - assert(address); - assert(answer); - - n = local_gateways(q->manager->rtnl, q->ifindex, af, &addresses); - if (n < 0) - return n; - - return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address); -} - static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; - unsigned i; int r; assert(q); assert(state); - /* Tries to synthesize localhost RR replies where appropriate */ + /* Tries to synthesize localhost RR replies (and others) where appropriate. Note that this is done *after* the + * the normal lookup finished. The data from the network hence takes precedence over the data we + * synthesize. (But note that many scopes refuse to resolve certain domain names) */ if (!IN_SET(*state, - DNS_TRANSACTION_FAILURE, + DNS_TRANSACTION_RCODE_FAILURE, DNS_TRANSACTION_NO_SERVERS, DNS_TRANSACTION_TIMEOUT, - DNS_TRANSACTION_ATTEMPTS_MAX_REACHED)) + DNS_TRANSACTION_ATTEMPTS_MAX_REACHED, + DNS_TRANSACTION_NETWORK_DOWN, + DNS_TRANSACTION_NOT_FOUND)) return 0; - for (i = 0; i < q->question->n_keys; i++) { - union in_addr_union address; - const char *name; - int af; + r = dns_synthesize_answer( + q->manager, + q->question_utf8, + q->ifindex, + &answer); - if (q->question->keys[i]->class != DNS_CLASS_IN && - q->question->keys[i]->class != DNS_CLASS_ANY) - continue; + if (r <= 0) + return r; - name = DNS_RESOURCE_KEY_NAME(q->question->keys[i]); + dns_query_reset_answer(q); - if (is_localhost(name)) { - - r = synthesize_localhost_rr(q, q->question->keys[i], &answer); - if (r < 0) - return log_error_errno(r, "Failed to synthesize localhost RRs: %m"); - - } else if (manager_is_own_hostname(q->manager, name)) { - - r = synthesize_system_hostname_rr(q, q->question->keys[i], &answer); - if (r < 0) - return log_error_errno(r, "Failed to synthesize system hostname RRs: %m"); - - } else if (is_gateway_hostname(name)) { - - r = synthesize_gateway_rr(q, q->question->keys[i], &answer); - if (r < 0) - return log_error_errno(r, "Failed to synthesize gateway RRs: %m"); - - } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) || - dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) { - - r = synthesize_localhost_ptr(q, q->question->keys[i], &answer); - if (r < 0) - return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m"); - - } else if (dns_name_address(name, &af, &address) > 0) { - - r = synthesize_system_hostname_ptr(q, af, &address, &answer); - if (r < 0) - return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m"); - - r = synthesize_gateway_ptr(q, af, &address, &answer); - if (r < 0) - return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m"); - } - } - - if (!answer) - return 0; - - dns_answer_unref(q->answer); 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 = dns_synthesize_protocol(q->flags); + q->answer_family = dns_synthesize_family(q->flags); + q->answer_authenticated = true; *state = DNS_TRANSACTION_SUCCESS; return 1; } +static int dns_query_try_etc_hosts(DnsQuery *q) { + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + int r; + + assert(q); + + /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is done. The + * data from /etc/hosts hence takes precedence over the network. */ + + r = manager_etc_hosts_lookup( + q->manager, + q->question_utf8, + &answer); + if (r <= 0) + return r; + + dns_query_reset_answer(q); + + q->answer = answer; + answer = NULL; + q->answer_rcode = DNS_RCODE_SUCCESS; + q->answer_protocol = dns_synthesize_protocol(q->flags); + q->answer_family = dns_synthesize_family(q->flags); + q->answer_authenticated = true; + + return 1; +} + int dns_query_go(DnsQuery *q) { DnsScopeMatch found = DNS_SCOPE_NO; DnsScope *s, *first = NULL; - DnsTransaction *t; - const char *name; - Iterator i; + DnsQueryCandidate *c; int r; assert(q); @@ -619,13 +676,21 @@ int dns_query_go(DnsQuery *q) { if (q->state != DNS_TRANSACTION_NULL) return 0; - assert(q->question); - assert(q->question->n_keys > 0); - - name = DNS_RESOURCE_KEY_NAME(q->question->keys[0]); + r = dns_query_try_etc_hosts(q); + if (r < 0) + return r; + if (r > 0) { + dns_query_complete(q, DNS_TRANSACTION_SUCCESS); + return 1; + } LIST_FOREACH(scopes, s, q->manager->dns_scopes) { DnsScopeMatch match; + const char *name; + + name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol)); + if (!name) + continue; match = dns_scope_good_domain(s, q->ifindex, q->flags, name); if (match < 0) @@ -650,17 +715,25 @@ int dns_query_go(DnsQuery *q) { if (found == DNS_SCOPE_NO) { DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS; - dns_query_synthesize_reply(q, &state); + r = dns_query_synthesize_reply(q, &state); + if (r < 0) + return r; + dns_query_complete(q, state); return 1; } - r = dns_query_add_transaction_split(q, first); + r = dns_query_add_candidate(q, first); if (r < 0) goto fail; LIST_FOREACH(scopes, s, first->scopes_next) { DnsScopeMatch match; + const char *name; + + name = dns_question_first_name(dns_query_question_for_protocol(q, s->protocol)); + if (!name) + continue; match = dns_scope_good_domain(s, q->ifindex, q->flags, name); if (match < 0) @@ -669,15 +742,12 @@ 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; } - q->answer = dns_answer_unref(q->answer); - q->answer_rcode = 0; - q->answer_family = AF_UNSPEC; - q->answer_protocol = _DNS_PROTOCOL_INVALID; + dns_query_reset_answer(q); r = sd_event_add_time( q->manager->event, @@ -688,17 +758,18 @@ int dns_query_go(DnsQuery *q) { if (r < 0) goto fail; + (void) sd_event_source_set_description(q->timeout_event_source, "query-timeout"); + 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,17 +782,113 @@ 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; + bool has_authenticated = false, has_non_authenticated = false; + DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID; + DnsTransaction *t; Iterator i; + int r; assert(q); - assert(IN_SET(q->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)); + + if (!c) { + r = dns_query_synthesize_reply(q, &state); + if (r < 0) + goto fail; + + dns_query_complete(q, state); + return; + } + + if (c->error_code != 0) { + /* If the candidate had an error condition of its own, start with that. */ + state = DNS_TRANSACTION_ERRNO; + q->answer = dns_answer_unref(q->answer); + q->answer_rcode = 0; + q->answer_dnssec_result = _DNSSEC_RESULT_INVALID; + q->answer_errno = c->error_code; + } + + SET_FOREACH(t, c->transactions, i) { + + switch (t->state) { + + case DNS_TRANSACTION_SUCCESS: { + /* We found a successfuly reply, merge it into the answer */ + r = dns_answer_extend(&q->answer, t->answer); + if (r < 0) + goto fail; + + q->answer_rcode = t->answer_rcode; + q->answer_errno = 0; + + if (t->answer_authenticated) { + has_authenticated = true; + dnssec_result_authenticated = t->answer_dnssec_result; + } else { + has_non_authenticated = true; + dnssec_result_non_authenticated = t->answer_dnssec_result; + } + + state = DNS_TRANSACTION_SUCCESS; + break; + } + + case DNS_TRANSACTION_NULL: + case DNS_TRANSACTION_PENDING: + case DNS_TRANSACTION_VALIDATING: + 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. */ + + if (state == DNS_TRANSACTION_SUCCESS) + continue; + + q->answer = dns_answer_unref(q->answer); + q->answer_rcode = t->answer_rcode; + q->answer_dnssec_result = t->answer_dnssec_result; + q->answer_errno = t->answer_errno; + + state = t->state; + break; + } + } + + if (state == DNS_TRANSACTION_SUCCESS) { + q->answer_authenticated = has_authenticated && !has_non_authenticated; + q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated; + } + + q->answer_protocol = c->scope->protocol; + q->answer_family = c->scope->family; + + dns_search_domain_unref(q->answer_search_domain); + q->answer_search_domain = dns_search_domain_ref(c->search_domain); + + r = dns_query_synthesize_reply(q, &state); + if (r < 0) + goto fail; + + dns_query_complete(q, state); + return; + +fail: + q->answer_errno = -r; + dns_query_complete(q, DNS_TRANSACTION_ERRNO); +} + +void dns_query_ready(DnsQuery *q) { + + DnsQueryCandidate *bad = NULL, *c; + bool pending = false; + + assert(q); + assert(DNS_TRANSACTION_IS_LIVE(q->state)); /* Note that this call might invalidate the query. Callers * should hence not attempt to access the query or transaction @@ -731,129 +898,150 @@ void dns_query_ready(DnsQuery *q) { if (q->block_ready > 0) return; - SET_FOREACH(t, q->transactions, i) { + LIST_FOREACH(candidates_by_query, c, q->candidates) { + DnsTransactionState state; - /* If we found a successful answer, ignore all answers from other scopes */ - if (state == DNS_TRANSACTION_SUCCESS && t->scope != scope) - continue; + state = dns_query_candidate_state(c); + switch (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; - } - - /* 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; - } - - if (state == DNS_TRANSACTION_SUCCESS) { - DnsAnswer *merged; - - merged = dns_answer_merge(answer, a); - if (!merged) { - dns_query_complete(q, DNS_TRANSACTION_RESOURCES); - return; - } - - dns_answer_unref(answer); - answer = merged; - } else { - dns_answer_unref(answer); - answer = dns_answer_ref(a); - } - - scope = t->scope; - state = DNS_TRANSACTION_SUCCESS; - continue; - } - - /* 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; - } - - dns_answer_unref(answer); - answer = dns_answer_ref(a); - - scope = t->scope; - state = DNS_TRANSACTION_FAILURE; - continue; - } - - if (state == DNS_TRANSACTION_NO_SERVERS && t->state != DNS_TRANSACTION_NO_SERVERS) - state = t->state; - } - - if (pending) { - - /* If so far we weren't successful, and there's - * something still pending, then wait for it */ - if (state != DNS_TRANSACTION_SUCCESS) + case DNS_TRANSACTION_SUCCESS: + /* One of the candidates 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_NULL: + case DNS_TRANSACTION_PENDING: + case DNS_TRANSACTION_VALIDATING: + /* One of the candidates is still going on, + * let's maybe wait for it */ + pending = true; + break; + + default: + /* Any kind of failure */ + bad = c; + 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; - } + if (pending) + return; - /* Try to synthesize a reply if we couldn't resolve something. */ - dns_query_synthesize_reply(q, &state); - - dns_query_complete(q, state); + dns_query_accept(q, bad); } -int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) { - _cleanup_(dns_question_unrefp) DnsQuestion *nq = NULL; +static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) { + _cleanup_(dns_question_unrefp) DnsQuestion *nq_idna = NULL, *nq_utf8 = NULL; + int r, k; + + assert(q); + + q->n_cname_redirects ++; + if (q->n_cname_redirects > CNAME_MAX) + return -ELOOP; + + r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna); + if (r < 0) + return r; + else if (r > 0) + log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna)); + + k = dns_question_is_equal(q->question_idna, q->question_utf8); + if (k < 0) + return r; + if (k > 0) { + /* Same question? Shortcut new question generation */ + nq_utf8 = dns_question_ref(nq_idna); + k = r; + } else { + k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8); + if (k < 0) + return k; + else if (k > 0) + log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8)); + } + + if (r == 0 && k == 0) /* No actual cname happened? */ + return -ELOOP; + + if (q->answer_protocol == DNS_PROTOCOL_DNS) { + /* Don't permit CNAME redirects from unicast DNS to LLMNR or MulticastDNS, so that global resources + * cannot invade the local namespace. The opposite way we permit: local names may redirect to global + * ones. */ + + q->flags &= ~(SD_RESOLVED_LLMNR|SD_RESOLVED_MDNS); /* mask away the local protocols */ + } + + /* Turn off searching for the new name */ + q->flags |= SD_RESOLVED_NO_SEARCH; + + dns_question_unref(q->question_idna); + q->question_idna = nq_idna; + nq_idna = NULL; + + dns_question_unref(q->question_utf8); + q->question_utf8 = nq_utf8; + nq_utf8 = NULL; + + dns_query_free_candidates(q); + dns_query_reset_answer(q); + + q->state = DNS_TRANSACTION_NULL; + + return 0; +} + +int dns_query_process_cname(DnsQuery *q) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL; + DnsQuestion *question; + DnsResourceRecord *rr; int r; assert(q); - if (q->n_cname_redirects > CNAME_MAX) + if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL)) + return DNS_QUERY_NOMATCH; + + question = dns_query_question_for_protocol(q, q->answer_protocol); + + DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); + if (r < 0) + return r; + if (r > 0) + return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */ + + r = dns_question_matches_cname_or_dname(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 DNS_QUERY_NOMATCH; /* No match and no cname to follow */ + + if (q->flags & SD_RESOLVED_NO_CNAME) return -ELOOP; - r = dns_question_cname_redirect(q->question, cname, &nq); + /* OK, let's actually follow the CNAME */ + r = dns_query_cname_redirect(q, cname); if (r < 0) return r; - dns_question_unref(q->question); - q->question = nq; - nq = NULL; + /* Let's see if the answer can already answer the new + * redirected question */ + r = dns_query_process_cname(q); + if (r != DNS_QUERY_NOMATCH) + return r; - q->n_cname_redirects++; + /* OK, it cannot, let's begin with the new query */ + r = dns_query_go(q); + if (r < 0) + return r; - dns_query_stop(q); - q->state = DNS_TRANSACTION_NULL; - - return 0; + return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */ } static int on_bus_track(sd_bus_track *t, void *userdata) { @@ -885,3 +1073,42 @@ int dns_query_bus_track(DnsQuery *q, sd_bus_message *m) { return 0; } + +DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) { + assert(q); + + switch (protocol) { + + case DNS_PROTOCOL_DNS: + return q->question_idna; + + case DNS_PROTOCOL_MDNS: + case DNS_PROTOCOL_LLMNR: + return q->question_utf8; + + default: + return NULL; + } +} + +const char *dns_query_string(DnsQuery *q) { + const char *name; + int r; + + /* Returns a somewhat useful human-readable lookup key string for this query */ + + if (q->request_address_string) + return q->request_address_string; + + if (q->request_address_valid) { + r = in_addr_to_string(q->request_family, &q->request_address, &q->request_address_string); + if (r >= 0) + return q->request_address_string; + } + + name = dns_question_first_name(q->question_utf8); + if (name) + return name; + + return dns_question_first_name(q->question_idna); +} diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index e7063d967..c2ac02f68 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,57 +21,113 @@ #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; + + /* The question, formatted in IDNA for use on classic DNS, and as UTF8 for use in LLMNR or mDNS. Note that even + * on classic DNS some labels might use UTF8 encoding. Specifically, DNS-SD service names (in contrast to their + * domain suffixes) use UTF-8 encoding even on DNS. Thus, the difference between these two fields is mostly + * relevant only for explicit *hostname* lookups as well as the domain suffixes of service lookups. */ + DnsQuestion *question_idna; + DnsQuestion *question_utf8; uint64_t flags; int ifindex; + /* If true, A or AAAA RR lookups will be suppressed on links with no routable address of the matching address + * family */ + bool suppress_unroutable_family; + 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; + DnssecResult answer_dnssec_result; + bool answer_authenticated; + DnsProtocol answer_protocol; + int answer_family; + DnsSearchDomain *answer_search_domain; + int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ /* 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; + char *request_address_string; /* 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); }; -int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question, int family, uint64_t flags); +enum { + DNS_QUERY_MATCH, + DNS_QUERY_NOMATCH, + DNS_QUERY_RESTARTED, +}; + +DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c); +void dns_query_candidate_notify(DnsQueryCandidate *c); + +int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question_utf8, DnsQuestion *question_idna, 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); +DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol); + +const char *dns_query_string(DnsQuery *q); + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuery*, dns_query_free); diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c index 48951221d..8e452e79a 100644 --- a/src/resolve/resolved-dns-question.c +++ b/src/resolve/resolved-dns-question.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,6 +19,7 @@ #include "alloc-util.h" #include "dns-domain.h" +#include "dns-type.h" #include "resolved-dns-question.h" DnsQuestion *dns_question_new(unsigned n) { @@ -89,7 +88,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 +98,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 +106,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_or_dname(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) { unsigned i; int r; @@ -116,8 +115,15 @@ int dns_question_matches_cname(DnsQuestion *q, DnsResourceRecord *rr) { if (!q) return 0; + if (!IN_SET(rr->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME)) + return 0; + for (i = 0; i < q->n_keys; i++) { - r = dns_resource_key_match_cname(q->keys[i], rr); + /* For a {C,D}NAME record we can never find a matching {C,D}NAME record */ + if (!dns_type_may_redirect(q->keys[i]->type)) + return 0; + + r = dns_resource_key_match_cname_or_dname(q->keys[i], rr->key, search_domain); if (r != 0) return r; } @@ -125,7 +131,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; @@ -144,62 +150,23 @@ int dns_question_is_valid(DnsQuestion *q) { return 0; /* Check that all keys in this question bear the same name */ - for (i = 1; i < q->n_keys; i++) { + for (i = 0; i < q->n_keys; i++) { assert(q->keys[i]); - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name); - if (r <= 0) - return r; - } - - 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) + if (i > 0) { + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), name); + 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) + if (!dns_type_is_valid_query(q->keys[i]->type)) return 0; } return 1; } -int dns_question_contains(DnsQuestion *a, DnsResourceKey *k) { +int dns_question_contains(DnsQuestion *a, const DnsResourceKey *k) { unsigned j; int r; @@ -221,6 +188,9 @@ int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) { unsigned j; int r; + if (a == b) + return 1; + if (!a) return !b || b->n_keys == 0; if (!b) @@ -245,25 +215,36 @@ int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b) { int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret) { _cleanup_(dns_question_unrefp) DnsQuestion *n = NULL; + DnsResourceKey *key; bool same = true; - unsigned i; int r; assert(cname); assert(ret); + assert(IN_SET(cname->key->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME)); - if (!q) { - n = dns_question_new(0); - if (!n) - return -ENOMEM; - - *ret = n; - n = 0; + if (dns_question_size(q) <= 0) { + *ret = NULL; return 0; } - for (i = 0; i < q->n_keys; i++) { - r = dns_name_equal(DNS_RESOURCE_KEY_NAME(q->keys[i]), cname->cname.name); + DNS_QUESTION_FOREACH(key, q) { + _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(key), 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(key), d); if (r < 0) return r; @@ -273,9 +254,9 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, } } + /* Fully the same, indicate we didn't do a thing */ if (same) { - /* Shortcut, the names are already right */ - *ret = dns_question_ref(q); + *ret = NULL; return 0; } @@ -284,10 +265,10 @@ int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, return -ENOMEM; /* Create a new question, and patch in the new name */ - for (i = 0; i < q->n_keys; i++) { + DNS_QUESTION_FOREACH(key, q) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *k = NULL; - k = dns_resource_key_new_redirect(q->keys[i], cname); + k = dns_resource_key_new_redirect(key, cname); if (!k) return -ENOMEM; @@ -301,3 +282,187 @@ 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, bool convert_idna) { + _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL; + _cleanup_free_ char *buf = NULL; + int r; + + assert(ret); + assert(name); + + if (!IN_SET(family, AF_INET, AF_INET6, AF_UNSPEC)) + return -EAFNOSUPPORT; + + if (convert_idna) { + r = dns_name_apply_idna(name, &buf); + if (r < 0) + return r; + + name = buf; + } + + 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 *service, + const char *type, + const char *domain, + bool with_txt, + bool convert_idna) { + + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + _cleanup_(dns_question_unrefp) DnsQuestion *q = NULL; + _cleanup_free_ char *buf = NULL, *joined = NULL; + const char *name; + int r; + + assert(ret); + + /* We support three modes of invocation: + * + * 1. Only a domain is specified, in which case we assume a properly encoded SRV RR name, including service + * type and possibly a service name. If specified in this way we assume it's already IDNA converted if + * that's necessary. + * + * 2. Both service type and a domain specified, in which case a normal SRV RR is assumed, without a DNS-SD + * style prefix. In this case we'll IDNA convert the domain, if that's requested. + * + * 3. All three of service name, type and domain are specified, in which case a DNS-SD service is put + * together. The service name is never IDNA converted, and the domain is if requested. + * + * It's not supported to specify a service name without a type, or no domain name. + */ + + if (!domain) + return -EINVAL; + + if (type) { + if (convert_idna) { + r = dns_name_apply_idna(domain, &buf); + if (r < 0) + return r; + + domain = buf; + } + + r = dns_service_join(service, type, domain, &joined); + if (r < 0) + return r; + + name = joined; + } else { + if (service) + return -EINVAL; + + name = domain; + } + + 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 13cd1f20f..ea4147897 100644 --- a/src/resolve/resolved-dns-question.h +++ b/src/resolve/resolved-dns-question.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,9 +21,10 @@ typedef struct DnsQuestion DnsQuestion; +#include "macro.h" #include "resolved-dns-rr.h" -/* A simple array of resources keys */ +/* A simple array of resource keys */ struct DnsQuestion { unsigned n_ref; @@ -37,15 +36,34 @@ 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, bool convert_idna); +int dns_question_new_reverse(DnsQuestion **ret, int family, const union in_addr_union *a); +int dns_question_new_service(DnsQuestion **ret, const char *service, const char *type, const char *domain, bool with_txt, bool convert_idna); + 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_contains(DnsQuestion *a, DnsResourceKey *k); +int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain); +int dns_question_matches_cname_or_dname(DnsQuestion *q, DnsResourceRecord *rr, const char* search_domain); +int dns_question_is_valid_for_query(DnsQuestion *q); +int dns_question_contains(DnsQuestion *a, const 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); + +static inline unsigned dns_question_size(DnsQuestion *q) { + return q ? q->n_keys : 0; +} + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuestion*, dns_question_unref); + +#define _DNS_QUESTION_FOREACH(u, key, q) \ + for (unsigned UNIQ_T(i, u) = ({ \ + (key) = ((q) && (q)->n_keys > 0) ? (q)->keys[0] : NULL; \ + 0; \ + }); \ + (q) && (UNIQ_T(i, u) < (q)->n_keys); \ + UNIQ_T(i, u)++, (key) = (UNIQ_T(i, u) < (q)->n_keys ? (q)->keys[UNIQ_T(i, u)] : NULL)) + +#define DNS_QUESTION_FOREACH(key, q) _DNS_QUESTION_FOREACH(UNIQ, key, q) diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index ba2ea686f..40f8e28df 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -25,10 +23,13 @@ #include "dns-domain.h" #include "dns-type.h" #include "hexdecoct.h" +#include "resolved-dns-dnssec.h" #include "resolved-dns-packet.h" #include "resolved-dns-rr.h" +#include "string-table.h" #include "string-util.h" #include "strv.h" +#include "terminal-util.h" DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name) { DnsResourceKey *k; @@ -50,17 +51,62 @@ DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char * return k; } -DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key) { - assert(key); - - return dns_resource_key_new(key->class, DNS_TYPE_CNAME, DNS_RESOURCE_KEY_NAME(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) { @@ -85,6 +131,10 @@ DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) { if (!k) return NULL; + /* Static/const keys created with DNS_RESOURCE_KEY_CONST will + * set this to -1, they should not be reffed/unreffed */ + assert(k->n_ref != (unsigned) -1); + assert(k->n_ref > 0); k->n_ref++; @@ -95,6 +145,7 @@ DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) { if (!k) return NULL; + assert(k->n_ref != (unsigned) -1); assert(k->n_ref > 0); if (k->n_ref == 1) { @@ -106,9 +157,20 @@ DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) { return NULL; } +bool dns_resource_key_is_address(const DnsResourceKey *key) { + assert(key); + + /* Check if this is an A or AAAA resource key */ + + return key->class == DNS_CLASS_IN && IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_AAAA); +} + int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) { int r; + if (a == b) + return 1; + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(a), DNS_RESOURCE_KEY_NAME(b)); if (r <= 0) return r; @@ -122,30 +184,90 @@ 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, DnsResourceRecord *rr, const char *search_domain) { + int r; + assert(key); assert(rr); + if (key == rr->key) + return 1; + + /* 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_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain) { + int r; + assert(key); - assert(rr); + assert(cname); - if (rr->key->class != key->class && key->class != DNS_CLASS_ANY) + if (cname->class != key->class && key->class != DNS_CLASS_ANY) return 0; - if (rr->key->type != DNS_TYPE_CNAME) + if (cname->type == DNS_TYPE_CNAME) + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname)); + else if (cname->type == DNS_TYPE_DNAME) + r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(cname)); + 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 (cname->type == DNS_TYPE_CNAME) + return dns_name_equal(joined, DNS_RESOURCE_KEY_NAME(cname)); + else if (cname->type == DNS_TYPE_DNAME) + return dns_name_endswith(joined, DNS_RESOURCE_KEY_NAME(cname)); + } + + return 0; +} + +int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa) { + assert(soa); + assert(key); + + /* Checks whether 'soa' is a SOA record for the specified key. */ + + if (soa->class != key->class) + return 0; + + if (soa->type != DNS_TYPE_SOA) + return 0; + + return dns_name_endswith(DNS_RESOURCE_KEY_NAME(key), DNS_RESOURCE_KEY_NAME(soa)); } static void dns_resource_key_hash_func(const void *i, struct siphash *state) { @@ -186,9 +308,12 @@ const struct hash_ops dns_resource_key_hash_ops = { int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) { char cbuf[strlen("CLASS") + DECIMAL_STR_MAX(uint16_t)], tbuf[strlen("TYPE") + DECIMAL_STR_MAX(uint16_t)]; - const char *c, *t; + const char *c, *t, *n; char *s; + /* If we cannot convert the CLASS/TYPE into a known string, + use the format recommended by RFC 3597, Section 5. */ + c = dns_class_to_string(key->class); if (!c) { sprintf(cbuf, "CLASS%u", key->class); @@ -201,13 +326,54 @@ int dns_resource_key_to_string(const DnsResourceKey *key, char **ret) { t = tbuf; } - if (asprintf(&s, "%s %s %-5s", DNS_RESOURCE_KEY_NAME(key), c, t) < 0) + n = DNS_RESOURCE_KEY_NAME(key); + if (asprintf(&s, "%s%s %s %-5s", n, endswith(n, ".") ? "" : ".", c, t) < 0) return -ENOMEM; *ret = s; return 0; } +bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) { + assert(a); + assert(b); + + /* Try to replace one RR key by another if they are identical, thus saving a bit of memory. Note that we do + * this only for RR keys, not for RRs themselves, as they carry a lot of additional metadata (where they come + * from, validity data, and suchlike), and cannot be replaced so easily by other RRs that have the same + * superficial data. */ + + if (!*a) + return false; + if (!*b) + return false; + + /* We refuse merging const keys */ + if ((*a)->n_ref == (unsigned) -1) + return false; + if ((*b)->n_ref == (unsigned) -1) + return false; + + /* Already the same? */ + if (*a == *b) + return true; + + /* Are they really identical? */ + if (dns_resource_key_equal(*a, *b) <= 0) + return false; + + /* Keep the one which already has more references. */ + if ((*a)->n_ref > (*b)->n_ref) { + dns_resource_key_unref(*b); + *b = dns_resource_key_ref(*a); + } else { + dns_resource_key_unref(*a); + *a = dns_resource_key_ref(*b); + } + + return true; +} + DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) { DnsResourceRecord *rr; @@ -217,6 +383,8 @@ DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) { rr->n_ref = 1; rr->key = dns_resource_key_ref(key); + rr->expiry = USEC_INFINITY; + rr->n_skip_labels_signer = rr->n_skip_labels_source = (unsigned) -1; return rr; } @@ -273,7 +441,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: @@ -318,13 +486,20 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) { case DNS_TYPE_AAAA: break; + case DNS_TYPE_TLSA: + free(rr->tlsa.data); + break; + + case DNS_TYPE_OPENPGPKEY: default: free(rr->generic.data); } + free(rr->wire_format); dns_resource_key_unref(rr->key); } + free(rr->to_string); free(rr); return NULL; @@ -394,12 +569,19 @@ int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const u return 0; } +#define FIELD_EQUAL(a, b, field) \ + ((a).field ## _size == (b).field ## _size && \ + memcmp((a).field, (b).field, (a).field ## _size) == 0) + int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b) { int r; assert(a); assert(b); + if (a == b) + return 1; + r = dns_resource_key_equal(a->key, b->key); if (r <= 0) return r; @@ -430,7 +612,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; @@ -472,36 +654,30 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor return a->ds.key_tag == b->ds.key_tag && a->ds.algorithm == b->ds.algorithm && a->ds.digest_type == b->ds.digest_type && - a->ds.digest_size == b->ds.digest_size && - memcmp(a->ds.digest, b->ds.digest, a->ds.digest_size) == 0; + FIELD_EQUAL(a->ds, b->ds, digest); case DNS_TYPE_SSHFP: return a->sshfp.algorithm == b->sshfp.algorithm && a->sshfp.fptype == b->sshfp.fptype && - a->sshfp.fingerprint_size == b->sshfp.fingerprint_size && - memcmp(a->sshfp.fingerprint, b->sshfp.fingerprint, a->sshfp.fingerprint_size) == 0; + FIELD_EQUAL(a->sshfp, b->sshfp, fingerprint); case DNS_TYPE_DNSKEY: - return a->dnskey.zone_key_flag == b->dnskey.zone_key_flag && - a->dnskey.sep_flag == b->dnskey.sep_flag && + return a->dnskey.flags == b->dnskey.flags && + a->dnskey.protocol == b->dnskey.protocol && a->dnskey.algorithm == b->dnskey.algorithm && - a->dnskey.key_size == b->dnskey.key_size && - memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0; + FIELD_EQUAL(a->dnskey, b->dnskey, key); case DNS_TYPE_RRSIG: /* do the fast comparisons first */ - if (a->rrsig.type_covered != b->rrsig.type_covered || - a->rrsig.algorithm != b->rrsig.algorithm || - a->rrsig.labels != b->rrsig.labels || - a->rrsig.original_ttl != b->rrsig.original_ttl || - a->rrsig.expiration != b->rrsig.expiration || - a->rrsig.inception != b->rrsig.inception || - a->rrsig.key_tag != b->rrsig.key_tag || - a->rrsig.signature_size != b->rrsig.signature_size || - memcmp(a->rrsig.signature, b->rrsig.signature, a->rrsig.signature_size) != 0) - return false; - - return dns_name_equal(a->rrsig.signer, b->rrsig.signer); + return a->rrsig.type_covered == b->rrsig.type_covered && + a->rrsig.algorithm == b->rrsig.algorithm && + a->rrsig.labels == b->rrsig.labels && + a->rrsig.original_ttl == b->rrsig.original_ttl && + a->rrsig.expiration == b->rrsig.expiration && + a->rrsig.inception == b->rrsig.inception && + a->rrsig.key_tag == b->rrsig.key_tag && + FIELD_EQUAL(a->rrsig, b->rrsig, signature) && + dns_name_equal(a->rrsig.signer, b->rrsig.signer); case DNS_TYPE_NSEC: return dns_name_equal(a->nsec.next_domain_name, b->nsec.next_domain_name) && @@ -509,16 +685,20 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor case DNS_TYPE_NSEC3: return a->nsec3.algorithm == b->nsec3.algorithm && - a->nsec3.flags == b->nsec3.flags && - a->nsec3.iterations == b->nsec3.iterations && - a->nsec3.salt_size == b->nsec3.salt_size && - memcmp(a->nsec3.salt, b->nsec3.salt, a->nsec3.salt_size) == 0 && - memcmp(a->nsec3.next_hashed_name, b->nsec3.next_hashed_name, a->nsec3.next_hashed_name_size) == 0 && - bitmap_equal(a->nsec3.types, b->nsec3.types); + a->nsec3.flags == b->nsec3.flags && + a->nsec3.iterations == b->nsec3.iterations && + FIELD_EQUAL(a->nsec3, b->nsec3, salt) && + FIELD_EQUAL(a->nsec3, b->nsec3, next_hashed_name) && + bitmap_equal(a->nsec3.types, b->nsec3.types); + + case DNS_TYPE_TLSA: + return a->tlsa.cert_usage == b->tlsa.cert_usage && + a->tlsa.selector == b->tlsa.selector && + a->tlsa.matching_type == b->tlsa.matching_type && + FIELD_EQUAL(a->tlsa, b->tlsa, data); default: - return a->generic.size == b->generic.size && - memcmp(a->generic.data, b->generic.data, a->generic.size) == 0; + return FIELD_EQUAL(a->generic, b->generic, data); } } @@ -600,16 +780,56 @@ static char *format_types(Bitmap *types) { return strjoin("( ", str, " )", NULL); } -int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { +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; +} + +const char *dns_resource_record_to_string(DnsResourceRecord *rr) { _cleanup_free_ char *k = NULL, *t = NULL; char *s; int r; assert(rr); + if (rr->to_string) + return rr->to_string; + r = dns_resource_key_to_string(rr->key, &k); if (r < 0) - return r; + return NULL; switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { @@ -621,7 +841,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { rr->srv.port, strna(rr->srv.name)); if (r < 0) - return -ENOMEM; + return NULL; break; case DNS_TYPE_PTR: @@ -630,26 +850,25 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { case DNS_TYPE_DNAME: s = strjoin(k, " ", rr->ptr.name, NULL); if (!s) - return -ENOMEM; + return NULL; break; case DNS_TYPE_HINFO: s = strjoin(k, " ", rr->hinfo.cpu, " ", rr->hinfo.os, NULL); if (!s) - return -ENOMEM; + return NULL; break; 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; + return NULL; s = strjoin(k, " ", t, NULL); if (!s) - return -ENOMEM; - + return NULL; break; case DNS_TYPE_A: { @@ -657,22 +876,22 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x); if (r < 0) - return r; + return NULL; s = strjoin(k, " ", x, NULL); if (!s) - return -ENOMEM; + return NULL; break; } case DNS_TYPE_AAAA: r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t); if (r < 0) - return r; + return NULL; s = strjoin(k, " ", t, NULL); if (!s) - return -ENOMEM; + return NULL; break; case DNS_TYPE_SOA: @@ -686,7 +905,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { rr->soa.expire, rr->soa.minimum); if (r < 0) - return -ENOMEM; + return NULL; break; case DNS_TYPE_MX: @@ -695,7 +914,7 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { rr->mx.priority, rr->mx.exchange); if (r < 0) - return -ENOMEM; + return NULL; break; case DNS_TYPE_LOC: @@ -708,17 +927,17 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { rr->loc.horiz_pre, rr->loc.vert_pre); if (!t) - return -ENOMEM; + return NULL; s = strjoin(k, " ", t, NULL); if (!s) - return -ENOMEM; + return NULL; break; case DNS_TYPE_DS: t = hexmem(rr->ds.digest, rr->ds.digest_size); if (!t) - return -ENOMEM; + return NULL; r = asprintf(&s, "%s %u %u %u %s", k, @@ -727,13 +946,13 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { rr->ds.digest_type, t); if (r < 0) - return -ENOMEM; + return NULL; break; case DNS_TYPE_SSHFP: t = hexmem(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size); if (!t) - return -ENOMEM; + return NULL; r = asprintf(&s, "%s %u %u %s", k, @@ -741,80 +960,113 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { rr->sshfp.fptype, t); if (r < 0) - return -ENOMEM; + return NULL; break; case DNS_TYPE_DNSKEY: { - const char *alg; + _cleanup_free_ char *alg = NULL; + char *ss; + int n, n1; + uint16_t key_tag; - alg = dnssec_algorithm_to_string(rr->dnskey.algorithm); + key_tag = dnssec_keytag(rr, true); - t = base64mem(rr->dnskey.key, rr->dnskey.key_size); - if (!t) - return -ENOMEM; - - r = asprintf(&s, "%s %u 3 %.*s%.*u %s", - k, - dnskey_to_flags(rr), - alg ? -1 : 0, alg, - alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm, - t); + r = dnssec_algorithm_to_string_alloc(rr->dnskey.algorithm, &alg); if (r < 0) - return -ENOMEM; + return NULL; + + r = asprintf(&s, "%s %n%u %u %s %n", + k, + &n1, + rr->dnskey.flags, + rr->dnskey.protocol, + alg, + &n); + if (r < 0) + return NULL; + + r = base64_append(&s, n, + rr->dnskey.key, rr->dnskey.key_size, + 8, columns()); + if (r < 0) + return NULL; + + r = asprintf(&ss, "%s\n" + "%*s-- Flags:%s%s%s\n" + "%*s-- Key tag: %u", + s, + n1, "", + rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "", + rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "", + rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "", + n1, "", + key_tag); + if (r < 0) + return NULL; + free(s); + s = ss; + break; } case DNS_TYPE_RRSIG: { - const char *type, *alg; + _cleanup_free_ char *alg = NULL; char expiration[strlen("YYYYMMDDHHmmSS") + 1], inception[strlen("YYYYMMDDHHmmSS") + 1]; + const char *type; + int n; type = dns_type_to_string(rr->rrsig.type_covered); - alg = dnssec_algorithm_to_string(rr->rrsig.algorithm); - t = base64mem(rr->rrsig.signature, rr->rrsig.signature_size); - if (!t) - return -ENOMEM; + r = dnssec_algorithm_to_string_alloc(rr->rrsig.algorithm, &alg); + if (r < 0) + return NULL; r = format_timestamp_dns(expiration, sizeof(expiration), rr->rrsig.expiration); if (r < 0) - return r; + return NULL; r = format_timestamp_dns(inception, sizeof(inception), rr->rrsig.inception); if (r < 0) - return r; + return NULL; /* TYPE?? follows * http://tools.ietf.org/html/rfc3597#section-5 */ - r = asprintf(&s, "%s %s%.*u %.*s%.*u %u %u %s %s %u %s %s", + r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %n", k, type ?: "TYPE", type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered, - alg ? -1 : 0, alg, - alg ? 0 : 1, alg ? 0u : (unsigned) rr->rrsig.algorithm, + alg, rr->rrsig.labels, rr->rrsig.original_ttl, expiration, inception, rr->rrsig.key_tag, rr->rrsig.signer, - t); + &n); if (r < 0) - return -ENOMEM; + return NULL; + + r = base64_append(&s, n, + rr->rrsig.signature, rr->rrsig.signature_size, + 8, columns()); + if (r < 0) + return NULL; + break; } case DNS_TYPE_NSEC: t = format_types(rr->nsec.types); if (!t) - return -ENOMEM; + return NULL; r = asprintf(&s, "%s %s %s", k, rr->nsec.next_domain_name, t); if (r < 0) - return -ENOMEM; + return NULL; break; case DNS_TYPE_NSEC3: { @@ -823,16 +1075,16 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { if (rr->nsec3.salt_size > 0) { salt = hexmem(rr->nsec3.salt, rr->nsec3.salt_size); if (!salt) - return -ENOMEM; + return NULL; } hash = base32hexmem(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, false); if (!hash) - return -ENOMEM; + return NULL; t = format_types(rr->nsec3.types); if (!t) - return -ENOMEM; + return NULL; r = asprintf(&s, "%s %"PRIu8" %"PRIu8" %"PRIu16" %s %s %s", k, @@ -843,50 +1095,427 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) { hash, t); if (r < 0) - return -ENOMEM; + return NULL; break; } + case DNS_TYPE_TLSA: { + const char *cert_usage, *selector, *matching_type; + char *ss; + int n; + + cert_usage = tlsa_cert_usage_to_string(rr->tlsa.cert_usage); + selector = tlsa_selector_to_string(rr->tlsa.selector); + matching_type = tlsa_matching_type_to_string(rr->tlsa.matching_type); + + r = asprintf(&s, "%s %u %u %u %n", + k, + rr->tlsa.cert_usage, + rr->tlsa.selector, + rr->tlsa.matching_type, + &n); + if (r < 0) + return NULL; + + r = base64_append(&s, n, + rr->tlsa.data, rr->tlsa.data_size, + 8, columns()); + if (r < 0) + return NULL; + + r = asprintf(&ss, "%s\n" + "%*s-- Cert. usage: %s\n" + "%*s-- Selector: %s\n" + "%*s-- Matching type: %s", + s, + n - 6, "", cert_usage, + n - 6, "", selector, + n - 6, "", matching_type); + if (r < 0) + return NULL; + free(s); + s = ss; + + break; + } + + case DNS_TYPE_OPENPGPKEY: { + int n; + + r = asprintf(&s, "%s %n", + k, + &n); + if (r < 0) + return NULL; + + r = base64_append(&s, n, + rr->generic.data, rr->generic.data_size, + 8, columns()); + if (r < 0) + return NULL; + break; + } + default: - t = hexmem(rr->generic.data, rr->generic.size); + t = hexmem(rr->generic.data, rr->generic.data_size); if (!t) - return -ENOMEM; + return NULL; - r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.size, t); + /* Format as documented in RFC 3597, Section 5 */ + r = asprintf(&s, "%s \\# %zu %s", k, rr->generic.data_size, t); if (r < 0) - return -ENOMEM; + return NULL; break; } - *ret = s; + rr->to_string = s; + return s; +} + +int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) { + + DnsPacket packet = { + .n_ref = 1, + .protocol = DNS_PROTOCOL_DNS, + .on_stack = true, + .refuse_compression = true, + .canonical_form = canonical, + }; + + size_t start, rds; + int r; + + assert(rr); + + /* Generates the RR in wire-format, optionally in the + * canonical form as discussed in the DNSSEC RFC 4034, Section + * 6.2. We allocate a throw-away DnsPacket object on the stack + * here, because we need some book-keeping for memory + * management, and can reuse the DnsPacket serializer, that + * can generate the canonical form, too, but also knows label + * compression and suchlike. */ + + if (rr->wire_format && rr->wire_format_canonical == canonical) + return 0; + + r = dns_packet_append_rr(&packet, rr, &start, &rds); + if (r < 0) + return r; + + assert(start == 0); + assert(packet._data); + + free(rr->wire_format); + rr->wire_format = packet._data; + rr->wire_format_size = packet.size; + rr->wire_format_rdata_offset = rds; + rr->wire_format_canonical = canonical; + + packet._data = NULL; + dns_packet_unref(&packet); + return 0; } -const char *dns_class_to_string(uint16_t class) { +int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) { + const char *n; + int r; - switch (class) { + assert(rr); + assert(ret); - case DNS_CLASS_IN: - return "IN"; + /* Returns the RRset's signer, if it is known. */ - case DNS_CLASS_ANY: - return "ANY"; - } + if (rr->n_skip_labels_signer == (unsigned) -1) + return -ENODATA; - return NULL; -} - -int dns_class_from_string(const char *s, uint16_t *class) { - assert(s); - assert(class); - - if (strcaseeq(s, "IN")) - *class = DNS_CLASS_IN; - else if (strcaseeq(s, "ANY")) - *class = DNS_CLASS_ANY; - else + n = DNS_RESOURCE_KEY_NAME(rr->key); + r = dns_name_skip(n, rr->n_skip_labels_signer, &n); + if (r < 0) + return r; + if (r == 0) return -EINVAL; + *ret = n; return 0; } + +int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) { + const char *n; + int r; + + assert(rr); + assert(ret); + + /* Returns the RRset's synthesizing source, if it is known. */ + + if (rr->n_skip_labels_source == (unsigned) -1) + return -ENODATA; + + n = DNS_RESOURCE_KEY_NAME(rr->key); + r = dns_name_skip(n, rr->n_skip_labels_source, &n); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + *ret = n; + return 0; +} + +int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone) { + const char *signer; + int r; + + assert(rr); + + r = dns_resource_record_signer(rr, &signer); + if (r < 0) + return r; + + return dns_name_equal(zone, signer); +} + +int dns_resource_record_is_synthetic(DnsResourceRecord *rr) { + int r; + + assert(rr); + + /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */ + + if (rr->n_skip_labels_source == (unsigned) -1) + return -ENODATA; + + if (rr->n_skip_labels_source == 0) + return 0; + + if (rr->n_skip_labels_source > 1) + return 1; + + r = dns_name_startswith(DNS_RESOURCE_KEY_NAME(rr->key), "*"); + if (r < 0) + return r; + + return !r; +} + +static void dns_resource_record_hash_func(const void *i, struct siphash *state) { + const DnsResourceRecord *rr = i; + + assert(rr); + + dns_resource_key_hash_func(rr->key, state); + + switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) { + + case DNS_TYPE_SRV: + siphash24_compress(&rr->srv.priority, sizeof(rr->srv.priority), state); + siphash24_compress(&rr->srv.weight, sizeof(rr->srv.weight), state); + siphash24_compress(&rr->srv.port, sizeof(rr->srv.port), state); + dns_name_hash_func(rr->srv.name, state); + break; + + case DNS_TYPE_PTR: + case DNS_TYPE_NS: + case DNS_TYPE_CNAME: + case DNS_TYPE_DNAME: + dns_name_hash_func(rr->ptr.name, state); + break; + + case DNS_TYPE_HINFO: + string_hash_func(rr->hinfo.cpu, state); + string_hash_func(rr->hinfo.os, state); + break; + + case DNS_TYPE_TXT: + case DNS_TYPE_SPF: { + DnsTxtItem *j; + + LIST_FOREACH(items, j, rr->txt.items) { + siphash24_compress(j->data, j->length, state); + + /* Add an extra NUL byte, so that "a" followed by "b" doesn't result in the same hash as "ab" + * followed by "". */ + siphash24_compress_byte(0, state); + } + break; + } + + case DNS_TYPE_A: + siphash24_compress(&rr->a.in_addr, sizeof(rr->a.in_addr), state); + break; + + case DNS_TYPE_AAAA: + siphash24_compress(&rr->aaaa.in6_addr, sizeof(rr->aaaa.in6_addr), state); + break; + + case DNS_TYPE_SOA: + dns_name_hash_func(rr->soa.mname, state); + dns_name_hash_func(rr->soa.rname, state); + siphash24_compress(&rr->soa.serial, sizeof(rr->soa.serial), state); + siphash24_compress(&rr->soa.refresh, sizeof(rr->soa.refresh), state); + siphash24_compress(&rr->soa.retry, sizeof(rr->soa.retry), state); + siphash24_compress(&rr->soa.expire, sizeof(rr->soa.expire), state); + siphash24_compress(&rr->soa.minimum, sizeof(rr->soa.minimum), state); + break; + + case DNS_TYPE_MX: + siphash24_compress(&rr->mx.priority, sizeof(rr->mx.priority), state); + dns_name_hash_func(rr->mx.exchange, state); + break; + + case DNS_TYPE_LOC: + siphash24_compress(&rr->loc.version, sizeof(rr->loc.version), state); + siphash24_compress(&rr->loc.size, sizeof(rr->loc.size), state); + siphash24_compress(&rr->loc.horiz_pre, sizeof(rr->loc.horiz_pre), state); + siphash24_compress(&rr->loc.vert_pre, sizeof(rr->loc.vert_pre), state); + siphash24_compress(&rr->loc.latitude, sizeof(rr->loc.latitude), state); + siphash24_compress(&rr->loc.longitude, sizeof(rr->loc.longitude), state); + siphash24_compress(&rr->loc.altitude, sizeof(rr->loc.altitude), state); + break; + + case DNS_TYPE_SSHFP: + siphash24_compress(&rr->sshfp.algorithm, sizeof(rr->sshfp.algorithm), state); + siphash24_compress(&rr->sshfp.fptype, sizeof(rr->sshfp.fptype), state); + siphash24_compress(rr->sshfp.fingerprint, rr->sshfp.fingerprint_size, state); + break; + + case DNS_TYPE_DNSKEY: + siphash24_compress(&rr->dnskey.flags, sizeof(rr->dnskey.flags), state); + siphash24_compress(&rr->dnskey.protocol, sizeof(rr->dnskey.protocol), state); + siphash24_compress(&rr->dnskey.algorithm, sizeof(rr->dnskey.algorithm), state); + siphash24_compress(rr->dnskey.key, rr->dnskey.key_size, state); + break; + + case DNS_TYPE_RRSIG: + siphash24_compress(&rr->rrsig.type_covered, sizeof(rr->rrsig.type_covered), state); + siphash24_compress(&rr->rrsig.algorithm, sizeof(rr->rrsig.algorithm), state); + siphash24_compress(&rr->rrsig.labels, sizeof(rr->rrsig.labels), state); + siphash24_compress(&rr->rrsig.original_ttl, sizeof(rr->rrsig.original_ttl), state); + siphash24_compress(&rr->rrsig.expiration, sizeof(rr->rrsig.expiration), state); + siphash24_compress(&rr->rrsig.inception, sizeof(rr->rrsig.inception), state); + siphash24_compress(&rr->rrsig.key_tag, sizeof(rr->rrsig.key_tag), state); + dns_name_hash_func(rr->rrsig.signer, state); + siphash24_compress(rr->rrsig.signature, rr->rrsig.signature_size, state); + break; + + case DNS_TYPE_NSEC: + dns_name_hash_func(rr->nsec.next_domain_name, state); + /* FIXME: we leave out the type bitmap here. Hash + * would be better if we'd take it into account + * too. */ + break; + + case DNS_TYPE_DS: + siphash24_compress(&rr->ds.key_tag, sizeof(rr->ds.key_tag), state); + siphash24_compress(&rr->ds.algorithm, sizeof(rr->ds.algorithm), state); + siphash24_compress(&rr->ds.digest_type, sizeof(rr->ds.digest_type), state); + siphash24_compress(rr->ds.digest, rr->ds.digest_size, state); + break; + + case DNS_TYPE_NSEC3: + siphash24_compress(&rr->nsec3.algorithm, sizeof(rr->nsec3.algorithm), state); + siphash24_compress(&rr->nsec3.flags, sizeof(rr->nsec3.flags), state); + siphash24_compress(&rr->nsec3.iterations, sizeof(rr->nsec3.iterations), state); + siphash24_compress(rr->nsec3.salt, rr->nsec3.salt_size, state); + siphash24_compress(rr->nsec3.next_hashed_name, rr->nsec3.next_hashed_name_size, state); + /* FIXME: We leave the bitmaps out */ + break; + + case DNS_TYPE_TLSA: + siphash24_compress(&rr->tlsa.cert_usage, sizeof(rr->tlsa.cert_usage), state); + siphash24_compress(&rr->tlsa.selector, sizeof(rr->tlsa.selector), state); + siphash24_compress(&rr->tlsa.matching_type, sizeof(rr->tlsa.matching_type), state); + siphash24_compress(&rr->tlsa.data, rr->tlsa.data_size, state); + break; + + case DNS_TYPE_OPENPGPKEY: + default: + siphash24_compress(rr->generic.data, rr->generic.data_size, state); + break; + } +} + +static int dns_resource_record_compare_func(const void *a, const void *b) { + const DnsResourceRecord *x = a, *y = b; + int ret; + + ret = dns_resource_key_compare_func(x->key, y->key); + if (ret != 0) + return ret; + + if (dns_resource_record_equal(x, y)) + return 0; + + /* This is a bit dirty, we don't implement proper ordering, but + * the hashtable doesn't need ordering anyway, hence we don't + * care. */ + return x < y ? -1 : 1; +} + +const struct hash_ops dns_resource_record_hash_ops = { + .hash = dns_resource_record_hash_func, + .compare = dns_resource_record_compare_func, +}; + +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 true; + + 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); +} + +static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = { + /* Mnemonics as listed on https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */ + [DNSSEC_ALGORITHM_RSAMD5] = "RSAMD5", + [DNSSEC_ALGORITHM_DH] = "DH", + [DNSSEC_ALGORITHM_DSA] = "DSA", + [DNSSEC_ALGORITHM_ECC] = "ECC", + [DNSSEC_ALGORITHM_RSASHA1] = "RSASHA1", + [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1] = "DSA-NSEC3-SHA1", + [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1", + [DNSSEC_ALGORITHM_RSASHA256] = "RSASHA256", + [DNSSEC_ALGORITHM_RSASHA512] = "RSASHA512", + [DNSSEC_ALGORITHM_ECC_GOST] = "ECC-GOST", + [DNSSEC_ALGORITHM_ECDSAP256SHA256] = "ECDSAP256SHA256", + [DNSSEC_ALGORITHM_ECDSAP384SHA384] = "ECDSAP384SHA384", + [DNSSEC_ALGORITHM_INDIRECT] = "INDIRECT", + [DNSSEC_ALGORITHM_PRIVATEDNS] = "PRIVATEDNS", + [DNSSEC_ALGORITHM_PRIVATEOID] = "PRIVATEOID", +}; +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_algorithm, int, 255); + +static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = { + /* Names as listed on https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */ + [DNSSEC_DIGEST_SHA1] = "SHA-1", + [DNSSEC_DIGEST_SHA256] = "SHA-256", + [DNSSEC_DIGEST_GOST_R_34_11_94] = "GOST_R_34.11-94", + [DNSSEC_DIGEST_SHA384] = "SHA-384", +}; +DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(dnssec_digest, int, 255); diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 9e2207c0a..2e0dfbaba 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,37 +22,113 @@ #include #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 */ +/* DNSKEY RR flags */ +#define DNSKEY_FLAG_SEP (UINT16_C(1) << 0) +#define DNSKEY_FLAG_REVOKE (UINT16_C(1) << 7) +#define DNSKEY_FLAG_ZONE_KEY (UINT16_C(1) << 8) + +/* mDNS RR flags */ +#define MDNS_RR_CACHE_FLUSH (UINT16_C(1) << 15) + +/* DNSSEC algorithm identifiers, see + * http://tools.ietf.org/html/rfc4034#appendix-A.1 and + * https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */ enum { - DNS_CLASS_IN = 0x01, - DNS_CLASS_ANY = 0xFF, - _DNS_CLASS_MAX, - _DNS_CLASS_INVALID = -1 + DNSSEC_ALGORITHM_RSAMD5 = 1, + DNSSEC_ALGORITHM_DH, + DNSSEC_ALGORITHM_DSA, + DNSSEC_ALGORITHM_ECC, + DNSSEC_ALGORITHM_RSASHA1, + DNSSEC_ALGORITHM_DSA_NSEC3_SHA1, + DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1, + DNSSEC_ALGORITHM_RSASHA256 = 8, /* RFC 5702 */ + DNSSEC_ALGORITHM_RSASHA512 = 10, /* RFC 5702 */ + DNSSEC_ALGORITHM_ECC_GOST = 12, /* RFC 5933 */ + DNSSEC_ALGORITHM_ECDSAP256SHA256 = 13, /* RFC 6605 */ + DNSSEC_ALGORITHM_ECDSAP384SHA384 = 14, /* RFC 6605 */ + DNSSEC_ALGORITHM_INDIRECT = 252, + DNSSEC_ALGORITHM_PRIVATEDNS, + DNSSEC_ALGORITHM_PRIVATEOID, + _DNSSEC_ALGORITHM_MAX_DEFINED +}; + +/* DNSSEC digest identifiers, see + * https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */ +enum { + DNSSEC_DIGEST_SHA1 = 1, + DNSSEC_DIGEST_SHA256 = 2, /* RFC 4509 */ + DNSSEC_DIGEST_GOST_R_34_11_94 = 3, /* RFC 5933 */ + DNSSEC_DIGEST_SHA384 = 4, /* RFC 6605 */ + _DNSSEC_DIGEST_MAX_DEFINED +}; + +/* DNSSEC NSEC3 hash algorithms, see + * https://www.iana.org/assignments/dnssec-nsec3-parameters/dnssec-nsec3-parameters.xhtml */ +enum { + NSEC3_ALGORITHM_SHA1 = 1, + _NSEC3_ALGORITHM_MAX_DEFINED }; struct DnsResourceKey { - unsigned n_ref; + unsigned n_ref; /* (unsigned -1) for const keys, see below */ uint16_t class, type; char *_name; /* don't access directy, use DNS_RESOURCE_KEY_NAME()! */ }; +/* Creates a temporary resource key. This is only useful to quickly + * look up something, without allocating a full DnsResourceKey object + * for it. Note that it is not OK to take references to this kind of + * resource key object. */ +#define DNS_RESOURCE_KEY_CONST(c, t, n) \ + ((DnsResourceKey) { \ + .n_ref = (unsigned) -1, \ + .class = c, \ + .type = t, \ + ._name = (char*) n, \ + }) + + +struct DnsTxtItem { + size_t length; + LIST_FIELDS(DnsTxtItem, items); + uint8_t data[]; +}; + struct DnsResourceRecord { unsigned n_ref; DnsResourceKey *key; + + char *to_string; + uint32_t ttl; - bool unparseable; + usec_t expiry; /* RRSIG signature expiry */ + + /* How many labels to strip to determine "signer" of the RRSIG (aka, the zone). -1 if not signed. */ + unsigned n_skip_labels_signer; + /* How many labels to strip to determine "synthesizing source" of this RR, i.e. the wildcard's immediate parent. -1 if not signed. */ + unsigned n_skip_labels_source; + + bool unparseable:1; + + bool wire_format_canonical:1; + void *wire_format; + size_t wire_format_size; + size_t wire_format_rdata_offset; + union { struct { void *data; - size_t size; - } generic; + size_t data_size; + } generic, opt; struct { uint16_t priority; @@ -73,7 +147,7 @@ struct DnsResourceRecord { } hinfo; struct { - char **strings; + DnsTxtItem *items; } txt, spf; struct { @@ -99,6 +173,7 @@ struct DnsResourceRecord { char *exchange; } mx; + /* https://tools.ietf.org/html/rfc1876 */ struct { uint8_t version; uint8_t size; @@ -109,14 +184,6 @@ struct DnsResourceRecord { uint32_t altitude; } loc; - struct { - uint16_t key_tag; - uint8_t algorithm; - uint8_t digest_type; - void *digest; - size_t digest_size; - } ds; - /* https://tools.ietf.org/html/rfc4255#section-3.1 */ struct { uint8_t algorithm; @@ -127,8 +194,8 @@ struct DnsResourceRecord { /* http://tools.ietf.org/html/rfc4034#section-2.1 */ struct { - bool zone_key_flag:1; - bool sep_flag:1; + uint16_t flags; + uint8_t protocol; uint8_t algorithm; void* key; size_t key_size; @@ -148,11 +215,21 @@ struct DnsResourceRecord { size_t signature_size; } rrsig; + /* https://tools.ietf.org/html/rfc4034#section-4.1 */ struct { char *next_domain_name; Bitmap *types; } nsec; + /* https://tools.ietf.org/html/rfc4034#section-5.1 */ + struct { + uint16_t key_tag; + uint8_t algorithm; + uint8_t digest_type; + void *digest; + size_t digest_size; + } ds; + struct { uint8_t algorithm; uint8_t flags; @@ -163,11 +240,20 @@ struct DnsResourceRecord { size_t next_hashed_name_size; Bitmap *types; } nsec3; + + /* https://tools.ietf.org/html/draft-ietf-dane-protocol-23 */ + struct { + uint8_t cert_usage; + uint8_t selector; + uint8_t matching_type; + void *data; + size_t data_size; + } tlsa; }; }; static inline const char* DNS_RESOURCE_KEY_NAME(const DnsResourceKey *key) { - if (_unlikely_(!key)) + if (!key) return NULL; if (key->_name) @@ -176,18 +262,47 @@ static inline const char* DNS_RESOURCE_KEY_NAME(const DnsResourceKey *key) { return (char*) key + sizeof(DnsResourceKey); } +static inline const void* DNS_RESOURCE_RECORD_RDATA(DnsResourceRecord *rr) { + if (!rr) + return NULL; + + if (!rr->wire_format) + return NULL; + + assert(rr->wire_format_rdata_offset <= rr->wire_format_size); + return (uint8_t*) rr->wire_format + rr->wire_format_rdata_offset; +} + +static inline size_t DNS_RESOURCE_RECORD_RDATA_SIZE(DnsResourceRecord *rr) { + if (!rr) + return 0; + if (!rr->wire_format) + return 0; + + assert(rr->wire_format_rdata_offset <= rr->wire_format_size); + return rr->wire_format_size - rr->wire_format_rdata_offset; +} + 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_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); +bool dns_resource_key_is_address(const 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, DnsResourceRecord *rr, const char *search_domain); +int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsResourceKey *cname, const char *search_domain); +int dns_resource_key_match_soa(const DnsResourceKey *key, const DnsResourceKey *soa); int dns_resource_key_to_string(const DnsResourceKey *key, char **ret); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref); +static inline bool dns_key_is_shared(const DnsResourceKey *key) { + return IN_SET(key->type, DNS_TYPE_PTR); +} + +bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b); + DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key); DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name); DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr); @@ -195,10 +310,24 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr); int dns_resource_record_new_reverse(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name); int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const union in_addr_union *address, const char *name); int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecord *b); -int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret); +const char* dns_resource_record_to_string(DnsResourceRecord *rr); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref); -const char *dns_class_to_string(uint16_t type); -int dns_class_from_string(const char *name, uint16_t *class); +int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical); + +int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret); +int dns_resource_record_source(DnsResourceRecord *rr, const char **ret); +int dns_resource_record_is_signer(DnsResourceRecord *rr, const char *zone); +int dns_resource_record_is_synthetic(DnsResourceRecord *rr); + +DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i); +bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); extern const struct hash_ops dns_resource_key_hash_ops; +extern const struct hash_ops dns_resource_record_hash_ops; + +int dnssec_algorithm_to_string_alloc(int i, char **ret); +int dnssec_algorithm_from_string(const char *s) _pure_; + +int dnssec_digest_to_string_alloc(int i, char **ret); +int dnssec_digest_from_string(const char *s) _pure_; diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index b15370b01..a406872a3 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -30,6 +28,7 @@ #include "random-util.h" #include "resolved-dns-scope.h" #include "resolved-llmnr.h" +#include "resolved-mdns.h" #include "socket-util.h" #include "strv.h" @@ -56,9 +55,24 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int s->family = family; s->resend_timeout = MULTICAST_RESEND_TIMEOUT_MIN_USEC; + if (protocol == DNS_PROTOCOL_DNS) { + /* Copy DNSSEC mode from the link if it is set there, + * otherwise take the manager's DNSSEC mode. Note that + * we copy this only at scope creation time, and do + * not update it from the on, even if the setting + * changes. */ + + if (l) + s->dnssec_mode = link_get_dnssec_mode(l); + else + s->dnssec_mode = manager_get_dnssec_mode(m); + } else + s->dnssec_mode = DNSSEC_NO; + LIST_PREPEND(scopes, m->dns_scopes, s); dns_scope_llmnr_membership(s, true); + dns_scope_mdns_membership(s, true); log_debug("New scope on link %s, protocol %s, family %s", l ? l->name : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family)); @@ -69,8 +83,25 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int return 0; } +static void dns_scope_abort_transactions(DnsScope *s) { + assert(s); + + while (s->transactions) { + DnsTransaction *t = s->transactions; + + /* Abort the transaction, but make sure it is not + * freed while we still look at it */ + + t->block_gc++; + if (DNS_TRANSACTION_IS_LIVE(t->state)) + dns_transaction_complete(t, DNS_TRANSACTION_ABORTED); + t->block_gc--; + + dns_transaction_free(t); + } +} + DnsScope* dns_scope_free(DnsScope *s) { - DnsTransaction *t; DnsResourceRecord *rr; if (!s) @@ -79,19 +110,13 @@ DnsScope* dns_scope_free(DnsScope *s) { 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_mdns_membership(s, false); + dns_scope_abort_transactions(s); - while ((t = hashmap_steal_first(s->transactions))) { - /* Abort the transaction, but make sure it is not - * freed while we still look at it */ + while (s->query_candidates) + dns_query_candidate_free(s->query_candidates); - t->block_gc++; - dns_transaction_complete(t, DNS_TRANSACTION_ABORTED); - t->block_gc--; - - dns_transaction_free(t); - } - - hashmap_free(s->transactions); + hashmap_free(s->transactions_by_key); while ((rr = ordered_hashmap_steal_first(s->conflict_queue))) dns_resource_record_unref(rr); @@ -103,7 +128,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 +160,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) { @@ -150,17 +174,15 @@ void dns_scope_packet_lost(DnsScope *s, usec_t usec) { s->resend_timeout = MIN(s->resend_timeout * 2, MULTICAST_RESEND_TIMEOUT_MAX_USEC); } -int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { +static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) { union in_addr_union addr; int ifindex = 0, r; int family; - uint16_t port; uint32_t mtu; assert(s); assert(p); assert(p->protocol == s->protocol); - assert((s->protocol == DNS_PROTOCOL_DNS) != (fd < 0)); if (s->link) { mtu = s->link->mtu; @@ -169,7 +191,10 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { mtu = manager_find_mtu(s->manager); switch (s->protocol) { + case DNS_PROTOCOL_DNS: + assert(fd >= 0); + if (DNS_PACKET_QDCOUNT(p) > 1) return -EOPNOTSUPP; @@ -186,6 +211,8 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { break; case DNS_PROTOCOL_LLMNR: + assert(fd < 0); + if (DNS_PACKET_QDCOUNT(p) > 1) return -EOPNOTSUPP; @@ -193,7 +220,6 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { return -EBUSY; family = s->family; - port = LLMNR_PORT; if (family == AF_INET) { addr.in = LLMNR_MULTICAST_IPV4_ADDRESS; @@ -206,7 +232,32 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { if (fd < 0) return fd; - r = manager_send(s->manager, fd, ifindex, family, &addr, port, p); + r = manager_send(s->manager, fd, ifindex, family, &addr, LLMNR_PORT, p); + if (r < 0) + return r; + + break; + + case DNS_PROTOCOL_MDNS: + assert(fd < 0); + + if (!ratelimit_test(&s->ratelimit)) + return -EBUSY; + + family = s->family; + + if (family == AF_INET) { + addr.in = MDNS_MULTICAST_IPV4_ADDRESS; + fd = manager_mdns_ipv4_fd(s->manager); + } else if (family == AF_INET6) { + addr.in6 = MDNS_MULTICAST_IPV6_ADDRESS; + fd = manager_mdns_ipv6_fd(s->manager); + } else + return -EAFNOSUPPORT; + if (fd < 0) + return fd; + + r = manager_send(s->manager, fd, ifindex, family, &addr, MDNS_PORT, p); if (r < 0) return r; @@ -219,8 +270,39 @@ int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p) { return 1; } -static int dns_scope_socket(DnsScope *s, int type, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) { - DnsServer *srv = NULL; +int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p) { + int r; + + assert(s); + assert(p); + assert(p->protocol == s->protocol); + assert((s->protocol == DNS_PROTOCOL_DNS) == (fd >= 0)); + + do { + /* If there are multiple linked packets, set the TC bit in all but the last of them */ + if (p->more) { + assert(p->protocol == DNS_PROTOCOL_MDNS); + dns_packet_set_flags(p, true, true); + } + + r = dns_scope_emit_one(s, fd, p); + if (r < 0) + return r; + + p = p->more; + } while (p); + + return 0; +} + +static int dns_scope_socket( + DnsScope *s, + int type, + int family, + const union in_addr_union *address, + DnsServer *server, + uint16_t port) { + _cleanup_close_ int fd = -1; union sockaddr_union sa = {}; socklen_t salen; @@ -228,26 +310,27 @@ static int dns_scope_socket(DnsScope *s, int type, int family, const union in_ad int ret, r; assert(s); - assert((family == AF_UNSPEC) == !address); - if (family == AF_UNSPEC) { - srv = dns_scope_get_dns_server(s); - if (!srv) - return -ESRCH; + if (server) { + assert(family == AF_UNSPEC); + assert(!address); - sa.sa.sa_family = srv->family; - if (srv->family == AF_INET) { + sa.sa.sa_family = server->family; + if (server->family == AF_INET) { sa.in.sin_port = htobe16(port); - sa.in.sin_addr = srv->address.in; + sa.in.sin_addr = server->address.in; salen = sizeof(sa.in); - } else if (srv->family == AF_INET6) { + } else if (server->family == AF_INET6) { sa.in6.sin6_port = htobe16(port); - sa.in6.sin6_addr = srv->address.in6; + sa.in6.sin6_addr = server->address.in6; sa.in6.sin6_scope_id = s->link ? s->link->ifindex : 0; salen = sizeof(sa.in6); } else return -EAFNOSUPPORT; } else { + assert(family != AF_UNSPEC); + assert(address); + sa.sa.sa_family = family; if (family == AF_INET) { @@ -305,36 +388,34 @@ static int dns_scope_socket(DnsScope *s, int type, int family, const union in_ad if (r < 0 && errno != EINPROGRESS) return -errno; - if (server) - *server = srv; - ret = fd; fd = -1; return ret; } -int dns_scope_udp_dns_socket(DnsScope *s, DnsServer **server) { - return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, 53, server); +int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port) { + return dns_scope_socket(s, SOCK_DGRAM, AF_UNSPEC, NULL, server, port); } -int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) { - return dns_scope_socket(s, SOCK_STREAM, family, address, port, server); +int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port) { + return dns_scope_socket(s, SOCK_STREAM, family, address, server, port); } DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain) { - char **i; + DnsSearchDomain *d; assert(s); assert(domain); + /* Checks if the specified domain is something to look up on + * this scope. Note that this accepts non-qualified hostnames, + * i.e. those without any search path prefixed yet. */ + if (ifindex != 0 && (!s->link || s->link->ifindex != ifindex)) return DNS_SCOPE_NO; - if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family) & flags) == 0) - return DNS_SCOPE_NO; - - if (dns_name_root(domain) != 0) + if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, 0) & flags) == 0) return DNS_SCOPE_NO; /* Never resolve any loopback hostname or IP address via DNS, @@ -345,15 +426,38 @@ 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) + /* Never respond to some of the domains listed in RFC6303 */ + if (dns_name_endswith(domain, "0.in-addr.arpa") > 0 || + dns_name_equal(domain, "255.255.255.255.in-addr.arpa") > 0 || + dns_name_equal(domain, "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.0.ip6.arpa") > 0) + return DNS_SCOPE_NO; + + /* Never respond to some of the domains listed in RFC6761 */ + if (dns_name_endswith(domain, "invalid") > 0) + return DNS_SCOPE_NO; + + /* 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: + + /* Exclude link-local IP ranges */ 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) + dns_name_endswith(domain, "8.e.f.ip6.arpa") == 0 && + dns_name_endswith(domain, "9.e.f.ip6.arpa") == 0 && + dns_name_endswith(domain, "a.e.f.ip6.arpa") == 0 && + dns_name_endswith(domain, "b.e.f.ip6.arpa") == 0 && + /* If networks use .local in their private setups, they are supposed to also add .local to their search + * domains, which we already checked above. Otherwise, we consider .local specific to mDNS and won't + * send such queries ordinary DNS servers. */ + dns_name_endswith(domain, "local") == 0) return DNS_SCOPE_MAYBE; return DNS_SCOPE_NO; @@ -371,7 +475,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; @@ -383,38 +487,56 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co } } -int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) { +bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) { + int key_family; + assert(s); assert(key); - if (s->protocol == DNS_PROTOCOL_DNS) - return true; + /* Check if it makes sense to resolve the specified key on + * this scope. Note that this call assumes as fully qualified + * name, i.e. the search suffixes already appended. */ + + if (key->class != DNS_CLASS_IN) + return false; + + if (s->protocol == DNS_PROTOCOL_DNS) { + + /* On classic DNS, looking up non-address RRs is always + * fine. (Specifically, we want to permit looking up + * DNSKEY and DS records on the root and top-level + * domains.) */ + if (!dns_resource_key_is_address(key)) + return true; + + /* However, we refuse to look up A and AAAA RRs on the + * root and single-label domains, under the assumption + * that those should be resolved via LLMNR or search + * path only, and should not be leaked onto the + * internet. */ + return !(dns_name_is_single_label(DNS_RESOURCE_KEY_NAME(key)) || + dns_name_is_root(DNS_RESOURCE_KEY_NAME(key))); + } /* On mDNS and LLMNR, send A and AAAA queries only on the * respective scopes */ - if (s->family == AF_INET && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_AAAA) - return false; + key_family = dns_type_to_af(key->type); + if (key_family < 0) + return true; - if (s->family == AF_INET6 && key->class == DNS_CLASS_IN && key->type == DNS_TYPE_A) - return false; - - return true; + return key_family == s->family; } -int dns_scope_llmnr_membership(DnsScope *s, bool b) { +static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in, struct in6_addr in6) { int fd; assert(s); - - if (s->protocol != DNS_PROTOCOL_LLMNR) - return 0; - assert(s->link); if (s->family == AF_INET) { struct ip_mreqn mreqn = { - .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS, + .imr_multiaddr = in, .imr_ifindex = s->link->ifindex, }; @@ -433,7 +555,7 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) { } else if (s->family == AF_INET6) { struct ipv6_mreq mreq = { - .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS, + .ipv6mr_multiaddr = in6, .ipv6mr_interface = s->link->ifindex, }; @@ -452,6 +574,22 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) { return 0; } +int dns_scope_llmnr_membership(DnsScope *s, bool b) { + + if (s->protocol != DNS_PROTOCOL_LLMNR) + return 0; + + return dns_scope_multicast_membership(s, b, LLMNR_MULTICAST_IPV4_ADDRESS, LLMNR_MULTICAST_IPV6_ADDRESS); +} + +int dns_scope_mdns_membership(DnsScope *s, bool b) { + + if (s->protocol != DNS_PROTOCOL_MDNS) + return 0; + + return dns_scope_multicast_membership(s, b, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS); +} + static int dns_scope_make_reply_packet( DnsScope *s, uint16_t id, @@ -502,7 +640,7 @@ static int dns_scope_make_reply_packet( if (answer) { for (i = 0; i < answer->n_rrs; i++) { - r = dns_packet_append_rr(p, answer->items[i].rr, NULL); + r = dns_packet_append_rr(p, answer->items[i].rr, NULL, NULL); if (r < 0) return r; } @@ -512,7 +650,7 @@ static int dns_scope_make_reply_packet( if (soa) { for (i = 0; i < soa->n_rrs; i++) { - r = dns_packet_append_rr(p, soa->items[i].rr, NULL); + r = dns_packet_append_rr(p, soa->items[i].rr, NULL, NULL); if (r < 0) return r; } @@ -543,6 +681,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 +715,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,15 +776,15 @@ 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; /* Refuse reusing transactions that completed based on cached * 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) + IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_RCODE_FAILURE) && + t->answer_source != DNS_TRANSACTION_NETWORK) return NULL; return t; @@ -674,7 +816,11 @@ static int dns_scope_make_conflict_packet( 0 /* (ad) */, 0 /* (cd) */, 0)); - random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t)); + + /* For mDNS, the transaction ID should always be 0 */ + if (s->protocol != DNS_PROTOCOL_MDNS) + random_bytes(&DNS_PACKET_HEADER(p)->id, sizeof(uint16_t)); + DNS_PACKET_HEADER(p)->qdcount = htobe16(1); DNS_PACKET_HEADER(p)->arcount = htobe16(1); @@ -682,7 +828,7 @@ static int dns_scope_make_conflict_packet( if (r < 0) return r; - r = dns_packet_append_rr(p, rr, NULL); + r = dns_packet_append_rr(p, rr, NULL, NULL); if (r < 0) return r; @@ -715,7 +861,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata return 0; } - r = dns_scope_emit(scope, -1, p); + r = dns_scope_emit_udp(scope, -1, p); if (r < 0) log_debug_errno(r, "Failed to send conflict packet: %m"); } @@ -764,6 +910,8 @@ int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr) { if (r < 0) return log_debug_errno(r, "Failed to add conflict dispatch event: %m"); + (void) sd_event_source_set_description(scope->conflict_event_source, "scope-conflict"); + return 0; } @@ -846,3 +994,35 @@ void dns_scope_dump(DnsScope *s, FILE *f) { dns_cache_dump(&s->cache, f); } } + +DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) { + assert(s); + + if (s->protocol != DNS_PROTOCOL_DNS) + return NULL; + + if (s->link) + return s->link->search_domains; + + return s->manager->search_domains; +} + +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); +} + +bool dns_scope_network_good(DnsScope *s) { + /* Checks whether the network is in good state for lookups on this scope. For mDNS/LLMNR/Classic DNS scopes + * bound to links this is easy, as they don't even exist if the link isn't in a suitable state. For the global + * DNS scope we check whether there are any links that are up and have an address. */ + + if (s->link) + return true; + + return manager_routable(s->manager, AF_UNSPEC); +} diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index b75f21289..291e5817d 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,9 +23,10 @@ typedef struct DnsScope DnsScope; -#include "resolved-dns-server.h" -#include "resolved-dns-packet.h" #include "resolved-dns-cache.h" +#include "resolved-dns-dnssec.h" +#include "resolved-dns-packet.h" +#include "resolved-dns-server.h" #include "resolved-dns-zone.h" #include "resolved-link.h" @@ -44,11 +43,10 @@ struct DnsScope { DnsProtocol protocol; int family; + DnssecMode dnssec_mode; 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); }; @@ -71,17 +80,18 @@ DnsScope* dns_scope_free(DnsScope *s); void dns_scope_packet_received(DnsScope *s, usec_t rtt); void dns_scope_packet_lost(DnsScope *s, usec_t usec); -int dns_scope_emit(DnsScope *s, int fd, DnsPacket *p); -int dns_scope_tcp_socket(DnsScope *s, int family, const union in_addr_union *address, uint16_t port, DnsServer **server); -int dns_scope_udp_dns_socket(DnsScope *s, DnsServer **server); +int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p); +int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port); +int dns_scope_socket_udp(DnsScope *s, DnsServer *server, uint16_t port); DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, const char *domain); -int dns_scope_good_key(DnsScope *s, DnsResourceKey *key); +bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key); DnsServer *dns_scope_get_dns_server(DnsScope *s); void dns_scope_next_dns_server(DnsScope *s); int dns_scope_llmnr_membership(DnsScope *s, bool b); +int dns_scope_mdns_membership(DnsScope *s, bool b); void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p); @@ -91,3 +101,9 @@ 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_name_needs_search_domain(DnsScope *s, const char *name); + +bool dns_scope_network_good(DnsScope *s); diff --git a/src/resolve/resolved-dns-search-domain.c b/src/resolve/resolved-dns-search-domain.c new file mode 100644 index 000000000..732471027 --- /dev/null +++ b/src/resolve/resolved-dns-search-domain.c @@ -0,0 +1,227 @@ +/*** + 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 . +***/ + +#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 (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 000000000..eaacef4ed --- /dev/null +++ b/src/resolve/resolved-dns-search-domain.h @@ -0,0 +1,74 @@ +#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 . +***/ + +#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 route_only: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 e803f635a..27342a0e0 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,14 +17,26 @@ along with systemd; If not, see . ***/ +#include + #include "alloc-util.h" #include "resolved-dns-server.h" +#include "resolved-resolv-conf.h" #include "siphash24.h" +#include "string-table.h" +#include "string-util.h" /* After how much time to repeat classic DNS requests */ #define DNS_TIMEOUT_MIN_USEC (500 * USEC_PER_MSEC) #define DNS_TIMEOUT_MAX_USEC (5 * USEC_PER_SEC) +/* The amount of time to wait before retrying with a full feature set */ +#define DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC (6 * USEC_PER_HOUR) +#define DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC (5 * USEC_PER_MINUTE) + +/* The number of times we will attempt a certain feature set before degrading */ +#define DNS_SERVER_FEATURE_RETRY_ATTEMPTS 3 + int dns_server_new( Manager *m, DnsServer **ret, @@ -35,36 +45,61 @@ 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->verified_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST; + s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC; + s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX; s->type = type; s->family = family; s->address = *in_addr; s->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); - 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 - assert_not_reached("Unknown server type"); + switch (type) { - s->manager = m; + case DNS_SERVER_LINK: + s->link = l; + 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->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 +120,447 @@ 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) { - if (!s) - return NULL; - - 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) - manager_set_dns_server(s->manager, NULL); - - free(s); - - return NULL; -} - DnsServer* dns_server_unref(DnsServer *s) { if (!s) return NULL; assert(s->n_ref > 0); + s->n_ref --; - if (s->n_ref == 1) - dns_server_free(s); - else - s->n_ref --; + if (s->n_ref > 0) + return NULL; + free(s->server_string); + free(s); return NULL; } -void dns_server_packet_received(DnsServer *s, usec_t rtt) { +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->current_dns_server == s) + manager_set_dns_server(s->manager, NULL); + + dns_server_unref(s); +} + +void dns_server_move_back_and_unmark(DnsServer *s) { + DnsServer *tail; + 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 (!s->marked) + return; + + 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_lost(DnsServer *s, usec_t usec) { +static void dns_server_verified(DnsServer *s, DnsServerFeatureLevel level) { assert(s); - if (s->resend_timeout <= usec) - s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC); + if (s->verified_feature_level > level) + return; + + if (s->verified_feature_level != level) { + log_debug("Verified we get a response at feature level %s from DNS server %s.", + dns_server_feature_level_to_string(level), + dns_server_string(s)); + s->verified_feature_level = level; + } + + assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &s->verified_usec) >= 0); +} + +void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t rtt, size_t size) { + assert(s); + + if (protocol == IPPROTO_UDP) { + if (s->possible_feature_level == level) + s->n_failed_udp = 0; + + /* If the RRSIG data is missing, then we can only validate EDNS0 at max */ + if (s->packet_rrsig_missing && level >= DNS_SERVER_FEATURE_LEVEL_DO) + level = DNS_SERVER_FEATURE_LEVEL_DO - 1; + + /* If the OPT RR got lost, then we can only validate UDP at max */ + if (s->packet_bad_opt && level >= DNS_SERVER_FEATURE_LEVEL_EDNS0) + level = DNS_SERVER_FEATURE_LEVEL_EDNS0 - 1; + + /* Even if we successfully receive a reply to a request announcing support for large packets, + that does not mean we can necessarily receive large packets. */ + if (level == DNS_SERVER_FEATURE_LEVEL_LARGE) + level = DNS_SERVER_FEATURE_LEVEL_LARGE - 1; + + } else if (protocol == IPPROTO_TCP) { + + if (s->possible_feature_level == level) + s->n_failed_tcp = 0; + + /* Successful TCP connections are only useful to verify the TCP feature level. */ + level = DNS_SERVER_FEATURE_LEVEL_TCP; + } + + dns_server_verified(s, level); + + /* Remember the size of the largest UDP packet we received from a server, + we know that we can always announce support for packets with at least + this size. */ + if (protocol == IPPROTO_UDP && s->received_udp_packet_max < size) + s->received_udp_packet_max = size; + + if (s->max_rtt < rtt) { + s->max_rtt = rtt; + s->resend_timeout = CLAMP(s->max_rtt * 2, DNS_TIMEOUT_MIN_USEC, DNS_TIMEOUT_MAX_USEC); + } +} + +void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t usec) { + assert(s); + assert(s->manager); + + if (s->possible_feature_level == level) { + if (protocol == IPPROTO_UDP) + s->n_failed_udp ++; + else if (protocol == IPPROTO_TCP) + s->n_failed_tcp ++; + } + + if (s->resend_timeout > usec) + return; + + s->resend_timeout = MIN(s->resend_timeout * 2, DNS_TIMEOUT_MAX_USEC); +} + +void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel level) { + assert(s); + + /* Invoked whenever we get a FORMERR, SERVFAIL or NOTIMP rcode from a server. */ + + if (s->possible_feature_level != level) + return; + + s->packet_failed = true; +} + +void dns_server_packet_truncated(DnsServer *s, DnsServerFeatureLevel level) { + assert(s); + + /* Invoked whenever we get a packet with TC bit set. */ + + if (s->possible_feature_level != level) + return; + + s->packet_truncated = true; +} + +void dns_server_packet_rrsig_missing(DnsServer *s, DnsServerFeatureLevel level) { + assert(s); + + if (level < DNS_SERVER_FEATURE_LEVEL_DO) + return; + + /* If the RRSIG RRs are missing, we have to downgrade what we previously verified */ + if (s->verified_feature_level >= DNS_SERVER_FEATURE_LEVEL_DO) + s->verified_feature_level = DNS_SERVER_FEATURE_LEVEL_DO-1; + + s->packet_rrsig_missing = true; +} + +void dns_server_packet_bad_opt(DnsServer *s, DnsServerFeatureLevel level) { + assert(s); + + if (level < DNS_SERVER_FEATURE_LEVEL_EDNS0) + return; + + /* If the OPT RR got lost, we have to downgrade what we previously verified */ + if (s->verified_feature_level >= DNS_SERVER_FEATURE_LEVEL_EDNS0) + s->verified_feature_level = DNS_SERVER_FEATURE_LEVEL_EDNS0-1; + + s->packet_bad_opt = true; +} + +static bool dns_server_grace_period_expired(DnsServer *s) { + usec_t ts; + + assert(s); + assert(s->manager); + + if (s->verified_usec == 0) + return false; + + assert_se(sd_event_now(s->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); + + if (s->verified_usec + s->features_grace_period_usec > ts) + return false; + + s->features_grace_period_usec = MIN(s->features_grace_period_usec * 2, DNS_SERVER_FEATURE_GRACE_PERIOD_MAX_USEC); + + return true; +} + +static void dns_server_reset_counters(DnsServer *s) { + assert(s); + + s->n_failed_udp = 0; + s->n_failed_tcp = 0; + s->packet_failed = false; + s->packet_truncated = false; + s->verified_usec = 0; + + /* Note that we do not reset s->packet_bad_opt and s->packet_rrsig_missing here. We reset them only when the + * grace period ends, but not when lowering the possible feature level, as a lower level feature level should + * not make RRSIGs appear or OPT appear, but rather make them disappear. If the reappear anyway, then that's + * indication for a differently broken OPT/RRSIG implementation, and we really don't want to support that + * either. + * + * This is particularly important to deal with certain Belkin routers which break OPT for certain lookups (A), + * but pass traffic through for others (AAAA). If we detect the broken behaviour on one lookup we should not + * reenable it for another, because we cannot validate things anyway, given that the RRSIG/OPT data will be + * incomplete. */ +} + +DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { + assert(s); + + if (s->possible_feature_level != DNS_SERVER_FEATURE_LEVEL_BEST && + dns_server_grace_period_expired(s)) { + + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST; + + dns_server_reset_counters(s); + + s->packet_bad_opt = false; + s->packet_rrsig_missing = false; + + log_info("Grace period over, resuming full feature set (%s) for DNS server %s.", + dns_server_feature_level_to_string(s->possible_feature_level), + dns_server_string(s)); + + } else if (s->possible_feature_level <= s->verified_feature_level) + s->possible_feature_level = s->verified_feature_level; + else { + DnsServerFeatureLevel p = s->possible_feature_level; + + if (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS && + s->possible_feature_level == DNS_SERVER_FEATURE_LEVEL_TCP) { + + /* We are at the TCP (lowest) level, and we tried a couple of TCP connections, and it didn't + * work. Upgrade back to UDP again. */ + log_debug("Reached maximum number of failed TCP connection attempts, trying UDP again..."); + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_UDP; + + } else if (s->packet_bad_opt && + s->possible_feature_level >= DNS_SERVER_FEATURE_LEVEL_EDNS0) { + + /* A reply to one of our EDNS0 queries didn't carry a valid OPT RR, then downgrade to below + * EDNS0 levels. After all, some records generate different responses with and without OPT RR + * in the request. Example: + * https://open.nlnetlabs.nl/pipermail/dnssec-trigger/2014-November/000376.html */ + + log_debug("Server doesn't support EDNS(0) properly, downgrading feature level..."); + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_UDP; + + } else if (s->packet_rrsig_missing && + s->possible_feature_level >= DNS_SERVER_FEATURE_LEVEL_DO) { + + /* RRSIG data was missing on a EDNS0 packet with DO bit set. This means the server doesn't + * augment responses with DNSSEC RRs. If so, let's better not ask the server for it anymore, + * after all some servers generate different replies depending if an OPT RR is in the query or + * not. */ + + log_debug("Detected server responses lack RRSIG records, downgrading feature level..."); + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_EDNS0; + + } else if (s->n_failed_udp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS && + s->possible_feature_level >= DNS_SERVER_FEATURE_LEVEL_UDP) { + + /* We lost too many UDP packets in a row, and are on a feature level of UDP or higher. If the + * packets are lost, maybe the server cannot parse them, hence downgrading sounds like a good + * idea. We might downgrade all the way down to TCP this way. */ + + log_debug("Lost too many UDP packets, downgrading feature level..."); + s->possible_feature_level--; + + } else if (s->packet_failed && + s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) { + + /* We got a failure packet, and are at a feature level above UDP. Note that in this case we + * downgrade no further than UDP, under the assumption that a failure packet indicates an + * incompatible packet contents, but not a problem with the transport. */ + + log_debug("Got server failure, downgrading feature level..."); + s->possible_feature_level--; + + } else if (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS && + s->packet_truncated && + s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) { + + /* We got too many TCP connection failures in a row, we had at least one truncated packet, and + * are on a feature level above UDP. By downgrading things and getting rid of DNSSEC or EDNS0 + * data we hope to make the packet smaller, so that it still works via UDP given that TCP + * appears not to be a fallback. Note that if we are already at the lowest UDP level, we don't + * go further down, since that's TCP, and TCP failed too often after all. */ + + log_debug("Got too many failed TCP connection failures and truncated UDP packets, downgrading feature level..."); + s->possible_feature_level--; + } + + if (p != s->possible_feature_level) { + + /* We changed the feature level, reset the counting */ + dns_server_reset_counters(s); + + log_warning("Using degraded feature set (%s) for DNS server %s.", + dns_server_feature_level_to_string(s->possible_feature_level), + dns_server_string(s)); + } + } + + return s->possible_feature_level; +} + +int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level) { + size_t packet_size; + bool edns_do; + int r; + + assert(server); + assert(packet); + assert(packet->protocol == DNS_PROTOCOL_DNS); + + /* Fix the OPT field in the packet to match our current feature level. */ + + r = dns_packet_truncate_opt(packet); + if (r < 0) + return r; + + if (level < DNS_SERVER_FEATURE_LEVEL_EDNS0) + return 0; + + edns_do = level >= DNS_SERVER_FEATURE_LEVEL_DO; + + if (level >= DNS_SERVER_FEATURE_LEVEL_LARGE) + packet_size = DNS_PACKET_UNICAST_SIZE_LARGE_MAX; + else + packet_size = server->received_udp_packet_max; + + return dns_packet_append_opt(packet, packet_size, edns_do, NULL); +} + +const char *dns_server_string(DnsServer *server) { + assert(server); + + if (!server->server_string) + (void) in_addr_to_string(server->family, &server->address, &server->server_string); + + return strna(server->server_string); +} + +bool dns_server_dnssec_supported(DnsServer *server) { + assert(server); + + /* Returns whether the server supports DNSSEC according to what we know about it */ + + if (server->possible_feature_level < DNS_SERVER_FEATURE_LEVEL_DO) + return false; + + if (server->packet_bad_opt) + return false; + + if (server->packet_rrsig_missing) + return false; + + /* DNSSEC servers need to support TCP properly (see RFC5966), if they don't, we assume DNSSEC is borked too */ + if (server->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS) + return false; + + return true; +} + +void dns_server_warn_downgrade(DnsServer *server) { + assert(server); + + if (server->warned_downgrade) + return; + + log_struct(LOG_NOTICE, + LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_DOWNGRADE), + LOG_MESSAGE("Server %s does not support DNSSEC, downgrading to non-DNSSEC mode.", dns_server_string(server)), + "DNS_SERVER=%s", dns_server_string(server), + "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(server->possible_feature_level), + NULL); + + server->warned_downgrade = true; } static void dns_server_hash_func(const void *p, struct siphash *state) { @@ -161,3 +587,154 @@ 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) + log_info("Switching to %s DNS server %s.", + dns_server_type_to_string(s->type), + dns_server_string(s)); + + 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 chosen 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); +} + +static const char* const dns_server_type_table[_DNS_SERVER_TYPE_MAX] = { + [DNS_SERVER_SYSTEM] = "system", + [DNS_SERVER_FALLBACK] = "fallback", + [DNS_SERVER_LINK] = "link", +}; +DEFINE_STRING_TABLE_LOOKUP(dns_server_type, DnsServerType); + +static const char* const dns_server_feature_level_table[_DNS_SERVER_FEATURE_LEVEL_MAX] = { + [DNS_SERVER_FEATURE_LEVEL_TCP] = "TCP", + [DNS_SERVER_FEATURE_LEVEL_UDP] = "UDP", + [DNS_SERVER_FEATURE_LEVEL_EDNS0] = "UDP+EDNS0", + [DNS_SERVER_FEATURE_LEVEL_DO] = "UDP+EDNS0+DO", + [DNS_SERVER_FEATURE_LEVEL_LARGE] = "UDP+EDNS0+DO+LARGE", +}; +DEFINE_STRING_TABLE_LOOKUP(dns_server_feature_level, DnsServerFeatureLevel); diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 10111fd6b..9f4a69c37 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -24,15 +22,35 @@ #include "in-addr-util.h" typedef struct DnsServer DnsServer; -typedef enum DnsServerSource DnsServerSource; typedef enum DnsServerType { DNS_SERVER_SYSTEM, DNS_SERVER_FALLBACK, DNS_SERVER_LINK, } DnsServerType; +#define _DNS_SERVER_TYPE_MAX (DNS_SERVER_LINK + 1) + +const char* dns_server_type_to_string(DnsServerType i) _const_; +DnsServerType dns_server_type_from_string(const char *s) _pure_; + +typedef enum DnsServerFeatureLevel { + DNS_SERVER_FEATURE_LEVEL_TCP, + DNS_SERVER_FEATURE_LEVEL_UDP, + DNS_SERVER_FEATURE_LEVEL_EDNS0, + DNS_SERVER_FEATURE_LEVEL_DO, + DNS_SERVER_FEATURE_LEVEL_LARGE, + _DNS_SERVER_FEATURE_LEVEL_MAX, + _DNS_SERVER_FEATURE_LEVEL_INVALID = -1 +} DnsServerFeatureLevel; + +#define DNS_SERVER_FEATURE_LEVEL_WORST 0 +#define DNS_SERVER_FEATURE_LEVEL_BEST (_DNS_SERVER_FEATURE_LEVEL_MAX - 1) + +const char* dns_server_feature_level_to_string(int i) _const_; +int dns_server_feature_level_from_string(const char *s) _pure_; #include "resolved-link.h" +#include "resolved-manager.h" struct DnsServer { Manager *manager; @@ -40,33 +58,85 @@ struct DnsServer { unsigned n_ref; DnsServerType type; - Link *link; int family; union in_addr_union address; + char *server_string; + usec_t resend_timeout; usec_t max_rtt; + DnsServerFeatureLevel verified_feature_level; + DnsServerFeatureLevel possible_feature_level; + + size_t received_udp_packet_max; + + unsigned n_failed_udp; + unsigned n_failed_tcp; + + bool packet_failed:1; + bool packet_truncated:1; + bool packet_bad_opt:1; + bool packet_rrsig_missing:1; + + usec_t verified_usec; + usec_t features_grace_period_usec; + + /* Whether we already warned about downgrading to non-DNSSEC mode for this server */ + bool warned_downgrade:1; + + /* Used when GC'ing old DNS servers when configuration changes. */ 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_packet_received(DnsServer *s, usec_t rtt); -void dns_server_packet_lost(DnsServer *s, usec_t usec); +void dns_server_unlink(DnsServer *s); +void dns_server_move_back_and_unmark(DnsServer *s); + +void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t rtt, size_t size); +void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel level, usec_t usec); +void dns_server_packet_failed(DnsServer *s, DnsServerFeatureLevel level); +void dns_server_packet_truncated(DnsServer *s, DnsServerFeatureLevel level); +void dns_server_packet_rrsig_missing(DnsServer *s, DnsServerFeatureLevel level); +void dns_server_packet_bad_opt(DnsServer *s, DnsServerFeatureLevel level); + +DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s); + +int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeatureLevel level); + +const char *dns_server_string(DnsServer *server); + +bool dns_server_dnssec_supported(DnsServer *server); + +void dns_server_warn_downgrade(DnsServer *server); + +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); diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index 1c501182f..a1040aeff 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -347,7 +345,6 @@ DnsStream *dns_stream_free(DnsStream *s) { DEFINE_TRIVIAL_CLEANUP_FUNC(DnsStream*, dns_stream_free); int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd) { - static const int one = 1; _cleanup_(dns_stream_freep) DnsStream *s = NULL; int r; @@ -364,14 +361,12 @@ int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd) { s->fd = -1; s->protocol = protocol; - r = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one)); - if (r < 0) - return -errno; - r = sd_event_add_io(m->event, &s->io_event_source, fd, EPOLLIN, on_stream_io, s); if (r < 0) return r; + (void) sd_event_source_set_description(s->io_event_source, "dns-stream-io"); + r = sd_event_add_time( m->event, &s->timeout_event_source, @@ -381,6 +376,8 @@ int dns_stream_new(Manager *m, DnsStream **ret, DnsProtocol protocol, int fd) { if (r < 0) return r; + (void) sd_event_source_set_description(s->timeout_event_source, "dns-stream-timeout"); + LIST_PREPEND(streams, m->dns_streams, s); s->manager = m; s->fd = fd; diff --git a/src/resolve/resolved-dns-stream.h b/src/resolve/resolved-dns-stream.h index fb81e9f1a..5ccc84224 100644 --- a/src/resolve/resolved-dns-stream.h +++ b/src/resolve/resolved-dns-stream.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c new file mode 100644 index 000000000..f4a43dee8 --- /dev/null +++ b/src/resolve/resolved-dns-synthesize.c @@ -0,0 +1,413 @@ +/*** + This file is part of systemd. + + Copyright 2014 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 . +***/ + +#include "alloc-util.h" +#include "hostname-util.h" +#include "local-addresses.h" +#include "resolved-dns-synthesize.h" + +int dns_synthesize_ifindex(int ifindex) { + + /* When the caller asked for resolving on a specific + * interface, we synthesize the answer for that + * interface. However, if nothing specific was claimed and we + * only return localhost RRs, we synthesize the answer for + * localhost. */ + + if (ifindex > 0) + return ifindex; + + return LOOPBACK_IFINDEX; +} + +int dns_synthesize_family(uint64_t flags) { + + /* Picks an address family depending on set flags. This is + * purely for synthesized answers, where the family we return + * for the reply should match what was requested in the + * question, even though we are synthesizing the answer + * here. */ + + if (!(flags & SD_RESOLVED_DNS)) { + if (flags & (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_MDNS_IPV4)) + return AF_INET; + if (flags & (SD_RESOLVED_LLMNR_IPV6|SD_RESOLVED_MDNS_IPV6)) + return AF_INET6; + } + + return AF_UNSPEC; +} + +DnsProtocol dns_synthesize_protocol(uint64_t flags) { + + /* Similar as dns_synthesize_family() but does this for the + * protocol. If resolving via DNS was requested, we claim it + * was DNS. Similar, if nothing specific was + * requested. However, if only resolving via LLMNR was + * requested we return that. */ + + if (flags & SD_RESOLVED_DNS) + return DNS_PROTOCOL_DNS; + if (flags & SD_RESOLVED_LLMNR) + return DNS_PROTOCOL_LLMNR; + if (flags & SD_RESOLVED_MDNS) + return DNS_PROTOCOL_MDNS; + + return DNS_PROTOCOL_DNS; +} + +static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) { + int r; + + assert(m); + assert(key); + assert(answer); + + r = dns_answer_reserve(answer, 2); + if (r < 0) + return r; + + if (IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_ANY)) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, DNS_RESOURCE_KEY_NAME(key)); + if (!rr) + return -ENOMEM; + + rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK); + + r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + + if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, DNS_RESOURCE_KEY_NAME(key)); + if (!rr) + return -ENOMEM; + + rr->aaaa.in6_addr = in6addr_loopback; + + r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + + return 0; +} + +static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, int ifindex, DnsAnswerFlags flags) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_PTR, from); + if (!rr) + return -ENOMEM; + + rr->ptr.name = strdup(to); + if (!rr->ptr.name) + return -ENOMEM; + + return dns_answer_add(*answer, rr, ifindex, flags); +} + +static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) { + int r; + + assert(m); + assert(key); + assert(answer); + + if (IN_SET(key->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) { + r = dns_answer_reserve(answer, 1); + if (r < 0) + return r; + + r = answer_add_ptr(answer, DNS_RESOURCE_KEY_NAME(key), "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + + return 0; +} + +static int answer_add_addresses_rr( + DnsAnswer **answer, + const char *name, + struct local_address *addresses, + unsigned n_addresses) { + + unsigned j; + int r; + + assert(answer); + assert(name); + + r = dns_answer_reserve(answer, n_addresses); + if (r < 0) + return r; + + for (j = 0; j < n_addresses; j++) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + r = dns_resource_record_new_address(&rr, addresses[j].family, &addresses[j].address, name); + if (r < 0) + return r; + + r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + + return 0; +} + +static int answer_add_addresses_ptr( + DnsAnswer **answer, + const char *name, + struct local_address *addresses, + unsigned n_addresses, + int af, const union in_addr_union *match) { + + unsigned j; + int r; + + assert(answer); + assert(name); + + for (j = 0; j < n_addresses; j++) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + if (af != AF_UNSPEC) { + + if (addresses[j].family != af) + continue; + + if (match && !in_addr_equal(af, match, &addresses[j].address)) + continue; + } + + r = dns_answer_reserve(answer, 1); + if (r < 0) + return r; + + r = dns_resource_record_new_reverse(&rr, addresses[j].family, &addresses[j].address, name); + if (r < 0) + return r; + + r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + + return 0; +} + +static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) { + _cleanup_free_ struct local_address *addresses = NULL; + int n = 0, af; + + assert(m); + assert(key); + assert(answer); + + af = dns_type_to_af(key->type); + if (af >= 0) { + n = local_addresses(m->rtnl, ifindex, af, &addresses); + if (n < 0) + return n; + + if (n == 0) { + struct local_address buffer[2]; + + /* If we have no local addresses then use ::1 + * and 127.0.0.2 as local ones. */ + + if (af == AF_INET || af == AF_UNSPEC) + buffer[n++] = (struct local_address) { + .family = AF_INET, + .ifindex = dns_synthesize_ifindex(ifindex), + .address.in.s_addr = htobe32(0x7F000002), + }; + + if (af == AF_INET6 || af == AF_UNSPEC) + buffer[n++] = (struct local_address) { + .family = AF_INET6, + .ifindex = dns_synthesize_ifindex(ifindex), + .address.in6 = in6addr_loopback, + }; + + return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), buffer, n); + } + } + + return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n); +} + +static int synthesize_system_hostname_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) { + _cleanup_free_ struct local_address *addresses = NULL; + int n, r; + + assert(m); + assert(address); + assert(answer); + + if (af == AF_INET && address->in.s_addr == htobe32(0x7F000002)) { + + /* Always map the IPv4 address 127.0.0.2 to the local + * hostname, in addition to "localhost": */ + + r = dns_answer_reserve(answer, 3); + if (r < 0) + return r; + + r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->llmnr_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + + r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", m->mdns_hostname, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + + r = answer_add_ptr(answer, "2.0.0.127.in-addr.arpa", "localhost", dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + + return 0; + } + + n = local_addresses(m->rtnl, ifindex, af, &addresses); + if (n < 0) + return n; + + r = answer_add_addresses_ptr(answer, m->llmnr_hostname, addresses, n, af, address); + if (r < 0) + return r; + + return answer_add_addresses_ptr(answer, m->mdns_hostname, addresses, n, af, address); +} + +static int synthesize_gateway_rr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) { + _cleanup_free_ struct local_address *addresses = NULL; + int n = 0, af; + + assert(m); + assert(key); + assert(answer); + + af = dns_type_to_af(key->type); + if (af >= 0) { + n = local_gateways(m->rtnl, ifindex, af, &addresses); + if (n < 0) + return n; + } + + return answer_add_addresses_rr(answer, DNS_RESOURCE_KEY_NAME(key), addresses, n); +} + +static int synthesize_gateway_ptr(Manager *m, int af, const union in_addr_union *address, int ifindex, DnsAnswer **answer) { + _cleanup_free_ struct local_address *addresses = NULL; + int n; + + assert(m); + assert(address); + assert(answer); + + n = local_gateways(m->rtnl, ifindex, af, &addresses); + if (n < 0) + return n; + + return answer_add_addresses_ptr(answer, "gateway", addresses, n, af, address); +} + +int dns_synthesize_answer( + Manager *m, + DnsQuestion *q, + int ifindex, + DnsAnswer **ret) { + + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsResourceKey *key; + bool found = false; + int r; + + assert(m); + assert(q); + + DNS_QUESTION_FOREACH(key, q) { + union in_addr_union address; + const char *name; + int af; + + if (key->class != DNS_CLASS_IN && + key->class != DNS_CLASS_ANY) + continue; + + name = DNS_RESOURCE_KEY_NAME(key); + + if (is_localhost(name)) { + + r = synthesize_localhost_rr(m, key, ifindex, &answer); + if (r < 0) + return log_error_errno(r, "Failed to synthesize localhost RRs: %m"); + + } else if (manager_is_own_hostname(m, name)) { + + r = synthesize_system_hostname_rr(m, key, ifindex, &answer); + if (r < 0) + return log_error_errno(r, "Failed to synthesize system hostname RRs: %m"); + + } else if (is_gateway_hostname(name)) { + + r = synthesize_gateway_rr(m, key, ifindex, &answer); + if (r < 0) + return log_error_errno(r, "Failed to synthesize gateway RRs: %m"); + + } else if ((dns_name_endswith(name, "127.in-addr.arpa") > 0 && dns_name_equal(name, "2.0.0.127.in-addr.arpa") == 0) || + dns_name_equal(name, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) { + + r = synthesize_localhost_ptr(m, key, ifindex, &answer); + if (r < 0) + return log_error_errno(r, "Failed to synthesize localhost PTR RRs: %m"); + + } else if (dns_name_address(name, &af, &address) > 0) { + + r = synthesize_system_hostname_ptr(m, af, &address, ifindex, &answer); + if (r < 0) + return log_error_errno(r, "Failed to synthesize system hostname PTR RR: %m"); + + r = synthesize_gateway_ptr(m, af, &address, ifindex, &answer); + if (r < 0) + return log_error_errno(r, "Failed to synthesize gateway hostname PTR RR: %m"); + } else + continue; + + found = true; + } + + r = found; + + if (ret) { + *ret = answer; + answer = NULL; + } + + return r; +} diff --git a/src/libsystemd/sd-event/event-util.h b/src/resolve/resolved-dns-synthesize.h similarity index 63% rename from src/libsystemd/sd-event/event-util.h rename to src/resolve/resolved-dns-synthesize.h index ae020340a..5d829bb2e 100644 --- a/src/libsystemd/sd-event/event-util.h +++ b/src/resolve/resolved-dns-synthesize.h @@ -1,11 +1,9 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** This file is part of systemd. - Copyright 2013 Lennart Poettering + Copyright 2016 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 @@ -21,12 +19,12 @@ along with systemd; If not, see . ***/ -#include "sd-event.h" +#include "resolved-dns-answer.h" +#include "resolved-dns-question.h" +#include "resolved-manager.h" -#include "util.h" +int dns_synthesize_ifindex(int ifindex); +int dns_synthesize_family(uint64_t flags); +DnsProtocol dns_synthesize_protocol(uint64_t flags); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event*, sd_event_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, sd_event_source_unref); - -#define _cleanup_event_unref_ _cleanup_(sd_event_unrefp) -#define _cleanup_event_source_unref_ _cleanup_(sd_event_source_unrefp) +int dns_synthesize_answer(Manager *m, DnsQuestion *q, int ifindex, DnsAnswer **ret); diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 6545f6cd8..d48fdd128 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,50 +17,103 @@ along with systemd; If not, see . ***/ +#include + #include "af-list.h" #include "alloc-util.h" #include "dns-domain.h" +#include "errno-list.h" #include "fd-util.h" #include "random-util.h" +#include "resolved-dns-cache.h" #include "resolved-dns-transaction.h" #include "resolved-llmnr.h" #include "string-table.h" +#define TRANSACTIONS_MAX 4096 + +static void dns_transaction_reset_answer(DnsTransaction *t) { + assert(t); + + t->received = dns_packet_unref(t->received); + t->answer = dns_answer_unref(t->answer); + t->answer_rcode = 0; + t->answer_dnssec_result = _DNSSEC_RESULT_INVALID; + t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID; + t->answer_authenticated = false; + t->answer_nsec_ttl = (uint32_t) -1; + t->answer_errno = 0; +} + +static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) { + DnsTransaction *z; + + assert(t); + + while ((z = set_steal_first(t->dnssec_transactions))) { + set_remove(z->notify_transactions, t); + dns_transaction_gc(z); + } +} + +static void dns_transaction_close_connection(DnsTransaction *t) { + assert(t); + + t->stream = dns_stream_free(t->stream); + t->dns_udp_event_source = sd_event_source_unref(t->dns_udp_event_source); + t->dns_udp_fd = safe_close(t->dns_udp_fd); +} + +static void dns_transaction_stop_timeout(DnsTransaction *t) { + assert(t); + + t->timeout_event_source = sd_event_source_unref(t->timeout_event_source); +} + DnsTransaction* dns_transaction_free(DnsTransaction *t) { - DnsQuery *q; + DnsQueryCandidate *c; DnsZoneItem *i; + DnsTransaction *z; if (!t) return NULL; - sd_event_source_unref(t->timeout_event_source); + log_debug("Freeing transaction %" PRIu16 ".", t->id); + + dns_transaction_close_connection(t); + dns_transaction_stop_timeout(t); dns_packet_unref(t->sent); - dns_packet_unref(t->received); - dns_answer_unref(t->cached); - - sd_event_source_unref(t->dns_udp_event_source); - safe_close(t->dns_udp_fd); + dns_transaction_reset_answer(t); dns_server_unref(t->server); - 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)); } - dns_resource_key_unref(t->key); + while ((c = set_steal_first(t->notify_query_candidates))) + set_remove(c->transactions, t); + set_free(t->notify_query_candidates); - while ((q = set_steal_first(t->queries))) - set_remove(q->transactions, t); - set_free(t->queries); - - while ((i = set_steal_first(t->zone_items))) + while ((i = set_steal_first(t->notify_zone_items))) i->probe_transaction = NULL; - set_free(t->zone_items); + set_free(t->notify_zone_items); + + while ((z = set_steal_first(t->notify_transactions))) + set_remove(z->dnssec_transactions, t); + set_free(t->notify_transactions); + + dns_transaction_flush_dnssec_transactions(t); + set_free(t->dnssec_transactions); + + dns_answer_unref(t->validated_keys); + dns_resource_key_unref(t->key); + free(t->key_string); free(t); return NULL; @@ -70,14 +121,36 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_free); -void dns_transaction_gc(DnsTransaction *t) { +bool dns_transaction_gc(DnsTransaction *t) { assert(t); if (t->block_gc > 0) - return; + return true; - if (set_isempty(t->queries) && set_isempty(t->zone_items)) + if (set_isempty(t->notify_query_candidates) && + set_isempty(t->notify_zone_items) && + set_isempty(t->notify_transactions)) { dns_transaction_free(t); + return false; + } + + return true; +} + +static uint16_t pick_new_id(Manager *m) { + uint16_t new_id; + + /* Find a fresh, unused transaction id. Note that this loop is bounded because there's a limit on the number of + * transactions, and it's much lower than the space of IDs. */ + + assert_cc(TRANSACTIONS_MAX < 0xFFFF); + + do + random_bytes(&new_id, sizeof(new_id)); + while (new_id == 0 || + hashmap_get(m->dns_transactions, UINT_TO_PTR(new_id))); + + return new_id; } int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) { @@ -88,11 +161,24 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) assert(s); assert(key); + /* Don't allow looking up invalid or pseudo RRs */ + if (!dns_type_is_valid_query(key->type)) + return -EINVAL; + if (dns_type_is_obsolete(key->type)) + return -EOPNOTSUPP; + + /* We only support the IN class */ + if (key->class != DNS_CLASS_IN && key->class != DNS_CLASS_ANY) + return -EOPNOTSUPP; + + if (hashmap_size(s->manager->dns_transactions) >= TRANSACTIONS_MAX) + return -EBUSY; + r = hashmap_ensure_allocated(&s->manager->dns_transactions, NULL); 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,13 +187,13 @@ 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->answer_dnssec_result = _DNSSEC_RESULT_INVALID; + t->answer_nsec_ttl = (uint32_t) -1; t->key = dns_resource_key_ref(key); + t->current_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; - /* Find a fresh, unused transaction id */ - do - random_bytes(&t->id, sizeof(t->id)); - while (t->id == 0 || - hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(t->id))); + t->id = pick_new_id(s->manager); r = hashmap_put(s->manager->dns_transactions, UINT_TO_PTR(t->id), t); if (r < 0) { @@ -115,14 +201,17 @@ 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; + s->manager->n_transactions_total ++; + if (ret) *ret = t; @@ -131,11 +220,20 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) return 0; } -static void dns_transaction_stop(DnsTransaction *t) { +static void dns_transaction_shuffle_id(DnsTransaction *t) { + uint16_t new_id; assert(t); - t->timeout_event_source = sd_event_source_unref(t->timeout_event_source); - t->stream = dns_stream_free(t->stream); + /* Pick a new ID for this transaction. */ + + new_id = pick_new_id(t->scope->manager); + assert_se(hashmap_remove_and_put(t->scope->manager->dns_transactions, UINT_TO_PTR(t->id), UINT_TO_PTR(new_id), t) >= 0); + + log_debug("Transaction %" PRIu16 " is now %" PRIu16 ".", t->id, new_id); + t->id = new_id; + + /* Make sure we generate a new packet with the new ID */ + t->sent = dns_packet_unref(t->sent); } static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { @@ -150,7 +248,9 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { in_addr_to_string(p->family, &p->sender, &pretty); - log_debug("Transaction on scope %s on %s/%s got tentative packet from %s", + log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s got tentative packet from %s.", + t->id, + dns_transaction_key_string(t), 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), @@ -166,7 +266,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { log_debug("We have the lexicographically larger IP address and thus lost in the conflict."); t->block_gc++; - while ((z = set_first(t->zone_items))) { + while ((z = set_first(t->notify_zone_items))) { /* First, make sure the zone item drops the reference * to us */ dns_zone_item_probe_stop(z); @@ -181,39 +281,150 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { } void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { - DnsQuery *q; + DnsQueryCandidate *c; DnsZoneItem *z; + DnsTransaction *d; Iterator i; + const char *st; assert(t); - assert(!IN_SET(state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)); + assert(!DNS_TRANSACTION_IS_LIVE(state)); + + if (state == DNS_TRANSACTION_DNSSEC_FAILED) + log_struct(LOG_NOTICE, + LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_FAILURE), + LOG_MESSAGE("DNSSEC validation failed for question %s: %s", dns_transaction_key_string(t), dnssec_result_to_string(t->answer_dnssec_result)), + "DNS_TRANSACTION=%" PRIu16, t->id, + "DNS_QUESTION=%s", dns_transaction_key_string(t), + "DNSSEC_RESULT=%s", dnssec_result_to_string(t->answer_dnssec_result), + "DNS_SERVER=%s", dns_server_string(t->server), + "DNS_SERVER_FEATURE_LEVEL=%s", dns_server_feature_level_to_string(t->server->possible_feature_level), + NULL); /* Note that this call might invalidate the query. Callers * 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>", + if (state == DNS_TRANSACTION_ERRNO) + st = errno_to_name(t->answer_errno); + else + st = dns_transaction_state_to_string(state); + + log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s).", + t->id, + dns_transaction_key_string(t), 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)); + st, + t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source), + t->answer_authenticated ? "authenticated" : "unsigned"); t->state = state; - dns_transaction_stop(t); + dns_transaction_close_connection(t); + dns_transaction_stop_timeout(t); /* 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(z, t->zone_items, i) - dns_zone_item_ready(z); - t->block_gc--; + SET_FOREACH(c, t->notify_query_candidates, i) + dns_query_candidate_notify(c); + SET_FOREACH(z, t->notify_zone_items, i) + dns_zone_item_notify(z); + + if (!set_isempty(t->notify_transactions)) { + DnsTransaction **nt; + unsigned j, n = 0; + + /* We need to be careful when notifying other + * transactions, as that might destroy other + * transactions in our list. Hence, in order to be + * able to safely iterate through the list of + * transactions, take a GC lock on all of them + * first. Then, in a second loop, notify them, but + * first unlock that specific transaction. */ + + nt = newa(DnsTransaction*, set_size(t->notify_transactions)); + SET_FOREACH(d, t->notify_transactions, i) { + nt[n++] = d; + d->block_gc++; + } + + assert(n == set_size(t->notify_transactions)); + + for (j = 0; j < n; j++) { + if (set_contains(t->notify_transactions, nt[j])) + dns_transaction_notify(nt[j], t); + + nt[j]->block_gc--; + dns_transaction_gc(nt[j]); + } + } + + t->block_gc--; dns_transaction_gc(t); } +static int dns_transaction_pick_server(DnsTransaction *t) { + DnsServer *server; + + assert(t); + assert(t->scope->protocol == DNS_PROTOCOL_DNS); + + server = dns_scope_get_dns_server(t->scope); + if (!server) + return -ESRCH; + + t->current_feature_level = dns_server_possible_feature_level(server); + + if (server == t->server) + return 0; + + dns_server_unref(t->server); + t->server = dns_server_ref(server); + + return 1; +} + +static void dns_transaction_retry(DnsTransaction *t) { + int r; + + assert(t); + + log_debug("Retrying transaction %" PRIu16 ".", t->id); + + /* Before we try again, switch to a new server. */ + dns_scope_next_dns_server(t->scope); + + r = dns_transaction_go(t); + if (r < 0) { + t->answer_errno = -r; + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); + } +} + +static int dns_transaction_maybe_restart(DnsTransaction *t) { + assert(t); + + if (!t->server) + return 0; + + if (t->current_feature_level <= dns_server_possible_feature_level(t->server)) + return 0; + + /* The server's current feature level is lower than when we sent the original query. We learnt something from + the response or possibly an auxiliary DNSSEC response that we didn't know before. We take that as reason to + restart the whole transaction. This is a good idea to deal with servers that respond rubbish if we include + OPT RR or DO bit. One of these cases is documented here, for example: + https://open.nlnetlabs.nl/pipermail/dnssec-trigger/2014-November/000376.html */ + + log_debug("Server feature level is now lower than when we began our transaction. Restarting with new ID."); + dns_transaction_shuffle_id(t); + return dns_transaction_go(t); +} + static int on_stream_complete(DnsStream *s, int error) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; DnsTransaction *t; @@ -228,13 +439,31 @@ static int on_stream_complete(DnsStream *s, int error) { t->stream = dns_stream_free(t->stream); + if (ERRNO_IS_DISCONNECT(error)) { + usec_t usec; + + if (t->scope->protocol == DNS_PROTOCOL_LLMNR) { + /* If the LLMNR/TCP connection failed, the host doesn't support LLMNR, and we cannot answer the + * question on this scope. */ + dns_transaction_complete(t, DNS_TRANSACTION_NOT_FOUND); + return 0; + } + + log_debug_errno(error, "Connection failure for DNS TCP stream: %m"); + assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0); + dns_server_packet_lost(t->server, IPPROTO_TCP, t->current_feature_level, usec - t->start_usec); + + dns_transaction_retry(t); + return 0; + } if (error != 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); + t->answer_errno = error; + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); return 0; } if (dns_packet_validate_reply(p) <= 0) { - log_debug("Invalid LLMNR TCP packet."); + log_debug("Invalid TCP reply packet."); dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return 0; } @@ -245,32 +474,46 @@ static int on_stream_complete(DnsStream *s, int error) { dns_transaction_process_reply(t, p); t->block_gc--; - /* If the response wasn't useful, then complete the transition now */ + /* If the response wasn't useful, then complete the transition + * now. After all, we are the worst feature set now with TCP + * sockets, and there's really no point in retrying. */ if (t->state == DNS_TRANSACTION_PENDING) dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); + else + dns_transaction_gc(t); return 0; } static int dns_transaction_open_tcp(DnsTransaction *t) { - DnsServer *server = NULL; _cleanup_close_ int fd = -1; int r; assert(t); - if (t->stream) - return 0; + dns_transaction_close_connection(t); switch (t->scope->protocol) { + case DNS_PROTOCOL_DNS: - fd = dns_scope_tcp_socket(t->scope, AF_UNSPEC, NULL, 53, &server); + r = dns_transaction_pick_server(t); + if (r < 0) + return r; + + if (!dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(t->key->type)) + return -EOPNOTSUPP; + + r = dns_server_adjust_opt(t->server, t->sent, t->current_feature_level); + if (r < 0) + return r; + + fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, 53); break; case DNS_PROTOCOL_LLMNR: /* When we already received a reply to this (but it was truncated), send to its sender address */ if (t->received) - fd = dns_scope_tcp_socket(t->scope, t->received->family, &t->received->sender, t->received->sender_port, NULL); + fd = dns_scope_socket_tcp(t->scope, t->received->family, &t->received->sender, NULL, t->received->sender_port); else { union in_addr_union address; int family = AF_UNSPEC; @@ -287,7 +530,7 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { if (family != t->scope->family) return -ESRCH; - fd = dns_scope_tcp_socket(t->scope, family, &address, LLMNR_PORT, NULL); + fd = dns_scope_socket_tcp(t->scope, family, &address, NULL, LLMNR_PORT); } break; @@ -302,7 +545,6 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { r = dns_stream_new(t->scope->manager, &t->stream, t->scope->protocol, fd); if (r < 0) return r; - fd = -1; r = dns_stream_write_packet(t->stream, t->sent); @@ -311,9 +553,6 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { return r; } - dns_server_unref(t->server); - t->server = dns_server_ref(server); - t->received = dns_packet_unref(t->received); t->stream->complete = on_stream_complete; t->stream->transaction = t; @@ -323,17 +562,221 @@ static int dns_transaction_open_tcp(DnsTransaction *t) { if (t->scope->link) t->stream->ifindex = t->scope->link->ifindex; + dns_transaction_reset_answer(t); + + t->tried_stream = true; + return 0; } -static void dns_transaction_next_dns_server(DnsTransaction *t) { +static void dns_transaction_cache_answer(DnsTransaction *t) { assert(t); - t->server = dns_server_unref(t->server); - t->dns_udp_event_source = sd_event_source_unref(t->dns_udp_event_source); - t->dns_udp_fd = safe_close(t->dns_udp_fd); + /* For mDNS we cache whenever we get the packet, rather than + * in each transaction. */ + if (!IN_SET(t->scope->protocol, DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR)) + return; - dns_scope_next_dns_server(t->scope); + /* We never cache if this packet is from the local host, under + * the assumption that a locally running DNS server would + * cache this anyway, and probably knows better when to flush + * the cache then we could. */ + if (!DNS_PACKET_SHALL_CACHE(t->received)) + return; + + dns_cache_put(&t->scope->cache, + t->key, + t->answer_rcode, + t->answer, + t->answer_authenticated, + t->answer_nsec_ttl, + 0, + t->received->family, + &t->received->sender); +} + +static bool dns_transaction_dnssec_is_live(DnsTransaction *t) { + DnsTransaction *dt; + Iterator i; + + assert(t); + + SET_FOREACH(dt, t->dnssec_transactions, i) + if (DNS_TRANSACTION_IS_LIVE(dt->state)) + return true; + + return false; +} + +static int dns_transaction_dnssec_ready(DnsTransaction *t) { + DnsTransaction *dt; + Iterator i; + + assert(t); + + /* Checks whether the auxiliary DNSSEC transactions of our transaction have completed, or are still + * ongoing. Returns 0, if we aren't ready for the DNSSEC validation, positive if we are. */ + + SET_FOREACH(dt, t->dnssec_transactions, i) { + + switch (dt->state) { + + case DNS_TRANSACTION_NULL: + case DNS_TRANSACTION_PENDING: + case DNS_TRANSACTION_VALIDATING: + /* Still ongoing */ + return 0; + + case DNS_TRANSACTION_RCODE_FAILURE: + if (dt->answer_rcode != DNS_RCODE_NXDOMAIN) { + log_debug("Auxiliary DNSSEC RR query failed with rcode=%s.", dns_rcode_to_string(dt->answer_rcode)); + goto fail; + } + + /* Fall-through: NXDOMAIN is good enough for us. This is because some DNS servers erronously + * return NXDOMAIN for empty non-terminals (Akamai...), and we need to handle that nicely, when + * asking for parent SOA or similar RRs to make unsigned proofs. */ + + case DNS_TRANSACTION_SUCCESS: + /* All good. */ + break; + + case DNS_TRANSACTION_DNSSEC_FAILED: + /* We handle DNSSEC failures different from other errors, as we care about the DNSSEC + * validationr result */ + + log_debug("Auxiliary DNSSEC RR query failed validation: %s", dnssec_result_to_string(dt->answer_dnssec_result)); + t->answer_dnssec_result = dt->answer_dnssec_result; /* Copy error code over */ + dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED); + return 0; + + + default: + log_debug("Auxiliary DNSSEC RR query failed with %s", dns_transaction_state_to_string(dt->state)); + goto fail; + } + } + + /* All is ready, we can go and validate */ + return 1; + +fail: + t->answer_dnssec_result = DNSSEC_FAILED_AUXILIARY; + dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED); + return 0; +} + +static void dns_transaction_process_dnssec(DnsTransaction *t) { + int r; + + assert(t); + + /* Are there ongoing DNSSEC transactions? If so, let's wait for them. */ + r = dns_transaction_dnssec_ready(t); + if (r < 0) + goto fail; + if (r == 0) /* We aren't ready yet (or one of our auxiliary transactions failed, and we shouldn't validate now */ + return; + + /* See if we learnt things from the additional DNSSEC transactions, that we didn't know before, and better + * restart the lookup immediately. */ + r = dns_transaction_maybe_restart(t); + if (r < 0) + goto fail; + if (r > 0) /* Transaction got restarted... */ + return; + + /* All our auxiliary DNSSEC transactions are complete now. Try + * to validate our RRset now. */ + r = dns_transaction_validate_dnssec(t); + if (r == -EBADMSG) { + dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); + return; + } + if (r < 0) + goto fail; + + if (t->answer_dnssec_result == DNSSEC_INCOMPATIBLE_SERVER && + t->scope->dnssec_mode == DNSSEC_YES) { + /* We are not in automatic downgrade mode, and the + * server is bad, refuse operation. */ + dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED); + return; + } + + if (!IN_SET(t->answer_dnssec_result, + _DNSSEC_RESULT_INVALID, /* No DNSSEC validation enabled */ + DNSSEC_VALIDATED, /* Answer is signed and validated successfully */ + DNSSEC_UNSIGNED, /* Answer is right-fully unsigned */ + DNSSEC_INCOMPATIBLE_SERVER)) { /* Server does not do DNSSEC (Yay, we are downgrade attack vulnerable!) */ + dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED); + return; + } + + if (t->answer_dnssec_result == DNSSEC_INCOMPATIBLE_SERVER) + dns_server_warn_downgrade(t->server); + + dns_transaction_cache_answer(t); + + if (t->answer_rcode == DNS_RCODE_SUCCESS) + dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); + else + dns_transaction_complete(t, DNS_TRANSACTION_RCODE_FAILURE); + + return; + +fail: + t->answer_errno = -r; + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); +} + +static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags *flags) { + int r; + + assert(t); + + /* Checks whether the answer is positive, i.e. either a direct + * answer to the question, or a CNAME/DNAME for it */ + + r = dns_answer_match_key(t->answer, t->key, flags); + if (r != 0) + return r; + + r = dns_answer_find_cname_or_dname(t->answer, t->key, NULL, flags); + if (r != 0) + return r; + + return false; +} + +static int dns_transaction_fix_rcode(DnsTransaction *t) { + int r; + + assert(t); + + /* Fix up the RCODE to SUCCESS if we get at least one matching RR in a response. Note that this contradicts the + * DNS RFCs a bit. Specifically, RFC 6604 Section 3 clarifies that the RCODE shall say something about a + * CNAME/DNAME chain element coming after the last chain element contained in the message, and not the first + * one included. However, it also indicates that not all DNS servers implement this correctly. Moreover, when + * using DNSSEC we usually only can prove the first element of a CNAME/DNAME chain anyway, hence let's settle + * on always processing the RCODE as referring to the immediate look-up we do, i.e. the first element of a + * CNAME/DNAME chain. This way, we uniformly handle CNAME/DNAME chains, regardless if the DNS server + * incorrectly implements RCODE, whether DNSSEC is in use, or whether the DNS server only supplied us with an + * incomplete CNAME/DNAME chain. + * + * Or in other words: if we get at least one positive reply in a message we patch NXDOMAIN to become SUCCESS, + * and then rely on the CNAME chasing logic to figure out that there's actually a CNAME error with a new + * lookup. */ + + if (t->answer_rcode != DNS_RCODE_NXDOMAIN) + return 0; + + r = dns_transaction_has_positive_answer(t, NULL); + if (r <= 0) + return r; + + t->answer_rcode = DNS_RCODE_SUCCESS; + return 0; } void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { @@ -342,15 +785,20 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { assert(t); assert(p); - assert(t->state == DNS_TRANSACTION_PENDING); assert(t->scope); assert(t->scope->manager); + if (t->state != DNS_TRANSACTION_PENDING) + return; + /* Note that this call might invalidate the query. Callers * should hence not attempt to access the query or transaction * after calling this function. */ + log_debug("Processing incoming packet on transaction %" PRIu16".", t->id); + switch (t->scope->protocol) { + case DNS_PROTOCOL_LLMNR: assert(t->scope->link); @@ -373,7 +821,24 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { break; + case DNS_PROTOCOL_MDNS: + assert(t->scope->link); + + /* For mDNS we will not accept any packets from other interfaces */ + if (p->ifindex != t->scope->link->ifindex) + return; + + if (p->family != t->scope->family) + return; + + break; + case DNS_PROTOCOL_DNS: + /* Note that we do not need to verify the + * addresses/port numbers of incoming traffic, as we + * invoked connect() on our UDP socket in which case + * the kernel already does the needed verification for + * us. */ break; default: @@ -385,6 +850,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 */ @@ -402,22 +869,42 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); switch (t->scope->protocol) { + case DNS_PROTOCOL_DNS: assert(t->server); - dns_server_packet_received(t->server, ts - t->start_usec); + if (IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) { + + /* Request failed, immediately try again with reduced features */ + log_debug("Server returned error: %s", dns_rcode_to_string(DNS_PACKET_RCODE(p))); + + dns_server_packet_failed(t->server, t->current_feature_level); + dns_transaction_retry(t); + return; + } else if (DNS_PACKET_TC(p)) + dns_server_packet_truncated(t->server, t->current_feature_level); break; + case DNS_PROTOCOL_LLMNR: case DNS_PROTOCOL_MDNS: dns_scope_packet_received(t->scope, ts - t->start_usec); + break; - break; default: - break; + assert_not_reached("Invalid DNS protocol."); } if (DNS_PACKET_TC(p)) { + + /* Truncated packets for mDNS are not allowed. Give up immediately. */ + if (t->scope->protocol == DNS_PROTOCOL_MDNS) { + dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); + return; + } + + log_debug("Reply truncated, retrying via TCP."); + /* Response was truncated, let's try again with good old TCP */ r = dns_transaction_open_tcp(t); if (r == -ESRCH) { @@ -425,47 +912,101 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS); return; } + if (r == -EOPNOTSUPP) { + /* Tried to ask for DNSSEC RRs, on a server that doesn't do DNSSEC */ + dns_transaction_complete(t, DNS_TRANSACTION_RR_TYPE_UNSUPPORTED); + return; + } if (r < 0) { /* On LLMNR, if we cannot connect to the host, * we immediately give up */ - if (t->scope->protocol == DNS_PROTOCOL_LLMNR) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return; - } + if (t->scope->protocol != DNS_PROTOCOL_DNS) + goto fail; /* On DNS, couldn't send? Try immediately again, with a new server */ - dns_transaction_next_dns_server(t); - - r = dns_transaction_go(t); - if (r < 0) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return; - } - - return; + dns_transaction_retry(t); } + + return; } - /* Parse and update the cache */ + /* After the superficial checks, actually parse the message. */ r = dns_packet_extract(p); if (r < 0) { dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return; } - /* 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); - return; + /* Report that the OPT RR was missing */ + if (t->server) { + if (!p->opt) + dns_server_packet_bad_opt(t->server, t->current_feature_level); + + dns_server_packet_received(t->server, p->ipproto, t->current_feature_level, ts - t->start_usec, p->size); } - /* 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); + /* See if we know things we didn't know before that indicate we better restart the lookup immediately. */ + r = dns_transaction_maybe_restart(t); + if (r < 0) + goto fail; + if (r > 0) /* Transaction got restarted... */ + return; - if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS) - dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); - else - dns_transaction_complete(t, DNS_TRANSACTION_FAILURE); + if (IN_SET(t->scope->protocol, DNS_PROTOCOL_DNS, DNS_PROTOCOL_LLMNR)) { + + /* Only consider responses with equivalent query section to the request */ + r = dns_packet_is_reply_for(p, t->key); + if (r < 0) + goto fail; + if (r == 0) { + dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); + 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); + t->answer_dnssec_result = _DNSSEC_RESULT_INVALID; + t->answer_authenticated = false; + + r = dns_transaction_fix_rcode(t); + if (r < 0) + goto fail; + + /* Block GC while starting requests for additional DNSSEC RRs */ + t->block_gc++; + r = dns_transaction_request_dnssec_keys(t); + t->block_gc--; + + /* Maybe the transaction is ready for GC'ing now? If so, free it and return. */ + if (!dns_transaction_gc(t)) + return; + + /* Requesting additional keys might have resulted in + * this transaction to fail, since the auxiliary + * request failed for some reason. If so, we are not + * in pending state anymore, and we should exit + * quickly. */ + if (t->state != DNS_TRANSACTION_PENDING) + return; + if (r < 0) + goto fail; + if (r > 0) { + /* There are DNSSEC transactions pending now. Update the state accordingly. */ + t->state = DNS_TRANSACTION_VALIDATING; + dns_transaction_close_connection(t); + dns_transaction_stop_timeout(t); + return; + } + } + + dns_transaction_process_dnssec(t); + return; + +fail: + t->answer_errno = -r; + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); } static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { @@ -477,66 +1018,377 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use assert(t->scope); r = manager_recv(t->scope->manager, fd, DNS_PROTOCOL_DNS, &p); - if (r <= 0) - return r; + if (ERRNO_IS_DISCONNECT(-r)) { + usec_t usec; - if (dns_packet_validate_reply(p) > 0 && - DNS_PACKET_ID(p) == t->id) - dns_transaction_process_reply(t, p); - else - log_debug("Invalid DNS packet."); + /* UDP connection failure get reported via ICMP and then are possible delivered to us on the next + * recvmsg(). Treat this like a lost packet. */ + log_debug_errno(r, "Connection failure for DNS UDP packet: %m"); + assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0); + dns_server_packet_lost(t->server, IPPROTO_UDP, t->current_feature_level, usec - t->start_usec); + + dns_transaction_retry(t); + return 0; + } + if (r < 0) { + dns_transaction_complete(t, DNS_TRANSACTION_ERRNO); + t->answer_errno = -r; + return 0; + } + + r = dns_packet_validate_reply(p); + if (r < 0) { + log_debug_errno(r, "Received invalid DNS packet as response, ignoring: %m"); + return 0; + } + if (r == 0) { + log_debug("Received inappropriate DNS packet as response, ignoring."); + return 0; + } + + if (DNS_PACKET_ID(p) != t->id) { + log_debug("Received packet with incorrect transaction ID, ignoring."); + return 0; + } + + dns_transaction_process_reply(t, p); return 0; } -static int dns_transaction_emit(DnsTransaction *t) { +static int dns_transaction_emit_udp(DnsTransaction *t) { int r; assert(t); - if (t->scope->protocol == DNS_PROTOCOL_DNS && !t->server) { - DnsServer *server = NULL; - _cleanup_close_ int fd = -1; + if (t->scope->protocol == DNS_PROTOCOL_DNS) { - fd = dns_scope_udp_dns_socket(t->scope, &server); - if (fd < 0) - return fd; - - r = sd_event_add_io(t->scope->manager->event, &t->dns_udp_event_source, fd, EPOLLIN, on_dns_packet, t); + r = dns_transaction_pick_server(t); if (r < 0) return r; - t->dns_udp_fd = fd; - fd = -1; - t->server = dns_server_ref(server); - } + if (t->current_feature_level < DNS_SERVER_FEATURE_LEVEL_UDP) + return -EAGAIN; - r = dns_scope_emit(t->scope, t->dns_udp_fd, t->sent); + if (!dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(t->key->type)) + return -EOPNOTSUPP; + + if (r > 0 || t->dns_udp_fd < 0) { /* Server changed, or no connection yet. */ + int fd; + + dns_transaction_close_connection(t); + + fd = dns_scope_socket_udp(t->scope, t->server, 53); + if (fd < 0) + return fd; + + r = sd_event_add_io(t->scope->manager->event, &t->dns_udp_event_source, fd, EPOLLIN, on_dns_packet, t); + if (r < 0) { + safe_close(fd); + return r; + } + + (void) sd_event_source_set_description(t->dns_udp_event_source, "dns-transaction-udp"); + t->dns_udp_fd = fd; + } + + r = dns_server_adjust_opt(t->server, t->sent, t->current_feature_level); + if (r < 0) + return r; + } else + dns_transaction_close_connection(t); + + r = dns_scope_emit_udp(t->scope, t->dns_udp_fd, t->sent); if (r < 0) return r; + dns_transaction_reset_answer(t); + return 0; } static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdata) { DnsTransaction *t = userdata; - int r; assert(s); assert(t); - /* Timeout reached? Try again, with a new server */ - dns_transaction_next_dns_server(t); + if (!t->initial_jitter_scheduled || t->initial_jitter_elapsed) { + /* Timeout reached? Increase the timeout for the server used */ + switch (t->scope->protocol) { - /* ... and possibly increased timeout */ - if (t->server) - dns_server_packet_lost(t->server, usec - t->start_usec); - else - dns_scope_packet_lost(t->scope, usec - t->start_usec); + case DNS_PROTOCOL_DNS: + assert(t->server); + dns_server_packet_lost(t->server, t->stream ? IPPROTO_TCP : IPPROTO_UDP, t->current_feature_level, usec - t->start_usec); + break; - r = dns_transaction_go(t); + case DNS_PROTOCOL_LLMNR: + case DNS_PROTOCOL_MDNS: + dns_scope_packet_lost(t->scope, usec - t->start_usec); + break; + + default: + assert_not_reached("Invalid DNS protocol."); + } + + if (t->initial_jitter_scheduled) + t->initial_jitter_elapsed = true; + } + + log_debug("Timeout reached on transaction %" PRIu16 ".", t->id); + + dns_transaction_retry(t); + return 0; +} + +static usec_t transaction_get_resend_timeout(DnsTransaction *t) { + assert(t); + assert(t->scope); + + switch (t->scope->protocol) { + + case DNS_PROTOCOL_DNS: + assert(t->server); + return t->server->resend_timeout; + + case DNS_PROTOCOL_MDNS: + assert(t->n_attempts > 0); + return (1 << (t->n_attempts - 1)) * USEC_PER_SEC; + + case DNS_PROTOCOL_LLMNR: + return t->scope->resend_timeout; + + default: + assert_not_reached("Invalid DNS protocol."); + } +} + +static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { + int r; + + assert(t); + + dns_transaction_stop_timeout(t); + + r = dns_scope_network_good(t->scope); if (r < 0) - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); + return r; + if (r == 0) { + dns_transaction_complete(t, DNS_TRANSACTION_NETWORK_DOWN); + return 0; + } + + if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) { + dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED); + return 0; + } + + if (t->scope->protocol == DNS_PROTOCOL_LLMNR && t->tried_stream) { + /* If we already tried via a stream, then we don't + * retry on LLMNR. See RFC 4795, Section 2.7. */ + dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED); + return 0; + } + + t->n_attempts++; + t->start_usec = ts; + + dns_transaction_reset_answer(t); + dns_transaction_flush_dnssec_transactions(t); + + /* Check the trust anchor. Do so only on classic DNS, since DNSSEC does not apply otherwise. */ + if (t->scope->protocol == DNS_PROTOCOL_DNS) { + r = dns_trust_anchor_lookup_positive(&t->scope->manager->trust_anchor, t->key, &t->answer); + if (r < 0) + return r; + if (r > 0) { + t->answer_rcode = DNS_RCODE_SUCCESS; + t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR; + t->answer_authenticated = true; + dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); + return 0; + } + + if (dns_name_is_root(DNS_RESOURCE_KEY_NAME(t->key)) && + t->key->type == DNS_TYPE_DS) { + + /* Hmm, this is a request for the root DS? A + * DS RR doesn't exist in the root zone, and + * if our trust anchor didn't know it either, + * this means we cannot do any DNSSEC logic + * anymore. */ + + if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) { + /* We are in downgrade mode. In this + * case, synthesize an unsigned empty + * response, so that the any lookup + * depending on this one can continue + * assuming there was no DS, and hence + * the root zone was unsigned. */ + + t->answer_rcode = DNS_RCODE_SUCCESS; + t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR; + t->answer_authenticated = false; + dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); + } else + /* If we are not in downgrade mode, + * then fail the lookup, because we + * cannot reasonably answer it. There + * might be DS RRs, but we don't know + * them, and the DNS server won't tell + * them to us (and even if it would, + * we couldn't validate it and trust + * it). */ + dns_transaction_complete(t, DNS_TRANSACTION_NO_TRUST_ANCHOR); + + return 0; + } + } + + /* Check the zone, but only if this transaction is not used + * for probing or verifying a zone item. */ + if (set_isempty(t->notify_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; + t->answer_authenticated = true; + 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. */ + if (set_isempty(t->notify_zone_items)) { + + /* Before trying the cache, let's make sure we figured out a + * server to use. Should this cause a change of server this + * might flush the cache. */ + dns_scope_get_dns_server(t->scope); + + /* Let's then prune all outdated entries */ + dns_cache_prune(&t->scope->cache); + + r = dns_cache_lookup(&t->scope->cache, t->key, &t->answer_rcode, &t->answer, &t->answer_authenticated); + if (r < 0) + return r; + if (r > 0) { + 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_RCODE_FAILURE); + return 0; + } + } + + return 1; +} + +static int dns_transaction_make_packet_mdns(DnsTransaction *t) { + + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + bool add_known_answers = false; + DnsTransaction *other; + unsigned qdcount; + usec_t ts; + int r; + + assert(t); + assert(t->scope->protocol == DNS_PROTOCOL_MDNS); + + /* Discard any previously prepared packet, so we can start over and coalesce again */ + t->sent = dns_packet_unref(t->sent); + + r = dns_packet_new_query(&p, t->scope->protocol, 0, false); + if (r < 0) + return r; + + r = dns_packet_append_key(p, t->key, NULL); + if (r < 0) + return r; + + qdcount = 1; + + if (dns_key_is_shared(t->key)) + add_known_answers = true; + + /* + * For mDNS, we want to coalesce as many open queries in pending transactions into one single + * query packet on the wire as possible. To achieve that, we iterate through all pending transactions + * in our current scope, and see whether their timing contraints allow them to be sent. + */ + + assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); + + LIST_FOREACH(transactions_by_scope, other, t->scope->transactions) { + + /* Skip ourselves */ + if (other == t) + continue; + + if (other->state != DNS_TRANSACTION_PENDING) + continue; + + if (other->next_attempt_after > ts) + continue; + + if (qdcount >= UINT16_MAX) + break; + + r = dns_packet_append_key(p, other->key, NULL); + + /* + * If we can't stuff more questions into the packet, just give up. + * One of the 'other' transactions will fire later and take care of the rest. + */ + if (r == -EMSGSIZE) + break; + + if (r < 0) + return r; + + r = dns_transaction_prepare(other, ts); + if (r <= 0) + continue; + + ts += transaction_get_resend_timeout(other); + + r = sd_event_add_time( + other->scope->manager->event, + &other->timeout_event_source, + clock_boottime_or_monotonic(), + ts, 0, + on_transaction_timeout, other); + if (r < 0) + return r; + + (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout"); + + other->state = DNS_TRANSACTION_PENDING; + other->next_attempt_after = ts; + + qdcount ++; + + if (dns_key_is_shared(other->key)) + add_known_answers = true; + } + + DNS_PACKET_HEADER(p)->qdcount = htobe16(qdcount); + + /* Append known answer section if we're asking for any shared record */ + if (add_known_answers) { + r = dns_cache_export_shared_to_packet(&t->scope->cache, p); + if (r < 0) + return r; + } + + t->sent = p; + p = NULL; return 0; } @@ -547,19 +1399,16 @@ static int dns_transaction_make_packet(DnsTransaction *t) { assert(t); + if (t->scope->protocol == DNS_PROTOCOL_MDNS) + return dns_transaction_make_packet_mdns(t); + if (t->sent) return 0; - r = dns_packet_new_query(&p, t->scope->protocol, 0); + r = dns_packet_new_query(&p, t->scope->protocol, 0, t->scope->dnssec_mode != DNSSEC_NO); if (r < 0) return r; - r = dns_scope_good_key(t->scope, t->key); - if (r < 0) - return r; - if (r == 0) - return -EDOM; - r = dns_packet_append_key(p, t->key, NULL); if (r < 0) return r; @@ -573,120 +1422,74 @@ static int dns_transaction_make_packet(DnsTransaction *t) { return 0; } -static usec_t transaction_get_resend_timeout(DnsTransaction *t) { - assert(t); - assert(t->scope); - - switch (t->scope->protocol) { - case DNS_PROTOCOL_DNS: - assert(t->server); - - return t->server->resend_timeout; - case DNS_PROTOCOL_LLMNR: - case DNS_PROTOCOL_MDNS: - return t->scope->resend_timeout; - default: - assert_not_reached("Invalid DNS protocol."); - } -} - int dns_transaction_go(DnsTransaction *t) { - bool had_stream; usec_t ts; int r; assert(t); - had_stream = !!t->stream; + assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); - dns_transaction_stop(t); + r = dns_transaction_prepare(t, ts); + if (r <= 0) + return r; - log_debug("Excercising transaction on scope %s on %s/%s", + log_debug("Excercising transaction %" PRIu16 " for <%s> on scope %s on %s/%s.", + t->id, + dns_transaction_key_string(t), 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)); - if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) { - dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED); - return 0; - } - - if (t->scope->protocol == DNS_PROTOCOL_LLMNR && had_stream) { - /* If we already tried via a stream, then we don't - * retry on LLMNR. See RFC 4795, Section 2.7. */ - dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED); - return 0; - } - - assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); - - 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; - - /* Check the cache, but only if this transaction is not used - * for probing or verifying a zone item. */ - if (set_isempty(t->zone_items)) { - - /* Before trying the cache, let's make sure we figured out a - * server to use. Should this cause a change of server this - * might flush the cache. */ - dns_scope_get_dns_server(t->scope); - - /* 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); - if (r < 0) - return r; - if (r > 0) { - if (t->cached_rcode == DNS_RCODE_SUCCESS) - dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); - else - dns_transaction_complete(t, DNS_TRANSACTION_FAILURE); - return 0; - } - } - - if (t->scope->protocol == DNS_PROTOCOL_LLMNR && !t->initial_jitter) { - usec_t jitter; + if (!t->initial_jitter_scheduled && + (t->scope->protocol == DNS_PROTOCOL_LLMNR || + t->scope->protocol == DNS_PROTOCOL_MDNS)) { + usec_t jitter, accuracy; /* RFC 4795 Section 2.7 suggests all queries should be * delayed by a random time from 0 to JITTER_INTERVAL. */ - t->initial_jitter = true; + t->initial_jitter_scheduled = true; random_bytes(&jitter, sizeof(jitter)); - jitter %= LLMNR_JITTER_INTERVAL_USEC; + + switch (t->scope->protocol) { + + case DNS_PROTOCOL_LLMNR: + jitter %= LLMNR_JITTER_INTERVAL_USEC; + accuracy = LLMNR_JITTER_INTERVAL_USEC; + break; + + case DNS_PROTOCOL_MDNS: + jitter %= MDNS_JITTER_RANGE_USEC; + jitter += MDNS_JITTER_MIN_USEC; + accuracy = MDNS_JITTER_RANGE_USEC; + break; + default: + assert_not_reached("bad protocol"); + } r = sd_event_add_time( t->scope->manager->event, &t->timeout_event_source, clock_boottime_or_monotonic(), - ts + jitter, - LLMNR_JITTER_INTERVAL_USEC, + ts + jitter, accuracy, on_transaction_timeout, t); if (r < 0) return r; + (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout"); + t->n_attempts = 0; + t->next_attempt_after = ts; t->state = DNS_TRANSACTION_PENDING; - log_debug("Delaying LLMNR transaction for " USEC_FMT "us.", jitter); + log_debug("Delaying %s transaction for " USEC_FMT "us.", dns_protocol_to_string(t->scope->protocol), jitter); return 0; } /* Otherwise, we need to ask the network */ r = dns_transaction_make_packet(t); - if (r == -EDOM) { - /* Not the right request to make on this network? - * (i.e. an A request made on IPv6 or an AAAA request - * made on IPv4, on LLMNR or mDNS.) */ - dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS); - return 0; - } if (r < 0) return r; @@ -698,50 +1501,1526 @@ int dns_transaction_go(DnsTransaction *t) { * always be made via TCP on LLMNR */ r = dns_transaction_open_tcp(t); } else { - /* Try via UDP, and if that fails due to large size try via TCP */ - r = dns_transaction_emit(t); + /* Try via UDP, and if that fails due to large size or lack of + * support try via TCP */ + r = dns_transaction_emit_udp(t); if (r == -EMSGSIZE) + log_debug("Sending query via TCP since it is too large."); + if (r == -EAGAIN) + log_debug("Sending query via TCP since server doesn't support UDP."); + if (r == -EMSGSIZE || r == -EAGAIN) r = dns_transaction_open_tcp(t); } + if (r == -ESRCH) { /* No servers to send this to? */ dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS); return 0; - } else if (r < 0) { - if (t->scope->protocol != DNS_PROTOCOL_DNS) { - dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); - return 0; - } + } + if (r == -EOPNOTSUPP) { + /* Tried to ask for DNSSEC RRs, on a server that doesn't do DNSSEC */ + dns_transaction_complete(t, DNS_TRANSACTION_RR_TYPE_UNSUPPORTED); + return 0; + } + if (t->scope->protocol == DNS_PROTOCOL_LLMNR && ERRNO_IS_DISCONNECT(-r)) { + /* On LLMNR, if we cannot connect to a host via TCP when doing reverse lookups. This means we cannot + * answer this request with this protocol. */ + dns_transaction_complete(t, DNS_TRANSACTION_NOT_FOUND); + return 0; + } + if (r < 0) { + if (t->scope->protocol != DNS_PROTOCOL_DNS) + return r; /* Couldn't send? Try immediately again, with a new server */ - dns_transaction_next_dns_server(t); + dns_scope_next_dns_server(t->scope); return dns_transaction_go(t); } + ts += transaction_get_resend_timeout(t); + r = sd_event_add_time( t->scope->manager->event, &t->timeout_event_source, clock_boottime_or_monotonic(), - ts + transaction_get_resend_timeout(t), 0, + ts, 0, on_transaction_timeout, t); if (r < 0) return r; + (void) sd_event_source_set_description(t->timeout_event_source, "dns-transaction-timeout"); + t->state = DNS_TRANSACTION_PENDING; + t->next_attempt_after = ts; + return 1; } +static int dns_transaction_find_cyclic(DnsTransaction *t, DnsTransaction *aux) { + DnsTransaction *n; + Iterator i; + int r; + + assert(t); + assert(aux); + + /* Try to find cyclic dependencies between transaction objects */ + + if (t == aux) + return 1; + + SET_FOREACH(n, aux->dnssec_transactions, i) { + r = dns_transaction_find_cyclic(t, n); + if (r != 0) + return r; + } + + return 0; +} + +static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResourceKey *key, DnsTransaction **ret) { + DnsTransaction *aux; + int r; + + assert(t); + assert(ret); + assert(key); + + aux = dns_scope_find_transaction(t->scope, key, true); + if (!aux) { + r = dns_transaction_new(&aux, t->scope, key); + if (r < 0) + return r; + } else { + if (set_contains(t->dnssec_transactions, aux)) { + *ret = aux; + return 0; + } + + r = dns_transaction_find_cyclic(t, aux); + if (r < 0) + return r; + if (r > 0) { + log_debug("Detected potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).", + aux->id, + strna(dns_transaction_key_string(aux)), + t->id, + strna(dns_transaction_key_string(t))); + return -ELOOP; + } + } + + r = set_ensure_allocated(&t->dnssec_transactions, NULL); + if (r < 0) + goto gc; + + r = set_ensure_allocated(&aux->notify_transactions, NULL); + if (r < 0) + goto gc; + + r = set_put(t->dnssec_transactions, aux); + if (r < 0) + goto gc; + + r = set_put(aux->notify_transactions, t); + if (r < 0) { + (void) set_remove(t->dnssec_transactions, aux); + goto gc; + } + + *ret = aux; + return 1; + +gc: + dns_transaction_gc(aux); + return r; +} + +static int dns_transaction_request_dnssec_rr(DnsTransaction *t, DnsResourceKey *key) { + _cleanup_(dns_answer_unrefp) DnsAnswer *a = NULL; + DnsTransaction *aux; + int r; + + assert(t); + assert(key); + + /* Try to get the data from the trust anchor */ + r = dns_trust_anchor_lookup_positive(&t->scope->manager->trust_anchor, key, &a); + if (r < 0) + return r; + if (r > 0) { + r = dns_answer_extend(&t->validated_keys, a); + if (r < 0) + return r; + + return 0; + } + + /* This didn't work, ask for it via the network/cache then. */ + r = dns_transaction_add_dnssec_transaction(t, key, &aux); + if (r == -ELOOP) /* This would result in a cyclic dependency */ + return 0; + if (r < 0) + return r; + + if (aux->state == DNS_TRANSACTION_NULL) { + r = dns_transaction_go(aux); + if (r < 0) + return r; + } + + return 1; +} + +static int dns_transaction_negative_trust_anchor_lookup(DnsTransaction *t, const char *name) { + int r; + + assert(t); + + /* Check whether the specified name is in the the NTA + * database, either in the global one, or the link-local + * one. */ + + r = dns_trust_anchor_lookup_negative(&t->scope->manager->trust_anchor, name); + if (r != 0) + return r; + + if (!t->scope->link) + return 0; + + return set_contains(t->scope->link->dnssec_negative_trust_anchors, name); +} + +static int dns_transaction_has_unsigned_negative_answer(DnsTransaction *t) { + int r; + + assert(t); + + /* Checks whether the answer is negative, and lacks NSEC/NSEC3 + * RRs to prove it */ + + r = dns_transaction_has_positive_answer(t, NULL); + if (r < 0) + return r; + if (r > 0) + return false; + + /* Is this key explicitly listed as a negative trust anchor? + * If so, it's nothing we need to care about */ + r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key)); + if (r < 0) + return r; + if (r > 0) + return false; + + /* The answer does not contain any RRs that match to the + * question. If so, let's see if there are any NSEC/NSEC3 RRs + * included. If not, the answer is unsigned. */ + + r = dns_answer_contains_nsec_or_nsec3(t->answer); + if (r < 0) + return r; + if (r > 0) + return false; + + return true; +} + +static int dns_transaction_is_primary_response(DnsTransaction *t, DnsResourceRecord *rr) { + int r; + + assert(t); + assert(rr); + + /* Check if the specified RR is the "primary" response, + * i.e. either matches the question precisely or is a + * CNAME/DNAME for it. */ + + r = dns_resource_key_match_rr(t->key, rr, NULL); + if (r != 0) + return r; + + return dns_resource_key_match_cname_or_dname(t->key, rr->key, NULL); +} + +static bool dns_transaction_dnssec_supported(DnsTransaction *t) { + assert(t); + + /* Checks whether our transaction's DNS server is assumed to be compatible with DNSSEC. Returns false as soon + * as we changed our mind about a server, and now believe it is incompatible with DNSSEC. */ + + if (t->scope->protocol != DNS_PROTOCOL_DNS) + return false; + + /* If we have picked no server, then we are working from the cache or some other source, and DNSSEC might well + * be supported, hence return true. */ + if (!t->server) + return true; + + if (t->current_feature_level < DNS_SERVER_FEATURE_LEVEL_DO) + return false; + + return dns_server_dnssec_supported(t->server); +} + +static bool dns_transaction_dnssec_supported_full(DnsTransaction *t) { + DnsTransaction *dt; + Iterator i; + + assert(t); + + /* Checks whether our transaction our any of the auxiliary transactions couldn't do DNSSEC. */ + + if (!dns_transaction_dnssec_supported(t)) + return false; + + SET_FOREACH(dt, t->dnssec_transactions, i) + if (!dns_transaction_dnssec_supported(dt)) + return false; + + return true; +} + +int dns_transaction_request_dnssec_keys(DnsTransaction *t) { + DnsResourceRecord *rr; + + int r; + + assert(t); + + /* + * Retrieve all auxiliary RRs for the answer we got, so that + * we can verify signatures or prove that RRs are rightfully + * unsigned. Specifically: + * + * - For RRSIG we get the matching DNSKEY + * - For DNSKEY we get the matching DS + * - For unsigned SOA/NS we get the matching DS + * - For unsigned CNAME/DNAME/DS we get the parent SOA RR + * - For other unsigned RRs we get the matching SOA RR + * - For SOA/NS/DS queries with no matching response RRs, and no NSEC/NSEC3, the parent's SOA RR + * - For other queries with no matching response RRs, and no NSEC/NSEC3, the SOA RR + */ + + if (t->scope->dnssec_mode == DNSSEC_NO) + return 0; + if (t->answer_source != DNS_TRANSACTION_NETWORK) + return 0; /* We only need to validate stuff from the network */ + if (!dns_transaction_dnssec_supported(t)) + return 0; /* If we can't do DNSSEC anyway there's no point in geting the auxiliary RRs */ + + DNS_ANSWER_FOREACH(rr, t->answer) { + + if (dns_type_is_pseudo(rr->key->type)) + continue; + + /* If this RR is in the negative trust anchor, we don't need to validate it. */ + r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key)); + if (r < 0) + return r; + if (r > 0) + continue; + + switch (rr->key->type) { + + case DNS_TYPE_RRSIG: { + /* For each RRSIG we request the matching DNSKEY */ + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *dnskey = NULL; + + /* If this RRSIG is about a DNSKEY RR and the + * signer is the same as the owner, then we + * already have the DNSKEY, and we don't have + * to look for more. */ + if (rr->rrsig.type_covered == DNS_TYPE_DNSKEY) { + r = dns_name_equal(rr->rrsig.signer, DNS_RESOURCE_KEY_NAME(rr->key)); + if (r < 0) + return r; + if (r > 0) + continue; + } + + /* If the signer is not a parent of our + * original query, then this is about an + * auxiliary RRset, but not anything we asked + * for. In this case we aren't interested, + * because we don't want to request additional + * RRs for stuff we didn't really ask for, and + * also to avoid request loops, where + * additional RRs from one transaction result + * in another transaction whose additonal RRs + * point back to the original transaction, and + * we deadlock. */ + r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), rr->rrsig.signer); + if (r < 0) + return r; + if (r == 0) + continue; + + dnskey = dns_resource_key_new(rr->key->class, DNS_TYPE_DNSKEY, rr->rrsig.signer); + if (!dnskey) + return -ENOMEM; + + log_debug("Requesting DNSKEY to validate transaction %" PRIu16" (%s, RRSIG with key tag: %" PRIu16 ").", t->id, DNS_RESOURCE_KEY_NAME(rr->key), rr->rrsig.key_tag); + r = dns_transaction_request_dnssec_rr(t, dnskey); + if (r < 0) + return r; + break; + } + + case DNS_TYPE_DNSKEY: { + /* For each DNSKEY we request the matching DS */ + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds = NULL; + + /* If the DNSKEY we are looking at is not for + * zone we are interested in, nor any of its + * parents, we aren't interested, and don't + * request it. After all, we don't want to end + * up in request loops, and want to keep + * additional traffic down. */ + + r = dns_name_endswith(DNS_RESOURCE_KEY_NAME(t->key), DNS_RESOURCE_KEY_NAME(rr->key)); + if (r < 0) + return r; + if (r == 0) + continue; + + ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(rr->key)); + if (!ds) + return -ENOMEM; + + log_debug("Requesting DS to validate transaction %" PRIu16" (%s, DNSKEY with key tag: %" PRIu16 ").", t->id, DNS_RESOURCE_KEY_NAME(rr->key), dnssec_keytag(rr, false)); + r = dns_transaction_request_dnssec_rr(t, ds); + if (r < 0) + return r; + + break; + } + + case DNS_TYPE_SOA: + case DNS_TYPE_NS: { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *ds = NULL; + + /* For an unsigned SOA or NS, try to acquire + * the matching DS RR, as we are at a zone cut + * then, and whether a DS exists tells us + * whether the zone is signed. Do so only if + * this RR matches our original question, + * however. */ + + r = dns_resource_key_match_rr(t->key, rr, NULL); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dnssec_has_rrsig(t->answer, rr->key); + if (r < 0) + return r; + if (r > 0) + continue; + + ds = dns_resource_key_new(rr->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(rr->key)); + if (!ds) + return -ENOMEM; + + log_debug("Requesting DS to validate transaction %" PRIu16 " (%s, unsigned SOA/NS RRset).", t->id, DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_transaction_request_dnssec_rr(t, ds); + if (r < 0) + return r; + + break; + } + + case DNS_TYPE_DS: + case DNS_TYPE_CNAME: + case DNS_TYPE_DNAME: { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL; + const char *name; + + /* CNAMEs and DNAMEs cannot be located at a + * zone apex, hence ask for the parent SOA for + * unsigned CNAME/DNAME RRs, maybe that's the + * apex. But do all that only if this is + * actually a response to our original + * question. + * + * Similar for DS RRs, which are signed when + * the parent SOA is signed. */ + + r = dns_transaction_is_primary_response(t, rr); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dnssec_has_rrsig(t->answer, rr->key); + if (r < 0) + return r; + if (r > 0) + continue; + + r = dns_answer_has_dname_for_cname(t->answer, rr); + if (r < 0) + return r; + if (r > 0) + continue; + + name = DNS_RESOURCE_KEY_NAME(rr->key); + r = dns_name_parent(&name); + if (r < 0) + return r; + if (r == 0) + continue; + + soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, name); + if (!soa) + return -ENOMEM; + + log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned CNAME/DNAME/DS RRset).", t->id, DNS_RESOURCE_KEY_NAME(rr->key)); + r = dns_transaction_request_dnssec_rr(t, soa); + if (r < 0) + return r; + + break; + } + + default: { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL; + + /* For other unsigned RRsets (including + * NSEC/NSEC3!), look for proof the zone is + * unsigned, by requesting the SOA RR of the + * zone. However, do so only if they are + * directly relevant to our original + * question. */ + + r = dns_transaction_is_primary_response(t, rr); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dnssec_has_rrsig(t->answer, rr->key); + if (r < 0) + return r; + if (r > 0) + continue; + + soa = dns_resource_key_new(rr->key->class, DNS_TYPE_SOA, DNS_RESOURCE_KEY_NAME(rr->key)); + if (!soa) + return -ENOMEM; + + log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned non-SOA/NS RRset <%s>).", t->id, DNS_RESOURCE_KEY_NAME(rr->key), dns_resource_record_to_string(rr)); + r = dns_transaction_request_dnssec_rr(t, soa); + if (r < 0) + return r; + break; + }} + } + + /* Above, we requested everything necessary to validate what + * we got. Now, let's request what we need to validate what we + * didn't get... */ + + r = dns_transaction_has_unsigned_negative_answer(t); + if (r < 0) + return r; + if (r > 0) { + const char *name; + + name = DNS_RESOURCE_KEY_NAME(t->key); + + /* If this was a SOA or NS request, then this + * indicates that we are not at a zone apex, hence ask + * the parent name instead. If this was a DS request, + * then it's signed when the parent zone is signed, + * hence ask the parent in that case, too. */ + + if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) { + r = dns_name_parent(&name); + if (r < 0) + return r; + if (r > 0) + log_debug("Requesting parent SOA to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS/DS response).", t->id, DNS_RESOURCE_KEY_NAME(t->key)); + else + name = NULL; + } else + log_debug("Requesting SOA to validate transaction %" PRIu16 " (%s, unsigned empty non-SOA/NS/DS response).", t->id, DNS_RESOURCE_KEY_NAME(t->key)); + + if (name) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL; + + soa = dns_resource_key_new(t->key->class, DNS_TYPE_SOA, name); + if (!soa) + return -ENOMEM; + + r = dns_transaction_request_dnssec_rr(t, soa); + if (r < 0) + return r; + } + } + + return dns_transaction_dnssec_is_live(t); +} + +void dns_transaction_notify(DnsTransaction *t, DnsTransaction *source) { + assert(t); + assert(source); + + /* Invoked whenever any of our auxiliary DNSSEC transactions completed its work. If the state is still PENDING, + we are still in the loop that adds further DNSSEC transactions, hence don't check if we are ready yet. If + the state is VALIDATING however, we should check if we are complete now. */ + + if (t->state == DNS_TRANSACTION_VALIDATING) + dns_transaction_process_dnssec(t); +} + +static int dns_transaction_validate_dnskey_by_ds(DnsTransaction *t) { + DnsResourceRecord *rr; + int ifindex, r; + + assert(t); + + /* Add all DNSKEY RRs from the answer that are validated by DS + * RRs from the list of validated keys to the list of + * validated keys. */ + + DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, t->answer) { + + r = dnssec_verify_dnskey_by_ds_search(rr, t->validated_keys); + if (r < 0) + return r; + if (r == 0) + continue; + + /* If so, the DNSKEY is validated too. */ + r = dns_answer_add_extend(&t->validated_keys, rr, ifindex, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + + return 0; +} + +static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord *rr) { + int r; + + assert(t); + assert(rr); + + /* Checks if the RR we are looking for must be signed with an + * RRSIG. This is used for positive responses. */ + + if (t->scope->dnssec_mode == DNSSEC_NO) + return false; + + if (dns_type_is_pseudo(rr->key->type)) + return -EINVAL; + + r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key)); + if (r < 0) + return r; + if (r > 0) + return false; + + switch (rr->key->type) { + + case DNS_TYPE_RRSIG: + /* RRSIGs are the signatures themselves, they need no signing. */ + return false; + + case DNS_TYPE_SOA: + case DNS_TYPE_NS: { + DnsTransaction *dt; + Iterator i; + + /* For SOA or NS RRs we look for a matching DS transaction */ + + SET_FOREACH(dt, t->dnssec_transactions, i) { + + if (dt->key->class != rr->key->class) + continue; + if (dt->key->type != DNS_TYPE_DS) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), DNS_RESOURCE_KEY_NAME(rr->key)); + if (r < 0) + return r; + if (r == 0) + continue; + + /* We found a DS transactions for the SOA/NS + * RRs we are looking at. If it discovered signed DS + * RRs, then we need to be signed, too. */ + + if (!dt->answer_authenticated) + return false; + + return dns_answer_match_key(dt->answer, dt->key, NULL); + } + + /* We found nothing that proves this is safe to leave + * this unauthenticated, hence ask inist on + * authentication. */ + return true; + } + + case DNS_TYPE_DS: + case DNS_TYPE_CNAME: + case DNS_TYPE_DNAME: { + const char *parent = NULL; + DnsTransaction *dt; + Iterator i; + + /* + * CNAME/DNAME RRs cannot be located at a zone apex, hence look directly for the parent SOA. + * + * DS RRs are signed if the parent is signed, hence also look at the parent SOA + */ + + SET_FOREACH(dt, t->dnssec_transactions, i) { + + if (dt->key->class != rr->key->class) + continue; + if (dt->key->type != DNS_TYPE_SOA) + continue; + + if (!parent) { + parent = DNS_RESOURCE_KEY_NAME(rr->key); + r = dns_name_parent(&parent); + if (r < 0) + return r; + if (r == 0) { + if (rr->key->type == DNS_TYPE_DS) + return true; + + /* A CNAME/DNAME without a parent? That's sooo weird. */ + log_debug("Transaction %" PRIu16 " claims CNAME/DNAME at root. Refusing.", t->id); + return -EBADMSG; + } + } + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), parent); + if (r < 0) + return r; + if (r == 0) + continue; + + return t->answer_authenticated; + } + + return true; + } + + default: { + DnsTransaction *dt; + Iterator i; + + /* Any other kind of RR (including DNSKEY/NSEC/NSEC3). Let's see if our SOA lookup was authenticated */ + + SET_FOREACH(dt, t->dnssec_transactions, i) { + + if (dt->key->class != rr->key->class) + continue; + if (dt->key->type != DNS_TYPE_SOA) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), DNS_RESOURCE_KEY_NAME(rr->key)); + if (r < 0) + return r; + if (r == 0) + continue; + + /* We found the transaction that was supposed to find + * the SOA RR for us. It was successful, but found no + * RR for us. This means we are not at a zone cut. In + * this case, we require authentication if the SOA + * lookup was authenticated too. */ + return t->answer_authenticated; + } + + return true; + }} +} + +static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKey *key) { + DnsTransaction *dt; + const char *tld; + Iterator i; + int r; + + /* If DNSSEC downgrade mode is on, checks whether the + * specified RR is one level below a TLD we have proven not to + * exist. In such a case we assume that this is a private + * domain, and permit it. + * + * This detects cases like the Fritz!Box router networks. Each + * Fritz!Box router serves a private "fritz.box" zone, in the + * non-existing TLD "box". Requests for the "fritz.box" domain + * are served by the router itself, while requests for the + * "box" domain will result in NXDOMAIN. + * + * Note that this logic is unable to detect cases where a + * router serves a private DNS zone directly under + * non-existing TLD. In such a case we cannot detect whether + * the TLD is supposed to exist or not, as all requests we + * make for it will be answered by the router's zone, and not + * by the root zone. */ + + assert(t); + + if (t->scope->dnssec_mode != DNSSEC_ALLOW_DOWNGRADE) + return false; /* In strict DNSSEC mode what doesn't exist, doesn't exist */ + + tld = DNS_RESOURCE_KEY_NAME(key); + r = dns_name_parent(&tld); + if (r < 0) + return r; + if (r == 0) + return false; /* Already the root domain */ + + if (!dns_name_is_single_label(tld)) + return false; + + SET_FOREACH(dt, t->dnssec_transactions, i) { + + if (dt->key->class != key->class) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), tld); + if (r < 0) + return r; + if (r == 0) + continue; + + /* We found an auxiliary lookup we did for the TLD. If + * that returned with NXDOMAIN, we know the TLD didn't + * exist, and hence this might be a private zone. */ + + return dt->answer_rcode == DNS_RCODE_NXDOMAIN; + } + + return false; +} + +static int dns_transaction_requires_nsec(DnsTransaction *t) { + DnsTransaction *dt; + const char *name; + Iterator i; + int r; + + assert(t); + + /* Checks if we need to insist on NSEC/NSEC3 RRs for proving + * this negative reply */ + + if (t->scope->dnssec_mode == DNSSEC_NO) + return false; + + if (dns_type_is_pseudo(t->key->type)) + return -EINVAL; + + r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(t->key)); + if (r < 0) + return r; + if (r > 0) + return false; + + r = dns_transaction_in_private_tld(t, t->key); + if (r < 0) + return r; + if (r > 0) { + /* The lookup is from a TLD that is proven not to + * exist, and we are in downgrade mode, hence ignore + * that fact that we didn't get any NSEC RRs.*/ + + log_info("Detected a negative query %s in a private DNS zone, permitting unsigned response.", dns_transaction_key_string(t)); + return false; + } + + name = DNS_RESOURCE_KEY_NAME(t->key); + + if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS, DNS_TYPE_DS)) { + + /* We got a negative reply for this SOA/NS lookup? If + * so, then we are not at a zone apex, and thus should + * look at the result of the parent SOA lookup. + * + * We got a negative reply for this DS lookup? DS RRs + * are signed when their parent zone is signed, hence + * also check the parent SOA in this case. */ + + r = dns_name_parent(&name); + if (r < 0) + return r; + if (r == 0) + return true; + } + + /* For all other RRs we check the SOA on the same level to see + * if it's signed. */ + + SET_FOREACH(dt, t->dnssec_transactions, i) { + + if (dt->key->class != t->key->class) + continue; + if (dt->key->type != DNS_TYPE_SOA) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), name); + if (r < 0) + return r; + if (r == 0) + continue; + + return dt->answer_authenticated; + } + + /* If in doubt, require NSEC/NSEC3 */ + return true; +} + +static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRecord *rr) { + DnsResourceRecord *rrsig; + bool found = false; + int r; + + /* Checks whether any of the DNSKEYs used for the RRSIGs for + * the specified RRset is authenticated (i.e. has a matching + * DS RR). */ + + r = dns_transaction_negative_trust_anchor_lookup(t, DNS_RESOURCE_KEY_NAME(rr->key)); + if (r < 0) + return r; + if (r > 0) + return false; + + DNS_ANSWER_FOREACH(rrsig, t->answer) { + DnsTransaction *dt; + Iterator i; + + r = dnssec_key_match_rrsig(rr->key, rrsig); + if (r < 0) + return r; + if (r == 0) + continue; + + SET_FOREACH(dt, t->dnssec_transactions, i) { + + if (dt->key->class != rr->key->class) + continue; + + if (dt->key->type == DNS_TYPE_DNSKEY) { + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), rrsig->rrsig.signer); + if (r < 0) + return r; + if (r == 0) + continue; + + /* OK, we found an auxiliary DNSKEY + * lookup. If that lookup is + * authenticated, report this. */ + + if (dt->answer_authenticated) + return true; + + found = true; + + } else if (dt->key->type == DNS_TYPE_DS) { + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(dt->key), rrsig->rrsig.signer); + if (r < 0) + return r; + if (r == 0) + continue; + + /* OK, we found an auxiliary DS + * lookup. If that lookup is + * authenticated and non-zero, we + * won! */ + + if (!dt->answer_authenticated) + return false; + + return dns_answer_match_key(dt->answer, dt->key, NULL); + } + } + } + + return found ? false : -ENXIO; +} + +static int dns_transaction_known_signed(DnsTransaction *t, DnsResourceRecord *rr) { + assert(t); + assert(rr); + + /* We know that the root domain is signed, hence if it appears + * not to be signed, there's a problem with the DNS server */ + + return rr->key->class == DNS_CLASS_IN && + dns_name_is_root(DNS_RESOURCE_KEY_NAME(rr->key)); +} + +static int dns_transaction_check_revoked_trust_anchors(DnsTransaction *t) { + DnsResourceRecord *rr; + int r; + + assert(t); + + /* Maybe warn the user that we encountered a revoked DNSKEY + * for a key from our trust anchor. Note that we don't care + * whether the DNSKEY can be authenticated or not. It's + * sufficient if it is self-signed. */ + + DNS_ANSWER_FOREACH(rr, t->answer) { + r = dns_trust_anchor_check_revoked(&t->scope->manager->trust_anchor, rr, t->answer); + if (r < 0) + return r; + } + + return 0; +} + +static int dns_transaction_invalidate_revoked_keys(DnsTransaction *t) { + bool changed; + int r; + + assert(t); + + /* Removes all DNSKEY/DS objects from t->validated_keys that + * our trust anchors database considers revoked. */ + + do { + DnsResourceRecord *rr; + + changed = false; + + DNS_ANSWER_FOREACH(rr, t->validated_keys) { + r = dns_trust_anchor_is_revoked(&t->scope->manager->trust_anchor, rr); + if (r < 0) + return r; + if (r > 0) { + r = dns_answer_remove_by_rr(&t->validated_keys, rr); + if (r < 0) + return r; + + assert(r > 0); + changed = true; + break; + } + } + } while (changed); + + return 0; +} + +static int dns_transaction_copy_validated(DnsTransaction *t) { + DnsTransaction *dt; + Iterator i; + int r; + + assert(t); + + /* Copy all validated RRs from the auxiliary DNSSEC transactions into our set of validated RRs */ + + SET_FOREACH(dt, t->dnssec_transactions, i) { + + if (DNS_TRANSACTION_IS_LIVE(dt->state)) + continue; + + if (!dt->answer_authenticated) + continue; + + r = dns_answer_extend(&t->validated_keys, dt->answer); + if (r < 0) + return r; + } + + return 0; +} + +int dns_transaction_validate_dnssec(DnsTransaction *t) { + _cleanup_(dns_answer_unrefp) DnsAnswer *validated = NULL; + enum { + PHASE_DNSKEY, /* Phase #1, only validate DNSKEYs */ + PHASE_NSEC, /* Phase #2, only validate NSEC+NSEC3 */ + PHASE_ALL, /* Phase #3, validate everything else */ + } phase; + DnsResourceRecord *rr; + DnsAnswerFlags flags; + int r; + + assert(t); + + /* We have now collected all DS and DNSKEY RRs in + * t->validated_keys, let's see which RRs we can now + * authenticate with that. */ + + if (t->scope->dnssec_mode == DNSSEC_NO) + return 0; + + /* Already validated */ + if (t->answer_dnssec_result != _DNSSEC_RESULT_INVALID) + return 0; + + /* Our own stuff needs no validation */ + if (IN_SET(t->answer_source, DNS_TRANSACTION_ZONE, DNS_TRANSACTION_TRUST_ANCHOR)) { + t->answer_dnssec_result = DNSSEC_VALIDATED; + t->answer_authenticated = true; + return 0; + } + + /* Cached stuff is not affected by validation. */ + if (t->answer_source != DNS_TRANSACTION_NETWORK) + return 0; + + if (!dns_transaction_dnssec_supported_full(t)) { + /* The server does not support DNSSEC, or doesn't augment responses with RRSIGs. */ + t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER; + log_debug("Not validating response for %" PRIu16 ", server lacks DNSSEC support.", t->id); + return 0; + } + + log_debug("Validating response from transaction %" PRIu16 " (%s).", t->id, dns_transaction_key_string(t)); + + /* First, see if this response contains any revoked trust + * anchors we care about */ + r = dns_transaction_check_revoked_trust_anchors(t); + if (r < 0) + return r; + + /* Third, copy all RRs we acquired successfully from auxiliary RRs over. */ + r = dns_transaction_copy_validated(t); + if (r < 0) + return r; + + /* Second, see if there are DNSKEYs we already know a + * validated DS for. */ + r = dns_transaction_validate_dnskey_by_ds(t); + if (r < 0) + return r; + + /* Fourth, remove all DNSKEY and DS RRs again that our trust + * anchor says are revoked. After all we might have marked + * some keys revoked above, but they might still be lingering + * in our validated_keys list. */ + r = dns_transaction_invalidate_revoked_keys(t); + if (r < 0) + return r; + + phase = PHASE_DNSKEY; + for (;;) { + bool changed = false, have_nsec = false; + + DNS_ANSWER_FOREACH(rr, t->answer) { + DnsResourceRecord *rrsig = NULL; + DnssecResult result; + + switch (rr->key->type) { + + case DNS_TYPE_RRSIG: + continue; + + case DNS_TYPE_DNSKEY: + /* We validate DNSKEYs only in the DNSKEY and ALL phases */ + if (phase == PHASE_NSEC) + continue; + break; + + case DNS_TYPE_NSEC: + case DNS_TYPE_NSEC3: + have_nsec = true; + + /* We validate NSEC/NSEC3 only in the NSEC and ALL phases */ + if (phase == PHASE_DNSKEY) + continue; + + break; + + default: + /* We validate all other RRs only in the ALL phases */ + if (phase != PHASE_ALL) + continue; + + break; + } + + r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig); + if (r < 0) + return r; + + log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result)); + + if (result == DNSSEC_VALIDATED) { + + if (rr->key->type == DNS_TYPE_DNSKEY) { + /* If we just validated a + * DNSKEY RRset, then let's + * add these keys to the set + * of validated keys for this + * transaction. */ + + r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + + /* some of the DNSKEYs we just + * added might already have + * been revoked, remove them + * again in that case. */ + r = dns_transaction_invalidate_revoked_keys(t); + if (r < 0) + return r; + } + + /* Add the validated RRset to the new + * list of validated RRsets, and + * remove it from the unvalidated + * RRsets. We mark the RRset as + * authenticated and cacheable. */ + r = dns_answer_move_by_key(&validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE); + if (r < 0) + return r; + + manager_dnssec_verdict(t->scope->manager, DNSSEC_SECURE, rr->key); + + /* Exit the loop, we dropped something from the answer, start from the beginning */ + changed = true; + break; + } + + /* If we haven't read all DNSKEYs yet a negative result of the validation is irrelevant, as + * there might be more DNSKEYs coming. Similar, if we haven't read all NSEC/NSEC3 RRs yet, we + * cannot do positive wildcard proofs yet, as those require the NSEC/NSEC3 RRs. */ + if (phase != PHASE_ALL) + continue; + + if (result == DNSSEC_VALIDATED_WILDCARD) { + bool authenticated = false; + const char *source; + + /* This RRset validated, but as a wildcard. This means we need to prove via NSEC/NSEC3 + * that no matching non-wildcard RR exists.*/ + + /* First step, determine the source of synthesis */ + r = dns_resource_record_source(rrsig, &source); + if (r < 0) + return r; + + r = dnssec_test_positive_wildcard( + validated, + DNS_RESOURCE_KEY_NAME(rr->key), + source, + rrsig->rrsig.signer, + &authenticated); + + /* Unless the NSEC proof showed that the key really doesn't exist something is off. */ + if (r == 0) + result = DNSSEC_INVALID; + else { + r = dns_answer_move_by_key(&validated, &t->answer, rr->key, authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0); + if (r < 0) + return r; + + manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, rr->key); + + /* Exit the loop, we dropped something from the answer, start from the beginning */ + changed = true; + break; + } + } + + if (result == DNSSEC_NO_SIGNATURE) { + r = dns_transaction_requires_rrsig(t, rr); + if (r < 0) + return r; + if (r == 0) { + /* Data does not require signing. In that case, just copy it over, + * but remember that this is by no means authenticated.*/ + r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0); + if (r < 0) + return r; + + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); + changed = true; + break; + } + + r = dns_transaction_known_signed(t, rr); + if (r < 0) + return r; + if (r > 0) { + /* This is an RR we know has to be signed. If it isn't this means + * the server is not attaching RRSIGs, hence complain. */ + + dns_server_packet_rrsig_missing(t->server, t->current_feature_level); + + if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) { + + /* Downgrading is OK? If so, just consider the information unsigned */ + + r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0); + if (r < 0) + return r; + + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); + changed = true; + break; + } + + /* Otherwise, fail */ + t->answer_dnssec_result = DNSSEC_INCOMPATIBLE_SERVER; + return 0; + } + + r = dns_transaction_in_private_tld(t, rr->key); + if (r < 0) + return r; + if (r > 0) { + _cleanup_free_ char *s = NULL; + + /* The data is from a TLD that is proven not to exist, and we are in downgrade + * mode, hence ignore the fact that this was not signed. */ + + (void) dns_resource_key_to_string(rr->key, &s); + log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.", strna(s ? strstrip(s) : NULL)); + + r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0); + if (r < 0) + return r; + + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); + changed = true; + break; + } + } + + if (IN_SET(result, + DNSSEC_MISSING_KEY, + DNSSEC_SIGNATURE_EXPIRED, + DNSSEC_UNSUPPORTED_ALGORITHM)) { + + r = dns_transaction_dnskey_authenticated(t, rr); + if (r < 0 && r != -ENXIO) + return r; + if (r == 0) { + /* The DNSKEY transaction was not authenticated, this means there's + * no DS for this, which means it's OK if no keys are found for this signature. */ + + r = dns_answer_move_by_key(&validated, &t->answer, rr->key, 0); + if (r < 0) + return r; + + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, rr->key); + changed = true; + break; + } + } + + r = dns_transaction_is_primary_response(t, rr); + if (r < 0) + return r; + if (r > 0) { + + /* Look for a matching DNAME for this CNAME */ + r = dns_answer_has_dname_for_cname(t->answer, rr); + if (r < 0) + return r; + if (r == 0) { + /* Also look among the stuff we already validated */ + r = dns_answer_has_dname_for_cname(validated, rr); + if (r < 0) + return r; + } + + if (r == 0) { + if (IN_SET(result, + DNSSEC_INVALID, + DNSSEC_SIGNATURE_EXPIRED, + DNSSEC_NO_SIGNATURE)) + manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, rr->key); + else /* DNSSEC_MISSING_KEY or DNSSEC_UNSUPPORTED_ALGORITHM */ + manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, rr->key); + + /* This is a primary response to our question, and it failed validation. That's + * fatal. */ + t->answer_dnssec_result = result; + return 0; + } + + /* This is a primary response, but we do have a DNAME RR in the RR that can replay this + * CNAME, hence rely on that, and we can remove the CNAME in favour of it. */ + } + + /* This is just some auxiliary data. Just remove the RRset and continue. */ + r = dns_answer_remove_by_key(&t->answer, rr->key); + if (r < 0) + return r; + + /* Exit the loop, we dropped something from the answer, start from the beginning */ + changed = true; + break; + } + + /* Restart the inner loop as long as we managed to achieve something */ + if (changed) + continue; + + if (phase == PHASE_DNSKEY && have_nsec) { + /* OK, we processed all DNSKEYs, and there are NSEC/NSEC3 RRs, look at those now. */ + phase = PHASE_NSEC; + continue; + } + + if (phase != PHASE_ALL) { + /* OK, we processed all DNSKEYs and NSEC/NSEC3 RRs, look at all the rest now. Note that in this + * third phase we start to remove RRs we couldn't validate. */ + phase = PHASE_ALL; + continue; + } + + /* We're done */ + break; + } + + dns_answer_unref(t->answer); + t->answer = validated; + validated = NULL; + + /* At this point the answer only contains validated + * RRsets. Now, let's see if it actually answers the question + * we asked. If so, great! If it doesn't, then see if + * NSEC/NSEC3 can prove this. */ + r = dns_transaction_has_positive_answer(t, &flags); + if (r > 0) { + /* Yes, it answers the question! */ + + if (flags & DNS_ANSWER_AUTHENTICATED) { + /* The answer is fully authenticated, yay. */ + t->answer_dnssec_result = DNSSEC_VALIDATED; + t->answer_rcode = DNS_RCODE_SUCCESS; + t->answer_authenticated = true; + } else { + /* The answer is not fully authenticated. */ + t->answer_dnssec_result = DNSSEC_UNSIGNED; + t->answer_authenticated = false; + } + + } else if (r == 0) { + DnssecNsecResult nr; + bool authenticated = false; + + /* Bummer! Let's check NSEC/NSEC3 */ + r = dnssec_nsec_test(t->answer, t->key, &nr, &authenticated, &t->answer_nsec_ttl); + if (r < 0) + return r; + + switch (nr) { + + case DNSSEC_NSEC_NXDOMAIN: + /* NSEC proves the domain doesn't exist. Very good. */ + log_debug("Proved NXDOMAIN via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t)); + t->answer_dnssec_result = DNSSEC_VALIDATED; + t->answer_rcode = DNS_RCODE_NXDOMAIN; + t->answer_authenticated = authenticated; + + manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, t->key); + break; + + case DNSSEC_NSEC_NODATA: + /* NSEC proves that there's no data here, very good. */ + log_debug("Proved NODATA via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t)); + t->answer_dnssec_result = DNSSEC_VALIDATED; + t->answer_rcode = DNS_RCODE_SUCCESS; + t->answer_authenticated = authenticated; + + manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, t->key); + break; + + case DNSSEC_NSEC_OPTOUT: + /* NSEC3 says the data might not be signed */ + log_debug("Data is NSEC3 opt-out via NSEC/NSEC3 for transaction %u (%s)", t->id, dns_transaction_key_string(t)); + t->answer_dnssec_result = DNSSEC_UNSIGNED; + t->answer_authenticated = false; + + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, t->key); + break; + + case DNSSEC_NSEC_NO_RR: + /* No NSEC data? Bummer! */ + + r = dns_transaction_requires_nsec(t); + if (r < 0) + return r; + if (r > 0) { + t->answer_dnssec_result = DNSSEC_NO_SIGNATURE; + manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, t->key); + } else { + t->answer_dnssec_result = DNSSEC_UNSIGNED; + t->answer_authenticated = false; + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, t->key); + } + + break; + + case DNSSEC_NSEC_UNSUPPORTED_ALGORITHM: + /* We don't know the NSEC3 algorithm used? */ + t->answer_dnssec_result = DNSSEC_UNSUPPORTED_ALGORITHM; + manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, t->key); + break; + + case DNSSEC_NSEC_FOUND: + case DNSSEC_NSEC_CNAME: + /* NSEC says it needs to be there, but we couldn't find it? Bummer! */ + t->answer_dnssec_result = DNSSEC_NSEC_MISMATCH; + manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, t->key); + break; + + default: + assert_not_reached("Unexpected NSEC result."); + } + } + + return 1; +} + +const char *dns_transaction_key_string(DnsTransaction *t) { + assert(t); + + if (!t->key_string) { + if (dns_resource_key_to_string(t->key, &t->key_string) < 0) + return "n/a"; + } + + return strstrip(t->key_string); +} + static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] = { [DNS_TRANSACTION_NULL] = "null", [DNS_TRANSACTION_PENDING] = "pending", - [DNS_TRANSACTION_FAILURE] = "failure", + [DNS_TRANSACTION_VALIDATING] = "validating", + [DNS_TRANSACTION_RCODE_FAILURE] = "rcode-failure", [DNS_TRANSACTION_SUCCESS] = "success", [DNS_TRANSACTION_NO_SERVERS] = "no-servers", [DNS_TRANSACTION_TIMEOUT] = "timeout", [DNS_TRANSACTION_ATTEMPTS_MAX_REACHED] = "attempts-max-reached", [DNS_TRANSACTION_INVALID_REPLY] = "invalid-reply", - [DNS_TRANSACTION_RESOURCES] = "resources", + [DNS_TRANSACTION_ERRNO] = "errno", [DNS_TRANSACTION_ABORTED] = "aborted", + [DNS_TRANSACTION_DNSSEC_FAILED] = "dnssec-failed", + [DNS_TRANSACTION_NO_TRUST_ANCHOR] = "no-trust-anchor", + [DNS_TRANSACTION_RR_TYPE_UNSUPPORTED] = "rr-type-unsupported", + [DNS_TRANSACTION_NETWORK_DOWN] = "network-down", + [DNS_TRANSACTION_NOT_FOUND] = "not-found", }; 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", + [DNS_TRANSACTION_TRUST_ANCHOR] = "trust-anchor", +}; +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 acf6a6f65..461719471 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,61 +21,119 @@ typedef struct DnsTransaction DnsTransaction; typedef enum DnsTransactionState DnsTransactionState; +typedef enum DnsTransactionSource DnsTransactionSource; enum DnsTransactionState { DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING, - DNS_TRANSACTION_FAILURE, + DNS_TRANSACTION_VALIDATING, + DNS_TRANSACTION_RCODE_FAILURE, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NO_SERVERS, DNS_TRANSACTION_TIMEOUT, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED, DNS_TRANSACTION_INVALID_REPLY, - DNS_TRANSACTION_RESOURCES, + DNS_TRANSACTION_ERRNO, DNS_TRANSACTION_ABORTED, + DNS_TRANSACTION_DNSSEC_FAILED, + DNS_TRANSACTION_NO_TRUST_ANCHOR, + DNS_TRANSACTION_RR_TYPE_UNSUPPORTED, + DNS_TRANSACTION_NETWORK_DOWN, + DNS_TRANSACTION_NOT_FOUND, /* like NXDOMAIN, but when LLMNR/TCP connections fail */ _DNS_TRANSACTION_STATE_MAX, _DNS_TRANSACTION_STATE_INVALID = -1 }; -#include "resolved-dns-scope.h" +#define DNS_TRANSACTION_IS_LIVE(state) IN_SET((state), DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_VALIDATING) + +enum DnsTransactionSource { + DNS_TRANSACTION_NETWORK, + DNS_TRANSACTION_CACHE, + DNS_TRANSACTION_ZONE, + DNS_TRANSACTION_TRUST_ANCHOR, + _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; DnsResourceKey *key; + char *key_string; DnsTransactionState state; + uint16_t id; - bool initial_jitter; + bool tried_stream:1; + + bool initial_jitter_scheduled:1; + bool initial_jitter_elapsed:1; DnsPacket *sent, *received; - DnsAnswer *cached; - int cached_rcode; + + DnsAnswer *answer; + int answer_rcode; + DnssecResult answer_dnssec_result; + DnsTransactionSource answer_source; + uint32_t answer_nsec_ttl; + int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ + + /* Indicates whether the primary answer is authenticated, + * i.e. whether the RRs from answer which directly match the + * question are authenticated, or, if there are none, whether + * the NODATA or NXDOMAIN case is. It says nothing about + * additional RRs listed in the answer, however they have + * their own DNS_ANSWER_AUTHORIZED FLAGS. Note that this bit + * is defined different than the AD bit in DNS packets, as + * that covers more than just the actual primary answer. */ + bool answer_authenticated; + + /* Contains DNSKEY, DS, SOA RRs we already verified and need + * to authenticate this reply */ + DnsAnswer *validated_keys; usec_t start_usec; + usec_t next_attempt_after; sd_event_source *timeout_event_source; unsigned n_attempts; + /* UDP connection logic, if we need it */ int dns_udp_fd; sd_event_source *dns_udp_event_source; - /* The active server */ - DnsServer *server; - /* 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; + /* The active server */ + DnsServer *server; + + /* The features of the DNS server at time of transaction start */ + DnsServerFeatureLevel current_feature_level; + + /* Query candidates this transaction is referenced by and that + * shall be notified about this specific transaction + * completing. */ + Set *notify_query_candidates; /* Zone items this transaction is referenced by and that shall * be notified about completion. */ - Set *zone_items; + Set *notify_zone_items; + + /* Other transactions that this transactions is referenced by + * and that shall be notified about completion. This is used + * when transactions want to validate their RRsets, but need + * another DNSKEY or DS RR to do so. */ + Set *notify_transactions; + + /* The opposite direction: the transactions this transaction + * created in order to request DNSKEY or DS RRs. */ + Set *dnssec_transactions; unsigned block_gc; @@ -87,22 +143,35 @@ struct DnsTransaction { int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key); DnsTransaction* dns_transaction_free(DnsTransaction *t); -void dns_transaction_gc(DnsTransaction *t); +bool dns_transaction_gc(DnsTransaction *t); int dns_transaction_go(DnsTransaction *t); void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p); void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state); +void dns_transaction_notify(DnsTransaction *t, DnsTransaction *source); +int dns_transaction_validate_dnssec(DnsTransaction *t); +int dns_transaction_request_dnssec_keys(DnsTransaction *t); + +const char *dns_transaction_key_string(DnsTransaction *t); + 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) +/* mDNS Jitter interval, see RFC 6762 Section 5.2 */ +#define MDNS_JITTER_MIN_USEC (20 * USEC_PER_MSEC) +#define MDNS_JITTER_RANGE_USEC (100 * USEC_PER_MSEC) + /* Maximum attempts to send DNS requests, across all DNS servers */ #define DNS_TRANSACTION_ATTEMPTS_MAX 16 /* 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-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c new file mode 100644 index 000000000..a75337eb6 --- /dev/null +++ b/src/resolve/resolved-dns-trust-anchor.c @@ -0,0 +1,743 @@ +/*** + 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 . +***/ + +#include + +#include "alloc-util.h" +#include "conf-files.h" +#include "def.h" +#include "dns-domain.h" +#include "fd-util.h" +#include "fileio.h" +#include "hexdecoct.h" +#include "parse-util.h" +#include "resolved-dns-trust-anchor.h" +#include "resolved-dns-dnssec.h" +#include "set.h" +#include "string-util.h" +#include "strv.h" + +static const char trust_anchor_dirs[] = CONF_PATHS_NULSTR("dnssec-trust-anchors.d"); + +/* The DS RR from https://data.iana.org/root-anchors/root-anchors.xml, retrieved December 2015 */ +static const uint8_t root_digest[] = + { 0x49, 0xAA, 0xC1, 0x1D, 0x7B, 0x6F, 0x64, 0x46, 0x70, 0x2E, 0x54, 0xA1, 0x60, 0x73, 0x71, 0x60, + 0x7A, 0x1A, 0x41, 0x85, 0x52, 0x00, 0xFD, 0x2C, 0xE1, 0xCD, 0xDE, 0x32, 0xF2, 0x4E, 0x8F, 0xB5 }; + +static bool dns_trust_anchor_knows_domain_positive(DnsTrustAnchor *d, const char *name) { + assert(d); + + /* Returns true if there's an entry for the specified domain + * name in our trust anchor */ + + return + hashmap_contains(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DNSKEY, name)) || + hashmap_contains(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DS, name)); +} + +static int dns_trust_anchor_add_builtin_positive(DnsTrustAnchor *d) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + int r; + + assert(d); + + r = hashmap_ensure_allocated(&d->positive_by_key, &dns_resource_key_hash_ops); + if (r < 0) + return r; + + /* Only add the built-in trust anchor if there's neither a DS + * nor a DNSKEY defined for the root domain. That way users + * have an easy way to override the root domain DS/DNSKEY + * data. */ + if (dns_trust_anchor_knows_domain_positive(d, ".")) + return 0; + + /* Add the RR from https://data.iana.org/root-anchors/root-anchors.xml */ + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, ""); + if (!rr) + return -ENOMEM; + + rr->ds.key_tag = 19036; + rr->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; + rr->ds.digest_type = DNSSEC_DIGEST_SHA256; + rr->ds.digest_size = sizeof(root_digest); + rr->ds.digest = memdup(root_digest, rr->ds.digest_size); + if (!rr->ds.digest) + return -ENOMEM; + + answer = dns_answer_new(1); + if (!answer) + return -ENOMEM; + + r = dns_answer_add(answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + + r = hashmap_put(d->positive_by_key, rr->key, answer); + if (r < 0) + return r; + + answer = NULL; + return 0; +} + +static int dns_trust_anchor_add_builtin_negative(DnsTrustAnchor *d) { + + static const char private_domains[] = + /* RFC 6761 says that .test is a special domain for + * testing and not to be installed in the root zone */ + "test\0" + + /* RFC 6761 says that these reverse IP lookup ranges + * are for private addresses, and hence should not + * show up in the root zone */ + "10.in-addr.arpa\0" + "16.172.in-addr.arpa\0" + "17.172.in-addr.arpa\0" + "18.172.in-addr.arpa\0" + "19.172.in-addr.arpa\0" + "20.172.in-addr.arpa\0" + "21.172.in-addr.arpa\0" + "22.172.in-addr.arpa\0" + "23.172.in-addr.arpa\0" + "24.172.in-addr.arpa\0" + "25.172.in-addr.arpa\0" + "26.172.in-addr.arpa\0" + "27.172.in-addr.arpa\0" + "28.172.in-addr.arpa\0" + "29.172.in-addr.arpa\0" + "30.172.in-addr.arpa\0" + "31.172.in-addr.arpa\0" + "168.192.in-addr.arpa\0" + + /* RFC 6762 reserves the .local domain for Multicast + * DNS, it hence cannot appear in the root zone. (Note + * that we by default do not route .local traffic to + * DNS anyway, except when a configured search domain + * suggests so.) */ + "local\0" + + /* These two are well known, popular private zone + * TLDs, that are blocked from delegation, according + * to: + * http://icannwiki.com/Name_Collision#NGPC_Resolution + * + * There's also ongoing work on making this official + * in an RRC: + * https://www.ietf.org/archive/id/draft-chapin-additional-reserved-tlds-02.txt */ + "home\0" + "corp\0" + + /* The following four TLDs are suggested for private + * zones in RFC 6762, Appendix G, and are hence very + * unlikely to be made official TLDs any day soon */ + "lan\0" + "intranet\0" + "internal\0" + "private\0"; + + const char *name; + int r; + + assert(d); + + /* Only add the built-in trust anchor if there's no negative + * trust anchor defined at all. This enables easy overriding + * of negative trust anchors. */ + + if (set_size(d->negative_by_name) > 0) + return 0; + + r = set_ensure_allocated(&d->negative_by_name, &dns_name_hash_ops); + if (r < 0) + return r; + + /* We add a couple of domains as default negative trust + * anchors, where it's very unlikely they will be installed in + * the root zone. If they exist they must be private, and thus + * unsigned. */ + + NULSTR_FOREACH(name, private_domains) { + + if (dns_trust_anchor_knows_domain_positive(d, name)) + continue; + + r = set_put_strdup(d->negative_by_name, name); + if (r < 0) + return r; + } + + return 0; +} + +static int dns_trust_anchor_load_positive(DnsTrustAnchor *d, const char *path, unsigned line, const char *s) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + _cleanup_free_ char *domain = NULL, *class = NULL, *type = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnsAnswer *old_answer = NULL; + const char *p = s; + int r; + + assert(d); + assert(line); + + r = extract_first_word(&p, &domain, NULL, EXTRACT_QUOTES); + if (r < 0) + return log_warning_errno(r, "Unable to parse domain in line %s:%u: %m", path, line); + + if (!dns_name_is_valid(domain)) { + log_warning("Domain name %s is invalid, at line %s:%u, ignoring line.", domain, path, line); + return -EINVAL; + } + + r = extract_many_words(&p, NULL, 0, &class, &type, NULL); + if (r < 0) + return log_warning_errno(r, "Unable to parse class and type in line %s:%u: %m", path, line); + if (r != 2) { + log_warning("Missing class or type in line %s:%u", path, line); + return -EINVAL; + } + + if (!strcaseeq(class, "IN")) { + log_warning("RR class %s is not supported, ignoring line %s:%u.", class, path, line); + return -EINVAL; + } + + if (strcaseeq(type, "DS")) { + _cleanup_free_ char *key_tag = NULL, *algorithm = NULL, *digest_type = NULL, *digest = NULL; + _cleanup_free_ void *dd = NULL; + uint16_t kt; + int a, dt; + size_t l; + + r = extract_many_words(&p, NULL, 0, &key_tag, &algorithm, &digest_type, &digest, NULL); + if (r < 0) { + log_warning_errno(r, "Failed to parse DS parameters on line %s:%u: %m", path, line); + return -EINVAL; + } + if (r != 4) { + log_warning("Missing DS parameters on line %s:%u", path, line); + return -EINVAL; + } + + r = safe_atou16(key_tag, &kt); + if (r < 0) + return log_warning_errno(r, "Failed to parse DS key tag %s on line %s:%u: %m", key_tag, path, line); + + a = dnssec_algorithm_from_string(algorithm); + if (a < 0) { + log_warning("Failed to parse DS algorithm %s on line %s:%u", algorithm, path, line); + return -EINVAL; + } + + dt = dnssec_digest_from_string(digest_type); + if (dt < 0) { + log_warning("Failed to parse DS digest type %s on line %s:%u", digest_type, path, line); + return -EINVAL; + } + + r = unhexmem(digest, strlen(digest), &dd, &l); + if (r < 0) { + log_warning("Failed to parse DS digest %s on line %s:%u", digest, path, line); + return -EINVAL; + } + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, domain); + if (!rr) + return log_oom(); + + rr->ds.key_tag = kt; + rr->ds.algorithm = a; + rr->ds.digest_type = dt; + rr->ds.digest_size = l; + rr->ds.digest = dd; + dd = NULL; + + } else if (strcaseeq(type, "DNSKEY")) { + _cleanup_free_ char *flags = NULL, *protocol = NULL, *algorithm = NULL, *key = NULL; + _cleanup_free_ void *k = NULL; + uint16_t f; + size_t l; + int a; + + r = extract_many_words(&p, NULL, 0, &flags, &protocol, &algorithm, &key, NULL); + if (r < 0) + return log_warning_errno(r, "Failed to parse DNSKEY parameters on line %s:%u: %m", path, line); + if (r != 4) { + log_warning("Missing DNSKEY parameters on line %s:%u", path, line); + return -EINVAL; + } + + if (!streq(protocol, "3")) { + log_warning("DNSKEY Protocol is not 3 on line %s:%u", path, line); + return -EINVAL; + } + + r = safe_atou16(flags, &f); + if (r < 0) + return log_warning_errno(r, "Failed to parse DNSKEY flags field %s on line %s:%u", flags, path, line); + if ((f & DNSKEY_FLAG_ZONE_KEY) == 0) { + log_warning("DNSKEY lacks zone key bit set on line %s:%u", path, line); + return -EINVAL; + } + if ((f & DNSKEY_FLAG_REVOKE)) { + log_warning("DNSKEY is already revoked on line %s:%u", path, line); + return -EINVAL; + } + + a = dnssec_algorithm_from_string(algorithm); + if (a < 0) { + log_warning("Failed to parse DNSKEY algorithm %s on line %s:%u", algorithm, path, line); + return -EINVAL; + } + + r = unbase64mem(key, strlen(key), &k, &l); + if (r < 0) + return log_warning_errno(r, "Failed to parse DNSKEY key data %s on line %s:%u", key, path, line); + + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, domain); + if (!rr) + return log_oom(); + + rr->dnskey.flags = f; + rr->dnskey.protocol = 3; + rr->dnskey.algorithm = a; + rr->dnskey.key_size = l; + rr->dnskey.key = k; + k = NULL; + + } else { + log_warning("RR type %s is not supported, ignoring line %s:%u.", type, path, line); + return -EINVAL; + } + + if (!isempty(p)) { + log_warning("Trailing garbage on line %s:%u, ignoring line.", path, line); + return -EINVAL; + } + + r = hashmap_ensure_allocated(&d->positive_by_key, &dns_resource_key_hash_ops); + if (r < 0) + return log_oom(); + + old_answer = hashmap_get(d->positive_by_key, rr->key); + answer = dns_answer_ref(old_answer); + + r = dns_answer_add_extend(&answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return log_error_errno(r, "Failed to add trust anchor RR: %m"); + + r = hashmap_replace(d->positive_by_key, rr->key, answer); + if (r < 0) + return log_error_errno(r, "Failed to add answer to trust anchor: %m"); + + old_answer = dns_answer_unref(old_answer); + answer = NULL; + + return 0; +} + +static int dns_trust_anchor_load_negative(DnsTrustAnchor *d, const char *path, unsigned line, const char *s) { + _cleanup_free_ char *domain = NULL; + const char *p = s; + int r; + + assert(d); + assert(line); + + r = extract_first_word(&p, &domain, NULL, EXTRACT_QUOTES); + if (r < 0) + return log_warning_errno(r, "Unable to parse line %s:%u: %m", path, line); + + if (!dns_name_is_valid(domain)) { + log_warning("Domain name %s is invalid, at line %s:%u, ignoring line.", domain, path, line); + return -EINVAL; + } + + if (!isempty(p)) { + log_warning("Trailing garbage at line %s:%u, ignoring line.", path, line); + return -EINVAL; + } + + r = set_ensure_allocated(&d->negative_by_name, &dns_name_hash_ops); + if (r < 0) + return log_oom(); + + r = set_put(d->negative_by_name, domain); + if (r < 0) + return log_oom(); + if (r > 0) + domain = NULL; + + return 0; +} + +static int dns_trust_anchor_load_files( + DnsTrustAnchor *d, + const char *suffix, + int (*loader)(DnsTrustAnchor *d, const char *path, unsigned n, const char *line)) { + + _cleanup_strv_free_ char **files = NULL; + char **f; + int r; + + assert(d); + assert(suffix); + assert(loader); + + r = conf_files_list_nulstr(&files, suffix, NULL, trust_anchor_dirs); + if (r < 0) + return log_error_errno(r, "Failed to enumerate %s trust anchor files: %m", suffix); + + STRV_FOREACH(f, files) { + _cleanup_fclose_ FILE *g = NULL; + char line[LINE_MAX]; + unsigned n = 0; + + g = fopen(*f, "r"); + if (!g) { + if (errno == ENOENT) + continue; + + log_warning_errno(errno, "Failed to open %s: %m", *f); + continue; + } + + FOREACH_LINE(line, g, log_warning_errno(errno, "Failed to read %s, ignoring: %m", *f)) { + char *l; + + n++; + + l = strstrip(line); + if (isempty(l)) + continue; + + if (*l == ';') + continue; + + (void) loader(d, *f, n, l); + } + } + + return 0; +} + +static int domain_name_cmp(const void *a, const void *b) { + char **x = (char**) a, **y = (char**) b; + + return dns_name_compare_func(*x, *y); +} + +static int dns_trust_anchor_dump(DnsTrustAnchor *d) { + DnsAnswer *a; + Iterator i; + + assert(d); + + if (hashmap_isempty(d->positive_by_key)) + log_info("No positive trust anchors defined."); + else { + log_info("Positive Trust Anchors:"); + HASHMAP_FOREACH(a, d->positive_by_key, i) { + DnsResourceRecord *rr; + + DNS_ANSWER_FOREACH(rr, a) + log_info("%s", dns_resource_record_to_string(rr)); + } + } + + if (set_isempty(d->negative_by_name)) + log_info("No negative trust anchors defined."); + else { + _cleanup_free_ char **l = NULL, *j = NULL; + + l = set_get_strv(d->negative_by_name); + if (!l) + return log_oom(); + + qsort_safe(l, set_size(d->negative_by_name), sizeof(char*), domain_name_cmp); + + j = strv_join(l, " "); + if (!j) + return log_oom(); + + log_info("Negative trust anchors: %s", j); + } + + return 0; +} + +int dns_trust_anchor_load(DnsTrustAnchor *d) { + int r; + + assert(d); + + /* If loading things from disk fails, we don't consider this fatal */ + (void) dns_trust_anchor_load_files(d, ".positive", dns_trust_anchor_load_positive); + (void) dns_trust_anchor_load_files(d, ".negative", dns_trust_anchor_load_negative); + + /* However, if the built-in DS fails, then we have a problem. */ + r = dns_trust_anchor_add_builtin_positive(d); + if (r < 0) + return log_error_errno(r, "Failed to add built-in positive trust anchor: %m"); + + r = dns_trust_anchor_add_builtin_negative(d); + if (r < 0) + return log_error_errno(r, "Failed to add built-in negative trust anchor: %m"); + + dns_trust_anchor_dump(d); + + return 0; +} + +void dns_trust_anchor_flush(DnsTrustAnchor *d) { + DnsAnswer *a; + DnsResourceRecord *rr; + + assert(d); + + while ((a = hashmap_steal_first(d->positive_by_key))) + dns_answer_unref(a); + d->positive_by_key = hashmap_free(d->positive_by_key); + + while ((rr = set_steal_first(d->revoked_by_rr))) + dns_resource_record_unref(rr); + d->revoked_by_rr = set_free(d->revoked_by_rr); + + d->negative_by_name = set_free_free(d->negative_by_name); +} + +int dns_trust_anchor_lookup_positive(DnsTrustAnchor *d, const DnsResourceKey *key, DnsAnswer **ret) { + DnsAnswer *a; + + assert(d); + assert(key); + assert(ret); + + /* We only serve DS and DNSKEY RRs. */ + if (!IN_SET(key->type, DNS_TYPE_DS, DNS_TYPE_DNSKEY)) + return 0; + + a = hashmap_get(d->positive_by_key, key); + if (!a) + return 0; + + *ret = dns_answer_ref(a); + return 1; +} + +int dns_trust_anchor_lookup_negative(DnsTrustAnchor *d, const char *name) { + assert(d); + assert(name); + + return set_contains(d->negative_by_name, name); +} + +static int dns_trust_anchor_revoked_put(DnsTrustAnchor *d, DnsResourceRecord *rr) { + int r; + + assert(d); + + r = set_ensure_allocated(&d->revoked_by_rr, &dns_resource_record_hash_ops); + if (r < 0) + return r; + + r = set_put(d->revoked_by_rr, rr); + if (r < 0) + return r; + if (r > 0) + dns_resource_record_ref(rr); + + return r; +} + +static int dns_trust_anchor_remove_revoked(DnsTrustAnchor *d, DnsResourceRecord *rr) { + _cleanup_(dns_answer_unrefp) DnsAnswer *new_answer = NULL; + DnsAnswer *old_answer; + int r; + + /* Remember that this is a revoked trust anchor RR */ + r = dns_trust_anchor_revoked_put(d, rr); + if (r < 0) + return r; + + /* Remove this from the positive trust anchor */ + old_answer = hashmap_get(d->positive_by_key, rr->key); + if (!old_answer) + return 0; + + new_answer = dns_answer_ref(old_answer); + + r = dns_answer_remove_by_rr(&new_answer, rr); + if (r <= 0) + return r; + + /* We found the key! Warn the user */ + log_struct(LOG_WARNING, + LOG_MESSAGE_ID(SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED), + LOG_MESSAGE("DNSSEC Trust anchor %s has been revoked. Please update the trust anchor, or upgrade your operating system."), strna(dns_resource_record_to_string(rr)), + "TRUST_ANCHOR=%s", dns_resource_record_to_string(rr), + NULL); + + if (dns_answer_size(new_answer) <= 0) { + assert_se(hashmap_remove(d->positive_by_key, rr->key) == old_answer); + dns_answer_unref(old_answer); + return 1; + } + + r = hashmap_replace(d->positive_by_key, new_answer->items[0].rr->key, new_answer); + if (r < 0) + return r; + + new_answer = NULL; + dns_answer_unref(old_answer); + return 1; +} + +static int dns_trust_anchor_check_revoked_one(DnsTrustAnchor *d, DnsResourceRecord *revoked_dnskey) { + DnsAnswer *a; + int r; + + assert(d); + assert(revoked_dnskey); + assert(revoked_dnskey->key->type == DNS_TYPE_DNSKEY); + assert(revoked_dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE); + + a = hashmap_get(d->positive_by_key, revoked_dnskey->key); + if (a) { + DnsResourceRecord *anchor; + + /* First, look for the precise DNSKEY in our trust anchor database */ + + DNS_ANSWER_FOREACH(anchor, a) { + + if (anchor->dnskey.protocol != revoked_dnskey->dnskey.protocol) + continue; + + if (anchor->dnskey.algorithm != revoked_dnskey->dnskey.algorithm) + continue; + + if (anchor->dnskey.key_size != revoked_dnskey->dnskey.key_size) + continue; + + /* Note that we allow the REVOKE bit to be + * different! It will be set in the revoked + * key, but unset in our version of it */ + if (((anchor->dnskey.flags ^ revoked_dnskey->dnskey.flags) | DNSKEY_FLAG_REVOKE) != DNSKEY_FLAG_REVOKE) + continue; + + if (memcmp(anchor->dnskey.key, revoked_dnskey->dnskey.key, anchor->dnskey.key_size) != 0) + continue; + + dns_trust_anchor_remove_revoked(d, anchor); + break; + } + } + + a = hashmap_get(d->positive_by_key, &DNS_RESOURCE_KEY_CONST(revoked_dnskey->key->class, DNS_TYPE_DS, DNS_RESOURCE_KEY_NAME(revoked_dnskey->key))); + if (a) { + DnsResourceRecord *anchor; + + /* Second, look for DS RRs matching this DNSKEY in our trust anchor database */ + + DNS_ANSWER_FOREACH(anchor, a) { + + /* We set mask_revoke to true here, since our + * DS fingerprint will be the one of the + * unrevoked DNSKEY, but the one we got passed + * here has the bit set. */ + r = dnssec_verify_dnskey_by_ds(revoked_dnskey, anchor, true); + if (r < 0) + return r; + if (r == 0) + continue; + + dns_trust_anchor_remove_revoked(d, anchor); + break; + } + } + + return 0; +} + +int dns_trust_anchor_check_revoked(DnsTrustAnchor *d, DnsResourceRecord *dnskey, DnsAnswer *rrs) { + DnsResourceRecord *rrsig; + int r; + + assert(d); + assert(dnskey); + + /* Looks if "dnskey" is a self-signed RR that has been revoked + * and matches one of our trust anchor entries. If so, removes + * it from the trust anchor and returns > 0. */ + + if (dnskey->key->type != DNS_TYPE_DNSKEY) + return 0; + + /* Is this DNSKEY revoked? */ + if ((dnskey->dnskey.flags & DNSKEY_FLAG_REVOKE) == 0) + return 0; + + /* Could this be interesting to us at all? If not, + * there's no point in looking for and verifying a + * self-signed RRSIG. */ + if (!dns_trust_anchor_knows_domain_positive(d, DNS_RESOURCE_KEY_NAME(dnskey->key))) + return 0; + + /* Look for a self-signed RRSIG in the other rrs belonging to this DNSKEY */ + DNS_ANSWER_FOREACH(rrsig, rrs) { + DnssecResult result; + + if (rrsig->key->type != DNS_TYPE_RRSIG) + continue; + + r = dnssec_rrsig_match_dnskey(rrsig, dnskey, true); + if (r < 0) + return r; + if (r == 0) + continue; + + r = dnssec_verify_rrset(rrs, dnskey->key, rrsig, dnskey, USEC_INFINITY, &result); + if (r < 0) + return r; + if (result != DNSSEC_VALIDATED) + continue; + + /* Bingo! This is a revoked self-signed DNSKEY. Let's + * see if this precise one exists in our trust anchor + * database, too. */ + r = dns_trust_anchor_check_revoked_one(d, dnskey); + if (r < 0) + return r; + + return 1; + } + + return 0; +} + +int dns_trust_anchor_is_revoked(DnsTrustAnchor *d, DnsResourceRecord *rr) { + assert(d); + + if (!IN_SET(rr->key->type, DNS_TYPE_DS, DNS_TYPE_DNSKEY)) + return 0; + + return set_contains(d->revoked_by_rr, rr); +} diff --git a/src/resolve/resolved-dns-trust-anchor.h b/src/resolve/resolved-dns-trust-anchor.h new file mode 100644 index 000000000..635c75fde --- /dev/null +++ b/src/resolve/resolved-dns-trust-anchor.h @@ -0,0 +1,43 @@ +#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 . +***/ + +typedef struct DnsTrustAnchor DnsTrustAnchor; + +#include "hashmap.h" +#include "resolved-dns-answer.h" +#include "resolved-dns-rr.h" + +/* This contains a fixed database mapping domain names to DS or DNSKEY records. */ + +struct DnsTrustAnchor { + Hashmap *positive_by_key; + Set *negative_by_name; + Set *revoked_by_rr; +}; + +int dns_trust_anchor_load(DnsTrustAnchor *d); +void dns_trust_anchor_flush(DnsTrustAnchor *d); + +int dns_trust_anchor_lookup_positive(DnsTrustAnchor *d, const DnsResourceKey* key, DnsAnswer **answer); +int dns_trust_anchor_lookup_negative(DnsTrustAnchor *d, const char *name); + +int dns_trust_anchor_check_revoked(DnsTrustAnchor *d, DnsResourceRecord *dnskey, DnsAnswer *rrs); +int dns_trust_anchor_is_revoked(DnsTrustAnchor *d, DnsResourceRecord *rr); diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 48dcf76da..f52383cfd 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -39,7 +37,7 @@ void dns_zone_item_probe_stop(DnsZoneItem *i) { t = i->probe_transaction; i->probe_transaction = NULL; - set_remove(t->zone_items, i); + set_remove(t->notify_zone_items, i); dns_transaction_gc(t); } @@ -163,7 +161,6 @@ static int dns_zone_link_item(DnsZone *z, DnsZoneItem *i) { } static int dns_zone_item_probe_start(DnsZoneItem *i) { - _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; DnsTransaction *t; int r; @@ -172,22 +169,24 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { if (i->probe_transaction) return 0; - key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)); - if (!key) - return -ENOMEM; - - t = dns_scope_find_transaction(i->scope, key, false); + t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)), false); if (!t) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + + key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)); + if (!key) + return -ENOMEM; + r = dns_transaction_new(&t, i->scope, key); if (r < 0) return r; } - r = set_ensure_allocated(&t->zone_items, NULL); + r = set_ensure_allocated(&t->notify_zone_items, NULL); if (r < 0) goto gc; - r = set_put(t->zone_items, i); + r = set_put(t->notify_zone_items, i); if (r < 0) goto gc; @@ -205,7 +204,7 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { } } - dns_zone_item_ready(i); + dns_zone_item_notify(i); return 0; gc: @@ -222,9 +221,9 @@ int dns_zone_put(DnsZone *z, DnsScope *s, DnsResourceRecord *rr, bool probe) { assert(s); assert(rr); - if (rr->key->class == DNS_CLASS_ANY) + if (dns_class_is_pseudo(rr->key->class)) return -EINVAL; - if (rr->key->type == DNS_TYPE_ANY) + if (dns_type_is_pseudo(rr->key->type)) return -EINVAL; existing = dns_zone_get(z, rr); @@ -283,97 +282,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; - - return 0; - } /* First iteration, count what we have */ - 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; - /* If this is a generic match, then we have to - * go through the list by the name and look - * for everything manually */ + /* If this is a generic match, then we have to + * go through the list by the name and look + * for everything manually */ - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); + 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; + + k = dns_resource_key_match_rr(key, j->rr, NULL); + if (k < 0) + return k; + if (k > 0) { + n_answer++; + added = true; + } + + } + + if (found && !added) + need_soa = true; + + } else { + bool found = false; + + /* If this is a specific match, then look for + * the right key immediately */ + + 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; + + found = true; + n_answer++; + } + + 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; - - 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) - n_soa++; - - } else { - bool found = false; - - /* If this is a specific match, then look for - * the right key immediately */ - - 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; - - 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,111 +359,122 @@ 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 (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) { + bool found = false, added = false; + int k; - 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; - first = hashmap_get(z->by_name, DNS_RESOURCE_KEY_NAME(q->keys[i])); + found = true; + + if (j->state != DNS_ZONE_ITEM_PROBING) + tentative = false; + + 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, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + + added = true; + } + } + + 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; + + 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; + + found = true; + + if (j->state != DNS_ZONE_ITEM_PROBING) + tentative = false; + + r = dns_answer_add(answer, j->rr, 0, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + + if (!found) { + bool add_soa = false; + + 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; - if (j->state != DNS_ZONE_ITEM_PROBING) tentative = false; - 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; - - added = true; - } + add_soa = true; } - if (found && !added) { - r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(q->keys[i]), LLMNR_DEFAULT_TTL); + if (add_soa) { + r = dns_answer_add_soa(soa, DNS_RESOURCE_KEY_NAME(key), LLMNR_DEFAULT_TTL); if (r < 0) return r; } - } 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; - - found = true; - - 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; - - 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; - - if (j->state != DNS_ZONE_ITEM_PROBING) - tentative = false; - - 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 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) { - _cleanup_free_ char *pretty = NULL; - assert(i); if (!IN_SET(i->state, DNS_ZONE_ITEM_PROBING, DNS_ZONE_ITEM_VERIFYING, DNS_ZONE_ITEM_ESTABLISHED)) return; - dns_resource_record_to_string(i->rr, &pretty); - log_info("Detected conflict on %s", strna(pretty)); + log_info("Detected conflict on %s", strna(dns_resource_record_to_string(i->rr))); dns_zone_item_probe_stop(i); @@ -497,16 +486,14 @@ void dns_zone_item_conflict(DnsZoneItem *i) { manager_next_hostname(i->scope->manager); } -void dns_zone_item_ready(DnsZoneItem *i) { - _cleanup_free_ char *pretty = NULL; - +void dns_zone_item_notify(DnsZoneItem *i) { assert(i); assert(i->probe_transaction); if (i->block_ready > 0) return; - if (IN_SET(i->probe_transaction->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING)) + if (IN_SET(i->probe_transaction->state, DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_VALIDATING)) return; if (i->probe_transaction->state == DNS_TRANSACTION_SUCCESS) { @@ -536,15 +523,13 @@ void dns_zone_item_ready(DnsZoneItem *i) { log_debug("Got a successful probe reply, but peer has lexicographically lower IP address and thus lost."); } - dns_resource_record_to_string(i->rr, &pretty); - log_debug("Record %s successfully probed.", strna(pretty)); + log_debug("Record %s successfully probed.", strna(dns_resource_record_to_string(i->rr))); dns_zone_item_probe_stop(i); i->state = DNS_ZONE_ITEM_ESTABLISHED; } static int dns_zone_item_verify(DnsZoneItem *i) { - _cleanup_free_ char *pretty = NULL; int r; assert(i); @@ -552,8 +537,7 @@ static int dns_zone_item_verify(DnsZoneItem *i) { if (i->state != DNS_ZONE_ITEM_ESTABLISHED) return 0; - dns_resource_record_to_string(i->rr, &pretty); - log_debug("Verifying RR %s", strna(pretty)); + log_debug("Verifying RR %s", strna(dns_resource_record_to_string(i->rr))); i->state = DNS_ZONE_ITEM_VERIFYING; r = dns_zone_item_probe_start(i); @@ -638,7 +622,6 @@ void dns_zone_verify_all(DnsZone *zone) { void dns_zone_dump(DnsZone *zone, FILE *f) { Iterator iterator; DnsZoneItem *i; - int r; if (!zone) return; @@ -650,10 +633,10 @@ void dns_zone_dump(DnsZone *zone, FILE *f) { DnsZoneItem *j; LIST_FOREACH(by_key, j, i) { - _cleanup_free_ char *t = NULL; + const char *t; - r = dns_resource_record_to_string(j->rr, &t); - if (r < 0) { + t = dns_resource_record_to_string(j->rr); + if (!t) { log_oom(); continue; } diff --git a/src/resolve/resolved-dns-zone.h b/src/resolve/resolved-dns-zone.h index 495d17cdb..408833c35 100644 --- a/src/resolve/resolved-dns-zone.h +++ b/src/resolve/resolved-dns-zone.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -31,9 +29,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,10 +65,10 @@ 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); +void dns_zone_item_notify(DnsZoneItem *i); int dns_zone_check_conflicts(DnsZone *zone, DnsResourceRecord *rr); int dns_zone_verify_conflicts(DnsZone *zone, DnsResourceKey *key); diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c new file mode 100644 index 000000000..ee82c9682 --- /dev/null +++ b/src/resolve/resolved-etc-hosts.c @@ -0,0 +1,448 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "fd-util.h" +#include "fileio.h" +#include "hostname-util.h" +#include "resolved-etc-hosts.h" +#include "resolved-dns-synthesize.h" +#include "string-util.h" +#include "strv.h" +#include "time-util.h" + +/* Recheck /etc/hosts at most once every 2s */ +#define ETC_HOSTS_RECHECK_USEC (2*USEC_PER_SEC) + +typedef struct EtcHostsItem { + int family; + union in_addr_union address; + + char **names; +} EtcHostsItem; + +typedef struct EtcHostsItemByName { + char *name; + + EtcHostsItem **items; + size_t n_items, n_allocated; +} EtcHostsItemByName; + +void manager_etc_hosts_flush(Manager *m) { + EtcHostsItem *item; + EtcHostsItemByName *bn; + + while ((item = set_steal_first(m->etc_hosts_by_address))) { + strv_free(item->names); + free(item); + } + + while ((bn = hashmap_steal_first(m->etc_hosts_by_name))) { + free(bn->name); + free(bn->items); + free(bn); + } + + m->etc_hosts_by_address = set_free(m->etc_hosts_by_address); + m->etc_hosts_by_name = hashmap_free(m->etc_hosts_by_name); + + m->etc_hosts_mtime = USEC_INFINITY; +} + +static void etc_hosts_item_hash_func(const void *p, struct siphash *state) { + const EtcHostsItem *item = p; + + siphash24_compress(&item->family, sizeof(item->family), state); + + if (item->family == AF_INET) + siphash24_compress(&item->address.in, sizeof(item->address.in), state); + else if (item->family == AF_INET6) + siphash24_compress(&item->address.in6, sizeof(item->address.in6), state); +} + +static int etc_hosts_item_compare_func(const void *a, const void *b) { + const EtcHostsItem *x = a, *y = b; + + if (x->family != y->family) + return x->family - y->family; + + if (x->family == AF_INET) + return memcmp(&x->address.in.s_addr, &y->address.in.s_addr, sizeof(struct in_addr)); + + if (x->family == AF_INET6) + return memcmp(&x->address.in6.s6_addr, &y->address.in6.s6_addr, sizeof(struct in6_addr)); + + return trivial_compare_func(a, b); +} + +static const struct hash_ops etc_hosts_item_ops = { + .hash = etc_hosts_item_hash_func, + .compare = etc_hosts_item_compare_func, +}; + +static int add_item(Manager *m, int family, const union in_addr_union *address, char **names) { + + EtcHostsItem key = { + .family = family, + .address = *address, + }; + EtcHostsItem *item; + char **n; + int r; + + assert(m); + assert(address); + + r = in_addr_is_null(family, address); + if (r < 0) + return r; + if (r > 0) + /* This is an 0.0.0.0 or :: item, which we assume means that we shall map the specified hostname to + * nothing. */ + item = NULL; + else { + /* If this is a normal address, then, simply add entry mapping it to the specified names */ + + item = set_get(m->etc_hosts_by_address, &key); + if (item) { + r = strv_extend_strv(&item->names, names, true); + if (r < 0) + return log_oom(); + } else { + + r = set_ensure_allocated(&m->etc_hosts_by_address, &etc_hosts_item_ops); + if (r < 0) + return log_oom(); + + item = new0(EtcHostsItem, 1); + if (!item) + return log_oom(); + + item->family = family; + item->address = *address; + item->names = names; + + r = set_put(m->etc_hosts_by_address, item); + if (r < 0) { + free(item); + return log_oom(); + } + } + } + + STRV_FOREACH(n, names) { + EtcHostsItemByName *bn; + + bn = hashmap_get(m->etc_hosts_by_name, *n); + if (!bn) { + r = hashmap_ensure_allocated(&m->etc_hosts_by_name, &dns_name_hash_ops); + if (r < 0) + return log_oom(); + + bn = new0(EtcHostsItemByName, 1); + if (!bn) + return log_oom(); + + bn->name = strdup(*n); + if (!bn->name) { + free(bn); + return log_oom(); + } + + r = hashmap_put(m->etc_hosts_by_name, bn->name, bn); + if (r < 0) { + free(bn->name); + free(bn); + return log_oom(); + } + } + + if (item) { + if (!GREEDY_REALLOC(bn->items, bn->n_allocated, bn->n_items+1)) + return log_oom(); + + bn->items[bn->n_items++] = item; + } + } + + return 0; +} + +static int parse_line(Manager *m, unsigned nr, const char *line) { + _cleanup_free_ char *address = NULL; + _cleanup_strv_free_ char **names = NULL; + union in_addr_union in; + bool suppressed = false; + int family, r; + + assert(m); + assert(line); + + r = extract_first_word(&line, &address, NULL, EXTRACT_RELAX); + if (r < 0) + return log_error_errno(r, "Couldn't extract address, in line /etc/hosts:%u.", nr); + if (r == 0) { + log_error("Premature end of line, in line /etc/hosts:%u.", nr); + return -EINVAL; + } + + r = in_addr_from_string_auto(address, &family, &in); + if (r < 0) + return log_error_errno(r, "Address '%s' is invalid, in line /etc/hosts:%u.", address, nr); + + for (;;) { + _cleanup_free_ char *name = NULL; + + r = extract_first_word(&line, &name, NULL, EXTRACT_RELAX); + if (r < 0) + return log_error_errno(r, "Couldn't extract host name, in line /etc/hosts:%u.", nr); + if (r == 0) + break; + + r = dns_name_is_valid(name); + if (r <= 0) + return log_error_errno(r, "Hostname %s is not valid, ignoring, in line /etc/hosts:%u.", name, nr); + + if (is_localhost(name)) { + /* Suppress the "localhost" line that is often seen */ + suppressed = true; + continue; + } + + r = strv_push(&names, name); + if (r < 0) + return log_oom(); + + name = NULL; + } + + if (strv_isempty(names)) { + + if (suppressed) + return 0; + + log_error("Line is missing any host names, in line /etc/hosts:%u.", nr); + return -EINVAL; + } + + /* Takes possession of the names strv */ + r = add_item(m, family, &in, names); + if (r < 0) + return r; + + names = NULL; + return r; +} + +int manager_etc_hosts_read(Manager *m) { + _cleanup_fclose_ FILE *f = NULL; + char line[LINE_MAX]; + struct stat st; + usec_t ts; + unsigned nr = 0; + int r; + + assert_se(sd_event_now(m->event, clock_boottime_or_monotonic(), &ts) >= 0); + + /* See if we checked /etc/hosts recently already */ + if (m->etc_hosts_last != USEC_INFINITY && m->etc_hosts_last + ETC_HOSTS_RECHECK_USEC > ts) + return 0; + + m->etc_hosts_last = ts; + + if (m->etc_hosts_mtime != USEC_INFINITY) { + if (stat("/etc/hosts", &st) < 0) { + if (errno == ENOENT) { + r = 0; + goto clear; + } + + return log_error_errno(errno, "Failed to stat /etc/hosts: %m"); + } + + /* Did the mtime change? If not, there's no point in re-reading the file. */ + if (timespec_load(&st.st_mtim) == m->etc_hosts_mtime) + return 0; + } + + f = fopen("/etc/hosts", "re"); + if (!f) { + if (errno == ENOENT) { + r = 0; + goto clear; + } + + return log_error_errno(errno, "Failed to open /etc/hosts: %m"); + } + + /* Take the timestamp at the beginning of processing, so that any changes made later are read on the next + * invocation */ + r = fstat(fileno(f), &st); + if (r < 0) + return log_error_errno(errno, "Failed to fstat() /etc/hosts: %m"); + + manager_etc_hosts_flush(m); + + FOREACH_LINE(line, f, return log_error_errno(errno, "Failed to read /etc/hosts: %m")) { + char *l; + + nr ++; + + l = strstrip(line); + if (isempty(l)) + continue; + if (l[0] == '#') + continue; + + r = parse_line(m, nr, l); + if (r == -ENOMEM) /* On OOM we abandon the half-built-up structure. All other errors we ignore and proceed */ + goto clear; + } + + m->etc_hosts_mtime = timespec_load(&st.st_mtim); + m->etc_hosts_last = ts; + + return 1; + +clear: + manager_etc_hosts_flush(m); + return r; +} + +int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) { + bool found_a = false, found_aaaa = false; + EtcHostsItemByName *bn; + EtcHostsItem k = {}; + DnsResourceKey *t; + const char *name; + unsigned i; + int r; + + assert(m); + assert(q); + assert(answer); + + r = manager_etc_hosts_read(m); + if (r < 0) + return r; + + name = dns_question_first_name(q); + if (!name) + return 0; + + r = dns_name_address(name, &k.family, &k.address); + if (r > 0) { + EtcHostsItem *item; + DnsResourceKey *found_ptr = NULL; + + item = set_get(m->etc_hosts_by_address, &k); + if (!item) + return 0; + + /* We have an address in /etc/hosts that matches the queried name. Let's return successful. Actual data + * we'll only return if the request was for PTR. */ + + DNS_QUESTION_FOREACH(t, q) { + if (!IN_SET(t->type, DNS_TYPE_PTR, DNS_TYPE_ANY)) + continue; + if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY)) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name); + if (r < 0) + return r; + if (r > 0) { + found_ptr = t; + break; + } + } + + if (found_ptr) { + char **n; + + r = dns_answer_reserve(answer, strv_length(item->names)); + if (r < 0) + return r; + + STRV_FOREACH(n, item->names) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + rr = dns_resource_record_new(found_ptr); + if (!rr) + return -ENOMEM; + + rr->ptr.name = strdup(*n); + if (!rr->ptr.name) + return -ENOMEM; + + r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + } + + return 1; + } + + bn = hashmap_get(m->etc_hosts_by_name, name); + if (!bn) + return 0; + + r = dns_answer_reserve(answer, bn->n_items); + if (r < 0) + return r; + + DNS_QUESTION_FOREACH(t, q) { + if (!IN_SET(t->type, DNS_TYPE_A, DNS_TYPE_AAAA, DNS_TYPE_ANY)) + continue; + if (!IN_SET(t->class, DNS_CLASS_IN, DNS_CLASS_ANY)) + continue; + + r = dns_name_equal(DNS_RESOURCE_KEY_NAME(t), name); + if (r < 0) + return r; + if (r == 0) + continue; + + if (IN_SET(t->type, DNS_TYPE_A, DNS_TYPE_ANY)) + found_a = true; + if (IN_SET(t->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) + found_aaaa = true; + + if (found_a && found_aaaa) + break; + } + + for (i = 0; i < bn->n_items; i++) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + + if ((found_a && bn->items[i]->family != AF_INET) && + (found_aaaa && bn->items[i]->family != AF_INET6)) + continue; + + r = dns_resource_record_new_address(&rr, bn->items[i]->family, &bn->items[i]->address, bn->name); + if (r < 0) + return r; + + r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + if (r < 0) + return r; + } + + return 1; +} diff --git a/src/import/pull-dkr.h b/src/resolve/resolved-etc-hosts.h similarity index 50% rename from src/import/pull-dkr.h rename to src/resolve/resolved-etc-hosts.h index 33d18cb39..9d5a175f1 100644 --- a/src/import/pull-dkr.h +++ b/src/resolve/resolved-etc-hosts.h @@ -1,9 +1,9 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#pragma once /*** This file is part of systemd. - Copyright 2014 Lennart Poettering + Copyright 2016 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -19,19 +19,10 @@ along with systemd; If not, see . ***/ -#pragma once +#include "resolved-manager.h" +#include "resolved-dns-question.h" +#include "resolved-dns-answer.h" -#include "sd-event.h" -#include "util.h" - -typedef enum { DKR_PULL_V1, DKR_PULL_V2 } DkrPullVersion; -typedef struct DkrPull DkrPull; - -typedef void (*DkrPullFinished)(DkrPull *pull, int error, void *userdata); - -int dkr_pull_new(DkrPull **pull, sd_event *event, const char *index_url, const char *image_root, DkrPullFinished on_finished, void *userdata); -DkrPull* dkr_pull_unref(DkrPull *pull); - -DEFINE_TRIVIAL_CLEANUP_FUNC(DkrPull*, dkr_pull_unref); - -int dkr_pull_start(DkrPull *pull, const char *name, const char *tag, const char *local, bool force_local, DkrPullVersion version); +void manager_etc_hosts_flush(Manager *m); +int manager_etc_hosts_read(Manager *m); +int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer); diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf index 8e78fbf06..82f26215d 100644 --- a/src/resolve/resolved-gperf.gperf +++ b/src/resolve/resolved-gperf.gperf @@ -14,6 +14,8 @@ 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_resolve_support, 0, offsetof(Manager, llmnr_support) +Resolve.DNSSEC, config_parse_dnssec_mode, 0, offsetof(Manager, dnssec_mode) diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c new file mode 100644 index 000000000..df7516f4f --- /dev/null +++ b/src/resolve/resolved-link-bus.c @@ -0,0 +1,550 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "alloc-util.h" +#include "bus-util.h" +#include "parse-util.h" +#include "resolve-util.h" +#include "resolved-bus.h" +#include "resolved-link-bus.h" +#include "strv.h" + +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_resolve_support, resolve_support, ResolveSupport); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_dnssec_mode, dnssec_mode, DnssecMode); + +static int property_get_dns( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = userdata; + DnsServer *s; + int r; + + assert(reply); + assert(l); + + r = sd_bus_message_open_container(reply, 'a', "(iay)"); + if (r < 0) + return r; + + LIST_FOREACH(servers, s, l->dns_servers) { + r = bus_dns_server_append(reply, s, false); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_domains( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = userdata; + DnsSearchDomain *d; + int r; + + assert(reply); + assert(l); + + r = sd_bus_message_open_container(reply, 'a', "(sb)"); + if (r < 0) + return r; + + LIST_FOREACH(domains, d, l->search_domains) { + r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_scopes_mask( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = userdata; + uint64_t mask; + + assert(reply); + assert(l); + + mask = (l->unicast_scope ? SD_RESOLVED_DNS : 0) | + (l->llmnr_ipv4_scope ? SD_RESOLVED_LLMNR_IPV4 : 0) | + (l->llmnr_ipv6_scope ? SD_RESOLVED_LLMNR_IPV6 : 0) | + (l->mdns_ipv4_scope ? SD_RESOLVED_MDNS_IPV4 : 0) | + (l->mdns_ipv6_scope ? SD_RESOLVED_MDNS_IPV6 : 0); + + return sd_bus_message_append(reply, "t", mask); +} + +static int property_get_ntas( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = userdata; + const char *name; + Iterator i; + int r; + + assert(reply); + assert(l); + + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; + + SET_FOREACH(name, l->dnssec_negative_trust_anchors, i) { + r = sd_bus_message_append(reply, "s", name); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + +static int property_get_dnssec_supported( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Link *l = userdata; + + assert(reply); + assert(l); + + return sd_bus_message_append(reply, "b", link_dnssec_supported(l)); +} + +int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ struct in_addr_data *dns = NULL; + size_t allocated = 0, n = 0; + Link *l = userdata; + unsigned i; + int r; + + assert(message); + assert(l); + + r = sd_bus_message_enter_container(message, 'a', "(iay)"); + if (r < 0) + return r; + + for (;;) { + int family; + size_t sz; + const void *d; + + assert_cc(sizeof(int) == sizeof(int32_t)); + + r = sd_bus_message_enter_container(message, 'r', "iay"); + if (r < 0) + return r; + if (r == 0) + break; + + r = sd_bus_message_read(message, "i", &family); + if (r < 0) + return r; + + if (!IN_SET(family, AF_INET, AF_INET6)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family); + + r = sd_bus_message_read_array(message, 'y', &d, &sz); + if (r < 0) + return r; + if (sz != FAMILY_ADDRESS_SIZE(family)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size"); + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (!GREEDY_REALLOC(dns, allocated, n+1)) + return -ENOMEM; + + dns[n].family = family; + memcpy(&dns[n].address, d, sz); + n++; + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + dns_server_mark_all(l->dns_servers); + + for (i = 0; i < n; i++) { + DnsServer *s; + + s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address); + if (s) + dns_server_move_back_and_unmark(s); + else { + r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address); + if (r < 0) + goto clear; + } + + } + + dns_server_unlink_marked(l->dns_servers); + link_allocate_scopes(l); + + return sd_bus_reply_method_return(message, NULL); + +clear: + dns_server_unlink_all(l->dns_servers); + return r; +} + +int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + int r; + + assert(message); + assert(l); + + r = sd_bus_message_enter_container(message, 'a', "(sb)"); + if (r < 0) + return r; + + for (;;) { + const char *name; + int route_only; + + r = sd_bus_message_read(message, "(sb)", &name, &route_only); + if (r < 0) + return r; + if (r == 0) + break; + + 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 search domain %s", name); + if (!route_only && dns_name_is_root(name)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain"); + } + + dns_search_domain_mark_all(l->search_domains); + + r = sd_bus_message_rewind(message, false); + if (r < 0) + return r; + + for (;;) { + DnsSearchDomain *d; + const char *name; + int route_only; + + r = sd_bus_message_read(message, "(sb)", &name, &route_only); + if (r < 0) + goto clear; + if (r == 0) + break; + + r = dns_search_domain_find(l->search_domains, name, &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, &d, DNS_SEARCH_DOMAIN_LINK, l, name); + if (r < 0) + goto clear; + } + + d->route_only = route_only; + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + goto clear; + + dns_search_domain_unlink_marked(l->search_domains); + return sd_bus_reply_method_return(message, NULL); + +clear: + dns_search_domain_unlink_all(l->search_domains); + return r; +} + +int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + ResolveSupport mode; + const char *llmnr; + int r; + + assert(message); + assert(l); + + r = sd_bus_message_read(message, "s", &llmnr); + if (r < 0) + return r; + + if (isempty(llmnr)) + mode = RESOLVE_SUPPORT_YES; + else { + mode = resolve_support_from_string(llmnr); + if (mode < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr); + } + + l->llmnr_support = mode; + link_allocate_scopes(l); + link_add_rrs(l, false); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + ResolveSupport mode; + const char *mdns; + int r; + + assert(message); + assert(l); + + r = sd_bus_message_read(message, "s", &mdns); + if (r < 0) + return r; + + if (isempty(mdns)) + mode = RESOLVE_SUPPORT_NO; + else { + mode = resolve_support_from_string(mdns); + if (mode < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns); + } + + l->mdns_support = mode; + link_allocate_scopes(l); + link_add_rrs(l, false); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + const char *dnssec; + DnssecMode mode; + int r; + + assert(message); + assert(l); + + r = sd_bus_message_read(message, "s", &dnssec); + if (r < 0) + return r; + + if (isempty(dnssec)) + mode = _DNSSEC_MODE_INVALID; + else { + mode = dnssec_mode_from_string(dnssec); + if (mode < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec); + } + + link_set_dnssec_mode(l, mode); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_set_free_free_ Set *ns = NULL; + _cleanup_free_ char **ntas = NULL; + Link *l = userdata; + int r; + char **i; + + assert(message); + assert(l); + + r = sd_bus_message_read_strv(message, &ntas); + if (r < 0) + return r; + + STRV_FOREACH(i, ntas) { + r = dns_name_is_valid(*i); + if (r < 0) + return r; + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i); + } + + ns = set_new(&dns_name_hash_ops); + if (!ns) + return -ENOMEM; + + STRV_FOREACH(i, ntas) { + r = set_put_strdup(ns, *i); + if (r < 0) + return r; + } + + set_free_free(l->dnssec_negative_trust_anchors); + l->dnssec_negative_trust_anchors = ns; + ns = NULL; + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Link *l = userdata; + + assert(message); + assert(l); + + link_flush_settings(l); + link_allocate_scopes(l); + link_add_rrs(l, false); + + return sd_bus_reply_method_return(message, NULL); +} + +const sd_bus_vtable link_vtable[] = { + SD_BUS_VTABLE_START(0), + + SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0), + SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0), + SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0), + SD_BUS_PROPERTY("LLMNR", "s", property_get_resolve_support, offsetof(Link, llmnr_support), 0), + SD_BUS_PROPERTY("MulticastDNS", "s", property_get_resolve_support, offsetof(Link, mdns_support), 0), + SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, offsetof(Link, dnssec_mode), 0), + SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0), + SD_BUS_PROPERTY("DNSSECSupport", "b", property_get_dnssec_supported, 0, 0), + + SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0), + SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_search_domains, 0), + SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0), + SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0), + SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0), + SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, 0), + SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, 0), + + SD_BUS_VTABLE_END +}; + +int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) { + _cleanup_free_ char *e = NULL; + Manager *m = userdata; + int ifindex; + Link *link; + int r; + + assert(bus); + assert(path); + assert(interface); + assert(found); + assert(m); + + r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/link", &e); + if (r <= 0) + return 0; + + r = parse_ifindex(e, &ifindex); + if (r < 0) + return 0; + + link = hashmap_get(m->links, INT_TO_PTR(ifindex)); + if (!link) + return 0; + + *found = link; + return 1; +} + +char *link_bus_path(Link *link) { + _cleanup_free_ char *ifindex = NULL; + char *p; + int r; + + assert(link); + + if (asprintf(&ifindex, "%i", link->ifindex) < 0) + return NULL; + + r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex, &p); + if (r < 0) + return NULL; + + return p; +} + +int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) { + _cleanup_strv_free_ char **l = NULL; + Manager *m = userdata; + Link *link; + Iterator i; + unsigned c = 0; + + assert(bus); + assert(path); + assert(m); + assert(nodes); + + l = new0(char*, hashmap_size(m->links) + 1); + if (!l) + return -ENOMEM; + + HASHMAP_FOREACH(link, m->links, i) { + char *p; + + p = link_bus_path(link); + if (!p) + return -ENOMEM; + + l[c++] = p; + } + + l[c] = NULL; + *nodes = l; + l = NULL; + + return 1; +} diff --git a/src/resolve/resolved-link-bus.h b/src/resolve/resolved-link-bus.h new file mode 100644 index 000000000..31e6cd2b4 --- /dev/null +++ b/src/resolve/resolved-link-bus.h @@ -0,0 +1,38 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "sd-bus.h" + +#include "resolved-link.h" + +extern const sd_bus_vtable link_vtable[]; + +int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error); +char *link_bus_path(Link *link); +int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error); + +int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_search_domains(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error); diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 289264107..c5863b3aa 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -46,7 +44,10 @@ int link_new(Manager *m, Link **ret, int ifindex) { return -ENOMEM; l->ifindex = ifindex; - l->llmnr_support = SUPPORT_YES; + l->llmnr_support = RESOLVE_SUPPORT_YES; + l->mdns_support = RESOLVE_SUPPORT_NO; + l->dnssec_mode = _DNSSEC_MODE_INVALID; + l->operstate = IF_OPER_UNKNOWN; r = hashmap_put(m->links, INT_TO_PTR(ifindex), l); if (r < 0) @@ -61,37 +62,48 @@ int link_new(Manager *m, Link **ret, int ifindex) { return 0; } +void link_flush_settings(Link *l) { + assert(l); + + l->llmnr_support = RESOLVE_SUPPORT_YES; + l->mdns_support = RESOLVE_SUPPORT_NO; + l->dnssec_mode = _DNSSEC_MODE_INVALID; + + dns_server_unlink_all(l->dns_servers); + dns_search_domain_unlink_all(l->search_domains); + + l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors); +} + Link *link_free(Link *l) { if (!l) return NULL; + link_flush_settings(l); + while (l->addresses) - link_address_free(l->addresses); + (void) 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); + dns_scope_free(l->mdns_ipv4_scope); + dns_scope_free(l->mdns_ipv6_scope); free(l); return NULL; } -static void link_allocate_scopes(Link *l) { +void link_allocate_scopes(Link *l) { int r; assert(l); - if (l->dns_servers) { + if (link_relevant(l, AF_UNSPEC, false) && + l->dns_servers) { if (!l->unicast_scope) { r = dns_scope_new(l->manager, &l->unicast_scope, l, DNS_PROTOCOL_DNS, AF_UNSPEC); if (r < 0) @@ -100,9 +112,9 @@ static void link_allocate_scopes(Link *l) { } else l->unicast_scope = dns_scope_free(l->unicast_scope); - if (link_relevant(l, AF_INET) && - l->llmnr_support != SUPPORT_NO && - l->manager->llmnr_support != SUPPORT_NO) { + if (link_relevant(l, AF_INET, true) && + l->llmnr_support != RESOLVE_SUPPORT_NO && + l->manager->llmnr_support != RESOLVE_SUPPORT_NO) { if (!l->llmnr_ipv4_scope) { r = dns_scope_new(l->manager, &l->llmnr_ipv4_scope, l, DNS_PROTOCOL_LLMNR, AF_INET); if (r < 0) @@ -111,9 +123,9 @@ static void link_allocate_scopes(Link *l) { } else l->llmnr_ipv4_scope = dns_scope_free(l->llmnr_ipv4_scope); - if (link_relevant(l, AF_INET6) && - l->llmnr_support != SUPPORT_NO && - l->manager->llmnr_support != SUPPORT_NO && + if (link_relevant(l, AF_INET6, true) && + l->llmnr_support != RESOLVE_SUPPORT_NO && + l->manager->llmnr_support != RESOLVE_SUPPORT_NO && socket_ipv6_is_supported()) { if (!l->llmnr_ipv6_scope) { r = dns_scope_new(l->manager, &l->llmnr_ipv6_scope, l, DNS_PROTOCOL_LLMNR, AF_INET6); @@ -122,6 +134,28 @@ static void link_allocate_scopes(Link *l) { } } else l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope); + + if (link_relevant(l, AF_INET, true) && + l->mdns_support != RESOLVE_SUPPORT_NO && + l->manager->mdns_support != RESOLVE_SUPPORT_NO) { + if (!l->mdns_ipv4_scope) { + r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET); + if (r < 0) + log_warning_errno(r, "Failed to allocate mDNS IPv4 scope: %m"); + } + } else + l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope); + + if (link_relevant(l, AF_INET6, true) && + l->mdns_support != RESOLVE_SUPPORT_NO && + l->manager->mdns_support != RESOLVE_SUPPORT_NO) { + if (!l->mdns_ipv6_scope) { + r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6); + if (r < 0) + log_warning_errno(r, "Failed to allocate mDNS IPv6 scope: %m"); + } + } else + l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope); } void link_add_rrs(Link *l, bool force_remove) { @@ -142,7 +176,8 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) { if (r < 0) return r; - sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu); + (void) sd_netlink_message_read_u32(m, IFLA_MTU, &l->mtu); + (void) sd_netlink_message_read_u8(m, IFLA_OPERSTATE, &l->operstate); if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) { strncpy(l->name, n, sizeof(l->name)-1); @@ -158,29 +193,32 @@ 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); r = sd_network_link_get_dns(l->ifindex, &nameservers); + if (r == -ENODATA) { + r = 0; + goto clear; + } 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 +226,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; } @@ -214,78 +241,315 @@ static int link_update_llmnr_support(Link *l) { assert(l); r = sd_network_link_get_llmnr(l->ifindex, &b); + if (r == -ENODATA) { + r = 0; + goto clear; + } if (r < 0) goto clear; - r = parse_boolean(b); - if (r < 0) { - if (streq(b, "resolve")) - l->llmnr_support = SUPPORT_RESOLVE; - else - goto clear; - - } else if (r > 0) - l->llmnr_support = SUPPORT_YES; - else - l->llmnr_support = SUPPORT_NO; + l->llmnr_support = resolve_support_from_string(b); + if (l->llmnr_support < 0) { + r = -EINVAL; + goto clear; + } return 0; clear: - l->llmnr_support = SUPPORT_YES; + l->llmnr_support = RESOLVE_SUPPORT_YES; return r; } -static int link_update_domains(Link *l) { +static int link_update_mdns_support(Link *l) { + _cleanup_free_ char *b = NULL; int r; - if (!l->unicast_scope) - return 0; + assert(l); - l->unicast_scope->domains = strv_free(l->unicast_scope->domains); + r = sd_network_link_get_mdns(l->ifindex, &b); + if (r == -ENODATA) { + r = 0; + goto clear; + } + if (r < 0) + goto clear; - r = sd_network_link_get_domains(l->ifindex, - &l->unicast_scope->domains); + l->mdns_support = resolve_support_from_string(b); + if (l->mdns_support < 0) { + r = -EINVAL; + goto clear; + } + + return 0; + +clear: + l->mdns_support = RESOLVE_SUPPORT_NO; + return r; +} + +void link_set_dnssec_mode(Link *l, DnssecMode mode) { + + assert(l); + + if (l->dnssec_mode == mode) + return; + + if ((l->dnssec_mode == _DNSSEC_MODE_INVALID) || + (l->dnssec_mode == DNSSEC_NO && mode != DNSSEC_NO) || + (l->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE && mode == DNSSEC_YES)) { + + /* When switching from non-DNSSEC mode to DNSSEC mode, flush the cache. Also when switching from the + * allow-downgrade mode to full DNSSEC mode, flush it too. */ + if (l->unicast_scope) + dns_cache_flush(&l->unicast_scope->cache); + } + + l->dnssec_mode = mode; +} + +static int link_update_dnssec_mode(Link *l) { + _cleanup_free_ char *m = NULL; + DnssecMode mode; + int r; + + assert(l); + + r = sd_network_link_get_dnssec(l->ifindex, &m); + if (r == -ENODATA) { + r = 0; + goto clear; + } + if (r < 0) + goto clear; + + mode = dnssec_mode_from_string(m); + if (mode < 0) { + r = -EINVAL; + goto clear; + } + + link_set_dnssec_mode(l, mode); + + return 0; + +clear: + l->dnssec_mode = _DNSSEC_MODE_INVALID; + return r; +} + +static int link_update_dnssec_negative_trust_anchors(Link *l) { + _cleanup_strv_free_ char **ntas = NULL; + _cleanup_set_free_free_ Set *ns = NULL; + char **i; + int r; + + assert(l); + + r = sd_network_link_get_dnssec_negative_trust_anchors(l->ifindex, &ntas); + if (r == -ENODATA) { + r = 0; + goto clear; + } + if (r < 0) + goto clear; + + ns = set_new(&dns_name_hash_ops); + if (!ns) + return -ENOMEM; + + STRV_FOREACH(i, ntas) { + r = set_put_strdup(ns, *i); + if (r < 0) + return r; + } + + set_free_free(l->dnssec_negative_trust_anchors); + l->dnssec_negative_trust_anchors = ns; + ns = NULL; + + return 0; + +clear: + l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors); + return r; +} + +static int link_update_search_domain_one(Link *l, const char *name, bool route_only) { + DnsSearchDomain *d; + int r; + + r = dns_search_domain_find(l->search_domains, name, &d); + if (r < 0) + return r; + if (r > 0) + dns_search_domain_move_back_and_unmark(d); + else { + r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name); + if (r < 0) + return r; + } + + d->route_only = route_only; + return 0; +} + +static int link_update_search_domains(Link *l) { + _cleanup_strv_free_ char **sdomains = NULL, **rdomains = NULL; + char **i; + int r, q; + + assert(l); + + r = sd_network_link_get_search_domains(l->ifindex, &sdomains); + if (r < 0 && r != -ENODATA) + goto clear; + + q = sd_network_link_get_route_domains(l->ifindex, &rdomains); + if (q < 0 && q != -ENODATA) { + r = q; + goto clear; + } + + if (r == -ENODATA && q == -ENODATA) { + /* networkd knows nothing about this interface, and that's fine. */ + r = 0; + goto clear; + } + + dns_search_domain_mark_all(l->search_domains); + + STRV_FOREACH(i, sdomains) { + r = link_update_search_domain_one(l, *i, false); + if (r < 0) + goto clear; + } + + STRV_FOREACH(i, rdomains) { + r = link_update_search_domain_one(l, *i, true); + 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; +} + +static int link_is_unmanaged(Link *l) { + _cleanup_free_ char *state = NULL; + int r; + + assert(l); + + r = sd_network_link_get_setup_state(l->ifindex, &state); + if (r == -ENODATA) + return 1; if (r < 0) return r; - return 0; + return STR_IN_SET(state, "pending", "unmanaged"); +} + +static void link_read_settings(Link *l) { + int r; + + assert(l); + + /* Read settings from networkd, except when networkd is not managing this interface. */ + + r = link_is_unmanaged(l); + if (r < 0) { + log_warning_errno(r, "Failed to determine whether interface %s is managed: %m", l->name); + return; + } + if (r > 0) { + + /* If this link used to be managed, but is now unmanaged, flush all our settings -- but only once. */ + if (l->is_managed) + link_flush_settings(l); + + l->is_managed = false; + return; + } + + l->is_managed = true; + + r = link_update_dns_servers(l); + if (r < 0) + log_warning_errno(r, "Failed to read DNS servers for interface %s, ignoring: %m", l->name); + + r = link_update_llmnr_support(l); + if (r < 0) + log_warning_errno(r, "Failed to read LLMNR support for interface %s, ignoring: %m", l->name); + + r = link_update_mdns_support(l); + if (r < 0) + log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name); + + r = link_update_dnssec_mode(l); + if (r < 0) + log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name); + + r = link_update_dnssec_negative_trust_anchors(l); + if (r < 0) + log_warning_errno(r, "Failed to read DNSSEC negative trust anchors for interface %s, ignoring: %m", l->name); + + 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); } int link_update_monitor(Link *l) { assert(l); - link_update_dns_servers(l); - link_update_llmnr_support(l); + link_read_settings(l); link_allocate_scopes(l); - link_update_domains(l); link_add_rrs(l, false); return 0; } -bool link_relevant(Link *l, int family) { +bool link_relevant(Link *l, int family, bool local_multicast) { _cleanup_free_ char *state = NULL; LinkAddress *a; assert(l); - /* A link is relevant if it isn't a loopback or pointopoint - * device, has a link beat, can do multicast and has at least - * one relevant IP address */ + /* A link is relevant for local multicast traffic if it isn't a loopback or pointopoint device, has a link + * beat, can do multicast and has at least one link-local (or better) IP address. + * + * A link is relevant for non-multicast traffic if it isn't a loopback device, has a link beat, and has at + * least one routable address.*/ - if (l->flags & (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_DORMANT)) + if (l->flags & (IFF_LOOPBACK|IFF_DORMANT)) return false; - if ((l->flags & (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) != (IFF_UP|IFF_LOWER_UP|IFF_MULTICAST)) + if ((l->flags & (IFF_UP|IFF_LOWER_UP)) != (IFF_UP|IFF_LOWER_UP)) return false; - sd_network_link_get_operational_state(l->ifindex, &state); + if (local_multicast) { + if (l->flags & IFF_POINTOPOINT) + return false; + + if ((l->flags & IFF_MULTICAST) != IFF_MULTICAST) + return false; + } + + /* Check kernel operstate + * https://www.kernel.org/doc/Documentation/networking/operstates.txt */ + if (!IN_SET(l->operstate, IF_OPER_UNKNOWN, IF_OPER_UP)) + return false; + + (void) sd_network_link_get_operational_state(l->ifindex, &state); if (state && !STR_IN_SET(state, "unknown", "degraded", "routable")) return false; LIST_FOREACH(addresses, a, l->addresses) - if (a->family == family && link_address_relevant(a)) + if ((family == AF_UNSPEC || a->family == family) && link_address_relevant(a, local_multicast)) return true; return false; @@ -303,31 +567,17 @@ 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); if (l->current_dns_server == s) return s; - if (s) { - _cleanup_free_ char *ip = NULL; + if (s) + log_info("Switching to DNS server %s for interface %s.", dns_server_string(s), l->name); - in_addr_to_string(s->family, &s->address, &ip); - 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 +600,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; } @@ -358,6 +610,30 @@ void link_next_dns_server(Link *l) { link_set_dns_server(l, l->dns_servers); } +DnssecMode link_get_dnssec_mode(Link *l) { + assert(l); + + if (l->dnssec_mode != _DNSSEC_MODE_INVALID) + return l->dnssec_mode; + + return manager_get_dnssec_mode(l->manager); +} + +bool link_dnssec_supported(Link *l) { + DnsServer *server; + + assert(l); + + if (link_get_dnssec_mode(l) == DNSSEC_NO) + return false; + + server = link_get_dns_server(l); + if (server) + return dns_server_dnssec_supported(server); + + return true; +} + int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr) { LinkAddress *a; @@ -417,10 +693,10 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { if (a->family == AF_INET) { if (!force_remove && - link_address_relevant(a) && + link_address_relevant(a, true) && a->link->llmnr_ipv4_scope && - a->link->llmnr_support == SUPPORT_YES && - a->link->manager->llmnr_support == SUPPORT_YES) { + a->link->llmnr_support == RESOLVE_SUPPORT_YES && + a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) { if (!a->link->manager->llmnr_host_ipv4_key) { a->link->manager->llmnr_host_ipv4_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_A, a->link->manager->llmnr_hostname); @@ -474,10 +750,10 @@ void link_address_add_rrs(LinkAddress *a, bool force_remove) { if (a->family == AF_INET6) { if (!force_remove && - link_address_relevant(a) && + link_address_relevant(a, true) && a->link->llmnr_ipv6_scope && - a->link->llmnr_support == SUPPORT_YES && - a->link->manager->llmnr_support == SUPPORT_YES) { + a->link->llmnr_support == RESOLVE_SUPPORT_YES && + a->link->manager->llmnr_support == RESOLVE_SUPPORT_YES) { if (!a->link->manager->llmnr_host_ipv6_key) { a->link->manager->llmnr_host_ipv6_key = dns_resource_key_new(DNS_CLASS_IN, DNS_TYPE_AAAA, a->link->manager->llmnr_hostname); @@ -551,13 +827,13 @@ int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) { return 0; } -bool link_address_relevant(LinkAddress *a) { +bool link_address_relevant(LinkAddress *a, bool local_multicast) { assert(a); if (a->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE)) return false; - if (IN_SET(a->scope, RT_SCOPE_HOST, RT_SCOPE_NOWHERE)) + if (a->scope >= (local_multicast ? RT_SCOPE_HOST : RT_SCOPE_LINK)) return false; return true; diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index e3ab27c24..f534c1282 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,13 +23,19 @@ #include "in-addr-util.h" #include "ratelimit.h" +#include "resolve-util.h" 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,34 +60,52 @@ struct Link { LIST_HEAD(DnsServer, dns_servers); DnsServer *current_dns_server; + unsigned n_dns_servers; - Support llmnr_support; + LIST_HEAD(DnsSearchDomain, search_domains); + unsigned n_search_domains; + + ResolveSupport llmnr_support; + ResolveSupport mdns_support; + DnssecMode dnssec_mode; + Set *dnssec_negative_trust_anchors; DnsScope *unicast_scope; DnsScope *llmnr_ipv4_scope; DnsScope *llmnr_ipv6_scope; + DnsScope *mdns_ipv4_scope; + DnsScope *mdns_ipv6_scope; + + bool is_managed; char name[IF_NAMESIZE]; uint32_t mtu; + uint8_t operstate; }; int link_new(Manager *m, Link **ret, int ifindex); Link *link_free(Link *l); int link_update_rtnl(Link *l, sd_netlink_message *m); int link_update_monitor(Link *l); -bool link_relevant(Link *l, int family); +bool link_relevant(Link *l, int family, bool local_multicast); LinkAddress* link_find_address(Link *l, int family, const union in_addr_union *in_addr); void link_add_rrs(Link *l, bool force_remove); +void link_flush_settings(Link *l); +void link_set_dnssec_mode(Link *l, DnssecMode mode); +void link_allocate_scopes(Link *l); + 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); +DnssecMode link_get_dnssec_mode(Link *l); +bool link_dnssec_supported(Link *l); + int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr_union *in_addr); LinkAddress *link_address_free(LinkAddress *a); int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m); -bool link_address_relevant(LinkAddress *l); +bool link_address_relevant(LinkAddress *l, bool local_multicast); void link_address_add_rrs(LinkAddress *a, bool force_remove); DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_free); diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index 6a7ff9d24..ef12abfbb 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -47,7 +45,7 @@ int manager_llmnr_start(Manager *m) { assert(m); - if (m->llmnr_support == SUPPORT_NO) + if (m->llmnr_support == RESOLVE_SUPPORT_NO) return 0; r = manager_llmnr_ipv4_udp_fd(m); @@ -80,7 +78,7 @@ int manager_llmnr_start(Manager *m) { eaddrinuse: log_warning("There appears to be another LLMNR responder running. Turning off LLMNR support."); - m->llmnr_support = SUPPORT_NO; + m->llmnr_support = RESOLVE_SUPPORT_NO; manager_llmnr_stop(m); return 0; @@ -117,7 +115,7 @@ static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *u dns_scope_process_query(scope, NULL, p); } else - log_debug("Invalid LLMNR UDP packet."); + log_debug("Invalid LLMNR UDP packet, ignoring."); return 0; } @@ -193,6 +191,8 @@ int manager_llmnr_ipv4_udp_fd(Manager *m) { if (r < 0) goto fail; + (void) sd_event_source_set_description(m->llmnr_ipv4_udp_event_source, "llmnr-ipv4-udp"); + return m->llmnr_ipv4_udp_fd; fail: @@ -267,10 +267,10 @@ int manager_llmnr_ipv6_udp_fd(Manager *m) { } r = sd_event_add_io(m->event, &m->llmnr_ipv6_udp_event_source, m->llmnr_ipv6_udp_fd, EPOLLIN, on_llmnr_packet, m); - if (r < 0) { - r = -errno; + if (r < 0) goto fail; - } + + (void) sd_event_source_set_description(m->llmnr_ipv6_udp_event_source, "llmnr-ipv6-udp"); return m->llmnr_ipv6_udp_fd; @@ -393,6 +393,8 @@ int manager_llmnr_ipv4_tcp_fd(Manager *m) { if (r < 0) goto fail; + (void) sd_event_source_set_description(m->llmnr_ipv4_tcp_event_source, "llmnr-ipv4-tcp"); + return m->llmnr_ipv4_tcp_fd; fail: @@ -461,10 +463,10 @@ int manager_llmnr_ipv6_tcp_fd(Manager *m) { } r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m); - if (r < 0) { - r = -errno; + if (r < 0) goto fail; - } + + (void) sd_event_source_set_description(m->llmnr_ipv6_tcp_event_source, "llmnr-ipv6-tcp"); return m->llmnr_ipv6_tcp_fd; diff --git a/src/resolve/resolved-llmnr.h b/src/resolve/resolved-llmnr.h index d489d481e..8133582fa 100644 --- a/src/resolve/resolved-llmnr.h +++ b/src/resolve/resolved-llmnr.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index a588538b5..bf5efe4cf 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,7 +19,6 @@ #include #include -#include #include #include "af-list.h" @@ -38,8 +35,11 @@ #include "random-util.h" #include "resolved-bus.h" #include "resolved-conf.h" +#include "resolved-etc-hosts.h" #include "resolved-llmnr.h" #include "resolved-manager.h" +#include "resolved-mdns.h" +#include "resolved-resolv-conf.h" #include "socket-util.h" #include "string-table.h" #include "string-util.h" @@ -193,7 +193,7 @@ fail: } static int manager_rtnl_listen(Manager *m) { - _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; sd_netlink_message *i; int r; @@ -204,7 +204,7 @@ static int manager_rtnl_listen(Manager *m) { if (r < 0) return r; - r = sd_netlink_attach_event(m->rtnl, m->event, 0); + r = sd_netlink_attach_event(m->rtnl, m->event, SD_EVENT_PRIORITY_IMPORTANT); if (r < 0) return r; @@ -286,7 +286,7 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void * r = manager_write_resolv_conf(m); if (r < 0) - log_warning_errno(r, "Could not update resolv.conf: %m"); + log_warning_errno(r, "Could not update "PRIVATE_RESOLV_CONF": %m"); return 0; } @@ -312,6 +312,12 @@ static int manager_network_monitor_listen(Manager *m) { if (r < 0) return r; + r = sd_event_source_set_priority(m->network_event_source, SD_EVENT_PRIORITY_IMPORTANT+5); + if (r < 0) + return r; + + (void) sd_event_source_set_description(m->network_event_source, "network-monitor"); + return 0; } @@ -351,7 +357,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"); @@ -419,6 +425,8 @@ static int manager_watch_hostname(Manager *m) { return log_error_errno(r, "Failed to add hostname event source: %m"); } + (void) sd_event_source_set_description(m->hostname_event_source, "hostname"); + r = determine_hostname(&m->llmnr_hostname, &m->mdns_hostname); if (r < 0) { log_info("Defaulting to hostname 'linux'."); @@ -472,12 +480,21 @@ int manager_new(Manager **ret) { m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1; m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1; + m->mdns_ipv4_fd = m->mdns_ipv6_fd = -1; m->hostname_fd = -1; - m->llmnr_support = SUPPORT_YES; + m->llmnr_support = RESOLVE_SUPPORT_YES; + m->mdns_support = RESOLVE_SUPPORT_NO; + m->dnssec_mode = DNSSEC_NO; m->read_resolv_conf = true; + m->need_builtin_fallbacks = true; + m->etc_hosts_last = m->etc_hosts_mtime = USEC_INFINITY; - r = manager_parse_dns_server(m, DNS_SERVER_FALLBACK, DNS_SERVERS); + r = dns_trust_anchor_load(&m->trust_anchor); + if (r < 0) + return r; + + r = manager_parse_config_file(m); if (r < 0) return r; @@ -527,6 +544,10 @@ int manager_start(Manager *m) { if (r < 0) return r; + r = manager_mdns_start(m); + if (r < 0) + return r; + return 0; } @@ -536,15 +557,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,7 +575,11 @@ 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); + manager_mdns_stop(m); sd_bus_slot_unref(m->prepare_for_sleep_slot); sd_event_source_unref(m->bus_retry_event_source); @@ -571,299 +597,14 @@ Manager *manager_free(Manager *m) { free(m->llmnr_hostname); free(m->mdns_hostname); + dns_trust_anchor_flush(&m->trust_anchor); + manager_etc_hosts_flush(m); + free(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 { @@ -1046,7 +787,7 @@ static int write_loop(int fd, void *message, size_t length) { int manager_write(Manager *m, int fd, DnsPacket *p) { int r; - log_debug("Sending %s packet with id %u", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p)); + log_debug("Sending %s packet with id %" PRIu16 ".", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p)); r = write_loop(fd, DNS_PACKET_DATA(p), p->size); if (r < 0) @@ -1161,7 +902,7 @@ int manager_send(Manager *m, int fd, int ifindex, int family, const union in_add assert(port > 0); assert(p); - log_debug("Sending %s packet with id %u on interface %i/%s", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p), ifindex, af_to_name(family)); + log_debug("Sending %s packet with id %" PRIu16 " on interface %i/%s.", DNS_PACKET_QR(p) ? "response" : "query", DNS_PACKET_ID(p), ifindex, af_to_name(family)); if (family == AF_INET) return manager_ipv4_send(m, fd, ifindex, &addr->in, port, p); @@ -1171,97 +912,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; @@ -1396,11 +1046,25 @@ DnsScope* manager_find_scope(Manager *m, DnsPacket *p) { if (!l) return NULL; - if (p->protocol == DNS_PROTOCOL_LLMNR) { + switch (p->protocol) { + case DNS_PROTOCOL_LLMNR: if (p->family == AF_INET) return l->llmnr_ipv4_scope; else if (p->family == AF_INET6) return l->llmnr_ipv6_scope; + + break; + + case DNS_PROTOCOL_MDNS: + if (p->family == AF_INET) + return l->mdns_ipv4_scope; + else if (p->family == AF_INET6) + return l->mdns_ipv6_scope; + + break; + + default: + break; } return NULL; @@ -1415,28 +1079,6 @@ void manager_verify_all(Manager *m) { dns_zone_verify_all(&s->zone); } -void manager_flush_dns_servers(Manager *m, DnsServerType t) { - DnsServer *s; - - assert(m); - - if (t == DNS_SERVER_SYSTEM) - while (m->dns_servers) { - s = m->dns_servers; - - LIST_REMOVE(servers, m->dns_servers, s); - dns_server_unref(s); - } - - 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); - } -} - int manager_is_own_hostname(Manager *m, const char *name) { int r; @@ -1455,9 +1097,145 @@ int manager_is_own_hostname(Manager *m, const char *name) { return 0; } -static const char* const support_table[_SUPPORT_MAX] = { - [SUPPORT_NO] = "no", - [SUPPORT_YES] = "yes", - [SUPPORT_RESOLVE] = "resolve", -}; -DEFINE_STRING_TABLE_LOOKUP(support, Support); +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; + + /* 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; + } + + /* 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 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_compile_search_domains(Manager *m, OrderedSet **domains) { + DnsSearchDomain *d; + Iterator i; + Link *l; + int r; + + assert(m); + assert(domains); + + 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; + } + + 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; +} + +DnssecMode manager_get_dnssec_mode(Manager *m) { + assert(m); + + if (m->dnssec_mode != _DNSSEC_MODE_INVALID) + return m->dnssec_mode; + + return DNSSEC_NO; +} + +bool manager_dnssec_supported(Manager *m) { + DnsServer *server; + Iterator i; + Link *l; + + assert(m); + + if (manager_get_dnssec_mode(m) == DNSSEC_NO) + return false; + + server = manager_get_dns_server(m); + if (server && !dns_server_dnssec_supported(server)) + return false; + + HASHMAP_FOREACH(l, m->links, i) + if (!link_dnssec_supported(l)) + return false; + + return true; +} + +void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key) { + + assert(verdict >= 0); + assert(verdict < _DNSSEC_VERDICT_MAX); + + if (log_get_max_level() >= LOG_DEBUG) { + _cleanup_free_ char *s = NULL; + + (void) dns_resource_key_to_string(key, &s); + + log_debug("Found verdict for lookup %s: %s", s ? strstrip(s) : "n/a", dnssec_verdict_to_string(verdict)); + } + + m->n_dnssec_verdict[verdict]++; +} + +bool manager_routable(Manager *m, int family) { + Iterator i; + Link *l; + + assert(m); + + /* Returns true if the host has at least one interface with a routable address of the specified type */ + + HASHMAP_FOREACH(l, m->links, i) + if (link_relevant(l, family, false)) + return true; + + return false; +} diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index fe7fe9950..e82a824f2 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,30 +20,32 @@ ***/ #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" +#include "resolve-util.h" typedef struct Manager Manager; -typedef enum Support Support; - -enum Support { - SUPPORT_NO, - SUPPORT_YES, - SUPPORT_RESOLVE, - _SUPPORT_MAX, - _SUPPORT_INVALID = -1 -}; #include "resolved-dns-query.h" +#include "resolved-dns-search-domain.h" +#include "resolved-dns-server.h" #include "resolved-dns-stream.h" +#include "resolved-dns-trust-anchor.h" #include "resolved-link.h" +#define MANAGER_SEARCH_DOMAINS_MAX 32 +#define MANAGER_DNS_SERVERS_MAX 32 + struct Manager { sd_event *event; - Support llmnr_support; + ResolveSupport llmnr_support; + ResolveSupport mdns_support; + DnssecMode dnssec_mode; /* Network */ Hashmap *links; @@ -67,11 +67,20 @@ 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 permit_domain_search; + + bool need_builtin_fallbacks:1; + + bool read_resolv_conf:1; usec_t resolv_conf_mtime; + DnsTrustAnchor trust_anchor; + LIST_HEAD(DnsScope, dns_scopes); DnsScope *unicast_scope; @@ -86,6 +95,13 @@ struct Manager { sd_event_source *llmnr_ipv4_tcp_event_source; sd_event_source *llmnr_ipv6_tcp_event_source; + /* mDNS */ + int mdns_ipv4_fd; + int mdns_ipv6_fd; + + sd_event_source *mdns_ipv4_event_source; + sd_event_source *mdns_ipv6_event_source; + /* dbus */ sd_bus *bus; sd_event_source *bus_retry_event_source; @@ -104,6 +120,14 @@ struct Manager { sd_bus_slot *prepare_for_sleep_slot; sd_event_source *sigusr1_event_source; + + unsigned n_transactions_total; + unsigned n_dnssec_verdict[_DNSSEC_VERDICT_MAX]; + + /* Data from /etc/hosts */ + Set* etc_hosts_by_address; + Hashmap* etc_hosts_by_name; + usec_t etc_hosts_last, etc_hosts_mtime; }; /* Manager */ @@ -112,13 +136,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 +154,18 @@ 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); -const char* support_to_string(Support p) _const_; -int support_from_string(const char *s) _pure_; +int manager_compile_dns_servers(Manager *m, OrderedSet **servers); +int manager_compile_search_domains(Manager *m, OrderedSet **domains); + +DnssecMode manager_get_dnssec_mode(Manager *m); +bool manager_dnssec_supported(Manager *m); + +void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResourceKey *key); + +bool manager_routable(Manager *m, int family); diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c new file mode 100644 index 000000000..bc8b8b809 --- /dev/null +++ b/src/resolve/resolved-mdns.c @@ -0,0 +1,287 @@ +/*** + This file is part of systemd. + + Copyright 2015 Daniel Mack + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . + ***/ + +#include +#include +#include + +#include "fd-util.h" +#include "resolved-manager.h" +#include "resolved-mdns.h" + +void manager_mdns_stop(Manager *m) { + assert(m); + + m->mdns_ipv4_event_source = sd_event_source_unref(m->mdns_ipv4_event_source); + m->mdns_ipv4_fd = safe_close(m->mdns_ipv4_fd); + + m->mdns_ipv6_event_source = sd_event_source_unref(m->mdns_ipv6_event_source); + m->mdns_ipv6_fd = safe_close(m->mdns_ipv6_fd); +} + +int manager_mdns_start(Manager *m) { + int r; + + assert(m); + + if (m->mdns_support == RESOLVE_SUPPORT_NO) + return 0; + + r = manager_mdns_ipv4_fd(m); + if (r == -EADDRINUSE) + goto eaddrinuse; + if (r < 0) + return r; + + if (socket_ipv6_is_supported()) { + r = manager_mdns_ipv6_fd(m); + if (r == -EADDRINUSE) + goto eaddrinuse; + if (r < 0) + return r; + } + + return 0; + +eaddrinuse: + log_warning("There appears to be another mDNS responder running. Turning off mDNS support."); + m->mdns_support = RESOLVE_SUPPORT_NO; + manager_mdns_stop(m); + + return 0; +} + +static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + Manager *m = userdata; + DnsScope *scope; + int r; + + r = manager_recv(m, fd, DNS_PROTOCOL_MDNS, &p); + if (r <= 0) + return r; + + scope = manager_find_scope(m, p); + if (!scope) { + log_warning("Got mDNS UDP packet on unknown scope. Ignoring."); + return 0; + } + + if (dns_packet_validate_reply(p) > 0) { + DnsResourceRecord *rr; + + log_debug("Got mDNS reply packet"); + + /* + * mDNS is different from regular DNS and LLMNR with regard to handling responses. + * While on other protocols, we can ignore every answer that doesn't match a question + * we broadcast earlier, RFC6762, section 18.1 recommends looking at and caching all + * incoming information, regardless of the DNS packet ID. + * + * Hence, extract the packet here, and try to find a transaction for answer the we got + * and complete it. Also store the new information in scope's cache. + */ + r = dns_packet_extract(p); + if (r < 0) { + log_debug("mDNS packet extraction failed."); + return 0; + } + + dns_scope_check_conflicts(scope, p); + + DNS_ANSWER_FOREACH(rr, p->answer) { + const char *name = DNS_RESOURCE_KEY_NAME(rr->key); + DnsTransaction *t; + + /* If the received reply packet contains ANY record that is not .local or .in-addr.arpa, + * we assume someone's playing tricks on us and discard the packet completely. */ + if (!(dns_name_endswith(name, "in-addr.arpa") > 0 || + dns_name_endswith(name, "local") > 0)) + return 0; + + t = dns_scope_find_transaction(scope, rr->key, false); + if (t) + dns_transaction_process_reply(t, p); + } + + dns_cache_put(&scope->cache, NULL, DNS_PACKET_RCODE(p), p->answer, false, (uint32_t) -1, 0, p->family, &p->sender); + + } else if (dns_packet_validate_query(p) > 0) { + log_debug("Got mDNS query packet for id %u", DNS_PACKET_ID(p)); + + dns_scope_process_query(scope, NULL, p); + } else + log_debug("Invalid mDNS UDP packet."); + + return 0; +} + +int manager_mdns_ipv4_fd(Manager *m) { + union sockaddr_union sa = { + .in.sin_family = AF_INET, + .in.sin_port = htobe16(MDNS_PORT), + }; + static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255; + int r; + + assert(m); + + if (m->mdns_ipv4_fd >= 0) + return m->mdns_ipv4_fd; + + m->mdns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->mdns_ipv4_fd < 0) + return -errno; + + r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv4_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + /* Disable Don't-Fragment bit in the IP header */ + r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = bind(m->mdns_ipv4_fd, &sa.sa, sizeof(sa.in)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = sd_event_add_io(m->event, &m->mdns_ipv4_event_source, m->mdns_ipv4_fd, EPOLLIN, on_mdns_packet, m); + if (r < 0) + goto fail; + + return m->mdns_ipv4_fd; + +fail: + m->mdns_ipv4_fd = safe_close(m->mdns_ipv4_fd); + return r; +} + +int manager_mdns_ipv6_fd(Manager *m) { + union sockaddr_union sa = { + .in6.sin6_family = AF_INET6, + .in6.sin6_port = htobe16(MDNS_PORT), + }; + static const int one = 1, ttl = 255; + int r; + + assert(m); + + if (m->mdns_ipv6_fd >= 0) + return m->mdns_ipv6_fd; + + m->mdns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); + if (m->mdns_ipv6_fd < 0) + return -errno; + + r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); + if (r < 0) { + r = -errno; + goto fail; + } + + /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ + r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv6_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = bind(m->mdns_ipv6_fd, &sa.sa, sizeof(sa.in6)); + if (r < 0) { + r = -errno; + goto fail; + } + + r = sd_event_add_io(m->event, &m->mdns_ipv6_event_source, m->mdns_ipv6_fd, EPOLLIN, on_mdns_packet, m); + if (r < 0) + goto fail; + + return m->mdns_ipv6_fd; + +fail: + m->mdns_ipv6_fd = safe_close(m->mdns_ipv6_fd); + return r; +} diff --git a/src/libsystemd-network/lldp-util.h b/src/resolve/resolved-mdns.h similarity index 74% rename from src/libsystemd-network/lldp-util.h rename to src/resolve/resolved-mdns.h index 112001e4b..5d274648f 100644 --- a/src/libsystemd-network/lldp-util.h +++ b/src/resolve/resolved-mdns.h @@ -1,10 +1,9 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +#pragma once /*** This file is part of systemd. - Copyright (C) 2014 Tom Gundersen - Copyright (C) 2014 Susant Sahani + Copyright 2015 Daniel Mack systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by @@ -20,7 +19,12 @@ along with systemd; If not, see . ***/ -#pragma once +#include "resolved-manager.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_lldp *, sd_lldp_free); -#define _cleanup_lldp_free_ _cleanup_(sd_lldp_freep) +#define MDNS_PORT 5353 + +int manager_mdns_ipv4_fd(Manager *m); +int manager_mdns_ipv6_fd(Manager *m); + +void manager_mdns_stop(Manager *m); +int manager_mdns_start(Manager *m); diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c new file mode 100644 index 000000000..065427b69 --- /dev/null +++ b/src/resolve/resolved-resolv-conf.c @@ -0,0 +1,267 @@ +/*** + This file is part of systemd. + + Copyright 2014 Tom Gundersen + + 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 . + ***/ + +#include + +#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) { + assert(s); + assert(f); + assert(count); + + (void) dns_server_string(s); + + if (!s->server_string) { + log_warning("Our of memory, or invalid DNS address. Ignoring server."); + return; + } + + if (*count == MAXNS) + fputs("# Too many DNS servers configured, the following entries may be ignored.\n", f); + (*count) ++; + + fprintf(f, "nameserver %s\n", s->server_string); +} + +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) { + + _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/libsystemd/sd-resolve/resolve-util.h b/src/resolve/resolved-resolv-conf.h similarity index 63% rename from src/libsystemd/sd-resolve/resolve-util.h rename to src/resolve/resolved-resolv-conf.h index 51a8a8af8..75fa080e4 100644 --- a/src/libsystemd/sd-resolve/resolve-util.h +++ b/src/resolve/resolved-resolv-conf.h @@ -1,11 +1,9 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** This file is part of systemd. - Copyright 2014 Daniel Buch + Copyright 2014 Tom Gundersen 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 @@ -21,12 +19,9 @@ along with systemd; If not, see . ***/ -#include "sd-resolve.h" +#include "resolved-manager.h" -#include "util.h" +#define PRIVATE_RESOLV_CONF "/run/systemd/resolve/resolv.conf" -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve*, sd_resolve_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_resolve_query*, sd_resolve_query_unref); - -#define _cleanup_resolve_unref_ _cleanup_(sd_resolve_unrefp) -#define _cleanup_resolve_query_unref_ _cleanup_(sd_resolve_query_unrefp) +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 7ba0546f4..c7e2ab14d 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -26,6 +24,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" @@ -80,10 +79,6 @@ int main(int argc, char *argv[]) { goto finish; } - r = manager_parse_config_file(m); - if (r < 0) - log_warning_errno(r, "Failed to parse configuration file: %m"); - r = manager_start(m); if (r < 0) { log_error_errno(r, "Failed to start manager: %m"); @@ -94,7 +89,7 @@ int main(int argc, char *argv[]) { * symlink */ r = manager_write_resolv_conf(m); if (r < 0) - log_warning_errno(r, "Could not create resolv.conf: %m"); + log_warning_errno(r, "Could not create "PRIVATE_RESOLV_CONF": %m"); sd_notify(false, "READY=1\n" diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in index 3eb19e42b..efc9c6733 100644 --- a/src/resolve/resolved.conf.in +++ b/src/resolve/resolved.conf.in @@ -14,4 +14,6 @@ [Resolve] #DNS= #FallbackDNS=@DNS_SERVERS@ +#Domains= #LLMNR=yes +#DNSSEC=no diff --git a/src/resolve/test-dnssec-complex.c b/src/resolve/test-dnssec-complex.c new file mode 100644 index 000000000..58c089eb4 --- /dev/null +++ b/src/resolve/test-dnssec-complex.c @@ -0,0 +1,236 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include + +#include "sd-bus.h" + +#include "af-list.h" +#include "alloc-util.h" +#include "bus-common-errors.h" +#include "dns-type.h" +#include "random-util.h" +#include "string-util.h" +#include "time-util.h" + +#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC) + +static void prefix_random(const char *name, char **ret) { + uint64_t i, u; + char *m = NULL; + + u = 1 + (random_u64() & 3); + + for (i = 0; i < u; i++) { + _cleanup_free_ char *b = NULL; + char *x; + + assert_se(asprintf(&b, "x%" PRIu64 "x", random_u64())); + x = strjoin(b, ".", name, NULL); + assert_se(x); + + free(m); + m = x; + } + + *ret = m; + } + +static void test_rr_lookup(sd_bus *bus, const char *name, uint16_t type, const char *result) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *m = NULL; + int r; + + /* If the name starts with a dot, we prefix one to three random labels */ + if (startswith(name, ".")) { + prefix_random(name + 1, &m); + name = m; + } + + assert_se(sd_bus_message_new_method_call( + bus, + &req, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "ResolveRecord") >= 0); + + assert_se(sd_bus_message_append(req, "isqqt", 0, name, DNS_CLASS_IN, type, UINT64_C(0)) >= 0); + + r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); + + if (r < 0) { + assert_se(result); + assert_se(sd_bus_error_has_name(&error, result)); + log_info("[OK] %s/%s resulted in <%s>.", name, dns_type_to_string(type), error.name); + } else { + assert_se(!result); + log_info("[OK] %s/%s succeeded.", name, dns_type_to_string(type)); + } +} + +static void test_hostname_lookup(sd_bus *bus, const char *name, int family, const char *result) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *m = NULL; + const char *af; + int r; + + af = family == AF_UNSPEC ? "AF_UNSPEC" : af_to_name(family); + + /* If the name starts with a dot, we prefix one to three random labels */ + if (startswith(name, ".")) { + prefix_random(name + 1, &m); + name = m; + } + + assert_se(sd_bus_message_new_method_call( + bus, + &req, + "org.freedesktop.resolve1", + "/org/freedesktop/resolve1", + "org.freedesktop.resolve1.Manager", + "ResolveHostname") >= 0); + + assert_se(sd_bus_message_append(req, "isit", 0, name, family, UINT64_C(0)) >= 0); + + r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply); + + if (r < 0) { + assert_se(result); + assert_se(sd_bus_error_has_name(&error, result)); + log_info("[OK] %s/%s resulted in <%s>.", name, af, error.name); + } else { + assert_se(!result); + log_info("[OK] %s/%s succeeded.", name, af); + } + +} + +int main(int argc, char* argv[]) { + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; + + /* Note that this is a manual test as it requires: + * + * Full network access + * A DNSSEC capable DNS server + * That zones contacted are still set up as they were when I wrote this. + */ + + assert_se(sd_bus_open_system(&bus) >= 0); + + /* Normally signed */ + test_rr_lookup(bus, "www.eurid.eu", DNS_TYPE_A, NULL); + test_hostname_lookup(bus, "www.eurid.eu", AF_UNSPEC, NULL); + + test_rr_lookup(bus, "sigok.verteiltesysteme.net", DNS_TYPE_A, NULL); + test_hostname_lookup(bus, "sigok.verteiltesysteme.net", AF_UNSPEC, NULL); + + /* Normally signed, NODATA */ + test_rr_lookup(bus, "www.eurid.eu", DNS_TYPE_RP, BUS_ERROR_NO_SUCH_RR); + test_rr_lookup(bus, "sigok.verteiltesysteme.net", DNS_TYPE_RP, BUS_ERROR_NO_SUCH_RR); + + /* Invalid signature */ + test_rr_lookup(bus, "sigfail.verteiltesysteme.net", DNS_TYPE_A, BUS_ERROR_DNSSEC_FAILED); + test_hostname_lookup(bus, "sigfail.verteiltesysteme.net", AF_INET, BUS_ERROR_DNSSEC_FAILED); + + /* Invalid signature, RSA, wildcard */ + test_rr_lookup(bus, ".wilda.rhybar.0skar.cz", DNS_TYPE_A, BUS_ERROR_DNSSEC_FAILED); + test_hostname_lookup(bus, ".wilda.rhybar.0skar.cz", AF_INET, BUS_ERROR_DNSSEC_FAILED); + + /* Invalid signature, ECDSA, wildcard */ + test_rr_lookup(bus, ".wilda.rhybar.ecdsa.0skar.cz", DNS_TYPE_A, BUS_ERROR_DNSSEC_FAILED); + test_hostname_lookup(bus, ".wilda.rhybar.ecdsa.0skar.cz", AF_INET, BUS_ERROR_DNSSEC_FAILED); + + /* NXDOMAIN in NSEC domain */ + test_rr_lookup(bus, "hhh.nasa.gov", DNS_TYPE_A, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, "hhh.nasa.gov", AF_UNSPEC, _BUS_ERROR_DNS "NXDOMAIN"); + + /* wildcard, NSEC zone */ + test_rr_lookup(bus, ".wilda.nsec.0skar.cz", DNS_TYPE_A, NULL); + test_hostname_lookup(bus, ".wilda.nsec.0skar.cz", AF_INET, NULL); + + /* wildcard, NSEC zone, NODATA */ + test_rr_lookup(bus, ".wilda.nsec.0skar.cz", DNS_TYPE_RP, BUS_ERROR_NO_SUCH_RR); + + /* wildcard, NSEC3 zone */ + test_rr_lookup(bus, ".wilda.0skar.cz", DNS_TYPE_A, NULL); + test_hostname_lookup(bus, ".wilda.0skar.cz", AF_INET, NULL); + + /* wildcard, NSEC3 zone, NODATA */ + test_rr_lookup(bus, ".wilda.0skar.cz", DNS_TYPE_RP, BUS_ERROR_NO_SUCH_RR); + + /* wildcard, NSEC zone, CNAME */ + test_rr_lookup(bus, ".wild.nsec.0skar.cz", DNS_TYPE_A, NULL); + test_hostname_lookup(bus, ".wild.nsec.0skar.cz", AF_UNSPEC, NULL); + test_hostname_lookup(bus, ".wild.nsec.0skar.cz", AF_INET, NULL); + + /* wildcard, NSEC zone, NODATA, CNAME */ + test_rr_lookup(bus, ".wild.nsec.0skar.cz", DNS_TYPE_RP, BUS_ERROR_NO_SUCH_RR); + + /* wildcard, NSEC3 zone, CNAME */ + test_rr_lookup(bus, ".wild.0skar.cz", DNS_TYPE_A, NULL); + test_hostname_lookup(bus, ".wild.0skar.cz", AF_UNSPEC, NULL); + test_hostname_lookup(bus, ".wild.0skar.cz", AF_INET, NULL); + + /* wildcard, NSEC3 zone, NODATA, CNAME */ + test_rr_lookup(bus, ".wild.0skar.cz", DNS_TYPE_RP, BUS_ERROR_NO_SUCH_RR); + + /* NODATA due to empty non-terminal in NSEC domain */ + test_rr_lookup(bus, "herndon.nasa.gov", DNS_TYPE_A, BUS_ERROR_NO_SUCH_RR); + test_hostname_lookup(bus, "herndon.nasa.gov", AF_UNSPEC, BUS_ERROR_NO_SUCH_RR); + test_hostname_lookup(bus, "herndon.nasa.gov", AF_INET, BUS_ERROR_NO_SUCH_RR); + test_hostname_lookup(bus, "herndon.nasa.gov", AF_INET6, BUS_ERROR_NO_SUCH_RR); + + /* NXDOMAIN in NSEC root zone: */ + test_rr_lookup(bus, "jasdhjas.kjkfgjhfjg", DNS_TYPE_A, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, "jasdhjas.kjkfgjhfjg", AF_UNSPEC, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, "jasdhjas.kjkfgjhfjg", AF_INET, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, "jasdhjas.kjkfgjhfjg", AF_INET6, _BUS_ERROR_DNS "NXDOMAIN"); + + /* NXDOMAIN in NSEC3 .com zone: */ + test_rr_lookup(bus, "kjkfgjhfjgsdfdsfd.com", DNS_TYPE_A, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, "kjkfgjhfjgsdfdsfd.com", AF_INET, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, "kjkfgjhfjgsdfdsfd.com", AF_INET6, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, "kjkfgjhfjgsdfdsfd.com", AF_UNSPEC, _BUS_ERROR_DNS "NXDOMAIN"); + + /* Unsigned A */ + test_rr_lookup(bus, "poettering.de", DNS_TYPE_A, NULL); + test_rr_lookup(bus, "poettering.de", DNS_TYPE_AAAA, NULL); + test_hostname_lookup(bus, "poettering.de", AF_UNSPEC, NULL); + test_hostname_lookup(bus, "poettering.de", AF_INET, NULL); + test_hostname_lookup(bus, "poettering.de", AF_INET6, NULL); + +#ifdef HAVE_LIBIDN + /* Unsigned A with IDNA conversion necessary */ + test_hostname_lookup(bus, "pöttering.de", AF_UNSPEC, NULL); + test_hostname_lookup(bus, "pöttering.de", AF_INET, NULL); + test_hostname_lookup(bus, "pöttering.de", AF_INET6, NULL); +#endif + + /* DNAME, pointing to NXDOMAIN */ + test_rr_lookup(bus, ".ireallyhpoethisdoesnexist.xn--kprw13d.", DNS_TYPE_A, _BUS_ERROR_DNS "NXDOMAIN"); + test_rr_lookup(bus, ".ireallyhpoethisdoesnexist.xn--kprw13d.", DNS_TYPE_RP, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, ".ireallyhpoethisdoesntexist.xn--kprw13d.", AF_UNSPEC, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, ".ireallyhpoethisdoesntexist.xn--kprw13d.", AF_INET, _BUS_ERROR_DNS "NXDOMAIN"); + test_hostname_lookup(bus, ".ireallyhpoethisdoesntexist.xn--kprw13d.", AF_INET6, _BUS_ERROR_DNS "NXDOMAIN"); + + return 0; +} diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c new file mode 100644 index 000000000..a093d86a9 --- /dev/null +++ b/src/resolve/test-dnssec.c @@ -0,0 +1,336 @@ +/*** + 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 . +***/ + +#include +#include +#include + +#include "alloc-util.h" +#include "resolved-dns-dnssec.h" +#include "resolved-dns-rr.h" +#include "string-util.h" +#include "hexdecoct.h" + +static void test_dnssec_verify_rrset2(void) { + + static const uint8_t signature_blob[] = { + 0x48, 0x45, 0xc8, 0x8b, 0xc0, 0x14, 0x92, 0xf5, 0x15, 0xc6, 0x84, 0x9d, 0x2f, 0xe3, 0x32, 0x11, + 0x7d, 0xf1, 0xe6, 0x87, 0xb9, 0x42, 0xd3, 0x8b, 0x9e, 0xaf, 0x92, 0x31, 0x0a, 0x53, 0xad, 0x8b, + 0xa7, 0x5c, 0x83, 0x39, 0x8c, 0x28, 0xac, 0xce, 0x6e, 0x9c, 0x18, 0xe3, 0x31, 0x16, 0x6e, 0xca, + 0x38, 0x31, 0xaf, 0xd9, 0x94, 0xf1, 0x84, 0xb1, 0xdf, 0x5a, 0xc2, 0x73, 0x22, 0xf6, 0xcb, 0xa2, + 0xe7, 0x8c, 0x77, 0x0c, 0x74, 0x2f, 0xc2, 0x13, 0xb0, 0x93, 0x51, 0xa9, 0x4f, 0xae, 0x0a, 0xda, + 0x45, 0xcc, 0xfd, 0x43, 0x99, 0x36, 0x9a, 0x0d, 0x21, 0xe0, 0xeb, 0x30, 0x65, 0xd4, 0xa0, 0x27, + 0x37, 0x3b, 0xe4, 0xc1, 0xc5, 0xa1, 0x2a, 0xd1, 0x76, 0xc4, 0x7e, 0x64, 0x0e, 0x5a, 0xa6, 0x50, + 0x24, 0xd5, 0x2c, 0xcc, 0x6d, 0xe5, 0x37, 0xea, 0xbd, 0x09, 0x34, 0xed, 0x24, 0x06, 0xa1, 0x22, + }; + + static const uint8_t dnskey_blob[] = { + 0x03, 0x01, 0x00, 0x01, 0xc3, 0x7f, 0x1d, 0xd1, 0x1c, 0x97, 0xb1, 0x13, 0x34, 0x3a, 0x9a, 0xea, + 0xee, 0xd9, 0x5a, 0x11, 0x1b, 0x17, 0xc7, 0xe3, 0xd4, 0xda, 0x20, 0xbc, 0x5d, 0xba, 0x74, 0xe3, + 0x37, 0x99, 0xec, 0x25, 0xce, 0x93, 0x7f, 0xbd, 0x22, 0x73, 0x7e, 0x14, 0x71, 0xe0, 0x60, 0x07, + 0xd4, 0x39, 0x8b, 0x5e, 0xe9, 0xba, 0x25, 0xe8, 0x49, 0xe9, 0x34, 0xef, 0xfe, 0x04, 0x5c, 0xa5, + 0x27, 0xcd, 0xa9, 0xda, 0x70, 0x05, 0x21, 0xab, 0x15, 0x82, 0x24, 0xc3, 0x94, 0xf5, 0xd7, 0xb7, + 0xc4, 0x66, 0xcb, 0x32, 0x6e, 0x60, 0x2b, 0x55, 0x59, 0x28, 0x89, 0x8a, 0x72, 0xde, 0x88, 0x56, + 0x27, 0x95, 0xd9, 0xac, 0x88, 0x4f, 0x65, 0x2b, 0x68, 0xfc, 0xe6, 0x41, 0xc1, 0x1b, 0xef, 0x4e, + 0xd6, 0xc2, 0x0f, 0x64, 0x88, 0x95, 0x5e, 0xdd, 0x3a, 0x02, 0x07, 0x50, 0xa9, 0xda, 0xa4, 0x49, + 0x74, 0x62, 0xfe, 0xd7, + }; + + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *nsec = NULL, *rrsig = NULL, *dnskey = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnssecResult result; + + nsec = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC, "nasa.gov"); + assert_se(nsec); + + nsec->nsec.next_domain_name = strdup("3D-Printing.nasa.gov"); + assert_se(nsec->nsec.next_domain_name); + + nsec->nsec.types = bitmap_new(); + assert_se(nsec->nsec.types); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_A) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NS) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_SOA) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_MX) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_TXT) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_RRSIG) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_NSEC) >= 0); + assert_se(bitmap_set(nsec->nsec.types, DNS_TYPE_DNSKEY) >= 0); + assert_se(bitmap_set(nsec->nsec.types, 65534) >= 0); + + log_info("NSEC: %s", strna(dns_resource_record_to_string(nsec))); + + rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV."); + assert_se(rrsig); + + rrsig->rrsig.type_covered = DNS_TYPE_NSEC; + rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256; + rrsig->rrsig.labels = 2; + rrsig->rrsig.original_ttl = 300; + rrsig->rrsig.expiration = 0x5689002f; + rrsig->rrsig.inception = 0x56617230; + rrsig->rrsig.key_tag = 30390; + rrsig->rrsig.signer = strdup("Nasa.Gov."); + assert_se(rrsig->rrsig.signer); + rrsig->rrsig.signature_size = sizeof(signature_blob); + rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); + assert_se(rrsig->rrsig.signature); + + log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV"); + assert_se(dnskey); + + dnskey->dnskey.flags = 256; + dnskey->dnskey.protocol = 3; + dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; + dnskey->dnskey.key_size = sizeof(dnskey_blob); + dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob)); + assert_se(dnskey->dnskey.key); + + log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); + log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false)); + + assert_se(dnssec_key_match_rrsig(nsec->key, rrsig) > 0); + assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); + + answer = dns_answer_new(1); + assert_se(answer); + assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + + /* Validate the RR as it if was 2015-12-11 today */ + assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0); + assert_se(result == DNSSEC_VALIDATED); +} + +static void test_dnssec_verify_rrset(void) { + + static const uint8_t signature_blob[] = { + 0x7f, 0x79, 0xdd, 0x5e, 0x89, 0x79, 0x18, 0xd0, 0x34, 0x86, 0x8c, 0x72, 0x77, 0x75, 0x48, 0x4d, + 0xc3, 0x7d, 0x38, 0x04, 0xab, 0xcd, 0x9e, 0x4c, 0x82, 0xb0, 0x92, 0xca, 0xe9, 0x66, 0xe9, 0x6e, + 0x47, 0xc7, 0x68, 0x8c, 0x94, 0xf6, 0x69, 0xcb, 0x75, 0x94, 0xe6, 0x30, 0xa6, 0xfb, 0x68, 0x64, + 0x96, 0x1a, 0x84, 0xe1, 0xdc, 0x16, 0x4c, 0x83, 0x6c, 0x44, 0xf2, 0x74, 0x4d, 0x74, 0x79, 0x8f, + 0xf3, 0xf4, 0x63, 0x0d, 0xef, 0x5a, 0xe7, 0xe2, 0xfd, 0xf2, 0x2b, 0x38, 0x7c, 0x28, 0x96, 0x9d, + 0xb6, 0xcd, 0x5c, 0x3b, 0x57, 0xe2, 0x24, 0x78, 0x65, 0xd0, 0x9e, 0x77, 0x83, 0x09, 0x6c, 0xff, + 0x3d, 0x52, 0x3f, 0x6e, 0xd1, 0xed, 0x2e, 0xf9, 0xee, 0x8e, 0xa6, 0xbe, 0x9a, 0xa8, 0x87, 0x76, + 0xd8, 0x77, 0xcc, 0x96, 0xa0, 0x98, 0xa1, 0xd1, 0x68, 0x09, 0x43, 0xcf, 0x56, 0xd9, 0xd1, 0x66, + }; + + static const uint8_t dnskey_blob[] = { + 0x03, 0x01, 0x00, 0x01, 0x9b, 0x49, 0x9b, 0xc1, 0xf9, 0x9a, 0xe0, 0x4e, 0xcf, 0xcb, 0x14, 0x45, + 0x2e, 0xc9, 0xf9, 0x74, 0xa7, 0x18, 0xb5, 0xf3, 0xde, 0x39, 0x49, 0xdf, 0x63, 0x33, 0x97, 0x52, + 0xe0, 0x8e, 0xac, 0x50, 0x30, 0x8e, 0x09, 0xd5, 0x24, 0x3d, 0x26, 0xa4, 0x49, 0x37, 0x2b, 0xb0, + 0x6b, 0x1b, 0xdf, 0xde, 0x85, 0x83, 0xcb, 0x22, 0x4e, 0x60, 0x0a, 0x91, 0x1a, 0x1f, 0xc5, 0x40, + 0xb1, 0xc3, 0x15, 0xc1, 0x54, 0x77, 0x86, 0x65, 0x53, 0xec, 0x10, 0x90, 0x0c, 0x91, 0x00, 0x5e, + 0x15, 0xdc, 0x08, 0x02, 0x4c, 0x8c, 0x0d, 0xc0, 0xac, 0x6e, 0xc4, 0x3e, 0x1b, 0x80, 0x19, 0xe4, + 0xf7, 0x5f, 0x77, 0x51, 0x06, 0x87, 0x61, 0xde, 0xa2, 0x18, 0x0f, 0x40, 0x8b, 0x79, 0x72, 0xfa, + 0x8d, 0x1a, 0x44, 0x47, 0x0d, 0x8e, 0x3a, 0x2d, 0xc7, 0x39, 0xbf, 0x56, 0x28, 0x97, 0xd9, 0x20, + 0x4f, 0x00, 0x51, 0x3b, + }; + + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *a = NULL, *rrsig = NULL, *dnskey = NULL; + _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; + DnssecResult result; + + a = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "nAsA.gov"); + assert_se(a); + + a->a.in_addr.s_addr = inet_addr("52.0.14.116"); + + log_info("A: %s", strna(dns_resource_record_to_string(a))); + + rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV."); + assert_se(rrsig); + + rrsig->rrsig.type_covered = DNS_TYPE_A; + rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256; + rrsig->rrsig.labels = 2; + rrsig->rrsig.original_ttl = 600; + rrsig->rrsig.expiration = 0x5683135c; + rrsig->rrsig.inception = 0x565b7da8; + rrsig->rrsig.key_tag = 63876; + rrsig->rrsig.signer = strdup("Nasa.Gov."); + assert_se(rrsig->rrsig.signer); + rrsig->rrsig.signature_size = sizeof(signature_blob); + rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); + assert_se(rrsig->rrsig.signature); + + log_info("RRSIG: %s", strna(dns_resource_record_to_string(rrsig))); + + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV"); + assert_se(dnskey); + + dnskey->dnskey.flags = 256; + dnskey->dnskey.protocol = 3; + dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; + dnskey->dnskey.key_size = sizeof(dnskey_blob); + dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob)); + assert_se(dnskey->dnskey.key); + + log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); + log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false)); + + assert_se(dnssec_key_match_rrsig(a->key, rrsig) > 0); + assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey, false) > 0); + + answer = dns_answer_new(1); + assert_se(answer); + assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + + /* Validate the RR as it if was 2015-12-2 today */ + assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey, 1449092754*USEC_PER_SEC, &result) >= 0); + assert_se(result == DNSSEC_VALIDATED); +} + +static void test_dnssec_verify_dns_key(void) { + + static const uint8_t ds1_fprint[] = { + 0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D, + 0x80, 0x67, 0x14, 0x01, + }; + static const uint8_t ds2_fprint[] = { + 0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE, + 0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98, + }; + static const uint8_t dnskey_blob[] = { + 0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e, + 0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc, + 0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48, + 0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49, + 0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde, + 0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe, + 0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf, + 0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45, + 0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77, + 0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39, + 0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d, + 0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68, + 0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39, + 0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4, + 0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba, + 0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73, + 0xe7, 0xea, 0x77, 0x03, + }; + + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL; + + /* The two DS RRs in effect for nasa.gov on 2015-12-01. */ + ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov"); + assert_se(ds1); + + ds1->ds.key_tag = 47857; + ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; + ds1->ds.digest_type = DNSSEC_DIGEST_SHA1; + ds1->ds.digest_size = sizeof(ds1_fprint); + ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size); + assert_se(ds1->ds.digest); + + log_info("DS1: %s", strna(dns_resource_record_to_string(ds1))); + + ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV"); + assert_se(ds2); + + ds2->ds.key_tag = 47857; + ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; + ds2->ds.digest_type = DNSSEC_DIGEST_SHA256; + ds2->ds.digest_size = sizeof(ds2_fprint); + ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size); + assert_se(ds2->ds.digest); + + log_info("DS2: %s", strna(dns_resource_record_to_string(ds2))); + + dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV"); + assert_se(dnskey); + + dnskey->dnskey.flags = 257; + dnskey->dnskey.protocol = 3; + dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; + dnskey->dnskey.key_size = sizeof(dnskey_blob); + dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob)); + assert_se(dnskey->dnskey.key); + + log_info("DNSKEY: %s", strna(dns_resource_record_to_string(dnskey))); + log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey, false)); + + assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds1, false) > 0); + assert_se(dnssec_verify_dnskey_by_ds(dnskey, ds2, false) > 0); +} + +static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) { + char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX]; + + assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r); + if (r < 0) + return; + + assert_se(streq(canonicalized, canonical)); +} + +static void test_dnssec_canonicalize(void) { + test_dnssec_canonicalize_one("", ".", 1); + test_dnssec_canonicalize_one(".", ".", 1); + test_dnssec_canonicalize_one("foo", "foo.", 4); + test_dnssec_canonicalize_one("foo.", "foo.", 4); + test_dnssec_canonicalize_one("FOO.", "foo.", 4); + test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8); + test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL); +} + +static void test_dnssec_nsec3_hash(void) { + static const uint8_t salt[] = { 0xB0, 0x1D, 0xFA, 0xCE }; + static const uint8_t next_hashed_name[] = { 0x84, 0x10, 0x26, 0x53, 0xc9, 0xfa, 0x4d, 0x85, 0x6c, 0x97, 0x82, 0xe2, 0x8f, 0xdf, 0x2d, 0x5e, 0x87, 0x69, 0xc4, 0x52 }; + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; + uint8_t h[DNSSEC_HASH_SIZE_MAX]; + _cleanup_free_ char *b = NULL; + int k; + + /* The NSEC3 RR for eurid.eu on 2015-12-14. */ + rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_NSEC3, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM.eurid.eu."); + assert_se(rr); + + rr->nsec3.algorithm = DNSSEC_DIGEST_SHA1; + rr->nsec3.flags = 1; + rr->nsec3.iterations = 1; + rr->nsec3.salt = memdup(salt, sizeof(salt)); + assert_se(rr->nsec3.salt); + rr->nsec3.salt_size = sizeof(salt); + rr->nsec3.next_hashed_name = memdup(next_hashed_name, sizeof(next_hashed_name)); + assert_se(rr->nsec3.next_hashed_name); + rr->nsec3.next_hashed_name_size = sizeof(next_hashed_name); + + log_info("NSEC3: %s", strna(dns_resource_record_to_string(rr))); + + k = dnssec_nsec3_hash(rr, "eurid.eu", &h); + assert_se(k >= 0); + + b = base32hexmem(h, k, false); + assert_se(b); + assert_se(strcasecmp(b, "PJ8S08RR45VIQDAQGE7EN3VHKNROTBMM") == 0); +} + +int main(int argc, char*argv[]) { + + test_dnssec_canonicalize(); + test_dnssec_verify_dns_key(); + test_dnssec_verify_rrset(); + test_dnssec_verify_rrset2(); + test_dnssec_nsec3_hash(); + + return 0; +} diff --git a/src/resolve/test-resolve-tables.c b/src/resolve/test-resolve-tables.c new file mode 100644 index 000000000..63660afc8 --- /dev/null +++ b/src/resolve/test-resolve-tables.c @@ -0,0 +1,27 @@ +/*** + This file is part of systemd + + Copyright 2013 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 . +***/ + +#include "dns-type.h" +#include "test-tables.h" + +int main(int argc, char **argv) { + test_table_sparse(dns_type, DNS_TYPE); + + return EXIT_SUCCESS; +} diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c index 5c45a3ae6..0acdf229e 100644 --- a/src/rfkill/rfkill.c +++ b/src/rfkill/rfkill.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/run/run.c b/src/run/run.c index e1accc467..e7f4c21f7 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -30,7 +28,6 @@ #include "bus-util.h" #include "calendarspec.h" #include "env-util.h" -#include "event-util.h" #include "fd-util.h" #include "formats-util.h" #include "parse-util.h" @@ -423,17 +420,9 @@ static int transient_unit_set_properties(sd_bus_message *m, char **properties) { return r; STRV_FOREACH(i, properties) { - r = sd_bus_message_open_container(m, 'r', "sv"); - if (r < 0) - return r; - r = bus_append_unit_property_assignment(m, *i); if (r < 0) return r; - - r = sd_bus_message_close_container(m); - if (r < 0) - return r; } return 0; @@ -741,8 +730,8 @@ static int start_transient_service( sd_bus *bus, char **argv) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *service = NULL, *pty_path = NULL; _cleanup_close_ int master = -1; @@ -766,7 +755,7 @@ static int start_transient_service( return log_error_errno(errno, "Failed to unlock tty: %m"); } else if (arg_transport == BUS_TRANSPORT_MACHINE) { - _cleanup_bus_unref_ sd_bus *system_bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *system_bus = NULL; const char *s; r = sd_bus_default_system(&system_bus); @@ -876,7 +865,7 @@ static int start_transient_service( if (master >= 0) { _cleanup_(pty_forward_freep) PTYForward *forward = NULL; - _cleanup_event_unref_ sd_event *event = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; char last_char = 0; r = sd_event_default(&event); @@ -916,8 +905,8 @@ static int start_transient_scope( sd_bus *bus, char **argv) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_strv_free_ char **env = NULL, **user_env = NULL; _cleanup_free_ char *scope = NULL; @@ -1060,8 +1049,8 @@ static int start_transient_timer( sd_bus *bus, char **argv) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL; _cleanup_free_ char *timer = NULL, *service = NULL; const char *object = NULL; @@ -1208,7 +1197,7 @@ static int start_transient_timer( } int main(int argc, char* argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *description = NULL, *command = NULL; int r; diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 35f2e1b67..2aa951fce 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -71,6 +69,7 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) { int calc_acl_mask_if_needed(acl_t *acl_p) { acl_entry_t i; int r; + bool need = false; assert(acl_p); @@ -85,17 +84,16 @@ int calc_acl_mask_if_needed(acl_t *acl_p) { if (tag == ACL_MASK) return 0; - if (IN_SET(tag, ACL_USER, ACL_GROUP)) { - if (acl_calc_mask(acl_p) < 0) - return -errno; - - return 1; - } + if (IN_SET(tag, ACL_USER, ACL_GROUP)) + need = true; } if (r < 0) return -errno; - return 0; + if (need && acl_calc_mask(acl_p) < 0) + return -errno; + + return need; } int add_base_acls_if_needed(acl_t *acl_p, const char *path) { @@ -398,3 +396,34 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) { old = NULL; return 0; } + +int add_acls_for_user(int fd, uid_t uid) { + _cleanup_(acl_freep) acl_t acl = NULL; + acl_entry_t entry; + acl_permset_t permset; + int r; + + acl = acl_get_fd(fd); + if (!acl) + return -errno; + + r = acl_find_uid(acl, uid, &entry); + if (r <= 0) { + if (acl_create_entry(&acl, &entry) < 0 || + acl_set_tag_type(entry, ACL_USER) < 0 || + acl_set_qualifier(entry, &uid) < 0) + return -errno; + } + + /* We do not recalculate the mask unconditionally here, + * so that the fchmod() mask above stays intact. */ + if (acl_get_permset(entry, &permset) < 0 || + acl_add_perm(permset, ACL_READ) < 0) + return -errno; + + r = calc_acl_mask_if_needed(&acl); + if (r < 0) + return r; + + return acl_set_fd(fd, acl); +} diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index cf612e872..396e9e067 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,9 +21,9 @@ #ifdef HAVE_ACL +#include #include #include -#include #include "macro.h" @@ -35,6 +33,7 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path); int acl_search_groups(const char* path, char ***ret_groups); int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask); int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl); +int add_acls_for_user(int fd, uid_t uid); /* acl_free takes multiple argument types. * Multiple cleanup functions are necessary. */ diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 30e03c065..3cb9e781f 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,10 @@ along with systemd; If not, see . ***/ +#include #include +#include #include -#include #include #include @@ -30,7 +29,6 @@ #include "fd-util.h" #include "fileio.h" #include "time-util.h" -#include "util.h" struct acpi_table_header { char signature[4]; diff --git a/src/shared/acpi-fpdt.h b/src/shared/acpi-fpdt.h index fc4fe6f10..fc28175d0 100644 --- a/src/shared/acpi-fpdt.h +++ b/src/shared/acpi-fpdt.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c index f6ac43adf..edd695fd2 100644 --- a/src/shared/apparmor-util.c +++ b/src/shared/apparmor-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,11 +17,12 @@ along with systemd; If not, see . ***/ +#include + #include "alloc-util.h" #include "apparmor-util.h" #include "fileio.h" #include "parse-util.h" -#include "util.h" bool mac_apparmor_use(void) { static int cached_use = -1; diff --git a/src/shared/apparmor-util.h b/src/shared/apparmor-util.h index a3d1b3b06..524f74015 100644 --- a/src/shared/apparmor-util.h +++ b/src/shared/apparmor-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/architecture.c b/src/shared/architecture.c index 73937bd5a..a9ecfc1cd 100644 --- a/src/shared/architecture.c +++ b/src/shared/architecture.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,6 +20,7 @@ #include #include "architecture.h" +#include "macro.h" #include "string-table.h" #include "string-util.h" diff --git a/src/shared/architecture.h b/src/shared/architecture.h index 61d067cad..26679e28c 100644 --- a/src/shared/architecture.h +++ b/src/shared/architecture.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,6 +21,7 @@ #include +#include "macro.h" #include "util.h" /* A cleaned up architecture definition. We don't want to get lost in diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index fbe2b6fec..6805873f9 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,13 +19,22 @@ #include #include +#include +#include #include +#include #include #include +#include +#include +#include #include #include #include #include +#include +#include +#include #include #include #include @@ -38,6 +45,8 @@ #include "fileio.h" #include "formats-util.h" #include "io-util.h" +#include "log.h" +#include "macro.h" #include "missing.h" #include "mkdir.h" #include "random-util.h" @@ -46,7 +55,9 @@ #include "string-util.h" #include "strv.h" #include "terminal-util.h" +#include "time-util.h" #include "umask-util.h" +#include "utf8.h" #include "util.h" #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2) @@ -59,7 +70,7 @@ static int lookup_key(const char *keyname, key_serial_t *ret) { serial = request_key("user", keyname, NULL, 0); if (serial == -1) - return -errno; + return negative_errno(); *ret = serial; return 0; @@ -201,8 +212,8 @@ int ask_password_tty( char **ret) { struct termios old_termios, new_termios; - char passphrase[LINE_MAX], *x; - size_t p = 0; + char passphrase[LINE_MAX + 1] = {}, *x; + size_t p = 0, codepoint = 0; int r; _cleanup_close_ int ttyfd = -1, notify = -1; struct pollfd pollfd[2]; @@ -366,8 +377,13 @@ int ask_password_tty( passphrase[p++] = c; - if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) - loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false); + if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) { + n = utf8_encoded_valid_unichar(passphrase + codepoint); + if (n >= 0) { + codepoint = p; + loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false); + } + } dirty = true; } diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h index 913cad9f8..9d7f65130 100644 --- a/src/shared/ask-password-api.h +++ b/src/shared/ask-password-api.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c index e605490c3..59a34a9d1 100644 --- a/src/shared/base-filesystem.c +++ b/src/shared/base-filesystem.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,8 +18,11 @@ ***/ #include +#include +#include #include #include +#include #include #include "alloc-util.h" diff --git a/src/shared/base-filesystem.h b/src/shared/base-filesystem.h index 39a496090..49599f0a6 100644 --- a/src/shared/base-filesystem.h +++ b/src/shared/base-filesystem.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/boot-timestamps.c b/src/shared/boot-timestamps.c index 879aca937..7e0152761 100644 --- a/src/shared/boot-timestamps.c +++ b/src/shared/boot-timestamps.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,6 +21,8 @@ #include "acpi-fpdt.h" #include "boot-timestamps.h" #include "efivars.h" +#include "macro.h" +#include "time-util.h" int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) { usec_t x = 0, y = 0, a; diff --git a/src/shared/boot-timestamps.h b/src/shared/boot-timestamps.h index a3d2405b5..6f691026b 100644 --- a/src/shared/boot-timestamps.h +++ b/src/shared/boot-timestamps.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index 73ceeba18..38557f0b8 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,14 +17,24 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include "sd-bus-protocol.h" #include "sd-bus.h" #include "sd-daemon.h" #include "sd-event.h" +#include "sd-id128.h" #include "alloc-util.h" -#include "bus-error.h" #include "bus-internal.h" #include "bus-label.h" #include "bus-message.h" @@ -35,7 +43,12 @@ #include "def.h" #include "env-util.h" #include "escape.h" +#include "extract-word.h" #include "fd-util.h" +#include "hashmap.h" +#include "install.h" +#include "kdbus.h" +#include "log.h" #include "macro.h" #include "missing.h" #include "parse-util.h" @@ -49,6 +62,7 @@ #include "string-util.h" #include "strv.h" #include "syslog-util.h" +#include "time-util.h" #include "unit-name.h" #include "user-util.h" #include "utf8.h" @@ -181,7 +195,7 @@ int bus_event_loop_with_idle( } int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) { - _cleanup_bus_message_unref_ sd_bus_message *rep = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *rep = NULL; int r, has_owner = 0; assert(c); @@ -207,7 +221,7 @@ int bus_name_has_owner(sd_bus *c, const char *name, sd_bus_error *error) { } static int check_good_user(sd_bus_message *m, uid_t good_user) { - _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL; + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; uid_t sender_uid; int r; @@ -257,8 +271,8 @@ int bus_test_polkit( return 1; #ifdef ENABLE_POLKIT else { - _cleanup_bus_message_unref_ sd_bus_message *request = NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *request = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; int authorized = false, challenge = false; const char *sender, **k, **v; @@ -361,7 +375,7 @@ static void async_polkit_query_free(AsyncPolkitQuery *q) { } static int async_polkit_callback(sd_bus_message *reply, void *userdata, sd_bus_error *error) { - _cleanup_bus_error_free_ sd_bus_error error_buffer = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error_buffer = SD_BUS_ERROR_NULL; AsyncPolkitQuery *q = userdata; int r; @@ -399,7 +413,7 @@ int bus_verify_polkit_async( sd_bus_error *error) { #ifdef ENABLE_POLKIT - _cleanup_bus_message_unref_ sd_bus_message *pk = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *pk = NULL; AsyncPolkitQuery *q; const char *sender, **k, **v; sd_bus_message_handler_t callback; @@ -587,7 +601,7 @@ int bus_check_peercred(sd_bus *c) { } int bus_connect_system_systemd(sd_bus **_bus) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; int r; assert(_bus); @@ -641,7 +655,7 @@ int bus_connect_system_systemd(sd_bus **_bus) { } int bus_connect_user_systemd(sd_bus **_bus) { - _cleanup_bus_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; _cleanup_free_ char *ee = NULL; const char *e; int r; @@ -907,8 +921,8 @@ int bus_print_property(const char *name, sd_bus_message *property, bool all) { } int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, char **filter, bool all) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -1091,7 +1105,7 @@ int bus_message_map_all_properties( const struct bus_properties_map *map, void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(m); @@ -1197,8 +1211,8 @@ int bus_map_all_properties( const struct bus_properties_map *map, void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -1382,7 +1396,7 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) { int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignment) { const char *eq, *field; - int r; + int r, rl; assert(m); assert(assignment); @@ -1393,20 +1407,18 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return -EINVAL; } + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + field = strndupa(assignment, eq - assignment); eq ++; if (streq(field, "CPUQuota")) { - if (isempty(eq)) { - - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(m, "v", "t", USEC_INFINITY); - - } else if (endswith(eq, "%")) { + if (isempty(eq)) + r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); + else if (endswith(eq, "%")) { double percent; if (sscanf(eq, "%lf%%", &percent) != 1 || percent <= 0) { @@ -1414,49 +1426,78 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return -EINVAL; } - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "CPUQuotaPerSecUSec"); - if (r < 0) - return bus_log_create_error(r); - - r = sd_bus_message_append(m, "v", "t", (usec_t) percent * USEC_PER_SEC / 100); + r = sd_bus_message_append(m, "sv", "CPUQuotaPerSecUSec", "t", (usec_t) percent * USEC_PER_SEC / 100); } else { log_error("CPU quota needs to be in percent."); return -EINVAL; } - if (r < 0) - return bus_log_create_error(r); + goto finish; - return 0; } else if (streq(field, "EnvironmentFile")) { - r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, "EnvironmentFiles"); - if (r < 0) - return r; - r = sd_bus_message_append(m, "v", "a(sb)", 1, + r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1, eq[0] == '-' ? eq + 1 : eq, eq[0] == '-'); + goto finish; + + } else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) { + char *n; + usec_t t; + size_t l; + r = parse_sec(eq, &t); if (r < 0) - return r; - return 0; + return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq); + + l = strlen(field); + n = newa(char, l + 2); + if (!n) + return log_oom(); + + /* Change suffix Sec → USec */ + strcpy(mempcpy(n, field, l - 3), "USec"); + r = sd_bus_message_append(m, "sv", n, "t", t); + goto finish; } r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); if (r < 0) return bus_log_create_error(r); - if (STR_IN_SET(field, + rl = rlimit_from_string(field); + if (rl >= 0) { + const char *sn; + struct rlimit l; + + r = rlimit_parse(rl, eq, &l); + if (r < 0) + return log_error_errno(r, "Failed to parse resource limit: %s", eq); + + r = sd_bus_message_append(m, "v", "t", l.rlim_max); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + sn = strjoina(field, "Soft"); + r = sd_bus_message_append(m, "sv", sn, "t", l.rlim_cur); + + } else if (STR_IN_SET(field, "CPUAccounting", "MemoryAccounting", "BlockIOAccounting", "TasksAccounting", "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); @@ -1628,21 +1669,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "a(st)", path, u); } - } else if (rlimit_from_string(field) >= 0) { - uint64_t rl; - - if (streq(eq, "infinity")) - rl = (uint64_t) -1; - else { - r = safe_atou64(eq, &rl); - if (r < 0) { - log_error("Invalid resource limit: %s", eq); - return -EINVAL; - } - } - - r = sd_bus_message_append(m, "v", "t", rl); - } else if (streq(field, "Nice")) { int32_t i; @@ -1712,16 +1738,6 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen r = sd_bus_message_append(m, "v", "i", sig); - } else if (streq(field, "AccuracySec")) { - usec_t u; - - r = parse_sec(eq, &u); - if (r < 0) { - log_error("Failed to parse %s value %s", field, eq); - return -EINVAL; - } - - r = sd_bus_message_append(m, "v", "t", u); } else if (streq(field, "TimerSlackNSec")) { nsec_t n; @@ -1835,6 +1851,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen return -EINVAL; } +finish: + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); if (r < 0) return bus_log_create_error(r); @@ -2007,13 +2028,21 @@ static const struct { { "start-limit", "start of the service was attempted too often" } }; -static void log_job_error_with_service_result(const char* service, const char *result) { - _cleanup_free_ char *service_shell_quoted = NULL; +static void log_job_error_with_service_result(const char* service, const char *result, const char *extra_args) { + _cleanup_free_ char *service_shell_quoted = NULL, *systemctl_extra_args = NULL; assert(service); service_shell_quoted = shell_maybe_quote(service); + systemctl_extra_args = strjoin("systemctl ", extra_args, " ", NULL); + if (!systemctl_extra_args) { + log_oom(); + return; + } + + systemctl_extra_args = strstrip(systemctl_extra_args); + if (!isempty(result)) { unsigned i; @@ -2022,27 +2051,30 @@ static void log_job_error_with_service_result(const char* service, const char *r break; if (i < ELEMENTSOF(explanations)) { - log_error("Job for %s failed because %s. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n", + log_error("Job for %s failed because %s. See \"%s status %s\" and \"journalctl -xe\" for details.\n", service, explanations[i].explanation, + systemctl_extra_args, strna(service_shell_quoted)); goto finish; } } - log_error("Job for %s failed. See \"systemctl status %s\" and \"journalctl -xe\" for details.\n", + log_error("Job for %s failed. See \"%s status %s\" and \"journalctl -xe\" for details.\n", service, + systemctl_extra_args, strna(service_shell_quoted)); finish: /* For some results maybe additional explanation is required */ if (streq_ptr(result, "start-limit")) - log_info("To force a start use \"systemctl reset-failed %1$s\" followed by \"systemctl start %1$s\" again.", + log_info("To force a start use \"%1$s reset-failed %2$s\" followed by \"%1$s start %2$s\" again.", + systemctl_extra_args, strna(service_shell_quoted)); } -static int check_wait_response(BusWaitForJobs *d, bool quiet) { +static int check_wait_response(BusWaitForJobs *d, bool quiet, const char *extra_args) { int r = 0; assert(d->result); @@ -2055,7 +2087,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet) { else if (streq(d->result, "dependency")) log_error("A dependency job for %s failed. See 'journalctl -xe' for details.", strna(d->name)); else if (streq(d->result, "invalid")) - log_error("Job for %s invalid.", strna(d->name)); + log_error("%s is not active, cannot reload.", strna(d->name)); else if (streq(d->result, "assert")) log_error("Assertion failed on job for %s.", strna(d->name)); else if (streq(d->result, "unsupported")) @@ -2069,7 +2101,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet) { if (q < 0) log_debug_errno(q, "Failed to get Result property of service %s: %m", d->name); - log_job_error_with_service_result(d->name, result); + log_job_error_with_service_result(d->name, result, extra_args); } else log_error("Job failed. See \"journalctl -xe\" for details."); } @@ -2093,7 +2125,7 @@ static int check_wait_response(BusWaitForJobs *d, bool quiet) { return r; } -int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) { +int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char *extra_args) { int r = 0; assert(d); @@ -2106,7 +2138,7 @@ int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet) { return log_error_errno(q, "Failed to wait for response: %m"); if (d->result) { - q = check_wait_response(d, quiet); + q = check_wait_response(d, quiet, extra_args); /* Return the first error as it is most likely to be * meaningful. */ if (q < 0 && r == 0) @@ -2141,7 +2173,7 @@ int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) { if (r < 0) return log_oom(); - return bus_wait_for_jobs(d, quiet); + return bus_wait_for_jobs(d, quiet, NULL); } int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, unsigned *n_changes) { @@ -2347,23 +2379,28 @@ int bus_property_get_rlimit( struct rlimit *rl; uint64_t u; rlim_t x; + const char *is_soft; assert(bus); assert(reply); assert(userdata); + is_soft = endswith(property, "Soft"); rl = *(struct rlimit**) userdata; if (rl) - x = rl->rlim_max; + x = is_soft ? rl->rlim_cur : rl->rlim_max; else { struct rlimit buf = {}; int z; + const char *s; - z = rlimit_from_string(strstr(property, "Limit")); + s = is_soft ? strndupa(property, is_soft - property) : property; + + z = rlimit_from_string(strstr(s, "Limit")); assert(z >= 0); getrlimit(z, &buf); - x = buf.rlim_max; + x = is_soft ? buf.rlim_cur : buf.rlim_max; } /* rlim_t might have different sizes, let's map diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 3925c10fd..204da5568 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,11 +19,18 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include + +#include "sd-bus-vtable.h" #include "sd-bus.h" #include "sd-event.h" #include "hashmap.h" #include "install.h" +#include "macro.h" #include "string-util.h" #include "time-util.h" @@ -137,21 +142,6 @@ typedef struct UnitInfo { int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus*, sd_bus_flush_close_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_slot*, sd_bus_slot_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, sd_bus_message_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_creds*, sd_bus_creds_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_track*, sd_bus_track_unref); - -#define _cleanup_bus_unref_ _cleanup_(sd_bus_unrefp) -#define _cleanup_bus_flush_close_unref_ _cleanup_(sd_bus_flush_close_unrefp) -#define _cleanup_bus_slot_unref_ _cleanup_(sd_bus_slot_unrefp) -#define _cleanup_bus_message_unref_ _cleanup_(sd_bus_message_unrefp) -#define _cleanup_bus_creds_unref_ _cleanup_(sd_bus_creds_unrefp) -#define _cleanup_bus_track_unref_ _cleanup_(sd_bus_slot_unrefp) -#define _cleanup_bus_error_free_ _cleanup_(sd_bus_error_free) - #define BUS_DEFINE_PROPERTY_GET_ENUM(function, name, type) \ int function(sd_bus *bus, \ const char *path, \ @@ -190,7 +180,7 @@ typedef struct BusWaitForJobs BusWaitForJobs; int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret); void bus_wait_for_jobs_free(BusWaitForJobs *d); int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path); -int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet); +int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char *extra_args); int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet); DEFINE_TRIVIAL_CLEANUP_FUNC(BusWaitForJobs*, bus_wait_for_jobs_free); diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 129ffc705..f3039b23f 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,7 +19,9 @@ #include #include +#include #include +#include #include #include "alloc-util.h" @@ -31,11 +31,11 @@ #include "formats-util.h" #include "locale-util.h" #include "macro.h" +#include "output-mode.h" #include "path-util.h" #include "process-util.h" #include "string-util.h" #include "terminal-util.h" -#include "util.h" static int compare(const void *a, const void *b) { const pid_t *p = a, *q = b; diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h index aa832454b..3ab7dfb33 100644 --- a/src/shared/cgroup-show.h +++ b/src/shared/cgroup-show.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,7 +21,9 @@ #include #include + #include "logs-show.h" +#include "output-mode.h" int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags); int show_cgroup(const char *controller, 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 71cc61370..a3ac7aeb8 100644 --- a/src/shared/clean-ipc.c +++ b/src/shared/clean-ipc.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,22 +18,29 @@ ***/ #include +#include #include +#include #include +#include +#include +#include #include #include #include #include #include +#include #include "clean-ipc.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "log.h" +#include "macro.h" #include "string-util.h" #include "strv.h" -#include "util.h" static int clean_sysvipc_shm(uid_t delete_uid) { _cleanup_fclose_ FILE *f = NULL; diff --git a/src/shared/clean-ipc.h b/src/shared/clean-ipc.h index 2de57fad2..44a83afcf 100644 --- a/src/shared/clean-ipc.h +++ b/src/shared/clean-ipc.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/condition.c b/src/shared/condition.c index a69719116..f93785865 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,9 +18,13 @@ ***/ #include +#include #include +#include #include #include +#include +#include #include #include "sd-id128.h" @@ -38,6 +40,8 @@ #include "glob-util.h" #include "hostname-util.h" #include "ima-util.h" +#include "list.h" +#include "macro.h" #include "mount-util.h" #include "parse-util.h" #include "path-util.h" @@ -231,7 +235,7 @@ static int condition_test_security(Condition *c) { assert(c->type == CONDITION_SECURITY); if (streq(c->parameter, "selinux")) - return mac_selinux_use(); + return mac_selinux_have(); if (streq(c->parameter, "smack")) return mac_smack_use(); if (streq(c->parameter, "apparmor")) diff --git a/src/shared/condition.h b/src/shared/condition.h index 0780e7812..bdda04b77 100644 --- a/src/shared/condition.h +++ b/src/shared/condition.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 486122b0f..e7fe9ac21 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -20,15 +18,17 @@ ***/ #include +#include +#include #include #include #include - -#include "sd-messages.h" +#include #include "alloc-util.h" #include "conf-files.h" #include "conf-parser.h" +#include "extract-word.h" #include "fd-util.h" #include "fs-util.h" #include "log.h" @@ -40,8 +40,8 @@ #include "string-util.h" #include "strv.h" #include "syslog-util.h" +#include "time-util.h" #include "utf8.h" -#include "util.h" int config_item_table_lookup( const void *table, diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index fb0234baa..a91c94c32 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,9 +19,14 @@ along with systemd; If not, see . ***/ -#include +#include #include +#include +#include +#include +#include "alloc-util.h" +#include "log.h" #include "macro.h" /* An abstract parser for simple, line based, shallow configuration diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c index ad3c17d5b..b2d464c11 100644 --- a/src/shared/dev-setup.c +++ b/src/shared/dev-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -26,6 +24,7 @@ #include "alloc-util.h" #include "dev-setup.h" #include "label.h" +#include "log.h" #include "path-util.h" #include "user-util.h" #include "util.h" diff --git a/src/shared/dev-setup.h b/src/shared/dev-setup.h index ab2748db7..5766a6206 100644 --- a/src/shared/dev-setup.h +++ b/src/shared/dev-setup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 7af15e009..45d24c007 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -24,11 +22,22 @@ #include #endif +#include +#include +#include +#include +#include + #include "alloc-util.h" #include "dns-domain.h" +#include "hashmap.h" #include "hexdecoct.h" +#include "in-addr-util.h" +#include "macro.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; @@ -37,7 +46,6 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) { assert(name); assert(*name); - assert(dest); n = *name; d = dest; @@ -51,12 +59,12 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) { if (*n == 0) break; - if (sz <= 0) - return -ENOSPC; - if (r >= DNS_LABEL_MAX) return -EINVAL; + if (sz <= 0) + return -ENOBUFS; + if (*n == '\\') { /* Escaped character */ @@ -68,9 +76,12 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) { else if (*n == '\\' || *n == '.') { /* Escaped backslash or dot */ - *(d++) = *(n++); + + if (d) + *(d++) = *n; sz--; r++; + n++; } else if (n[0] >= '0' && n[0] <= '9') { unsigned k; @@ -85,11 +96,17 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) { ((unsigned) (n[1] - '0') * 10) + ((unsigned) (n[2] - '0')); - /* Don't allow CC characters or anything that doesn't fit in 8bit */ - if (k < ' ' || k > 255 || k == 127) + /* Don't allow anything that doesn't + * fit in 8bit. Note that we do allow + * control characters, as some servers + * (e.g. cloudflare) are happy to + * generate labels with them + * inside. */ + if (k > 255) return -EINVAL; - *(d++) = (char) k; + if (d) + *(d++) = (char) k; sz--; r++; @@ -100,9 +117,12 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) { } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) { /* Normal character */ - *(d++) = *(n++); + + if (d) + *(d++) = *n; sz--; r++; + n++; } else return -EINVAL; } @@ -111,7 +131,7 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) { if (r == 0 && *n) return -EINVAL; - if (sz >= 1) + if (sz >= 1 && d) *d = 0; *name = n; @@ -137,20 +157,24 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha return 0; } - assert(**label_terminal == '.' || **label_terminal == 0); + terminal = *label_terminal; + assert(*terminal == '.' || *terminal == 0); - /* skip current terminal character */ - terminal = *label_terminal - 1; + /* Skip current terminal character (and accept domain names ending it ".") */ + if (*terminal == 0) + terminal--; + if (terminal >= name && *terminal == '.') + terminal--; - /* point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */ + /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */ for (;;) { if (terminal < name) { - /* reached the first label, so indicate that there are no more */ + /* Reached the first label, so indicate that there are no more */ terminal = NULL; break; } - /* find the start of the last label */ + /* Find the start of the last label */ if (*terminal == '.') { const char *y; unsigned slashes = 0; @@ -159,7 +183,7 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha slashes ++; if (slashes % 2 == 0) { - /* the '.' was not escaped */ + /* The '.' was not escaped */ name = terminal + 1; break; } else { @@ -180,30 +204,36 @@ 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; + + /* DNS labels must be between 1 and 63 characters long. A + * zero-length label does not exist. See RFC 2182, Section + * 11. */ + + if (l <= 0 || l > DNS_LABEL_MAX) + return -EINVAL; + if (sz < 1) + return -ENOBUFS; assert(p); - assert(ret); + assert(dest); - if (l > DNS_LABEL_MAX) - return -EINVAL; - - s = malloc(l * 4 + 1); - if (!s) - return -ENOMEM; - - q = s; + q = dest; while (l > 0) { if (*p == '.' || *p == '\\') { /* Dot or backslash */ + + if (sz < 3) + return -ENOBUFS; + *(q++) = '\\'; *(q++) = *p; + sz -= 2; + } else if (*p == '_' || *p == '-' || (*p >= '0' && *p <= '9') || @@ -211,25 +241,55 @@ int dns_label_escape(const char *p, size_t l, char **ret) { (*p >= 'A' && *p <= 'Z')) { /* Proper character */ + + if (sz < 2) + return -ENOBUFS; + *(q++) = *p; - } else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) { + sz -= 1; + + } else { /* Everything else */ + + if (sz < 5) + return -ENOBUFS; + *(q++) = '\\'; *(q++) = '0' + (char) ((uint8_t) *p / 100); *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10); *(q++) = '0' + (char) ((uint8_t) *p % 10); - } else - return -EINVAL; + sz -= 4; + } p++; l--; } *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 <= 0 || 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; @@ -238,32 +298,52 @@ int dns_label_escape(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) { #ifdef HAVE_LIBIDN _cleanup_free_ uint32_t *input = NULL; - size_t input_size; + size_t input_size, l; const char *p; bool contains_8bit = false; + char buffer[DNS_LABEL_MAX+1]; assert(encoded); assert(decoded); - assert(decoded_max >= DNS_LABEL_MAX); + + /* Converts an U-label into an A-label */ if (encoded_size <= 0) - return 0; + return -EINVAL; for (p = encoded; p < encoded + encoded_size; p++) if ((uint8_t) *p > 127) contains_8bit = true; - if (!contains_8bit) + if (!contains_8bit) { + if (encoded_size > DNS_LABEL_MAX) + return -EINVAL; + return 0; + } input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size); if (!input) return -ENOMEM; - if (idna_to_ascii_4i(input, input_size, decoded, 0) != 0) + if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0) return -EINVAL; - return strlen(decoded); + l = strlen(buffer); + + /* Verify that the the result is not longer than one DNS label. */ + if (l <= 0 || l > DNS_LABEL_MAX) + return -EINVAL; + if (l > decoded_max) + return -ENOBUFS; + + memcpy(decoded, buffer, l); + + /* If there's room, append a trailing NUL byte, but only then */ + if (decoded_max > l) + decoded[l] = 0; + + return (int) l; #else return 0; #endif @@ -277,11 +357,14 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, uint32_t *output = NULL; size_t w; - /* To be invoked after unescaping */ + /* To be invoked after unescaping. Converts an A-label into an U-label. */ assert(encoded); assert(decoded); + if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX) + return -EINVAL; + if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1) return 0; @@ -301,11 +384,16 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, if (!result) return -ENOMEM; if (w <= 0) - return 0; - if (w+1 > decoded_max) return -EINVAL; + if (w > decoded_max) + return -ENOBUFS; + + memcpy(decoded, result, w); + + /* Append trailing NUL byte if there's space, but only then. */ + if (decoded_max > w) + decoded[w] = 0; - memcpy(decoded, result, w+1); return w; #else return 0; @@ -315,16 +403,20 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, int dns_name_concat(const char *a, const char *b, char **_ret) { _cleanup_free_ char *ret = NULL; size_t n = 0, allocated = 0; - const char *p = a; + const char *p; bool first = true; int r; - assert(a); + if (a) + p = a; + else if (b) { + p = b; + b = NULL; + } else + goto finish; for (;;) { - _cleanup_free_ char *t = NULL; char label[DNS_LABEL_MAX]; - int k; r = dns_label_unescape(&p, label, sizeof(label)); if (r < 0) @@ -343,37 +435,47 @@ int dns_name_concat(const char *a, const char *b, char **_ret) { break; } - k = dns_label_undo_idna(label, r, label, sizeof(label)); - if (k < 0) - return k; - 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; - if (!first) - ret[n++] = '.'; - else - first = false; + r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; - memcpy(ret + n, t, r); + if (!first) + ret[n] = '.'; + } else { + char escaped[DNS_LABEL_ESCAPED_MAX]; + + 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) +finish: + if (n > DNS_HOSTNAME_MAX) return -EINVAL; if (_ret) { - if (!GREEDY_REALLOC(ret, allocated, n + 1)) - return -ENOMEM; + if (n == 0) { + /* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */ + if (!GREEDY_REALLOC(ret, allocated, 2)) + return -ENOMEM; + + ret[n++] = '.'; + } else { + if (!GREEDY_REALLOC(ret, allocated, n + 1)) + return -ENOMEM; + } ret[n] = 0; *_ret = ret; @@ -389,27 +491,18 @@ void dns_name_hash_func(const void *s, struct siphash *state) { assert(p); - while (*p) { + for (;;) { char label[DNS_LABEL_MAX+1]; - int k; r = dns_label_unescape(&p, label, sizeof(label)); if (r < 0) break; - - k = dns_label_undo_idna(label, r, label, sizeof(label)); - if (k < 0) - break; - if (k > 0) - r = k; - if (r == 0) break; - label[r] = 0; - ascii_strlower(label); - - string_hash_func(label, state); + ascii_strlower_n(label, r); + siphash24_compress(label, r, state); + siphash24_compress_byte(0, state); /* make sure foobar and foo.bar result in different hashes */ } /* enforce that all names are terminated by the empty label */ @@ -418,7 +511,7 @@ void dns_name_hash_func(const void *s, struct siphash *state) { int dns_name_compare_func(const void *a, const void *b) { const char *x, *y; - int r, q, k, w; + int r, q; assert(a); assert(b); @@ -427,7 +520,7 @@ int dns_name_compare_func(const void *a, const void *b) { y = (const char *) b + strlen(b); for (;;) { - char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1]; + char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; if (x == NULL && y == NULL) return 0; @@ -437,17 +530,7 @@ int dns_name_compare_func(const void *a, const void *b) { if (r < 0 || q < 0) return r - q; - k = dns_label_undo_idna(la, r, la, sizeof(la)); - w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); - if (k < 0 || w < 0) - return k - w; - if (k > 0) - r = k; - if (w > 0) - r = w; - - la[r] = lb[q] = 0; - r = strcasecmp(la, lb); + r = ascii_strcasecmp_nn(la, r, lb, q); if (r != 0) return r; } @@ -459,45 +542,35 @@ const struct hash_ops dns_name_hash_ops = { }; int dns_name_equal(const char *x, const char *y) { - int r, q, k, w; + int r, q; assert(x); assert(y); for (;;) { - char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1]; - - if (*x == 0 && *y == 0) - return true; + char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; r = dns_label_unescape(&x, la, sizeof(la)); if (r < 0) return r; - k = dns_label_undo_idna(la, r, la, sizeof(la)); - if (k < 0) - return k; - if (k > 0) - r = k; - q = dns_label_unescape(&y, lb, sizeof(lb)); if (q < 0) return q; - w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); - if (w < 0) - return w; - if (w > 0) - q = w; - la[r] = lb[q] = 0; - if (strcasecmp(la, lb)) + if (r != q) + return false; + if (r == 0) + return true; + + if (ascii_strcasecmp_n(la, lb, r) != 0) return false; } } int dns_name_endswith(const char *name, const char *suffix) { const char *n, *s, *saved_n = NULL; - int r, q, k, w; + int r, q; assert(name); assert(suffix); @@ -506,16 +579,11 @@ int dns_name_endswith(const char *name, const char *suffix) { s = suffix; for (;;) { - char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1]; + char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX]; 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_n) saved_n = n; @@ -523,20 +591,13 @@ int dns_name_endswith(const char *name, const char *suffix) { 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) return true; if (r == 0 && saved_n == n) return false; - ln[r] = ls[q] = 0; - - if (r != q || strcasecmp(ln, ls)) { + if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) { /* Not the same, let's jump back, and try with the next label again */ s = suffix; @@ -546,6 +607,91 @@ int dns_name_endswith(const char *name, const char *suffix) { } } +int dns_name_startswith(const char *name, const char *prefix) { + const char *n, *p; + int r, q; + + assert(name); + assert(prefix); + + n = name; + p = prefix; + + for (;;) { + char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX]; + + r = dns_label_unescape(&p, lp, sizeof(lp)); + if (r < 0) + return r; + if (r == 0) + return true; + + q = dns_label_unescape(&n, ln, sizeof(ln)); + if (q < 0) + return q; + + if (r != q) + return false; + if (ascii_strcasecmp_n(ln, lp, r) != 0) + return false; + } +} + +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; + + assert(name); + assert(old_suffix); + assert(new_suffix); + assert(ret); + + n = name; + s = old_suffix; + + for (;;) { + char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX]; + + if (!saved_before) + saved_before = n; + + r = dns_label_unescape(&n, ln, sizeof(ln)); + if (r < 0) + return r; + + if (!saved_after) + saved_after = n; + + q = dns_label_unescape(&s, ls, sizeof(ls)); + if (q < 0) + return q; + + if (r == 0 && q == 0) + break; + if (r == 0 && saved_after == n) { + *ret = NULL; /* doesn't match */ + return 0; + } + + if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) { + + /* 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 +830,493 @@ 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]; +bool dns_name_is_root(const char *name) { + + assert(name); + + /* There are exactly two ways to encode the root domain name: + * as empty string, or with a single dot. */ + + return STR_IN_SET(name, "", "."); +} + +bool dns_name_is_single_label(const char *name) { int r; assert(name); - r = dns_label_unescape(&name, label, sizeof(label)); + r = dns_name_parent(&name); + if (r <= 0) + return false; + + return dns_name_is_root(name); +} + +/* Encode a domain name according to RFC 1035 Section 3.1, without compression */ +int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical) { + uint8_t *label_length, *out; + int r; + + assert(domain); + assert(buffer); + + 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. Note that + * dns_label_unescape() returns 0 when it hits the end + * of the domain name, which we rely on here to encode + * the trailing NUL byte. */ + r = dns_label_unescape(&domain, (char *) out, len); + if (r < 0) + return r; + + /* Optionally, output the name in DNSSEC canonical + * format, as described in RFC 4034, section 6.2. Or + * in other words: in lower-case. */ + if (canonical) + ascii_strlower_n((char*) out, (size_t) r); + + /* Fill label length, move forward */ + *label_length = r; + out += r; + len -= r; + + } while (r != 0); + + /* Verify the maximum size of the encoded name. The trailing + * dot + NUL byte account are included this time, hence + * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this + * time. */ + if (out - buffer > DNS_HOSTNAME_MAX + 2) + return -EINVAL; + + 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; - return r == 0 && *name == 0; + r = dns_name_concat(type, domain, &n); + if (r < 0) + return r; + + return dns_name_concat(escaped, n, ret); } -int dns_name_single_label(const char *name) { - char label[DNS_LABEL_MAX+1]; +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 = strndup(a, an); + if (!name) + return -ENOMEM; + + type = strjoin(b, ".", c, NULL); + if (!type) + return -ENOMEM; + + d = p; + goto finish; + } + + } else if (srv_type_label_is_valid(a, an)) { + + /* OK, got . . */ + + name = NULL; + + type = strjoin(a, ".", b, NULL); + if (!type) + return -ENOMEM; + + 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; +} + +static int dns_name_build_suffix_table(const char *name, const char*table[]) { + const char *p; + unsigned n = 0; + int r; + + assert(name); + assert(table); + + p = name; + for (;;) { + if (n > DNS_N_LABELS_MAX) + return -EINVAL; + + table[n] = p; + r = dns_name_parent(&p); + if (r < 0) + return r; + if (r == 0) + break; + + n++; + } + + return (int) n; +} + +int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) { + const char* labels[DNS_N_LABELS_MAX+1]; + int n; + + assert(name); + assert(ret); + + n = dns_name_build_suffix_table(name, labels); + if (n < 0) + return n; + + if ((unsigned) n < n_labels) + return -EINVAL; + + *ret = labels[n - n_labels]; + return (int) (n - n_labels); +} + +int dns_name_skip(const char *a, unsigned n_labels, const char **ret) { + int r; + + assert(a); + assert(ret); + + for (; n_labels > 0; n_labels --) { + r = dns_name_parent(&a); + if (r < 0) + return r; + if (r == 0) { + *ret = ""; + return 0; + } + } + + *ret = a; + return 1; +} + +int dns_name_count_labels(const char *name) { + unsigned n = 0; + const char *p; int r; assert(name); - r = dns_label_unescape(&name, label, sizeof(label)); - if (r < 0) - return r; - if (r == 0) - return 0; + p = name; + for (;;) { + r = dns_name_parent(&p); + if (r < 0) + return r; + if (r == 0) + break; - r = dns_label_unescape(&name, label, sizeof(label)); - if (r < 0) - return r; + if (n >= DNS_N_LABELS_MAX) + return -EINVAL; - return r == 0 && *name == 0; + n++; + } + + return (int) n; +} + +int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b) { + int r; + + assert(a); + assert(b); + + r = dns_name_skip(a, n_labels, &a); + if (r <= 0) + return r; + + return dns_name_equal(a, b); +} + +int dns_name_common_suffix(const char *a, const char *b, const char **ret) { + const char *a_labels[DNS_N_LABELS_MAX+1], *b_labels[DNS_N_LABELS_MAX+1]; + int n = 0, m = 0, k = 0, r, q; + + assert(a); + assert(b); + assert(ret); + + /* Determines the common suffix of domain names a and b */ + + n = dns_name_build_suffix_table(a, a_labels); + if (n < 0) + return n; + + m = dns_name_build_suffix_table(b, b_labels); + if (m < 0) + return m; + + for (;;) { + char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; + const char *x, *y; + + if (k >= n || k >= m) { + *ret = a_labels[n - k]; + return 0; + } + + x = a_labels[n - 1 - k]; + r = dns_label_unescape(&x, la, sizeof(la)); + if (r < 0) + return r; + + y = b_labels[m - 1 - k]; + q = dns_label_unescape(&y, lb, sizeof(lb)); + if (q < 0) + return q; + + if (r != q || ascii_strcasecmp_n(la, lb, r) != 0) { + *ret = a_labels[n - k]; + return 0; + } + + k++; + } +} + +int dns_name_apply_idna(const char *name, char **ret) { + _cleanup_free_ char *buf = NULL; + size_t n = 0, allocated = 0; + bool first = true; + int r, q; + + assert(name); + assert(ret); + + for (;;) { + char label[DNS_LABEL_MAX]; + + r = dns_label_unescape(&name, label, sizeof(label)); + if (r < 0) + return r; + if (r == 0) + break; + + q = dns_label_apply_idna(label, r, label, sizeof(label)); + if (q < 0) + return q; + if (q > 0) + r = q; + + if (!GREEDY_REALLOC(buf, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) + return -ENOMEM; + + r = dns_label_escape(label, r, buf + n + !first, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + + if (first) + first = false; + else + buf[n++] = '.'; + + n +=r; + } + + if (n > DNS_HOSTNAME_MAX) + return -EINVAL; + + if (!GREEDY_REALLOC(buf, allocated, n + 1)) + return -ENOMEM; + + buf[n] = 0; + *ret = buf; + buf = NULL; + + return (int) n; } diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 1f0d242c1..2de3642cb 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,15 +20,37 @@ #pragma once +#include +#include +#include +#include + #include "hashmap.h" #include "in-addr-util.h" +/* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */ #define DNS_LABEL_MAX 63 -#define DNS_NAME_MAX 255 + +/* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */ +#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1) + +/* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */ +#define DNS_HOSTNAME_MAX 253 + +/* Maximum length of a full hostname, on the wire, including the final NUL byte */ +#define DNS_WIRE_FOMAT_HOSTNAME_MAX 255 + +/* Maximum number of labels per valid hostname */ +#define DNS_N_LABELS_MAX 127 int dns_label_unescape(const char **name, char *dest, size_t sz); 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); + +static inline int dns_name_parent(const char **name) { + return dns_label_unescape(name, NULL, DNS_LABEL_MAX); +} 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); @@ -61,9 +81,30 @@ extern const struct hash_ops dns_name_hash_ops; 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_startswith(const char *name, const char *prefix); + +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 canonical); + +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); + +int dns_name_suffix(const char *name, unsigned n_labels, const char **ret); +int dns_name_count_labels(const char *name); + +int dns_name_skip(const char *a, unsigned n_labels, const char **ret); +int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b); + +int dns_name_common_suffix(const char *a, const char *b, const char **ret); + +int dns_name_apply_idna(const char *name, char **ret); diff --git a/src/shared/dropin.c b/src/shared/dropin.c index 0d44401cc..cc1acd6f2 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,17 +17,27 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include + #include "alloc-util.h" #include "conf-files.h" #include "dropin.h" #include "escape.h" #include "fd-util.h" #include "fileio-label.h" +#include "hashmap.h" +#include "log.h" +#include "macro.h" #include "mkdir.h" #include "path-util.h" +#include "set.h" #include "string-util.h" #include "strv.h" -#include "util.h" +#include "unit-name.h" int drop_in_file(const char *dir, const char *unit, unsigned level, const char *name, char **_p, char **_q) { @@ -146,7 +154,7 @@ static int iterate_dir( errno = 0; de = readdir(d); - if (!de && errno != 0) + if (!de && errno > 0) return log_error_errno(errno, "Failed to read directory %s: %m", path); if (!de) diff --git a/src/shared/dropin.h b/src/shared/dropin.h index d4531fca2..c1936f397 100644 --- a/src/shared/dropin.h +++ b/src/shared/dropin.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,7 @@ along with systemd; If not, see . ***/ +#include "hashmap.h" #include "macro.h" #include "set.h" #include "unit-name.h" diff --git a/src/shared/efivars.c b/src/shared/efivars.c index 89deeb9b5..8631a5a5d 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,17 +17,27 @@ along with systemd; If not, see . ***/ +#include +#include #include +#include +#include +#include #include +#include #include +#include "sd-id128.h" + #include "alloc-util.h" #include "dirent-util.h" #include "efivars.h" #include "fd-util.h" #include "io-util.h" +#include "macro.h" #include "parse-util.h" #include "stdio-util.h" +#include "time-util.h" #include "utf8.h" #include "util.h" #include "virt.h" diff --git a/src/shared/efivars.h b/src/shared/efivars.h index e953a1273..b61d14c4e 100644 --- a/src/shared/efivars.h +++ b/src/shared/efivars.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,8 +20,11 @@ ***/ #include +#include +#include #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 5acfb0191..0d3da2e6d 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,14 @@ along with systemd; If not, see . ***/ +#include #include +#include +#include #include -#include +#include +#include +#include #include #include #include @@ -29,7 +32,8 @@ #include "alloc-util.h" #include "firewall-util.h" -#include "util.h" +#include "in-addr-util.h" +#include "macro.h" DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free); diff --git a/src/shared/firewall-util.h b/src/shared/firewall-util.h index 93152e397..c39b34cf8 100644 --- a/src/shared/firewall-util.h +++ b/src/shared/firewall-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,9 @@ along with systemd; If not, see . ***/ +#include +#include + #include "in-addr-util.h" #ifdef HAVE_LIBIPTC diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index eb2845cdd..a4e0cd326 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,16 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include + #include "alloc-util.h" #include "device-nodes.h" #include "fstab-util.h" +#include "macro.h" #include "mount-util.h" #include "parse-util.h" #include "path-util.h" diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h index 5ebea4401..679f6902f 100644 --- a/src/shared/fstab-util.h +++ b/src/shared/fstab-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/generator.c b/src/shared/generator.c index 9998c6441..cd3c35cd5 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,6 +17,7 @@ along with systemd; If not, see . ***/ +#include #include #include "alloc-util.h" @@ -28,11 +27,13 @@ #include "fileio.h" #include "fstab-util.h" #include "generator.h" +#include "log.h" +#include "macro.h" #include "mkdir.h" -#include "mount-util.h" #include "path-util.h" #include "special.h" #include "string-util.h" +#include "time-util.h" #include "unit-name.h" #include "util.h" @@ -187,7 +188,6 @@ int generator_write_timeouts( return write_drop_in_format(dir, unit, 50, "device-timeout", "# Automatically generated by %s\n\n" - "[Unit]\nJobTimeoutSec=" USEC_FMT, - program_invocation_short_name, - u / USEC_PER_SEC); + "[Unit]\nJobTimeoutSec=%s", + program_invocation_short_name, timeout); } diff --git a/src/shared/generator.h b/src/shared/generator.h index 6c3f38abb..a734e1397 100644 --- a/src/shared/generator.h +++ b/src/shared/generator.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/gpt.h b/src/shared/gpt.h index add1df420..52ab29ed5 100644 --- a/src/shared/gpt.h +++ b/src/shared/gpt.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -25,7 +23,7 @@ #include "sd-id128.h" -/* We only support root disk discovery for x86, x86-64 and ARM for +/* We only support root disk discovery for x86, x86-64, Itanium and ARM for * now, since EFI for anything else doesn't really exist, and we only * care for root partitions on the same disk as the EFI ESP. */ @@ -33,6 +31,7 @@ #define GPT_ROOT_X86_64 SD_ID128_MAKE(4f,68,bc,e3,e8,cd,4d,b1,96,e7,fb,ca,f9,84,b7,09) #define GPT_ROOT_ARM SD_ID128_MAKE(69,da,d7,10,2c,e4,4e,3c,b1,6c,21,a1,d4,9a,be,d3) #define GPT_ROOT_ARM_64 SD_ID128_MAKE(b9,21,b0,45,1d,f0,41,c3,af,44,4c,6f,28,0d,3f,ae) +#define GPT_ROOT_IA64 SD_ID128_MAKE(99,3d,8d,3d,f8,0e,42,25,85,5a,9d,af,8e,d7,ea,97) #define GPT_ESP SD_ID128_MAKE(c1,2a,73,28,f8,1f,11,d2,ba,4b,00,a0,c9,3e,c9,3b) #define GPT_SWAP SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f) @@ -46,6 +45,10 @@ # define GPT_ROOT_NATIVE GPT_ROOT_X86 #endif +#if defined(__ia64__) +# define GPT_ROOT_NATIVE GPT_ROOT_IA64 +#endif + #if defined(__aarch64__) && (__BYTE_ORDER != __BIG_ENDIAN) # define GPT_ROOT_NATIVE GPT_ROOT_ARM_64 # define GPT_ROOT_SECONDARY GPT_ROOT_ARM diff --git a/src/shared/ima-util.c b/src/shared/ima-util.c index 6c1954bbf..789064d65 100644 --- a/src/shared/ima-util.c +++ b/src/shared/ima-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/shared/ima-util.h b/src/shared/ima-util.h index d38216170..5be94761f 100644 --- a/src/shared/ima-util.h +++ b/src/shared/ima-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/import-util.c b/src/shared/import-util.c index ddc8c00a2..ab701ad8b 100644 --- a/src/shared/import-util.c +++ b/src/shared/import-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,14 @@ along with systemd; If not, see . ***/ +#include +#include + #include "alloc-util.h" #include "btrfs-util.h" #include "import-util.h" +#include "log.h" +#include "macro.h" #include "path-util.h" #include "string-table.h" #include "string-util.h" @@ -155,58 +158,6 @@ int raw_strip_suffixes(const char *p, char **ret) { return 0; } -bool dkr_digest_is_valid(const char *digest) { - /* 7 chars for prefix, 64 chars for the digest itself */ - if (strlen(digest) != 71) - return false; - - return startswith(digest, "sha256:") && in_charset(digest + 7, "0123456789abcdef"); -} - -bool dkr_ref_is_valid(const char *ref) { - const char *colon; - - if (isempty(ref)) - return false; - - colon = strchr(ref, ':'); - if (!colon) - return filename_is_valid(ref); - - return dkr_digest_is_valid(ref); -} - -bool dkr_name_is_valid(const char *name) { - const char *slash, *p; - - if (isempty(name)) - return false; - - slash = strchr(name, '/'); - if (!slash) - return false; - - if (!filename_is_valid(slash + 1)) - return false; - - p = strndupa(name, slash - name); - if (!filename_is_valid(p)) - return false; - - return true; -} - -bool dkr_id_is_valid(const char *id) { - - if (!filename_is_valid(id)) - return false; - - if (!in_charset(id, "0123456789abcdef")) - return false; - - return true; -} - int import_assign_pool_quota_and_warn(const char *path) { int r; diff --git a/src/shared/import-util.h b/src/shared/import-util.h index 9120a5119..77b17d91f 100644 --- a/src/shared/import-util.h +++ b/src/shared/import-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -42,10 +40,4 @@ ImportVerify import_verify_from_string(const char *s) _pure_; int tar_strip_suffixes(const char *name, char **ret); int raw_strip_suffixes(const char *name, char **ret); -bool dkr_name_is_valid(const char *name); -bool dkr_id_is_valid(const char *id); -bool dkr_ref_is_valid(const char *ref); -bool dkr_digest_is_valid(const char *digest); -#define dkr_tag_is_valid(tag) filename_is_valid(tag) - int import_assign_pool_quota_and_warn(const char *path); diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index 74b909d34..88143361d 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,15 +17,18 @@ along with systemd; If not, see . ***/ -#include +#include +#include +#include +#include -#include "alloc-util.h" #include "formats-util.h" #include "install-printf.h" +#include "install.h" +#include "macro.h" #include "specifier.h" #include "unit-name.h" #include "user-util.h" -#include "util.h" static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) { UnitFileInstallInfo *i = userdata; diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h index 655033782..acf519f4f 100644 --- a/src/shared/install-printf.h +++ b/src/shared/install-printf.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/shared/install.c b/src/shared/install.c index 17e03e59c..ef8f485ca 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,22 +17,31 @@ along with systemd; If not, see . ***/ +#include #include #include #include +#include +#include +#include +#include #include +#include #include #include "alloc-util.h" #include "conf-files.h" #include "conf-parser.h" #include "dirent-util.h" +#include "extract-word.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" #include "hashmap.h" #include "install-printf.h" #include "install.h" +#include "log.h" +#include "macro.h" #include "mkdir.h" #include "path-lookup.h" #include "path-util.h" @@ -45,7 +52,6 @@ #include "string-util.h" #include "strv.h" #include "unit-name.h" -#include "util.h" #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64 diff --git a/src/shared/install.h b/src/shared/install.h index 45a417df9..c1a43e23e 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -30,7 +28,10 @@ typedef struct UnitFileChange UnitFileChange; typedef struct UnitFileList UnitFileList; typedef struct UnitFileInstallInfo UnitFileInstallInfo; +#include + #include "hashmap.h" +#include "macro.h" #include "path-lookup.h" #include "strv.h" #include "unit-name.h" diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 0313b0946..5eb3bd35c 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,9 +19,17 @@ #include #include +#include +#include +#include #include #include +#include #include +#include + +#include "sd-id128.h" +#include "sd-journal.h" #include "alloc-util.h" #include "fd-util.h" @@ -34,11 +40,15 @@ #include "journal-internal.h" #include "log.h" #include "logs-show.h" +#include "macro.h" +#include "output-mode.h" #include "parse-util.h" #include "process-util.h" +#include "sparse-endian.h" #include "string-table.h" #include "string-util.h" #include "terminal-util.h" +#include "time-util.h" #include "utf8.h" #include "util.h" @@ -70,12 +80,11 @@ static int print_catalog(FILE *f, sd_journal *j) { static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) { size_t fl, nl; - void *buf; + char *buf; assert(data); assert(field); assert(target); - assert(target_size); fl = strlen(field); if (length < fl) @@ -85,16 +94,18 @@ static int parse_field(const void *data, size_t length, const char *field, char return 0; nl = length - fl; - buf = malloc(nl+1); + buf = new(char, nl+1); if (!buf) return log_oom(); memcpy(buf, (const char*) data + fl, nl); - ((char*)buf)[nl] = 0; + buf[nl] = 0; free(*target); *target = buf; - *target_size = nl; + + if (target_size) + *target_size = nl; return 1; } @@ -403,7 +414,7 @@ static int output_verbose( const void *data; size_t length; _cleanup_free_ char *cursor = NULL; - uint64_t realtime; + uint64_t realtime = 0; char ts[FORMAT_TIMESTAMP_MAX + 7]; int r; @@ -419,16 +430,15 @@ static int output_verbose( return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m"); else { _cleanup_free_ char *value = NULL; - size_t size; - r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size); + r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, NULL); if (r < 0) - log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m"); - else { - r = safe_atou64(value, &realtime); - if (r < 0) - log_debug_errno(r, "Failed to parse realtime timestamp: %m"); - } + return r; + assert(r > 0); + + r = safe_atou64(value, &realtime); + if (r < 0) + log_debug_errno(r, "Failed to parse realtime timestamp: %m"); } if (r < 0) { @@ -1241,7 +1251,7 @@ int show_journal_by_unit( bool system_unit, bool *ellipsized) { - _cleanup_journal_close_ sd_journal*j = NULL; + _cleanup_(sd_journal_closep) sd_journal *j = NULL; int r; assert(mode >= 0); diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h index 569e1faa5..9765a24ff 100644 --- a/src/shared/logs-show.h +++ b/src/shared/logs-show.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,12 +20,16 @@ ***/ #include +#include +#include #include #include "sd-journal.h" -#include "util.h" +#include "macro.h" #include "output-mode.h" +#include "time-util.h" +#include "util.h" int output_journal( FILE *f, diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 2c1da0a40..ed8a29c57 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,10 +17,15 @@ along with systemd; If not, see . ***/ +#include +#include #include +#include +#include +#include +#include +#include #include -#include - #include "alloc-util.h" #include "btrfs-util.h" #include "chattr-util.h" @@ -30,6 +33,10 @@ #include "dirent-util.h" #include "fd-util.h" #include "fs-util.h" +#include "hashmap.h" +#include "lockfile-util.h" +#include "log.h" +#include "macro.h" #include "machine-image.h" #include "mkdir.h" #include "path-util.h" @@ -37,7 +44,9 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "utf8.h" +#include "util.h" #include "xattr-util.h" static const char image_search_path[] = diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h index f041600fb..31b720d50 100644 --- a/src/shared/machine-image.h +++ b/src/shared/machine-image.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,9 +19,13 @@ along with systemd; If not, see . ***/ -#include "time-util.h" -#include "lockfile-util.h" +#include +#include + #include "hashmap.h" +#include "lockfile-util.h" +#include "macro.h" +#include "time-util.h" typedef enum ImageType { IMAGE_DIRECTORY, diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index 4172a63fd..e5674e413 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,10 +17,23 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include +#include +#include +#include +#include #include #include +#include +#include #include -#include +#include + +#include "sd-bus-protocol.h" +#include "sd-bus.h" #include "alloc-util.h" #include "btrfs-util.h" @@ -30,7 +41,10 @@ #include "fileio.h" #include "fs-util.h" #include "lockfile-util.h" +#include "log.h" #include "machine-pool.h" +#include "macro.h" +#include "missing.h" #include "mkdir.h" #include "mount-util.h" #include "parse-util.h" @@ -39,7 +53,6 @@ #include "signal-util.h" #include "stat-util.h" #include "string-util.h" -#include "util.h" #define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL) #define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL) diff --git a/src/shared/machine-pool.h b/src/shared/machine-pool.h index fe01d3d47..40fe5ecb3 100644 --- a/src/shared/machine-pool.h +++ b/src/shared/machine-pool.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,8 @@ along with systemd; If not, see . ***/ +#include + #include "sd-bus.h" /* Grow the /var/lib/machines directory after each 10MiB written */ diff --git a/src/shared/output-mode.h b/src/shared/output-mode.h index 81d7f05d9..c5470e7c1 100644 --- a/src/shared/output-mode.h +++ b/src/shared/output-mode.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/pager.c b/src/shared/pager.c index d149bc172..05b2b15e4 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,11 @@ along with systemd; If not, see . ***/ -#include +#include +#include +#include +#include +#include #include #include #include @@ -28,13 +30,13 @@ #include "copy.h" #include "fd-util.h" #include "locale-util.h" +#include "log.h" #include "macro.h" #include "pager.h" #include "process-util.h" #include "signal-util.h" #include "string-util.h" #include "terminal-util.h" -#include "util.h" static pid_t pager_pid = 0; diff --git a/src/shared/pager.h b/src/shared/pager.h index 67446170d..9fb05796b 100644 --- a/src/shared/pager.h +++ b/src/shared/pager.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 4a82bd18c..541062072 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -26,6 +24,8 @@ #include "alloc-util.h" #include "install.h" +#include "log.h" +#include "macro.h" #include "path-lookup.h" #include "path-util.h" #include "string-util.h" diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index e35c8d3c0..26c83d611 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include "macro.h" typedef struct LookupPaths { diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 2666b8f7e..061d31f4d 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,15 +17,27 @@ along with systemd; If not, see . ***/ +#include #include +#include +#include +#include +#include +#include #include #include +#include #include +#include + +#include "sd-event.h" #include "alloc-util.h" #include "fd-util.h" +#include "log.h" +#include "macro.h" #include "ptyfwd.h" -#include "util.h" +#include "time-util.h" struct PTYForward { sd_event *event; diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h index 9b3214221..a046eb4e5 100644 --- a/src/shared/ptyfwd.h +++ b/src/shared/ptyfwd.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -25,6 +23,8 @@ #include "sd-event.h" +#include "macro.h" + typedef struct PTYForward PTYForward; typedef enum PTYForwardFlags { diff --git a/src/shared/resolve-util.c b/src/shared/resolve-util.c new file mode 100644 index 000000000..e2da81bab --- /dev/null +++ b/src/shared/resolve-util.c @@ -0,0 +1,39 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "conf-parser.h" +#include "resolve-util.h" +#include "string-table.h" + +DEFINE_CONFIG_PARSE_ENUM(config_parse_resolve_support, resolve_support, ResolveSupport, "Failed to parse resolve support setting"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_dnssec_mode, dnssec_mode, DnssecMode, "Failed to parse DNSSEC mode setting"); + +static const char* const resolve_support_table[_RESOLVE_SUPPORT_MAX] = { + [RESOLVE_SUPPORT_NO] = "no", + [RESOLVE_SUPPORT_YES] = "yes", + [RESOLVE_SUPPORT_RESOLVE] = "resolve", +}; +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(resolve_support, ResolveSupport, RESOLVE_SUPPORT_YES); + +static const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = { + [DNSSEC_NO] = "no", + [DNSSEC_ALLOW_DOWNGRADE] = "allow-downgrade", + [DNSSEC_YES] = "yes", +}; +DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dnssec_mode, DnssecMode, DNSSEC_YES); diff --git a/src/shared/resolve-util.h b/src/shared/resolve-util.h new file mode 100644 index 000000000..8636a6c13 --- /dev/null +++ b/src/shared/resolve-util.h @@ -0,0 +1,60 @@ +#pragma once + +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "macro.h" + +typedef enum ResolveSupport ResolveSupport; +typedef enum DnssecMode DnssecMode; + +enum ResolveSupport { + RESOLVE_SUPPORT_NO, + RESOLVE_SUPPORT_YES, + RESOLVE_SUPPORT_RESOLVE, + _RESOLVE_SUPPORT_MAX, + _RESOLVE_SUPPORT_INVALID = -1 +}; + +enum DnssecMode { + /* No DNSSEC validation is done */ + DNSSEC_NO, + + /* Validate locally, if the server knows DO, but if not, + * don't. Don't trust the AD bit. If the server doesn't do + * DNSSEC properly, downgrade to non-DNSSEC operation. Of + * course, we then are vulnerable to a downgrade attack, but + * that's life and what is configured. */ + DNSSEC_ALLOW_DOWNGRADE, + + /* Insist on DNSSEC server support, and rather fail than downgrading. */ + DNSSEC_YES, + + _DNSSEC_MODE_MAX, + _DNSSEC_MODE_INVALID = -1 +}; + +int config_parse_resolve_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); +int config_parse_dnssec_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); + +const char* resolve_support_to_string(ResolveSupport p) _const_; +ResolveSupport resolve_support_from_string(const char *s) _pure_; + +const char* dnssec_mode_to_string(DnssecMode p) _const_; +DnssecMode dnssec_mode_from_string(const char *s) _pure_; diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 09baf5166..cebe0fce2 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,11 +17,13 @@ along with systemd; If not, see . ***/ +#include #include +#include +#include "macro.h" #include "seccomp-util.h" #include "string-util.h" -#include "util.h" const char* seccomp_arch_to_string(uint32_t c) { diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index 60d97154e..4ed2afc1b 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,6 +20,7 @@ ***/ #include +#include const char* seccomp_arch_to_string(uint32_t c); int seccomp_arch_from_string(const char *n, uint32_t *ret); diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 39b836d05..a0aef66bc 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,7 +17,13 @@ along with systemd; If not, see . ***/ +#include +#include +#include #include +#include +#include +#include #include "alloc-util.h" #include "conf-parser.h" @@ -27,11 +31,11 @@ #include "fd-util.h" #include "fileio.h" #include "log.h" +#include "macro.h" #include "parse-util.h" #include "sleep-config.h" #include "string-util.h" #include "strv.h" -#include "util.h" #define USE(x, y) do{ (x) = (y); (y) = NULL; } while(0) diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h index 5eda18ee3..51f462184 100644 --- a/src/shared/sleep-config.h +++ b/src/shared/sleep-config.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c index 3fcea6187..a46b7525f 100644 --- a/src/shared/spawn-ask-password-agent.c +++ b/src/shared/spawn-ask-password-agent.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/shared/spawn-ask-password-agent.h b/src/shared/spawn-ask-password-agent.h index 31b4beab5..fb0749b13 100644 --- a/src/shared/spawn-ask-password-agent.h +++ b/src/shared/spawn-ask-password-agent.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c index 8ea6cb830..cf3c8ad5a 100644 --- a/src/shared/spawn-polkit-agent.c +++ b/src/shared/spawn-polkit-agent.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -28,9 +26,11 @@ #include "fd-util.h" #include "io-util.h" #include "log.h" +#include "macro.h" #include "process-util.h" #include "spawn-polkit-agent.h" #include "stdio-util.h" +#include "time-util.h" #include "util.h" #ifdef ENABLE_POLKIT diff --git a/src/shared/spawn-polkit-agent.h b/src/shared/spawn-polkit-agent.h index c3bc1b845..42b2989de 100644 --- a/src/shared/spawn-polkit-agent.h +++ b/src/shared/spawn-polkit-agent.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/specifier.c b/src/shared/specifier.c index c5c4a4d7d..1c17eb525 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,15 +17,20 @@ along with systemd; If not, see . ***/ +#include +#include +#include +#include #include #include +#include "sd-id128.h" + #include "alloc-util.h" #include "hostname-util.h" #include "macro.h" #include "specifier.h" #include "string-util.h" -#include "util.h" /* * Generic infrastructure for replacing %x style specifiers in diff --git a/src/shared/specifier.h b/src/shared/specifier.h index fca206f66..6b1623ee6 100644 --- a/src/shared/specifier.h +++ b/src/shared/specifier.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index fc885f6cb..47d3a5a1f 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -21,18 +19,21 @@ #include #include +#include #include -#include +#include #include #include #include #include "base-filesystem.h" #include "fd-util.h" +#include "log.h" #include "missing.h" #include "mkdir.h" #include "path-util.h" #include "rm-rf.h" +#include "stdio-util.h" #include "string-util.h" #include "switch-root.h" #include "user-util.h" @@ -75,7 +76,7 @@ int switch_root(const char *new_root, const char *oldroot, bool detach_oldroot, char new_mount[PATH_MAX]; struct stat sb; - snprintf(new_mount, sizeof(new_mount), "%s%s", new_root, i); + xsprintf(new_mount, "%s%s", new_root, i); mkdir_p_label(new_mount, 0755); diff --git a/src/shared/switch-root.h b/src/shared/switch-root.h index adf893a92..a7a080b3e 100644 --- a/src/shared/switch-root.h +++ b/src/shared/switch-root.h @@ -1,7 +1,6 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once +#include /*** This file is part of systemd. diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c index 70caa542e..e1ccb3294 100644 --- a/src/shared/sysctl-util.c +++ b/src/shared/sysctl-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,19 +17,14 @@ along with systemd; If not, see . ***/ -#include -#include -#include -#include #include -#include #include #include "fileio.h" #include "log.h" +#include "macro.h" #include "string-util.h" #include "sysctl-util.h" -#include "util.h" char *sysctl_normalize(char *s) { char *n; diff --git a/src/shared/sysctl-util.h b/src/shared/sysctl-util.h index 2ee6454e5..2decb39f5 100644 --- a/src/shared/sysctl-util.h +++ b/src/shared/sysctl-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/test-tables.h b/src/shared/test-tables.h index 74f1716fe..228e51010 100644 --- a/src/shared/test-tables.h +++ b/src/shared/test-tables.h @@ -28,18 +28,25 @@ static inline void _test_table(const char *name, reverse_t reverse, int size, bool sparse) { - int i; + int i, boring = 0; for (i = -1; i < size + 1; i++) { const char* val = lookup(i); int rev; - if (val) + if (val) { rev = reverse(val); - else + boring = 0; + } else { rev = reverse("--no-such--value----"); + boring += i >= 0; + } + + if (boring < 1 || i == size) + printf("%s: %d → %s → %d\n", name, i, val, rev); + else if (boring == 1) + printf("%*s ...\n", (int) strlen(name), ""); - printf("%s: %d → %s → %d\n", name, i, val, rev); assert_se(!(i >= 0 && i < size ? sparse ? rev != i && rev != -1 : val == NULL || rev != i : val != NULL || rev != -1)); diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h index f758ce13e..ca0889f8a 100644 --- a/src/shared/udev-util.h +++ b/src/shared/udev-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/uid-range.c b/src/shared/uid-range.c index 079dd8752..eb251492c 100644 --- a/src/shared/uid-range.c +++ b/src/shared/uid-range.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -19,9 +17,13 @@ along with systemd; If not, see . ***/ +#include +#include +#include + +#include "macro.h" #include "uid-range.h" #include "user-util.h" -#include "util.h" static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) { assert(range); diff --git a/src/shared/uid-range.h b/src/shared/uid-range.h index 45335e939..4044eb4c9 100644 --- a/src/shared/uid-range.h +++ b/src/shared/uid-range.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c index 13b32a050..9750dcd81 100644 --- a/src/shared/utmp-wtmp.c +++ b/src/shared/utmp-wtmp.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,7 +20,11 @@ #include #include #include +#include +#include +#include #include +#include #include #include #include @@ -34,7 +36,9 @@ #include "path-util.h" #include "string-util.h" #include "terminal-util.h" +#include "time-util.h" #include "user-util.h" +#include "util.h" #include "utmp-wtmp.h" int utmp_get_runlevel(int *runlevel, int *previous) { diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h index e0ceb873a..438e270a2 100644 --- a/src/shared/utmp-wtmp.h +++ b/src/shared/utmp-wtmp.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,10 @@ along with systemd; If not, see . ***/ +#include +#include + +#include "time-util.h" #include "util.h" #ifdef HAVE_UTMP diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c index 7131e94cd..4f3e0125f 100644 --- a/src/shared/watchdog.c +++ b/src/shared/watchdog.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -22,11 +20,13 @@ #include #include #include +#include #include #include #include "fd-util.h" #include "log.h" +#include "time-util.h" #include "watchdog.h" static int watchdog_fd = -1; diff --git a/src/shared/watchdog.h b/src/shared/watchdog.h index b748b1585..f6ec178ea 100644 --- a/src/shared/watchdog.h +++ b/src/shared/watchdog.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,6 +19,9 @@ along with systemd; If not, see . ***/ +#include + +#include "time-util.h" #include "util.h" int watchdog_set_timeout(usec_t *usec); diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 95de36981..c8f074218 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index ba82adadb..99d4b6213 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -505,7 +503,7 @@ static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdat if (errno != -EAGAIN) log_warning_errno(errno, "Failed to accept() socket: %m"); } else { - getpeername_pretty(nfd, &peer); + getpeername_pretty(nfd, true, &peer); log_debug("New connection from %s", strna(peer)); r = add_connection_socket(context, nfd); diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index 25b5ff52e..ce7c26e7d 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c index 6c2f53774..a3d677f06 100644 --- a/src/system-update-generator/system-update-generator.c +++ b/src/system-update-generator/system-update-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index 51b82d57d..908ccabf8 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -247,7 +245,7 @@ static OutputFlags get_output_flags(void) { arg_all * OUTPUT_SHOW_ALL | arg_full * OUTPUT_FULL_WIDTH | (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH | - on_tty() * OUTPUT_COLOR | + colors_enabled() * OUTPUT_COLOR | !arg_quiet * OUTPUT_WARN_CUTOFF; } @@ -530,9 +528,9 @@ static int get_unit_list( int c, sd_bus_message **_reply) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; size_t size = c; int r; UnitInfo u; @@ -637,7 +635,7 @@ static int get_unit_list_recursive( return log_error_errno(r, "Failed to get machine names: %m"); STRV_FOREACH(i, machines) { - _cleanup_bus_flush_close_unref_ sd_bus *container = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *container = NULL; int k; r = sd_bus_open_system_machine(&container, *i); @@ -699,7 +697,7 @@ static int get_triggered_units( const char* path, char*** ret) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -725,8 +723,8 @@ static int get_listening( const char* unit_path, char*** listening) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *type, *path; int r, n = 0; @@ -962,7 +960,7 @@ static int get_next_elapse( const char *path, dual_timestamp *next) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; dual_timestamp t; int r; @@ -1003,7 +1001,7 @@ static int get_last_trigger( const char *path, usec_t *last) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(bus); @@ -1358,7 +1356,7 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) { } static int list_unit_files(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ UnitFileList *units = NULL; UnitFileList *unit; size_t size = 0; @@ -1404,7 +1402,7 @@ static int list_unit_files(int argc, char *argv[], void *userdata) { assert(c <= n_units); hashmap_free(h); } else { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; r = acquire_bus(BUS_MANAGER, &bus); @@ -1516,8 +1514,8 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha [DEPENDENCY_BEFORE] = "Before\0", }; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_strv_free_ char **ret = NULL; _cleanup_free_ char *path = NULL; int r; @@ -1742,7 +1740,7 @@ static int compare_machine_info(const void *a, const void *b) { } static int get_machine_properties(sd_bus *bus, struct machine_info *mi) { - _cleanup_bus_flush_close_unref_ sd_bus *container = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *container = NULL; int r; assert(mi); @@ -1930,7 +1928,7 @@ static int list_machines(int argc, char *argv[], void *userdata) { } static int get_default(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *_path = NULL; const char *path; int r; @@ -1942,7 +1940,7 @@ static int get_default(int argc, char *argv[], void *userdata) { path = _path; } else { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; r = acquire_bus(BUS_MANAGER, &bus); @@ -1979,7 +1977,7 @@ static void dump_unit_file_changes(const UnitFileChange *changes, unsigned n_cha for (i = 0; i < n_changes; i++) { if (changes[i].type == UNIT_FILE_SYMLINK) - log_info("Created symlink from %s to %s.", changes[i].path, changes[i].source); + log_info("Created symlink %s, pointing to %s.", changes[i].path, changes[i].source); else log_info("Removed symlink %s.", changes[i].path); } @@ -2010,8 +2008,8 @@ static int set_default(int argc, char *argv[], void *userdata) { unit_file_changes_free(changes, n_changes); r = 0; } else { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; sd_bus *bus; polkit_agent_open_if_enabled(); @@ -2128,8 +2126,8 @@ static bool output_show_job(struct job_info *job, char **patterns) { } static int list_jobs(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *name, *type, *state, *job_path, *unit_path; _cleanup_free_ struct job_info *jobs = NULL; size_t size = 0; @@ -2200,7 +2198,7 @@ static int cancel_job(int argc, char *argv[], void *userdata) { return r; STRV_FOREACH(name, strv_skip(argv, 1)) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; uint32_t id; int q; @@ -2228,7 +2226,7 @@ static int cancel_job(int argc, char *argv[], void *userdata) { } static int need_daemon_reload(sd_bus *bus, const char *unit) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *path; int b, r; @@ -2324,43 +2322,13 @@ static int unit_find_paths( assert(lp); if (!install_client_side() && !unit_name_is_valid(unit_name, UNIT_NAME_TEMPLATE)) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *unit_load_error = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *unit = NULL; - char *unit_load_error_name, *unit_load_error_message; unit = unit_dbus_path_from_name(unit_name); if (!unit) return log_oom(); - if (need_daemon_reload(bus, unit_name) > 0) - warn_unit_file_changed(unit_name); - - r = sd_bus_get_property( - bus, - "org.freedesktop.systemd1", - unit, - "org.freedesktop.systemd1.Unit", - "LoadError", - &error, - &unit_load_error, - "(ss)"); - if (r < 0) - return log_error_errno(r, "Failed to get LoadError: %s", bus_error_message(&error, r)); - - r = sd_bus_message_read( - unit_load_error, - "(ss)", - &unit_load_error_name, - &unit_load_error_message); - if (r < 0) - return bus_log_parse_error(r); - - if (!isempty(unit_load_error_name)) { - log_error("Unit %s is not loaded: %s", unit_name, unit_load_error_message); - return 0; - } - r = sd_bus_get_property_string( bus, "org.freedesktop.systemd1", @@ -2440,19 +2408,16 @@ static int unit_find_paths( } static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_free_ char *n = NULL, *state = NULL; - const char *path; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_free_ char *buf = NULL; + const char *path, *state; int r; assert(name); - r = unit_name_mangle(name, UNIT_NAME_NOGLOB, &n); - if (r < 0) - return log_error_errno(r, "Failed to mangle unit name: %m"); - - /* We don't use unit_dbus_path_from_name() directly since we - * don't want to load the unit if it isn't loaded. */ + /* We don't use unit_dbus_path_from_name() directly since we don't want to load the unit unnecessarily, if it + * isn't loaded. */ r = sd_bus_call_method( bus, @@ -2460,31 +2425,34 @@ static int check_one_unit(sd_bus *bus, const char *name, const char *good_states "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "GetUnit", - NULL, + &error, &reply, - "s", n); + "s", name); if (r < 0) { - if (!quiet) - puts("unknown"); - return 0; - } + if (!sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT)) + return log_error_errno(r, "Failed to retrieve unit: %s", bus_error_message(&error, r)); - r = sd_bus_message_read(reply, "o", &path); - if (r < 0) - return bus_log_parse_error(r); + /* The unit is currently not loaded, hence say it's "inactive", since all units that aren't loaded are + * considered inactive. */ + state = "inactive"; - r = sd_bus_get_property_string( - bus, - "org.freedesktop.systemd1", - path, - "org.freedesktop.systemd1.Unit", - "ActiveState", - NULL, - &state); - if (r < 0) { - if (!quiet) - puts("unknown"); - return 0; + } else { + r = sd_bus_message_read(reply, "o", &path); + if (r < 0) + return bus_log_parse_error(r); + + r = sd_bus_get_property_string( + bus, + "org.freedesktop.systemd1", + path, + "org.freedesktop.systemd1.Unit", + "ActiveState", + &error, + &buf); + if (r < 0) + return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r)); + + state = buf; } if (!quiet) @@ -2497,7 +2465,7 @@ static int check_triggering_units( sd_bus *bus, const char *name) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *path = NULL, *n = NULL, *state = NULL; _cleanup_strv_free_ char **triggered_by = NULL; bool print_warning_label = true; @@ -2568,6 +2536,7 @@ static const struct { { "try-restart", "TryRestartUnit" }, { "condrestart", "TryRestartUnit" }, { "reload-or-restart", "ReloadOrRestartUnit" }, + { "try-reload-or-restart", "ReloadOrTryRestartUnit" }, { "reload-or-try-restart", "ReloadOrTryRestartUnit" }, { "condreload", "ReloadOrTryRestartUnit" }, { "force-reload", "ReloadOrTryRestartUnit" } @@ -2601,7 +2570,7 @@ static int start_unit_one( sd_bus_error *error, BusWaitForJobs *w) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *path; int r; @@ -2631,7 +2600,13 @@ static int start_unit_one( verb = method_to_verb(method); - return log_error_errno(r, "Failed to %s %s: %s", verb, name, bus_error_message(error, r)); + log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r)); + + if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) && + !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED)) + log_error("See system logs and 'systemctl status %s' for details.", name); + + return r; } r = sd_bus_message_read(reply, "o", &path); @@ -2680,16 +2655,27 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r /* Query the manager only if any of the names are a glob, since * this is fairly expensive */ if (!strv_isempty(globs)) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ UnitInfo *unit_infos = NULL; + size_t allocated, n; r = get_unit_list(bus, NULL, globs, &unit_infos, 0, &reply); if (r < 0) return r; - for (i = 0; i < r; i++) - if (strv_extend(&mangled, unit_infos[i].id) < 0) + n = strv_length(mangled); + allocated = n + 1; + + for (i = 0; i < r; i++) { + if (!GREEDY_REALLOC(mangled, allocated, n+2)) return log_oom(); + + mangled[n] = strdup(unit_infos[i].id); + if (!mangled[n]) + return log_oom(); + + mangled[++n] = NULL; + } } *ret = mangled; @@ -2783,7 +2769,7 @@ static int start_unit(int argc, char *argv[], void *userdata) { } STRV_FOREACH(name, names) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int q; q = start_unit_one(bus, method, *name, mode, &error, w); @@ -2794,7 +2780,7 @@ static int start_unit(int argc, char *argv[], void *userdata) { if (!arg_no_block) { int q; - q = bus_wait_for_jobs(w, arg_quiet); + q = bus_wait_for_jobs(w, arg_quiet, arg_scope != UNIT_FILE_SYSTEM ? "--user" : NULL); if (q < 0) return q; @@ -2810,7 +2796,7 @@ static int start_unit(int argc, char *argv[], void *userdata) { static int logind_set_wall_message(void) { #ifdef HAVE_LOGIND - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; _cleanup_free_ char *m = NULL; int r; @@ -2846,7 +2832,7 @@ static int logind_set_wall_message(void) { * through PolicyKit */ static int logind_reboot(enum action a) { #ifdef HAVE_LOGIND - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *method, *description; sd_bus *bus; int r; @@ -2909,7 +2895,7 @@ static int logind_reboot(enum action a) { static int logind_check_inhibitors(enum action a) { #ifdef HAVE_LOGIND - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_strv_free_ char **sessions = NULL; const char *what, *who, *why, *mode; uint32_t uid, pid; @@ -3025,7 +3011,7 @@ static int logind_check_inhibitors(enum action a) { static int logind_prepare_firmware_setup(void) { #ifdef HAVE_LOGIND - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; int r; @@ -3071,7 +3057,7 @@ static int prepare_firmware_setup(void) { } static int set_exit_code(uint8_t code) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; int r; @@ -3177,6 +3163,7 @@ static int check_unit_generic(int code, const char *good_states, char **args) { sd_bus *bus; char **name; int r; + bool found = false; r = acquire_bus(BUS_MANAGER, &bus); if (r < 0) @@ -3192,11 +3179,13 @@ static int check_unit_generic(int code, const char *good_states, char **args) { state = check_one_unit(bus, *name, good_states, arg_quiet); if (state < 0) return state; - if (state == 0) - r = code; + if (state > 0) + found = true; } - return r; + /* use the given return code for the case that we won't find + * any unit which matches the list */ + return found ? 0 : code; } static int check_unit_active(int argc, char *argv[], void *userdata) { @@ -3232,7 +3221,7 @@ static int kill_unit(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; q = sd_bus_call_method( bus, @@ -3360,6 +3349,7 @@ typedef struct UnitStatusInfo { usec_t inactive_enter_timestamp; bool need_daemon_reload; + bool transient; /* Service */ pid_t main_pid; @@ -3459,7 +3449,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 +3465,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 +3832,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; } @@ -4388,8 +4383,8 @@ static int show_one( bool *new_line, bool *ellipsized) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; UnitStatusInfo info = { .memory_current = (uint64_t) -1, .memory_limit = (uint64_t) -1, @@ -4505,8 +4500,8 @@ static int get_unit_dbus_path_by_pid( uint32_t pid, char **unit) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; char *u; int r; @@ -4541,7 +4536,7 @@ static int show_all( bool *new_line, bool *ellipsized) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ UnitInfo *unit_infos = NULL; const UnitInfo *u; unsigned c; @@ -4646,8 +4641,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 @@ -4841,8 +4835,8 @@ static int cat(int argc, char *argv[], void *userdata) { } static int set_property(int argc, char *argv[], void *userdata) { - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *n = NULL; sd_bus *bus; char **i; @@ -4877,17 +4871,9 @@ static int set_property(int argc, char *argv[], void *userdata) { return bus_log_create_error(r); STRV_FOREACH(i, strv_skip(argv, 2)) { - r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); - if (r < 0) - return bus_log_create_error(r); - r = bus_append_unit_property_assignment(m, *i); if (r < 0) return r; - - r = sd_bus_message_close_container(m); - if (r < 0) - return bus_log_create_error(r); } r = sd_bus_message_close_container(m); @@ -4902,7 +4888,7 @@ static int set_property(int argc, char *argv[], void *userdata) { } static int daemon_reload(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *method; sd_bus *bus; int r; @@ -4976,7 +4962,7 @@ static int reset_failed(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to expand names: %m"); STRV_FOREACH(name, names) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; q = sd_bus_call_method( bus, @@ -4998,8 +4984,8 @@ static int reset_failed(int argc, char *argv[], void *userdata) { } static int show_environment(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *text; sd_bus *bus; int r; @@ -5039,7 +5025,7 @@ static int show_environment(int argc, char *argv[], void *userdata) { } static int switch_root(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_free_ char *cmdline_init = NULL; const char *root, *init; sd_bus *bus; @@ -5106,8 +5092,8 @@ static int switch_root(int argc, char *argv[], void *userdata) { } static int set_environment(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; const char *method; sd_bus *bus; int r; @@ -5147,8 +5133,8 @@ static int set_environment(int argc, char *argv[], void *userdata) { } static int import_environment(int argc, char *argv[], void *userdata) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; sd_bus *bus; int r; @@ -5443,8 +5429,8 @@ static int enable_unit(int argc, char *argv[], void *userdata) { r = 0; } else { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int expect_carries_install_info = false; bool send_force = true, send_preset_mode = false; const char *method; @@ -5610,8 +5596,8 @@ static int add_dependency(int argc, char *argv[], void *userdata) { unit_file_changes_free(changes, n_changes); } else { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; polkit_agent_open_if_enabled(); @@ -5674,8 +5660,8 @@ static int preset_all(int argc, char *argv[], void *userdata) { r = 0; } else { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; sd_bus *bus; polkit_agent_open_if_enabled(); @@ -5753,7 +5739,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { } } else { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; r = acquire_bus(BUS_MANAGER, &bus); @@ -5761,7 +5747,7 @@ static int unit_is_enabled(int argc, char *argv[], void *userdata) { return r; STRV_FOREACH(name, names) { - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *s; r = sd_bus_call_method( @@ -5796,7 +5782,7 @@ static int is_system_running(int argc, char *argv[], void *userdata) { sd_bus *bus; int r; - if (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted()) { + if (running_in_chroot() > 0 || (arg_transport == BUS_TRANSPORT_LOCAL && !sd_booted())) { if (!arg_quiet) puts("offline"); return EXIT_FAILURE; @@ -6239,8 +6225,8 @@ static void systemctl_help(void) { " try-restart NAME... Restart one or more units if active\n" " reload-or-restart NAME... Reload one or more units if possible,\n" " otherwise start or restart\n" - " reload-or-try-restart NAME... Reload one or more units if possible,\n" - " otherwise restart if active\n" + " try-reload-or-restart NAME... If active, reload one or more units,\n" + " if supported, otherwise restart\n" " isolate NAME Start one unit and stop all others\n" " kill NAME... Send signal to processes of a unit\n" " is-active PATTERN... Check whether units are active\n" @@ -6545,8 +6531,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 +6766,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(;;) { @@ -7325,70 +7315,71 @@ static int talk_initctl(void) { static int systemctl_main(int argc, char *argv[]) { static const Verb verbs[] = { - { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT, list_units }, - { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files }, - { "list-sockets", VERB_ANY, VERB_ANY, 0, list_sockets }, - { "list-timers", VERB_ANY, VERB_ANY, 0, list_timers }, - { "list-jobs", VERB_ANY, VERB_ANY, 0, list_jobs }, - { "list-machines", VERB_ANY, VERB_ANY, 0, list_machines }, - { "clear-jobs", VERB_ANY, 1, 0, daemon_reload }, - { "cancel", VERB_ANY, VERB_ANY, 0, cancel_job }, - { "start", 2, VERB_ANY, 0, start_unit }, - { "stop", 2, VERB_ANY, 0, start_unit }, - { "condstop", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */ - { "reload", 2, VERB_ANY, 0, start_unit }, - { "restart", 2, VERB_ANY, 0, start_unit }, - { "try-restart", 2, VERB_ANY, 0, start_unit }, - { "reload-or-restart", 2, VERB_ANY, 0, start_unit }, - { "reload-or-try-restart", 2, VERB_ANY, 0, start_unit }, - { "force-reload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with SysV */ - { "condreload", 2, VERB_ANY, 0, start_unit }, /* For compatibility with ALTLinux */ - { "condrestart", 2, VERB_ANY, 0, start_unit }, /* For compatibility with RH */ - { "isolate", 2, 2, 0, start_unit }, - { "kill", 2, VERB_ANY, 0, kill_unit }, - { "is-active", 2, VERB_ANY, 0, check_unit_active }, - { "check", 2, VERB_ANY, 0, check_unit_active }, - { "is-failed", 2, VERB_ANY, 0, check_unit_failed }, - { "show", VERB_ANY, VERB_ANY, 0, show }, - { "cat", 2, VERB_ANY, 0, cat }, - { "status", VERB_ANY, VERB_ANY, 0, show }, - { "help", VERB_ANY, VERB_ANY, 0, show }, - { "daemon-reload", VERB_ANY, 1, 0, daemon_reload }, - { "daemon-reexec", VERB_ANY, 1, 0, daemon_reload }, - { "show-environment", VERB_ANY, 1, 0, show_environment }, - { "set-environment", 2, VERB_ANY, 0, set_environment }, - { "unset-environment", 2, VERB_ANY, 0, set_environment }, - { "import-environment", VERB_ANY, VERB_ANY, 0, import_environment}, - { "halt", VERB_ANY, 1, 0, start_special }, - { "poweroff", VERB_ANY, 1, 0, start_special }, - { "reboot", VERB_ANY, 2, 0, start_special }, - { "kexec", VERB_ANY, 1, 0, start_special }, - { "suspend", VERB_ANY, 1, 0, start_special }, - { "hibernate", VERB_ANY, 1, 0, start_special }, - { "hybrid-sleep", VERB_ANY, 1, 0, start_special }, - { "default", VERB_ANY, 1, 0, start_special }, - { "rescue", VERB_ANY, 1, 0, start_special }, - { "emergency", VERB_ANY, 1, 0, start_special }, - { "exit", VERB_ANY, 2, 0, start_special }, - { "reset-failed", VERB_ANY, VERB_ANY, 0, reset_failed }, - { "enable", 2, VERB_ANY, 0, enable_unit }, - { "disable", 2, VERB_ANY, 0, enable_unit }, - { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled }, - { "reenable", 2, VERB_ANY, 0, enable_unit }, - { "preset", 2, VERB_ANY, 0, enable_unit }, - { "preset-all", VERB_ANY, 1, 0, preset_all }, - { "mask", 2, VERB_ANY, 0, enable_unit }, - { "unmask", 2, VERB_ANY, 0, enable_unit }, - { "link", 2, VERB_ANY, 0, enable_unit }, - { "switch-root", 2, VERB_ANY, 0, switch_root }, - { "list-dependencies", VERB_ANY, 2, 0, list_dependencies }, - { "set-default", 2, 2, 0, set_default }, - { "get-default", VERB_ANY, 1, 0, get_default, }, - { "set-property", 3, VERB_ANY, 0, set_property }, - { "is-system-running", VERB_ANY, 1, 0, is_system_running }, - { "add-wants", 3, VERB_ANY, 0, add_dependency }, - { "add-requires", 3, VERB_ANY, 0, add_dependency }, - { "edit", 2, VERB_ANY, 0, edit }, + { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_NOCHROOT, list_units }, + { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files }, + { "list-sockets", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_sockets }, + { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers }, + { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs }, + { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines }, + { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload }, + { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job }, + { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "condstop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */ + { "reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "reload-or-try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatbility with old systemctl <= 228 */ + { "try-reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, + { "force-reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with SysV */ + { "condreload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */ + { "condrestart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with RH */ + { "isolate", 2, 2, VERB_NOCHROOT, start_unit }, + { "kill", 2, VERB_ANY, VERB_NOCHROOT, kill_unit }, + { "is-active", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active }, + { "check", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active }, + { "is-failed", 2, VERB_ANY, VERB_NOCHROOT, check_unit_failed }, + { "show", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show }, + { "cat", 2, VERB_ANY, VERB_NOCHROOT, cat }, + { "status", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show }, + { "help", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show }, + { "daemon-reload", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload }, + { "daemon-reexec", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload }, + { "show-environment", VERB_ANY, 1, VERB_NOCHROOT, show_environment }, + { "set-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment }, + { "unset-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment }, + { "import-environment", VERB_ANY, VERB_ANY, VERB_NOCHROOT, import_environment}, + { "halt", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "poweroff", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "reboot", VERB_ANY, 2, VERB_NOCHROOT, start_special }, + { "kexec", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "suspend", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "hibernate", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "hybrid-sleep", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "default", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "rescue", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "emergency", VERB_ANY, 1, VERB_NOCHROOT, start_special }, + { "exit", VERB_ANY, 2, VERB_NOCHROOT, start_special }, + { "reset-failed", VERB_ANY, VERB_ANY, VERB_NOCHROOT, reset_failed }, + { "enable", 2, VERB_ANY, 0, enable_unit }, + { "disable", 2, VERB_ANY, 0, enable_unit }, + { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled }, + { "reenable", 2, VERB_ANY, 0, enable_unit }, + { "preset", 2, VERB_ANY, 0, enable_unit }, + { "preset-all", VERB_ANY, 1, 0, preset_all }, + { "mask", 2, VERB_ANY, 0, enable_unit }, + { "unmask", 2, VERB_ANY, 0, enable_unit }, + { "link", 2, VERB_ANY, 0, enable_unit }, + { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root }, + { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies }, + { "set-default", 2, 2, 0, set_default }, + { "get-default", VERB_ANY, 1, 0, get_default, }, + { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property }, + { "is-system-running", VERB_ANY, 1, 0, is_system_running }, + { "add-wants", 3, VERB_ANY, 0, add_dependency }, + { "add-requires", 3, VERB_ANY, 0, add_dependency }, + { "edit", 2, VERB_ANY, VERB_NOCHROOT, edit }, {} }; @@ -7470,7 +7461,7 @@ static int halt_now(enum action a) { static int logind_schedule_shutdown(void) { #ifdef HAVE_LOGIND - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char date[FORMAT_TIMESTAMP_MAX]; const char *action; sd_bus *bus; @@ -7598,7 +7589,7 @@ static int runlevel_main(void) { static int logind_cancel_shutdown(void) { #ifdef HAVE_LOGIND - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; sd_bus *bus; int r; @@ -7642,7 +7633,7 @@ int main(int argc, char*argv[]) { if (r <= 0) goto finish; - if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) { + if (arg_action != ACTION_SYSTEMCTL && running_in_chroot() > 0) { log_info("Running in chroot, ignoring request."); r = 0; goto finish; diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h index 896a027eb..2d4e1f26e 100644 --- a/src/systemd/_sd-common.h +++ b/src/systemd/_sd-common.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdcommonhfoo #define foosdcommonhfoo @@ -57,10 +55,10 @@ # ifdef __cplusplus # define _SD_BEGIN_DECLARATIONS \ extern "C" { \ - struct __useless_struct_to_allow_trailing_semicolon__ + struct _sd_useless_struct_to_allow_trailing_semicolon_ # else # define _SD_BEGIN_DECLARATIONS \ - struct __useless_struct_to_allow_trailing_semicolon__ + struct _sd_useless_struct_to_allow_trailing_semicolon_ # endif #endif @@ -68,11 +66,18 @@ # ifdef __cplusplus # define _SD_END_DECLARATIONS \ } \ - struct __useless_struct_to_allow_trailing_semicolon__ + struct _sd_useless_cpp_struct_to_allow_trailing_semicolon_ # else # define _SD_END_DECLARATIONS \ - struct __useless_struct_to_allow_trailing_semicolon__ + struct _sd_useless_struct_to_allow_trailing_semicolon_ # endif #endif +#define _SD_DEFINE_POINTER_CLEANUP_FUNC(type, func) \ + static inline void func##p(type **p) { \ + if (*p) \ + func(*p); \ + } \ + struct _sd_useless_struct_to_allow_trailing_semicolon_ + #endif diff --git a/src/systemd/sd-bus-protocol.h b/src/systemd/sd-bus-protocol.h index 5185a48b3..47b256d5b 100644 --- a/src/systemd/sd-bus-protocol.h +++ b/src/systemd/sd-bus-protocol.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdbusprotocolhfoo #define foosdbusprotocolhfoo diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h index c5d05a2db..6ad6d5197 100644 --- a/src/systemd/sd-bus-vtable.h +++ b/src/systemd/sd-bus-vtable.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdbusvtablehfoo #define foosdbusvtablehfoo diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 43cf247cd..2a2ef0eb9 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdbushfoo #define foosdbushfoo @@ -27,8 +25,9 @@ #include #include -#include "sd-id128.h" #include "sd-event.h" +#include "sd-id128.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; @@ -444,6 +443,14 @@ const char* sd_bus_track_contains(sd_bus_track *track, const char *names); const char* sd_bus_track_first(sd_bus_track *track); const char* sd_bus_track_next(sd_bus_track *track); +/* Define helpers so that __attribute__((cleanup(sd_bus_unrefp))) and similar may be used. */ +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus, sd_bus_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus, sd_bus_flush_close_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus_slot, sd_bus_slot_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus_message, sd_bus_message_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus_creds, sd_bus_creds_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_bus_track, sd_bus_track_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-daemon.h b/src/systemd/sd-daemon.h index 214e77cab..e6787b0a6 100644 --- a/src/systemd/sd-daemon.h +++ b/src/systemd/sd-daemon.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosddaemonhfoo #define foosddaemonhfoo @@ -22,8 +20,8 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "_sd-common.h" diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index fc1172582..5bfca6ece 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosddevicehfoo #define foosddevicehfoo @@ -23,8 +21,8 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "_sd-common.h" @@ -94,6 +92,9 @@ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const c int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent); int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device, sd_device_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_device_enumerator, sd_device_enumerator_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index c0146158f..2b865a80e 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosddhcpclienthfoo #define foosddhcpclienthfoo @@ -27,8 +25,8 @@ #include #include -#include "sd-event.h" #include "sd-dhcp-lease.h" +#include "sd-event.h" #include "_sd-common.h" @@ -42,6 +40,48 @@ enum { SD_DHCP_CLIENT_EVENT_RENEW = 4, }; +enum { + SD_DHCP_OPTION_PAD = 0, + SD_DHCP_OPTION_SUBNET_MASK = 1, + SD_DHCP_OPTION_TIME_OFFSET = 2, + SD_DHCP_OPTION_ROUTER = 3, + SD_DHCP_OPTION_DOMAIN_NAME_SERVER = 6, + SD_DHCP_OPTION_HOST_NAME = 12, + SD_DHCP_OPTION_BOOT_FILE_SIZE = 13, + SD_DHCP_OPTION_DOMAIN_NAME = 15, + SD_DHCP_OPTION_ROOT_PATH = 17, + SD_DHCP_OPTION_ENABLE_IP_FORWARDING = 19, + SD_DHCP_OPTION_ENABLE_IP_FORWARDING_NL = 20, + SD_DHCP_OPTION_POLICY_FILTER = 21, + SD_DHCP_OPTION_INTERFACE_MDR = 22, + SD_DHCP_OPTION_INTERFACE_TTL = 23, + SD_DHCP_OPTION_INTERFACE_MTU_AGING_TIMEOUT = 24, + SD_DHCP_OPTION_INTERFACE_MTU = 26, + SD_DHCP_OPTION_BROADCAST = 28, + SD_DHCP_OPTION_STATIC_ROUTE = 33, + SD_DHCP_OPTION_NTP_SERVER = 42, + SD_DHCP_OPTION_VENDOR_SPECIFIC = 43, + SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, + SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, + SD_DHCP_OPTION_OVERLOAD = 52, + SD_DHCP_OPTION_MESSAGE_TYPE = 53, + SD_DHCP_OPTION_SERVER_IDENTIFIER = 54, + SD_DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, + SD_DHCP_OPTION_ERROR_MESSAGE = 56, + SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, + SD_DHCP_OPTION_RENEWAL_T1_TIME = 58, + SD_DHCP_OPTION_REBINDING_T2_TIME = 59, + SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, + SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, + SD_DHCP_OPTION_FQDN = 81, + SD_DHCP_OPTION_NEW_POSIX_TIMEZONE = 100, + SD_DHCP_OPTION_NEW_TZDB_TIMEZONE = 101, + SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, + SD_DHCP_OPTION_PRIVATE_BASE = 224, + SD_DHCP_OPTION_PRIVATE_LAST = 254, + SD_DHCP_OPTION_END = 255, +}; + typedef struct sd_dhcp_client sd_dhcp_client; typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event, @@ -49,7 +89,6 @@ typedef void (*sd_dhcp_client_cb_t)(sd_dhcp_client *client, int event, int sd_dhcp_client_set_callback(sd_dhcp_client *client, sd_dhcp_client_cb_t cb, void *userdata); - int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option); int sd_dhcp_client_set_request_address(sd_dhcp_client *client, const struct in_addr *last_address); @@ -78,6 +117,8 @@ int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int pri int sd_dhcp_client_detach_event(sd_dhcp_client *client); sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_client, sd_dhcp_client_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h index 38222594e..2f565ca82 100644 --- a/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/sd-dhcp-lease.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosddhcpleasehfoo #define foosddhcpleasehfoo @@ -33,7 +31,7 @@ _SD_BEGIN_DECLARATIONS; typedef struct sd_dhcp_lease sd_dhcp_lease; -struct sd_dhcp_route; +typedef struct sd_dhcp_route sd_dhcp_route; sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease); sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); @@ -53,11 +51,17 @@ int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path); -int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, struct sd_dhcp_route **routes); +int sd_dhcp_lease_get_routes(sd_dhcp_lease *lease, sd_dhcp_route ***routes); int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len); int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); +int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination); +int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length); +int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index 55bceb1ea..8658197e8 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosddhcpserverhfoo #define foosddhcpserverhfoo @@ -27,6 +25,7 @@ #include #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; @@ -58,6 +57,8 @@ int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t); int sd_dhcp_server_forcerenew(sd_dhcp_server *server); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_server, sd_dhcp_server_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-dhcp6-client.h b/src/systemd/sd-dhcp6-client.h index 0ca6c07de..960806083 100644 --- a/src/systemd/sd-dhcp6-client.h +++ b/src/systemd/sd-dhcp6-client.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosddhcp6clienthfoo #define foosddhcp6clienthfoo @@ -26,8 +24,8 @@ #include #include -#include "sd-event.h" #include "sd-dhcp6-lease.h" +#include "sd-event.h" #include "_sd-common.h" @@ -41,6 +39,41 @@ enum { SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13, }; +enum { + SD_DHCP6_OPTION_CLIENTID = 1, + SD_DHCP6_OPTION_SERVERID = 2, + SD_DHCP6_OPTION_IA_NA = 3, + SD_DHCP6_OPTION_IA_TA = 4, + SD_DHCP6_OPTION_IAADDR = 5, + SD_DHCP6_OPTION_ORO = 6, + SD_DHCP6_OPTION_PREFERENCE = 7, + SD_DHCP6_OPTION_ELAPSED_TIME = 8, + SD_DHCP6_OPTION_RELAY_MSG = 9, + /* option code 10 is unassigned */ + SD_DHCP6_OPTION_AUTH = 11, + SD_DHCP6_OPTION_UNICAST = 12, + SD_DHCP6_OPTION_STATUS_CODE = 13, + SD_DHCP6_OPTION_RAPID_COMMIT = 14, + SD_DHCP6_OPTION_USER_CLASS = 15, + SD_DHCP6_OPTION_VENDOR_CLASS = 16, + SD_DHCP6_OPTION_VENDOR_OPTS = 17, + SD_DHCP6_OPTION_INTERFACE_ID = 18, + SD_DHCP6_OPTION_RECONF_MSG = 19, + SD_DHCP6_OPTION_RECONF_ACCEPT = 20, + + SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ + SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ + + SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */ + + /* option code 35 is unassigned */ + + SD_DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */ + + /* option codes 89-142 are unassigned */ + /* option codes 144-65535 are unassigned */ +}; + typedef struct sd_dhcp6_client sd_dhcp6_client; typedef void (*sd_dhcp6_client_cb_t)(sd_dhcp6_client *client, int event, @@ -72,6 +105,8 @@ sd_dhcp6_client *sd_dhcp6_client_ref(sd_dhcp6_client *client); sd_dhcp6_client *sd_dhcp6_client_unref(sd_dhcp6_client *client); int sd_dhcp6_client_new(sd_dhcp6_client **ret); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp6_client, sd_dhcp6_client_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-dhcp6-lease.h b/src/systemd/sd-dhcp6-lease.h index 3fc0ee4be..184fbb8e0 100644 --- a/src/systemd/sd-dhcp6-lease.h +++ b/src/systemd/sd-dhcp6-lease.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosddhcp6leasehfoo #define foosddhcp6leasehfoo @@ -47,6 +45,8 @@ int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ntp_fqdn); sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease); sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp6_lease, sd_dhcp6_lease_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 565de5495..1ea97e47f 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdeventhfoo #define foosdeventhfoo @@ -22,11 +20,11 @@ along with systemd; If not, see . ***/ -#include -#include -#include #include #include +#include +#include +#include #include "_sd-common.h" @@ -56,7 +54,8 @@ enum { SD_EVENT_PENDING, SD_EVENT_RUNNING, SD_EVENT_EXITING, - SD_EVENT_FINISHED + SD_EVENT_FINISHED, + SD_EVENT_PREPARING, }; enum { @@ -87,9 +86,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); @@ -130,6 +129,10 @@ int sd_event_source_get_time_clock(sd_event_source *s, clockid_t *clock); int sd_event_source_get_signal(sd_event_source *s); int sd_event_source_get_child_pid(sd_event_source *s, pid_t *pid); +/* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event_source, sd_event_source_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-hwdb.h b/src/systemd/sd-hwdb.h index 49269a073..710592049 100644 --- a/src/systemd/sd-hwdb.h +++ b/src/systemd/sd-hwdb.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdhwdbhfoo #define foosdhwdbhfoo @@ -44,6 +42,8 @@ int sd_hwdb_enumerate(sd_hwdb *hwdb, const char **key, const char **value); if (sd_hwdb_seek(hwdb, modalias) < 0) { } \ else while (sd_hwdb_enumerate(hwdb, &(key), &(value)) > 0) +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_hwdb, sd_hwdb_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-id128.h b/src/systemd/sd-id128.h index 9f445278b..a3bf5897b 100644 --- a/src/systemd/sd-id128.h +++ b/src/systemd/sd-id128.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdid128hfoo #define foosdid128hfoo diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index 6337d6145..3a2219c82 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdipv4acdfoo #define foosdipv4acdfoo @@ -23,10 +21,11 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; @@ -52,7 +51,9 @@ int sd_ipv4acd_start(sd_ipv4acd *ll); int sd_ipv4acd_stop(sd_ipv4acd *ll); sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *ll); sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *ll); -int sd_ipv4acd_new (sd_ipv4acd **ret); +int sd_ipv4acd_new(sd_ipv4acd **ret); + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4acd, sd_ipv4acd_unref); _SD_END_DECLARATIONS; diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index 2949f1dfb..67c566fe0 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdipv4llfoo #define foosdipv4llfoo @@ -22,10 +20,11 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; @@ -54,6 +53,8 @@ sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll); sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll); int sd_ipv4ll_new (sd_ipv4ll **ret); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4ll, sd_ipv4ll_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-journal.h b/src/systemd/sd-journal.h index 00237a215..abb9eca57 100644 --- a/src/systemd/sd-journal.h +++ b/src/systemd/sd-journal.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdjournalhfoo #define foosdjournalhfoo @@ -23,12 +21,13 @@ ***/ #include -#include #include +#include #include #include #include "sd-id128.h" + #include "_sd-common.h" /* Journal APIs. See sd-journal(3) for more information. */ @@ -128,6 +127,9 @@ int sd_journal_query_unique(sd_journal *j, const char *field); int sd_journal_enumerate_unique(sd_journal *j, const void **data, size_t *l); void sd_journal_restart_unique(sd_journal *j); +int sd_journal_enumerate_fields(sd_journal *j, const char **field); +void sd_journal_restart_fields(sd_journal *j); + int sd_journal_get_fd(sd_journal *j); int sd_journal_get_events(sd_journal *j); int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec); @@ -138,22 +140,33 @@ int sd_journal_reliable_fd(sd_journal *j); int sd_journal_get_catalog(sd_journal *j, char **text); int sd_journal_get_catalog_for_message_id(sd_id128_t id, char **text); -/* the inverse condition avoids ambiguity of danling 'else' after the macro */ +int sd_journal_has_runtime_files(sd_journal *j); +int sd_journal_has_persistent_files(sd_journal *j); + +/* The inverse condition avoids ambiguity of dangling 'else' after the macro */ #define SD_JOURNAL_FOREACH(j) \ if (sd_journal_seek_head(j) < 0) { } \ else while (sd_journal_next(j) > 0) -/* the inverse condition avoids ambiguity of danling 'else' after the macro */ +/* The inverse condition avoids ambiguity of dangling 'else' after the macro */ #define SD_JOURNAL_FOREACH_BACKWARDS(j) \ if (sd_journal_seek_tail(j) < 0) { } \ else while (sd_journal_previous(j) > 0) +/* Iterate through the data fields of the current journal entry */ #define SD_JOURNAL_FOREACH_DATA(j, data, l) \ for (sd_journal_restart_data(j); sd_journal_enumerate_data((j), &(data), &(l)) > 0; ) +/* Iterate through the all known values of a specific field */ #define SD_JOURNAL_FOREACH_UNIQUE(j, data, l) \ for (sd_journal_restart_unique(j); sd_journal_enumerate_unique((j), &(data), &(l)) > 0; ) +/* Iterate through all known field names */ +#define SD_JOURNAL_FOREACH_FIELD(j, field) \ + for (sd_journal_restart_fields(j); sd_journal_enumerate_fields((j), &(field)) > 0; ) + +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_journal, sd_journal_close); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index 31651ce13..ea952ef18 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdlldphfoo #define foosdlldphfoo @@ -23,10 +21,11 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; @@ -47,7 +46,7 @@ typedef struct sd_lldp_packet sd_lldp_packet; typedef void (*sd_lldp_cb_t)(sd_lldp *lldp, int event, void *userdata); int sd_lldp_new(int ifindex, const char *ifname, const struct ether_addr *mac, sd_lldp **ret); -void sd_lldp_free(sd_lldp *lldp); +sd_lldp* sd_lldp_unref(sd_lldp *lldp); int sd_lldp_start(sd_lldp *lldp); int sd_lldp_stop(sd_lldp *lldp); @@ -80,6 +79,9 @@ int sd_lldp_packet_get_destination_type(sd_lldp_packet *tlv, int *dest); int sd_lldp_get_packets(sd_lldp *lldp, sd_lldp_packet ***tlvs); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp, sd_lldp_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_lldp_packet, sd_lldp_packet_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h index 59c6eedcd..3c10ff032 100644 --- a/src/systemd/sd-login.h +++ b/src/systemd/sd-login.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdloginhfoo #define foosdloginhfoo @@ -22,8 +20,8 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "_sd-common.h" @@ -240,6 +238,8 @@ int sd_login_monitor_get_events(sd_login_monitor *m); /* Get timeout for poll(), as usec value relative to CLOCK_MONOTONIC's epoch */ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout_usec); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_login_monitor, sd_login_monitor_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-messages.h b/src/systemd/sd-messages.h index 8aedaec6d..8a72576ec 100644 --- a/src/systemd/sd-messages.h +++ b/src/systemd/sd-messages.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdmessageshfoo #define foosdmessageshfoo @@ -23,6 +21,7 @@ ***/ #include "sd-id128.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; @@ -85,6 +84,10 @@ _SD_BEGIN_DECLARATIONS; #define SD_MESSAGE_BOOTCHART SD_ID128_MAKE(9f,26,aa,56,2c,f4,40,c2,b1,6c,77,3d,04,79,b5,18) +#define SD_MESSAGE_DNSSEC_FAILURE SD_ID128_MAKE(16,75,d7,f1,72,17,40,98,b1,10,8b,f8,c7,dc,8f,5d) +#define SD_MESSAGE_DNSSEC_TRUST_ANCHOR_REVOKED SD_ID128_MAKE(4d,44,08,cf,d0,d1,44,85,91,84,d1,e6,5d,7c,8a,65) +#define SD_MESSAGE_DNSSEC_DOWNGRADE SD_ID128_MAKE(36,db,2d,fa,5a,90,45,e1,bd,4a,f5,f9,3e,1c,f0,57) + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index 80e24325f..762947531 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdndiscfoo #define foosdndiscfoo @@ -26,6 +24,7 @@ #include #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; @@ -78,6 +77,8 @@ int sd_ndisc_router_discovery_start(sd_ndisc *nd); be16toh((address).s6_addr16[6]), \ be16toh((address).s6_addr16[7]) +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index 2960deda0..b4798d247 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdnetlinkhfoo #define foosdnetlinkhfoo @@ -23,12 +21,13 @@ ***/ #include -#include #include +#include #include #include #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; @@ -73,6 +72,7 @@ int sd_netlink_message_append_flag(sd_netlink_message *m, unsigned short type); int sd_netlink_message_append_u8(sd_netlink_message *m, unsigned short type, uint8_t data); int sd_netlink_message_append_u16(sd_netlink_message *m, unsigned short type, uint16_t data); int sd_netlink_message_append_u32(sd_netlink_message *m, unsigned short type, uint32_t data); +int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, const void *data, size_t len); int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data); int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data); int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data); @@ -153,6 +153,9 @@ int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *family); int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state); int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink, sd_netlink_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_netlink_message, sd_netlink_message_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 4179015fb..e20d12c44 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdnetworkhfoo #define foosdnetworkhfoo @@ -23,8 +21,8 @@ along with systemd; If not, see . ***/ -#include #include +#include #include "_sd-common.h" @@ -64,8 +62,11 @@ int sd_network_get_dns(char ***dns); * representations of IP addresses */ int sd_network_get_ntp(char ***ntp); -/* Get the search/routing domains for all links. */ -int sd_network_get_domains(char ***domains); +/* Get the search domains for all links. */ +int sd_network_get_search_domains(char ***domains); + +/* Get the search domains for all links. */ +int sd_network_get_route_domains(char ***domains); /* Get setup state from ifindex. * Possible states: @@ -111,10 +112,34 @@ int sd_network_link_get_ntp(int ifindex, char ***addr); */ int sd_network_link_get_llmnr(int ifindex, char **llmnr); +/* Indicates whether or not MulticastDNS should be enabled for the + * link. + * Possible levels of support: yes, no, resolve + * Possible return codes: + * -ENODATA: networkd is not aware of the link + */ +int sd_network_link_get_mdns(int ifindex, char **mdns); + +/* Indicates whether or not DNSSEC should be enabled for the link + * Possible levels of support: yes, no, allow-downgrade + * Possible return codes: + * -ENODATA: networkd is not aware of the link + */ +int sd_network_link_get_dnssec(int ifindex, char **dnssec); + +/* Returns the list of per-interface DNSSEC negative trust anchors + * Possible return codes: + * -ENODATA: networkd is not aware of the link, or has no such data + */ +int sd_network_link_get_dnssec_negative_trust_anchors(int ifindex, char ***nta); + int sd_network_link_get_lldp(int ifindex, char **lldp); -/* Get the DNS domain names for a given link. */ -int sd_network_link_get_domains(int ifindex, char ***domains); +/* Get the search DNS domain names for a given link. */ +int sd_network_link_get_search_domains(int ifindex, char ***domains); + +/* Get the route DNS domain names for a given link. */ +int sd_network_link_get_route_domains(int ifindex, char ***domains); /* Get the CARRIERS to which current link is bound to. */ int sd_network_link_get_carrier_bound_to(int ifindex, char ***carriers); @@ -125,10 +150,6 @@ int sd_network_link_get_carrier_bound_by(int ifindex, char ***carriers); /* Get the timezone that was learnt on a specific link. */ int sd_network_link_get_timezone(int ifindex, char **timezone); -/* Returns whether or not domains that don't match any link should be resolved - * on this link. 1 for yes, 0 for no and negative value for error */ -int sd_network_link_get_wildcard_domain(int ifindex); - /* Monitor object */ typedef struct sd_network_monitor sd_network_monitor; @@ -150,6 +171,8 @@ int sd_network_monitor_get_events(sd_network_monitor *m); /* Get timeout for poll(), as usec value relative to CLOCK_MONOTONIC's epoch */ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *timeout_usec); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_network_monitor, sd_network_monitor_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-path.h b/src/systemd/sd-path.h index 328030363..be6abdcd0 100644 --- a/src/systemd/sd-path.h +++ b/src/systemd/sd-path.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdpathhfoo #define foosdpathhfoo diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h index 82c4b39ef..903b917f7 100644 --- a/src/systemd/sd-resolve.h +++ b/src/systemd/sd-resolve.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdresolvehfoo #define foosdresolvehfoo @@ -28,6 +26,7 @@ #include #include "sd-event.h" + #include "_sd-common.h" _SD_BEGIN_DECLARATIONS; @@ -43,9 +42,9 @@ typedef int (*sd_resolve_getaddrinfo_handler_t)(sd_resolve_query *q, int ret, co typedef int (*sd_resolve_getnameinfo_handler_t)(sd_resolve_query *q, int ret, const char *host, const char *serv, void *userdata); enum { - SD_RESOLVE_GET_HOST = 1ULL, - SD_RESOLVE_GET_SERVICE = 2ULL, - SD_RESOLVE_GET_BOTH = 3ULL + SD_RESOLVE_GET_HOST = UINT64_C(1), + SD_RESOLVE_GET_SERVICE = UINT64_C(2), + SD_RESOLVE_GET_BOTH = UINT64_C(3), }; int sd_resolve_default(sd_resolve **ret); @@ -110,6 +109,9 @@ void *sd_resolve_query_set_userdata(sd_resolve_query *q, void *userdata); sd_resolve *sd_resolve_query_get_resolve(sd_resolve_query *q); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_resolve, sd_resolve_unref); +_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_resolve_query, sd_resolve_query_unref); + _SD_END_DECLARATIONS; #endif diff --git a/src/systemd/sd-utf8.h b/src/systemd/sd-utf8.h index 205ee4221..678198387 100644 --- a/src/systemd/sd-utf8.h +++ b/src/systemd/sd-utf8.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #ifndef foosdutf8hfoo #define foosdutf8hfoo diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 675f94906..863c62832 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -280,7 +278,7 @@ static int putgrent_with_members(const struct group *gr, FILE *group) { errno = 0; if (putgrent(&t, group) != 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return 1; } @@ -288,7 +286,7 @@ static int putgrent_with_members(const struct group *gr, FILE *group) { errno = 0; if (putgrent(gr, group) != 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return 0; } @@ -330,7 +328,7 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) { errno = 0; if (putsgent(&t, gshadow) != 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return 1; } @@ -338,7 +336,7 @@ static int putsgent_with_members(const struct sgrp *sg, FILE *gshadow) { errno = 0; if (putsgent(sg, gshadow) != 0) - return errno ? -errno : -EIO; + return errno > 0 ? -errno : -EIO; return 0; } @@ -410,11 +408,13 @@ static int write_files(void) { i = hashmap_get(groups, gr->gr_name); if (i && i->todo_group) { + log_error("%s: Group \"%s\" already exists.", group_path, gr->gr_name); r = -EEXIST; goto finish; } if (hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) { + log_error("%s: Detected collision for GID " GID_FMT ".", group_path, gr->gr_gid); r = -EEXIST; goto finish; } @@ -482,6 +482,7 @@ static int write_files(void) { i = hashmap_get(groups, sg->sg_namp); if (i && i->todo_group) { + log_error("%s: Group \"%s\" already exists.", gshadow_path, sg->sg_namp); r = -EEXIST; goto finish; } @@ -548,11 +549,13 @@ static int write_files(void) { i = hashmap_get(users, pw->pw_name); if (i && i->todo_user) { + log_error("%s: User \"%s\" already exists.", passwd_path, pw->pw_name); r = -EEXIST; goto finish; } if (hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) { + log_error("%s: Detected collision for UID " UID_FMT ".", passwd_path, pw->pw_uid); r = -EEXIST; goto finish; } diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 507554850..5a6818a79 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -161,7 +159,6 @@ static int add_alias(const char *service, const char *alias) { } static int generate_unit_file(SysvStub *s) { - _cleanup_free_ char *before = NULL, *after = NULL, *wants = NULL, *conflicts = NULL; _cleanup_fclose_ FILE *f = NULL; const char *unit; char **p; @@ -174,14 +171,6 @@ static int generate_unit_file(SysvStub *s) { unit = strjoina(arg_dest, "/", s->name); - before = strv_join(s->before, " "); - after = strv_join(s->after, " "); - wants = strv_join(s->wants, " "); - conflicts = strv_join(s->conflicts, " "); - - if (!before || !after || !wants || !conflicts) - return log_oom(); - /* We might already have a symlink with the same name from a Provides:, * or from backup files like /etc/init.d/foo.bak. Real scripts always win, * so remove an existing link */ @@ -204,14 +193,14 @@ static int generate_unit_file(SysvStub *s) { if (s->description) fprintf(f, "Description=%s\n", s->description); - if (!isempty(before)) - fprintf(f, "Before=%s\n", before); - if (!isempty(after)) - fprintf(f, "After=%s\n", after); - if (!isempty(wants)) - fprintf(f, "Wants=%s\n", wants); - if (!isempty(conflicts)) - fprintf(f, "Conflicts=%s\n", conflicts); + STRV_FOREACH(p, s->before) + fprintf(f, "Before=%s\n", *p); + STRV_FOREACH(p, s->after) + fprintf(f, "After=%s\n", *p); + STRV_FOREACH(p, s->wants) + fprintf(f, "Wants=%s\n", *p); + STRV_FOREACH(p, s->conflicts) + fprintf(f, "Conflicts=%s\n", *p); fprintf(f, "\n[Service]\n" diff --git a/src/test/test-acl-util.c b/src/test/test-acl-util.c new file mode 100644 index 000000000..430dda8e7 --- /dev/null +++ b/src/test/test-acl-util.c @@ -0,0 +1,85 @@ +/*** + 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 . +***/ + +#include +#include +#include +#include + +#include "acl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "string-util.h" +#include "user-util.h" + +static void test_add_acls_for_user(void) { + char fn[] = "/tmp/test-empty.XXXXXX"; + _cleanup_close_ int fd = -1; + char *cmd; + uid_t uid; + int r; + + fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC); + assert_se(fd >= 0); + + /* Use the mode that user journal files use */ + assert_se(fchmod(fd, 0640) == 0); + + cmd = strjoina("ls -l ", fn); + assert_se(system(cmd) == 0); + + cmd = strjoina("getfacl -p ", fn); + assert_se(system(cmd) == 0); + + if (getuid() == 0) { + const char *nobody = "nobody"; + r = get_user_creds(&nobody, &uid, NULL, NULL, NULL); + if (r < 0) + uid = 0; + } else + uid = getuid(); + + r = add_acls_for_user(fd, uid); + assert_se(r >= 0); + + cmd = strjoina("ls -l ", fn); + assert_se(system(cmd) == 0); + + cmd = strjoina("getfacl -p ", fn); + assert_se(system(cmd) == 0); + + /* set the acls again */ + + r = add_acls_for_user(fd, uid); + assert_se(r >= 0); + + cmd = strjoina("ls -l ", fn); + assert_se(system(cmd) == 0); + + cmd = strjoina("getfacl -p ", fn); + assert_se(system(cmd) == 0); + + unlink(fn); +} + +int main(int argc, char **argv) { + test_add_acls_for_user(); + + return 0; +} diff --git a/src/test/test-architecture.c b/src/test/test-architecture.c index 35479d67c..f41e488d9 100644 --- a/src/test/test-architecture.c +++ b/src/test/test-architecture.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-ask-password-api.c b/src/test/test-ask-password-api.c new file mode 100644 index 000000000..86666597c --- /dev/null +++ b/src/test/test-ask-password-api.c @@ -0,0 +1,38 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "alloc-util.h" +#include "ask-password-api.h" +#include "log.h" + +static void ask_password(void) { + int r; + _cleanup_free_ char *ret; + + r = ask_password_tty("hello?", "da key", 0, 0, NULL, &ret); + assert(r >= 0); + + log_info("Got %s", ret); +} + +int main(int argc, char **argv) { + log_parse_environment(); + + ask_password(); +} diff --git a/src/test/test-barrier.c b/src/test/test-barrier.c index f37cb49c8..e6aa3b5cf 100644 --- a/src/test/test-barrier.c +++ b/src/test/test-barrier.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-boot-timestamps.c b/src/test/test-boot-timestamps.c index fab33d20c..d2add5880 100644 --- a/src/test/test-boot-timestamps.c +++ b/src/test/test-boot-timestamps.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c index 33356f838..ce29d8841 100644 --- a/src/test/test-btrfs.c +++ b/src/test/test-btrfs.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index 70819b037..8754cb338 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -75,7 +73,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 +121,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 +132,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-cap-list.c b/src/test/test-cap-list.c index 4418bafda..4132ec56f 100644 --- a/src/test/test-cap-list.c +++ b/src/test/test-cap-list.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-capability.c b/src/test/test-capability.c index fc8d3ffe0..629bb63c8 100644 --- a/src/test/test-capability.c +++ b/src/test/test-capability.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -66,8 +67,9 @@ static void show_capabilities(void) { cap_free(text); } -static int setup_tests(void) { +static int setup_tests(bool *run_ambient) { struct passwd *nobody; + int r; nobody = getpwnam("nobody"); if (!nobody) { @@ -77,6 +79,18 @@ static int setup_tests(void) { test_uid = nobody->pw_uid; test_gid = nobody->pw_gid; + *run_ambient = false; + + r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); + + /* There's support for PR_CAP_AMBIENT if the prctl() call + * succeeded or error code was something else than EINVAL. The + * EINVAL check should be good enough to rule out false + * positives. */ + + if (r >= 0 || errno != EINVAL) + *run_ambient = true; + return 0; } @@ -140,8 +154,53 @@ static void test_have_effective_cap(void) { assert_se(!have_effective_cap(CAP_CHOWN)); } +static void test_update_inherited_set(void) { + cap_t caps; + uint64_t set = 0; + cap_flag_value_t fv; + + caps = cap_get_proc(); + assert_se(caps); + assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); + assert(fv == CAP_CLEAR); + + set = (UINT64_C(1) << CAP_CHOWN); + + assert_se(!capability_update_inherited_set(caps, set)); + assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); + assert(fv == CAP_SET); + + cap_free(caps); +} + +static void test_set_ambient_caps(void) { + cap_t caps; + uint64_t set = 0; + cap_flag_value_t fv; + + caps = cap_get_proc(); + assert_se(caps); + assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); + assert(fv == CAP_CLEAR); + cap_free(caps); + + assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 0); + + set = (UINT64_C(1) << CAP_CHOWN); + + assert_se(!capability_ambient_set_apply(set, true)); + + caps = cap_get_proc(); + assert_se(!cap_get_flag(caps, CAP_CHOWN, CAP_INHERITABLE, &fv)); + assert(fv == CAP_SET); + cap_free(caps); + + assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 1); +} + int main(int argc, char *argv[]) { int r; + bool run_ambient; log_parse_environment(); log_open(); @@ -149,14 +208,19 @@ int main(int argc, char *argv[]) { if (getuid() != 0) return EXIT_TEST_SKIP; - r = setup_tests(); + r = setup_tests(&run_ambient); if (r < 0) return -r; show_capabilities(); test_drop_privileges(); + test_update_inherited_set(); + fork_test(test_have_effective_cap); + if (run_ambient) + fork_test(test_set_ambient_caps); + return 0; } diff --git a/src/test/test-cgroup-mask.c b/src/test/test-cgroup-mask.c index 274601352..ad15075a5 100644 --- a/src/test/test-cgroup-mask.c +++ b/src/test/test-cgroup-mask.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -40,6 +38,7 @@ static int test_cgroup_mask(void) { puts("manager_new: Permission denied. Skipping test."); return EXIT_TEST_SKIP; } + assert_se(r >= 0); /* Turn off all kinds of default accouning, so that we can * verify the masks resulting of our configuration and nothing diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index a48b324e2..43f890617 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c index c20a29ba1..72c32d9c8 100644 --- a/src/test/test-cgroup.c +++ b/src/test/test-cgroup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-condition.c b/src/test/test-condition.c index f224c6cdd..8903d10db 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -203,7 +203,7 @@ static void test_condition_test_security(void) { condition_free(condition); condition = condition_new(CONDITION_SECURITY, "selinux", false, true); - assert_se(condition_test(condition) != mac_selinux_use()); + assert_se(condition_test(condition) != mac_selinux_have()); condition_free(condition); condition = condition_new(CONDITION_SECURITY, "ima", false, false); diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c index 86ac513d4..03b3a9fa5 100644 --- a/src/test/test-conf-files.c +++ b/src/test/test-conf-files.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-daemon.c b/src/test/test-daemon.c index 45fb55444..4ce00f4b1 100644 --- a/src/test/test-daemon.c +++ b/src/test/test-daemon.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-date.c b/src/test/test-date.c index c6d8bf82e..7f497bb7d 100644 --- a/src/test/test-date.c +++ b/src/test/test-date.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -27,14 +25,16 @@ static void test_should_pass(const char *p) { usec_t t, q; - char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX]; + char buf[FORMAT_TIMESTAMP_MAX], buf_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *sp; assert_se(parse_timestamp(p, &t) >= 0); format_timestamp_us(buf, sizeof(buf), t); log_info("%s", buf); /* Chop off timezone */ - *strrchr(buf, ' ') = 0; + sp = strrchr(buf, ' '); + assert_se(sp); + *sp = 0; assert_se(parse_timestamp(buf, &q) >= 0); assert_se(q == t); diff --git a/src/test/test-device-nodes.c b/src/test/test-device-nodes.c index 646b168cc..af75b3894 100644 --- a/src/test/test-device-nodes.c +++ b/src/test/test-device-nodes.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index d5778748a..a9d09f59b 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -39,7 +37,7 @@ static void test_dns_label_unescape_one(const char *what, const char *expect, si static void test_dns_label_unescape(void) { test_dns_label_unescape_one("hallo", "hallo", 6, 5); - test_dns_label_unescape_one("hallo", "hallo", 4, -ENOSPC); + test_dns_label_unescape_one("hallo", "hallo", 4, -ENOBUFS); test_dns_label_unescape_one("", "", 10, 0); test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12); test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5); @@ -52,6 +50,66 @@ 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, false); + assert_se(r == ret); + + if (r < 0) + return; + + assert_se(!memcmp(buffer, expect, r)); +} + +static void test_dns_name_to_wire_format(void) { + static const char out0[] = { 0 }; + static const char out1[] = { 3, 'f', 'o', 'o', 0 }; + static const char out2[] = { 5, 'h', 'a', 'l', 'l', 'o', 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; + static const char out3[] = { 4, ' ', 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; + static const char out4[] = { 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', + 3, 'a', '1', '2', 0 }; + + test_dns_name_to_wire_format_one("", out0, sizeof(out0), sizeof(out0)); + + test_dns_name_to_wire_format_one("foo", out1, sizeof(out1), sizeof(out1)); + 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)); + + test_dns_name_to_wire_format_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", NULL, 500, -EINVAL); + test_dns_name_to_wire_format_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", out4, sizeof(out4), sizeof(out4)); +} + 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; @@ -72,7 +130,7 @@ static void test_dns_label_unescape_suffix_one(const char *what, const char *exp static void test_dns_label_unescape_suffix(void) { test_dns_label_unescape_suffix_one("hallo", "hallo", "", 6, 5, 0); - test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOSPC, -ENOSPC); + test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOBUFS, -ENOBUFS); test_dns_label_unescape_suffix_one("", "", "", 10, 0, 0); test_dns_label_unescape_suffix_one("hallo\\.foobar", "hallo.foobar", "", 20, 12, 0); test_dns_label_unescape_suffix_one("hallo.foobar", "foobar", "hallo", 10, 6, 5); @@ -80,9 +138,9 @@ static void test_dns_label_unescape_suffix(void) { test_dns_label_unescape_suffix_one("hallo\\", "hallo", "hallo", 20, -EINVAL, -EINVAL); test_dns_label_unescape_suffix_one("hallo\\032 ", "hallo ", "", 20, 7, 0); test_dns_label_unescape_suffix_one(".", "", "", 20, 0, 0); - test_dns_label_unescape_suffix_one("..", "", "", 20, 0, 0); + test_dns_label_unescape_suffix_one("..", "", "", 20, 0, -EINVAL); test_dns_label_unescape_suffix_one(".foobar", "foobar", "", 20, 6, -EINVAL); - test_dns_label_unescape_suffix_one("foobar.", "", "foobar", 20, 0, 6); + test_dns_label_unescape_suffix_one("foobar.", "foobar", "", 20, 6, 0); test_dns_label_unescape_suffix_one("foo\\\\bar", "foo\\bar", "", 20, 7, 0); test_dns_label_unescape_suffix_one("foo.bar", "bar", "foo", 20, 3, 3); test_dns_label_unescape_suffix_one("foo..bar", "bar", "", 20, 3, -EINVAL); @@ -96,7 +154,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) @@ -106,9 +164,9 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex } static void test_dns_label_escape(void) { - test_dns_label_escape_one("", 0, "", 0); + test_dns_label_escape_one("", 0, NULL, -EINVAL); test_dns_label_escape_one("hallo", 5, "hallo", 5); - test_dns_label_escape_one("hallo", 6, NULL, -EINVAL); + test_dns_label_escape_one("hallo", 6, "hallo\\000", 9); test_dns_label_escape_one("hallo hallo.foobar,waldi", 24, "hallo\\032hallo\\.foobar\\044waldi", 31); } @@ -126,15 +184,15 @@ static void test_dns_name_normalize_one(const char *what, const char *expect, in } static void test_dns_name_normalize(void) { - test_dns_name_normalize_one("", "", 0); + test_dns_name_normalize_one("", ".", 0); test_dns_name_normalize_one("f", "f", 0); test_dns_name_normalize_one("f.waldi", "f.waldi", 0); test_dns_name_normalize_one("f \\032.waldi", "f\\032\\032.waldi", 0); - test_dns_name_normalize_one("\\000", NULL, -EINVAL); + test_dns_name_normalize_one("\\000", "\\000", 0); test_dns_name_normalize_one("..", NULL, -EINVAL); test_dns_name_normalize_one(".foobar", NULL, -EINVAL); test_dns_name_normalize_one("foobar.", "foobar", 0); - test_dns_name_normalize_one(".", "", 0); + test_dns_name_normalize_one(".", ".", 0); } static void test_dns_name_equal_one(const char *a, const char *b, int ret) { @@ -156,7 +214,7 @@ static void test_dns_name_equal(void) { test_dns_name_equal_one("abc.def", "CBA.def", false); test_dns_name_equal_one("", "xxx", false); test_dns_name_equal_one("ab", "a", false); - test_dns_name_equal_one("\\000", "xxxx", -EINVAL); + test_dns_name_equal_one("\\000", "\\000", true); test_dns_name_equal_one(".", "", true); test_dns_name_equal_one(".", ".", true); test_dns_name_equal_one("..", "..", -EINVAL); @@ -216,21 +274,40 @@ 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_startswith_one(const char *a, const char *b, int ret) { + assert_se(dns_name_startswith(a, b) == ret); } -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_startswith(void) { + test_dns_name_startswith_one("", "", true); + test_dns_name_startswith_one("", "xxx", false); + test_dns_name_startswith_one("xxx", "", true); + test_dns_name_startswith_one("x", "x", true); + test_dns_name_startswith_one("x", "y", false); + test_dns_name_startswith_one("x.y", "x.y", true); + test_dns_name_startswith_one("x.y", "y.x", false); + test_dns_name_startswith_one("x.y", "x", true); + test_dns_name_startswith_one("x.y", "X", true); + test_dns_name_startswith_one("x.y", "y", false); + test_dns_name_startswith_one("x.y", "", true); + test_dns_name_startswith_one("x.y", "X", true); +} + +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_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) { @@ -261,10 +338,18 @@ static void test_dns_name_concat_one(const char *a, const char *b, int r, const } static void test_dns_name_concat(void) { + test_dns_name_concat_one("", "", 0, "."); + test_dns_name_concat_one(".", "", 0, "."); + test_dns_name_concat_one("", ".", 0, "."); + test_dns_name_concat_one(".", ".", 0, "."); test_dns_name_concat_one("foo", "bar", 0, "foo.bar"); test_dns_name_concat_one("foo.foo", "bar.bar", 0, "foo.foo.bar.bar"); test_dns_name_concat_one("foo", NULL, 0, "foo"); + test_dns_name_concat_one("foo", ".", 0, "foo"); test_dns_name_concat_one("foo.", "bar.", 0, "foo.bar"); + test_dns_name_concat_one(NULL, NULL, 0, "."); + test_dns_name_concat_one(NULL, ".", 0, "."); + test_dns_name_concat_one(NULL, "foo", 0, "foo"); } static void test_dns_name_is_valid_one(const char *s, int ret) { @@ -284,6 +369,259 @@ static void test_dns_name_is_valid(void) { test_dns_name_is_valid_one("\\zbar", 0); test_dns_name_is_valid_one("ä", 1); test_dns_name_is_valid_one("\n", 0); + + /* 256 characters*/ + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345", 0); + + /* 255 characters*/ + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a1234", 0); + + /* 254 characters*/ + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", 0); + + /* 253 characters*/ + test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", 1); + + /* label of 64 chars length */ + test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a123", 0); + + /* label of 63 chars length */ + test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a12", 1); +} + +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(dns_name_equal(c, z) > 0); +} + +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(dns_name_equal(joined, t) > 0); + } else + assert_se(!x && dns_name_equal(z, joined) > 0); +} + +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); +} + +static void test_dns_name_suffix_one(const char *name, unsigned n_labels, const char *result, int ret) { + const char *p = NULL; + + assert_se(ret == dns_name_suffix(name, n_labels, &p)); + assert_se(streq_ptr(p, result)); +} + +static void test_dns_name_suffix(void) { + test_dns_name_suffix_one("foo.bar", 2, "foo.bar", 0); + test_dns_name_suffix_one("foo.bar", 1, "bar", 1); + test_dns_name_suffix_one("foo.bar", 0, "", 2); + test_dns_name_suffix_one("foo.bar", 3, NULL, -EINVAL); + test_dns_name_suffix_one("foo.bar", 4, NULL, -EINVAL); + + test_dns_name_suffix_one("bar", 1, "bar", 0); + test_dns_name_suffix_one("bar", 0, "", 1); + test_dns_name_suffix_one("bar", 2, NULL, -EINVAL); + test_dns_name_suffix_one("bar", 3, NULL, -EINVAL); + + test_dns_name_suffix_one("", 0, "", 0); + test_dns_name_suffix_one("", 1, NULL, -EINVAL); + test_dns_name_suffix_one("", 2, NULL, -EINVAL); +} + +static void test_dns_name_count_labels_one(const char *name, int n) { + assert_se(dns_name_count_labels(name) == n); +} + +static void test_dns_name_count_labels(void) { + test_dns_name_count_labels_one("foo.bar.quux.", 3); + test_dns_name_count_labels_one("foo.bar.quux", 3); + test_dns_name_count_labels_one("foo.bar.", 2); + test_dns_name_count_labels_one("foo.bar", 2); + test_dns_name_count_labels_one("foo.", 1); + test_dns_name_count_labels_one("foo", 1); + test_dns_name_count_labels_one("", 0); + test_dns_name_count_labels_one(".", 0); + test_dns_name_count_labels_one("..", -EINVAL); +} + +static void test_dns_name_equal_skip_one(const char *a, unsigned n_labels, const char *b, int ret) { + assert_se(dns_name_equal_skip(a, n_labels, b) == ret); +} + +static void test_dns_name_equal_skip(void) { + test_dns_name_equal_skip_one("foo", 0, "bar", 0); + test_dns_name_equal_skip_one("foo", 0, "foo", 1); + test_dns_name_equal_skip_one("foo", 1, "foo", 0); + test_dns_name_equal_skip_one("foo", 2, "foo", 0); + + test_dns_name_equal_skip_one("foo.bar", 0, "foo.bar", 1); + test_dns_name_equal_skip_one("foo.bar", 1, "foo.bar", 0); + test_dns_name_equal_skip_one("foo.bar", 2, "foo.bar", 0); + test_dns_name_equal_skip_one("foo.bar", 3, "foo.bar", 0); + + test_dns_name_equal_skip_one("foo.bar", 0, "bar", 0); + test_dns_name_equal_skip_one("foo.bar", 1, "bar", 1); + test_dns_name_equal_skip_one("foo.bar", 2, "bar", 0); + test_dns_name_equal_skip_one("foo.bar", 3, "bar", 0); + + test_dns_name_equal_skip_one("foo.bar", 0, "", 0); + test_dns_name_equal_skip_one("foo.bar", 1, "", 0); + test_dns_name_equal_skip_one("foo.bar", 2, "", 1); + test_dns_name_equal_skip_one("foo.bar", 3, "", 0); + + test_dns_name_equal_skip_one("", 0, "", 1); + test_dns_name_equal_skip_one("", 1, "", 0); + test_dns_name_equal_skip_one("", 1, "foo", 0); + test_dns_name_equal_skip_one("", 2, "foo", 0); +} + +static void test_dns_name_compare_func(void) { + assert_se(dns_name_compare_func("", "") == 0); + assert_se(dns_name_compare_func("", ".") == 0); + assert_se(dns_name_compare_func(".", "") == 0); + assert_se(dns_name_compare_func("foo", "foo.") == 0); + assert_se(dns_name_compare_func("foo.", "foo") == 0); + assert_se(dns_name_compare_func("foo", "foo") == 0); + assert_se(dns_name_compare_func("foo.", "foo.") == 0); + assert_se(dns_name_compare_func("heise.de", "HEISE.DE.") == 0); + + assert_se(dns_name_compare_func("de.", "heise.de") != 0); +} + +static void test_dns_name_common_suffix_one(const char *a, const char *b, const char *result) { + const char *c; + + assert_se(dns_name_common_suffix(a, b, &c) >= 0); + assert_se(streq(c, result)); +} + +static void test_dns_name_common_suffix(void) { + test_dns_name_common_suffix_one("", "", ""); + test_dns_name_common_suffix_one("foo", "", ""); + test_dns_name_common_suffix_one("", "foo", ""); + test_dns_name_common_suffix_one("foo", "bar", ""); + test_dns_name_common_suffix_one("bar", "foo", ""); + test_dns_name_common_suffix_one("foo", "foo", "foo"); + test_dns_name_common_suffix_one("quux.foo", "foo", "foo"); + test_dns_name_common_suffix_one("foo", "quux.foo", "foo"); + test_dns_name_common_suffix_one("this.is.a.short.sentence", "this.is.another.short.sentence", "short.sentence"); + test_dns_name_common_suffix_one("FOO.BAR", "tEST.bAR", "BAR"); +} + +static void test_dns_name_apply_idna_one(const char *s, const char *result) { +#ifdef HAVE_LIBIDN + _cleanup_free_ char *buf = NULL; + assert_se(dns_name_apply_idna(s, &buf) >= 0); + assert_se(dns_name_equal(buf, result) > 0); +#endif +} + +static void test_dns_name_apply_idna(void) { + test_dns_name_apply_idna_one("", ""); + test_dns_name_apply_idna_one("foo", "foo"); + test_dns_name_apply_idna_one("foo.", "foo"); + test_dns_name_apply_idna_one("foo.bar", "foo.bar"); + test_dns_name_apply_idna_one("foo.bar.", "foo.bar"); + test_dns_name_apply_idna_one("föö", "xn--f-1gaa"); + test_dns_name_apply_idna_one("föö.", "xn--f-1gaa"); + test_dns_name_apply_idna_one("föö.bär", "xn--f-1gaa.xn--br-via"); + test_dns_name_apply_idna_one("föö.bär.", "xn--f-1gaa.xn--br-via"); } int main(int argc, char *argv[]) { @@ -294,12 +632,25 @@ int main(int argc, char *argv[]) { test_dns_name_normalize(); test_dns_name_equal(); test_dns_name_endswith(); + test_dns_name_startswith(); 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(); + test_dns_name_suffix(); + test_dns_name_count_labels(); + test_dns_name_equal_skip(); + test_dns_name_compare_func(); + test_dns_name_common_suffix(); + test_dns_name_apply_idna(); return 0; } diff --git a/src/test/test-ellipsize.c b/src/test/test-ellipsize.c index c597d5aec..d4f09b08a 100644 --- a/src/test/test-ellipsize.c +++ b/src/test/test-ellipsize.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-engine.c b/src/test/test-engine.c index 4f14c5878..ca66f5b68 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -25,9 +23,10 @@ #include "bus-util.h" #include "manager.h" +#include "test-helper.h" int main(int argc, char *argv[]) { - _cleanup_bus_error_free_ sd_bus_error err = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL; Manager *m = NULL; Unit *a = NULL, *b = NULL, *c = NULL, *d = NULL, *e = NULL, *g = NULL, *h = NULL; FILE *serial = NULL; @@ -38,8 +37,8 @@ int main(int argc, char *argv[]) { /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); r = manager_new(MANAGER_USER, true, &m); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { - printf("Skipping test: manager_new: %s", strerror(-r)); + if (MANAGER_SKIP_TEST(r)) { + printf("Skipping test: manager_new: %s\n", strerror(-r)); return EXIT_TEST_SKIP; } assert_se(r >= 0); diff --git a/src/test/test-env-replace.c b/src/test/test-env-replace.c index c1315bbf9..264acc6ea 100644 --- a/src/test/test-env-replace.c +++ b/src/test/test-env-replace.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 03ec0fcfc..92857cb5e 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "fileio.h" @@ -29,6 +30,7 @@ #include "mkdir.h" #include "path-util.h" #include "rm-rf.h" +#include "test-helper.h" #include "unit.h" #include "util.h" @@ -223,6 +225,20 @@ static void test_exec_capabilityboundingset(Manager *m) { test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED); } +static void test_exec_capabilityambientset(Manager *m) { + int r; + + /* Check if the kernel has support for ambient capabilities. Run + * the tests only if that's the case. Clearing all ambient + * capabilities is fine, since we are expecting them to be unset + * in the first place for the tests. */ + r = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0); + if (r >= 0 || errno != EINVAL) { + test(m, "exec-capabilityambientset.service", 0, CLD_EXITED); + test(m, "exec-capabilityambientset-merge.service", 0, CLD_EXITED); + } +} + static void test_exec_privatenetwork(Manager *m) { int r; @@ -265,6 +281,7 @@ int main(int argc, char *argv[]) { test_exec_umask, test_exec_runtimedirectory, test_exec_capabilityboundingset, + test_exec_capabilityambientset, test_exec_oomscoreadjust, test_exec_ioschedulingclass, NULL, @@ -296,8 +313,8 @@ int main(int argc, char *argv[]) { assert_se(unsetenv("VAR3") == 0); r = manager_new(MANAGER_USER, true, &m); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { - printf("Skipping test: manager_new: %s", strerror(-r)); + if (MANAGER_SKIP_TEST(r)) { + printf("Skipping test: manager_new: %s\n", strerror(-r)); return EXIT_TEST_SKIP; } assert_se(r >= 0); diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c index 65d3a0a96..7a23fa7b7 100644 --- a/src/test/test-extract-word.c +++ b/src/test/test-extract-word.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 871c71e17..5586a2d6c 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-firewall-util.c b/src/test/test-firewall-util.c index ff66bde09..77e809c5b 100644 --- a/src/test/test-firewall-util.c +++ b/src/test/test-firewall-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c index 27816ac77..ea3d1a690 100644 --- a/src/test/test-fstab-util.c +++ b/src/test/test-fstab-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-helper.h b/src/test/test-helper.h index f75dd3374..ddb10f88f 100644 --- a/src/test/test-helper.h +++ b/src/test/test-helper.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -23,9 +21,21 @@ #include "sd-daemon.h" +#include "macro.h" + #define TEST_REQ_RUNNING_SYSTEMD(x) \ if (sd_booted() > 0) { \ x; \ } else { \ printf("systemd not booted skipping '%s'\n", #x); \ } + +#define MANAGER_SKIP_TEST(r) \ + IN_SET(r, \ + -EPERM, \ + -EACCES, \ + -EADDRINUSE, \ + -EHOSTDOWN, \ + -ENOENT, \ + -ENOMEDIUM /* cannot determine cgroup */ \ + ) diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c index 590175433..17fde9f27 100644 --- a/src/test/test-hostname-util.c +++ b/src/test/test-hostname-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-hostname.c b/src/test/test-hostname.c index dd50c5148..b38507df5 100644 --- a/src/test/test-hostname.c +++ b/src/test/test-hostname.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-id128.c b/src/test/test-id128.c index 32cf3f80c..96aa008c0 100644 --- a/src/test/test-id128.c +++ b/src/test/test-id128.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index 08fde94f7..cd250ca7b 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-install.c b/src/test/test-install.c index ef6f1efb8..874d61762 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-ipcrm.c b/src/test/test-ipcrm.c index 5841cb3fb..2464d3245 100644 --- a/src/test/test-ipcrm.c +++ b/src/test/test-ipcrm.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-job-type.c b/src/test/test-job-type.c index 75ce3a349..7f0b9f253 100644 --- a/src/test/test-job-type.c +++ b/src/test/test-job-type.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-json.c b/src/test/test-json.c index 3995224ee..3fe2f58d0 100644 --- a/src/test/test-json.c +++ b/src/test/test-json.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-libudev.c b/src/test/test-libudev.c index 350eaf734..a7eb60e8c 100644 --- a/src/test/test-libudev.c +++ b/src/test/test-libudev.c @@ -1,4 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*** This file is part of systemd. @@ -25,6 +24,7 @@ #include "libudev.h" +#include "stdio-util.h" #include "string-util.h" #include "udev-util.h" #include "util.h" @@ -460,7 +460,7 @@ int main(int argc, char *argv[]) { /* add sys path if needed */ if (!startswith(syspath, "/sys")) { - snprintf(path, sizeof(path), "/sys/%s", syspath); + xsprintf(path, "/sys/%s", syspath); syspath = path; } diff --git a/src/test/test-log.c b/src/test/test-log.c index a01df9b04..55a2f9d23 100644 --- a/src/test/test-log.c +++ b/src/test/test-log.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c index 556938a0f..2748395ad 100644 --- a/src/test/test-loopback.c +++ b/src/test/test-loopback.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 5a12e959d..0b2f9e917 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-netlink-manual.c b/src/test/test-netlink-manual.c index a1e877406..79ff6ae74 100644 --- a/src/test/test-netlink-manual.c +++ b/src/test/test-netlink-manual.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-ns.c b/src/test/test-ns.c index 1175114a3..cf627be6c 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c index f0d5d7108..7d8677e17 100644 --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c index 65cb894ff..268da002a 100644 --- a/src/test/test-path-lookup.c +++ b/src/test/test-path-lookup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 3f0f0264a..53a585290 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-path.c b/src/test/test-path.c index 8302bdd28..7a3b14541 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -29,6 +29,7 @@ #include "rm-rf.h" #include "string-util.h" #include "strv.h" +#include "test-helper.h" #include "unit.h" #include "util.h" @@ -44,8 +45,8 @@ static int setup_test(Manager **m) { assert_se(m); r = manager_new(MANAGER_USER, true, &tmp); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { - printf("Skipping test: manager_new: %s", strerror(-r)); + if (MANAGER_SKIP_TEST(r)) { + printf("Skipping test: manager_new: %s\n", strerror(-r)); return -EXIT_TEST_SKIP; } assert_se(r >= 0); diff --git a/src/test/test-prioq.c b/src/test/test-prioq.c index 07273ffe7..d81880a65 100644 --- a/src/test/test-prioq.c +++ b/src/test/test-prioq.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-rbtree.c b/src/test/test-rbtree.c new file mode 100644 index 000000000..8ae416c55 --- /dev/null +++ b/src/test/test-rbtree.c @@ -0,0 +1,362 @@ +/*** + This file is part of systemd. See COPYING for details. + + 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 . +***/ + +/* + * Tests for RB-Tree + */ + +#undef NDEBUG +#include +#include +#include +#include "c-rbtree.h" + +/* verify that all API calls are exported */ +static void test_api(void) { + CRBTree t = {}; + CRBNode n = C_RBNODE_INIT(n); + + assert(!c_rbnode_is_linked(&n)); + + /* init, is_linked, add, remove, remove_init */ + + c_rbtree_add(&t, NULL, &t.root, &n); + assert(c_rbnode_is_linked(&n)); + + c_rbtree_remove_init(&t, &n); + assert(!c_rbnode_is_linked(&n)); + + c_rbtree_add(&t, NULL, &t.root, &n); + assert(c_rbnode_is_linked(&n)); + + c_rbtree_remove(&t, &n); + assert(c_rbnode_is_linked(&n)); /* @n wasn't touched */ + + c_rbnode_init(&n); + assert(!c_rbnode_is_linked(&n)); + + /* first, last, leftmost, rightmost, next, prev */ + + assert(!c_rbtree_first(&t)); + assert(!c_rbtree_last(&t)); + assert(&n == c_rbnode_leftmost(&n)); + assert(&n == c_rbnode_rightmost(&n)); + assert(!c_rbnode_next(&n)); + assert(!c_rbnode_prev(&n)); +} + +/* copied from c-rbtree.c, relies on internal representation */ +static inline _Bool c_rbnode_is_red(CRBNode *n) { + return !((unsigned long)n->__parent_and_color & 1UL); +} + +/* copied from c-rbtree.c, relies on internal representation */ +static inline _Bool c_rbnode_is_black(CRBNode *n) { + return !!((unsigned long)n->__parent_and_color & 1UL); +} + +static size_t validate(CRBTree *t) { + unsigned int i_black, n_black; + CRBNode *n, *p, *o; + size_t count = 0; + + assert(t); + assert(!t->root || c_rbnode_is_black(t->root)); + + /* traverse to left-most child, count black nodes */ + i_black = 0; + n = t->root; + while (n && n->left) { + if (c_rbnode_is_black(n)) + ++i_black; + n = n->left; + } + n_black = i_black; + + /* + * Traverse tree and verify correctness: + * 1) A node is either red or black + * 2) The root is black + * 3) All leaves are black + * 4) Every red node must have two black child nodes + * 5) Every path to a leaf contains the same number of black nodes + * + * Note that NULL nodes are considered black, which is why we don't + * check for 3). + */ + o = NULL; + while (n) { + ++count; + + /* verify natural order */ + assert(n > o); + o = n; + + /* verify consistency */ + assert(!n->right || c_rbnode_parent(n->right) == n); + assert(!n->left || c_rbnode_parent(n->left) == n); + + /* verify 2) */ + if (!c_rbnode_parent(n)) + assert(c_rbnode_is_black(n)); + + if (c_rbnode_is_red(n)) { + /* verify 4) */ + assert(!n->left || c_rbnode_is_black(n->left)); + assert(!n->right || c_rbnode_is_black(n->right)); + } else { + /* verify 1) */ + assert(c_rbnode_is_black(n)); + } + + /* verify 5) */ + if (!n->left && !n->right) + assert(i_black == n_black); + + /* get next node */ + if (n->right) { + n = n->right; + if (c_rbnode_is_black(n)) + ++i_black; + + while (n->left) { + n = n->left; + if (c_rbnode_is_black(n)) + ++i_black; + } + } else { + while ((p = c_rbnode_parent(n)) && n == p->right) { + n = p; + if (c_rbnode_is_black(p->right)) + --i_black; + } + + n = p; + if (p && c_rbnode_is_black(p->left)) + --i_black; + } + } + + return count; +} + +static void insert(CRBTree *t, CRBNode *n) { + CRBNode **i, *p; + + assert(t); + assert(n); + assert(!c_rbnode_is_linked(n)); + + i = &t->root; + p = NULL; + while (*i) { + p = *i; + if (n < *i) { + i = &(*i)->left; + } else { + assert(n > *i); + i = &(*i)->right; + } + } + + c_rbtree_add(t, p, i, n); +} + +static void shuffle(void **nodes, size_t n_memb) { + unsigned int i, j; + void *t; + + for (i = 0; i < n_memb; ++i) { + j = rand() % n_memb; + t = nodes[j]; + nodes[j] = nodes[i]; + nodes[i] = t; + } +} + +/* run some pseudo-random tests on the tree */ +static void test_shuffle(void) { + CRBNode *nodes[256]; + CRBTree t = {}; + unsigned int i, j; + size_t n; + + /* allocate and initialize all nodes */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { + nodes[i] = malloc(sizeof(*nodes[i])); + assert(nodes[i]); + c_rbnode_init(nodes[i]); + } + + /* shuffle nodes and validate *empty* tree */ + shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + n = validate(&t); + assert(n == 0); + + /* add all nodes and validate after each insertion */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { + insert(&t, nodes[i]); + n = validate(&t); + assert(n == i + 1); + } + + /* shuffle nodes again */ + shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + + /* remove all nodes (in different order) and validate on each round */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { + c_rbtree_remove(&t, nodes[i]); + n = validate(&t); + assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); + c_rbnode_init(nodes[i]); + } + + /* shuffle nodes and validate *empty* tree again */ + shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + n = validate(&t); + assert(n == 0); + + /* add all nodes again */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { + insert(&t, nodes[i]); + n = validate(&t); + assert(n == i + 1); + } + + /* 4 times, remove half of the nodes and add them again */ + for (j = 0; j < 4; ++j) { + /* shuffle nodes again */ + shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + + /* remove half of the nodes */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) { + c_rbtree_remove(&t, nodes[i]); + n = validate(&t); + assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); + c_rbnode_init(nodes[i]); + } + + /* shuffle the removed half */ + shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes) / 2); + + /* add the removed half again */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) { + insert(&t, nodes[i]); + n = validate(&t); + assert(n == sizeof(nodes) / sizeof(*nodes) / 2 + i + 1); + } + } + + /* shuffle nodes again */ + shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + + /* remove all */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { + c_rbtree_remove(&t, nodes[i]); + n = validate(&t); + assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); + c_rbnode_init(nodes[i]); + } + + /* free nodes again */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) + free(nodes[i]); +} + +typedef struct { + unsigned long key; + CRBNode rb; +} Node; + +#define node_from_rb(_rb) ((Node *)((char *)(_rb) - offsetof(Node, rb))) + +static int compare(CRBTree *t, void *k, CRBNode *n) { + unsigned long key = (unsigned long)k; + Node *node = node_from_rb(n); + + return (key < node->key) ? -1 : (key > node->key) ? 1 : 0; +} + +/* run tests against the c_rbtree_find*() helpers */ +static void test_map(void) { + CRBNode **slot, *p; + CRBTree t = {}; + Node *nodes[2048]; + unsigned long i; + + /* allocate and initialize all nodes */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { + nodes[i] = malloc(sizeof(*nodes[i])); + assert(nodes[i]); + nodes[i]->key = i; + c_rbnode_init(&nodes[i]->rb); + } + + /* shuffle nodes */ + shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + + /* add all nodes, and verify that each node is linked */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { + assert(!c_rbnode_is_linked(&nodes[i]->rb)); + assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); + + slot = c_rbtree_find_slot(&t, compare, (void *)nodes[i]->key, &p); + assert(slot); + c_rbtree_add(&t, p, slot, &nodes[i]->rb); + + assert(c_rbnode_is_linked(&nodes[i]->rb)); + assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); + } + + /* shuffle nodes again */ + shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + + /* remove all nodes (in different order) */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { + assert(c_rbnode_is_linked(&nodes[i]->rb)); + assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); + + c_rbtree_remove_init(&t, &nodes[i]->rb); + + assert(!c_rbnode_is_linked(&nodes[i]->rb)); + assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); + } + + /* free nodes again */ + for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) + free(nodes[i]); +} + +int main(int argc, char **argv) { + unsigned int i; + + /* we want stable tests, so use fixed seed */ + srand(0xdeadbeef); + + test_api(); + + /* + * The tests are pseudo random; run them multiple times, each run will + * have different orders and thus different results. + */ + for (i = 0; i < 4; ++i) { + test_shuffle(); + test_map(); + } + + return 0; +} diff --git a/src/test/test-replace-var.c b/src/test/test-replace-var.c index 2de209156..297effce7 100644 --- a/src/test/test-replace-var.c +++ b/src/test/test-replace-var.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-rlimit-util.c b/src/test/test-rlimit-util.c new file mode 100644 index 000000000..d9ac9368c --- /dev/null +++ b/src/test/test-rlimit-util.c @@ -0,0 +1,104 @@ +/*** + This file is part of systemd + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + 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 . +***/ + +#include + +#include "alloc-util.h" +#include "capability-util.h" +#include "macro.h" +#include "rlimit-util.h" +#include "string-util.h" +#include "util.h" + +static void test_rlimit_parse_format(int resource, const char *string, rlim_t soft, rlim_t hard, int ret, const char *formatted) { + _cleanup_free_ char *f = NULL; + struct rlimit rl = { + .rlim_cur = 4711, + .rlim_max = 4712, + }, rl2 = { + .rlim_cur = 4713, + .rlim_max = 4714 + }; + + assert_se(rlimit_parse(resource, string, &rl) == ret); + if (ret < 0) + return; + + assert_se(rl.rlim_cur == soft); + assert_se(rl.rlim_max == hard); + + assert_se(rlimit_format(&rl, &f) >= 0); + assert_se(streq(formatted, f)); + + assert_se(rlimit_parse(resource, formatted, &rl2) >= 0); + assert_se(memcmp(&rl, &rl2, sizeof(struct rlimit)) == 0); +} + +int main(int argc, char *argv[]) { + struct rlimit old, new, high; + struct rlimit err = { + .rlim_cur = 10, + .rlim_max = 5, + }; + + log_parse_environment(); + log_open(); + + assert_se(drop_capability(CAP_SYS_RESOURCE) == 0); + + assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); + new.rlim_cur = MIN(5U, old.rlim_max); + new.rlim_max = old.rlim_max; + assert_se(setrlimit(RLIMIT_NOFILE, &new) >= 0); + + assert_se(rlimit_from_string("LimitNOFILE") == RLIMIT_NOFILE); + assert_se(rlimit_from_string("DefaultLimitNOFILE") == -1); + + assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "LimitNOFILE")); + assert_se(rlimit_to_string(-1) == NULL); + + assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); + assert_se(setrlimit_closest(RLIMIT_NOFILE, &old) == 0); + assert_se(getrlimit(RLIMIT_NOFILE, &new) == 0); + assert_se(old.rlim_cur == new.rlim_cur); + assert_se(old.rlim_max == new.rlim_max); + + assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); + high = RLIMIT_MAKE_CONST(old.rlim_max == RLIM_INFINITY ? old.rlim_max : old.rlim_max + 1); + assert_se(setrlimit_closest(RLIMIT_NOFILE, &high) == 0); + assert_se(getrlimit(RLIMIT_NOFILE, &new) == 0); + assert_se(new.rlim_max == old.rlim_max); + assert_se(new.rlim_cur == new.rlim_max); + + assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); + assert_se(setrlimit_closest(RLIMIT_NOFILE, &err) == -EINVAL); + assert_se(getrlimit(RLIMIT_NOFILE, &new) == 0); + assert_se(old.rlim_cur == new.rlim_cur); + assert_se(old.rlim_max == new.rlim_max); + + test_rlimit_parse_format(RLIMIT_NOFILE, "4:5", 4, 5, 0, "4:5"); + test_rlimit_parse_format(RLIMIT_NOFILE, "6", 6, 6, 0, "6"); + test_rlimit_parse_format(RLIMIT_NOFILE, "infinity", RLIM_INFINITY, RLIM_INFINITY, 0, "infinity"); + test_rlimit_parse_format(RLIMIT_NOFILE, "infinity:infinity", RLIM_INFINITY, RLIM_INFINITY, 0, "infinity"); + test_rlimit_parse_format(RLIMIT_NOFILE, "8:infinity", 8, RLIM_INFINITY, 0, "8:infinity"); + test_rlimit_parse_format(RLIMIT_CPU, "25min:13h", (25*USEC_PER_MINUTE) / USEC_PER_SEC, (13*USEC_PER_HOUR) / USEC_PER_SEC, 0, "1500:46800"); + test_rlimit_parse_format(RLIMIT_NOFILE, "", 0, 0, -EINVAL, NULL); + test_rlimit_parse_format(RLIMIT_NOFILE, "5:4", 0, 0, -EILSEQ, NULL); + test_rlimit_parse_format(RLIMIT_NOFILE, "5:4:3", 0, 0, -EINVAL, NULL); + + return 0; +} diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index 8396ae60f..7f515b53d 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,6 +21,7 @@ #include "macro.h" #include "manager.h" +#include "test-helper.h" int main(int argc, char *argv[]) { Manager *m = NULL; @@ -35,8 +34,8 @@ int main(int argc, char *argv[]) { /* prepare the test */ assert_se(set_unit_path(TEST_DIR) >= 0); r = manager_new(MANAGER_USER, true, &m); - if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { - printf("Skipping test: manager_new: %s", strerror(-r)); + if (MANAGER_SKIP_TEST(r)) { + printf("Skipping test: manager_new: %s\n", strerror(-r)); return EXIT_TEST_SKIP; } assert_se(r >= 0); diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c index b3ccc7509..17b81747b 100644 --- a/src/test/test-sigbus.c +++ b/src/test/test-sigbus.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c new file mode 100644 index 000000000..3083501ce --- /dev/null +++ b/src/test/test-signal-util.c @@ -0,0 +1,49 @@ +/*** + This file is part of systemd. + + Copyright 2016 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 . +***/ + +#include "signal-util.h" + +static void test_block_signals(void) { + sigset_t ss; + + assert_se(sigprocmask(0, NULL, &ss) >= 0); + + assert_se(sigismember(&ss, SIGUSR1) == 0); + assert_se(sigismember(&ss, SIGALRM) == 0); + assert_se(sigismember(&ss, SIGVTALRM) == 0); + + { + BLOCK_SIGNALS(SIGUSR1, SIGVTALRM); + + assert_se(sigprocmask(0, NULL, &ss) >= 0); + assert_se(sigismember(&ss, SIGUSR1) == 1); + assert_se(sigismember(&ss, SIGALRM) == 0); + assert_se(sigismember(&ss, SIGVTALRM) == 1); + + } + + assert_se(sigprocmask(0, NULL, &ss) >= 0); + assert_se(sigismember(&ss, SIGUSR1) == 0); + assert_se(sigismember(&ss, SIGALRM) == 0); + assert_se(sigismember(&ss, SIGVTALRM) == 0); +} + +int main(int argc, char *argv[]) { + test_block_signals(); +} diff --git a/src/test/test-siphash24.c b/src/test/test-siphash24.c index a571a95a7..caae911f3 100644 --- a/src/test/test-siphash24.c +++ b/src/test/test-siphash24.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -30,7 +28,7 @@ static int do_test(const uint8_t *in, size_t len, const uint8_t *key) { unsigned i, j; out = siphash24(in, len, key); - assert_se(out == htole64(0xa129ca6149be45e5)); + assert_se(out == 0xa129ca6149be45e5); /* verify the internal state as given in the above paper */ siphash24_init(&state, key); @@ -44,7 +42,7 @@ static int do_test(const uint8_t *in, size_t len, const uint8_t *key) { assert_se(state.v2 == 0x634cb3577b01fd3d); assert_se(state.v3 == 0xa5224d6f55c7d9c8); out = siphash24_finalize(&state); - assert_se(out == htole64(0xa129ca6149be45e5)); + assert_se(out == 0xa129ca6149be45e5); assert_se(state.v0 == 0xf6bcd53893fecff1); assert_se(state.v1 == 0x54b9964c7ea0d937); assert_se(state.v2 == 0x1b38329c099bb55a); @@ -59,7 +57,7 @@ static int do_test(const uint8_t *in, size_t len, const uint8_t *key) { siphash24_compress(&in[i], j - i, &state); siphash24_compress(&in[j], len - j, &state); out = siphash24_finalize(&state); - assert_se(out == htole64(0xa129ca6149be45e5)); + assert_se(out == 0xa129ca6149be45e5); } } return 0; diff --git a/src/test/test-sleep.c b/src/test/test-sleep.c index fb115ce4f..97b6f3015 100644 --- a/src/test/test-sleep.c +++ b/src/test/test-sleep.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c index 1d8eda0c1..513218c39 100644 --- a/src/test/test-strbuf.c +++ b/src/test/test-strbuf.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index 25444c794..9b48e9599 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -55,7 +53,53 @@ static void test_string_erase(void) { assert_se(streq(string_erase(x), "xxxxxxxxx")); } +static void test_ascii_strcasecmp_n(void) { + + assert_se(ascii_strcasecmp_n("", "", 0) == 0); + assert_se(ascii_strcasecmp_n("", "", 1) == 0); + assert_se(ascii_strcasecmp_n("", "a", 1) < 0); + assert_se(ascii_strcasecmp_n("", "a", 2) < 0); + assert_se(ascii_strcasecmp_n("a", "", 1) > 0); + assert_se(ascii_strcasecmp_n("a", "", 2) > 0); + assert_se(ascii_strcasecmp_n("a", "a", 1) == 0); + assert_se(ascii_strcasecmp_n("a", "a", 2) == 0); + assert_se(ascii_strcasecmp_n("a", "b", 1) < 0); + assert_se(ascii_strcasecmp_n("a", "b", 2) < 0); + assert_se(ascii_strcasecmp_n("b", "a", 1) > 0); + assert_se(ascii_strcasecmp_n("b", "a", 2) > 0); + assert_se(ascii_strcasecmp_n("xxxxyxxxx", "xxxxYxxxx", 9) == 0); + assert_se(ascii_strcasecmp_n("xxxxxxxxx", "xxxxyxxxx", 9) < 0); + assert_se(ascii_strcasecmp_n("xxxxXxxxx", "xxxxyxxxx", 9) < 0); + assert_se(ascii_strcasecmp_n("xxxxxxxxx", "xxxxYxxxx", 9) < 0); + assert_se(ascii_strcasecmp_n("xxxxXxxxx", "xxxxYxxxx", 9) < 0); + + assert_se(ascii_strcasecmp_n("xxxxYxxxx", "xxxxYxxxx", 9) == 0); + assert_se(ascii_strcasecmp_n("xxxxyxxxx", "xxxxxxxxx", 9) > 0); + assert_se(ascii_strcasecmp_n("xxxxyxxxx", "xxxxXxxxx", 9) > 0); + assert_se(ascii_strcasecmp_n("xxxxYxxxx", "xxxxxxxxx", 9) > 0); + assert_se(ascii_strcasecmp_n("xxxxYxxxx", "xxxxXxxxx", 9) > 0); +} + +static void test_ascii_strcasecmp_nn(void) { + assert_se(ascii_strcasecmp_nn("", 0, "", 0) == 0); + assert_se(ascii_strcasecmp_nn("", 0, "", 1) < 0); + assert_se(ascii_strcasecmp_nn("", 1, "", 0) > 0); + assert_se(ascii_strcasecmp_nn("", 1, "", 1) == 0); + + assert_se(ascii_strcasecmp_nn("aaaa", 4, "aaAa", 4) == 0); + assert_se(ascii_strcasecmp_nn("aaa", 3, "aaAa", 4) < 0); + assert_se(ascii_strcasecmp_nn("aaa", 4, "aaAa", 4) < 0); + assert_se(ascii_strcasecmp_nn("aaaa", 4, "aaA", 3) > 0); + assert_se(ascii_strcasecmp_nn("aaaa", 4, "AAA", 4) > 0); + + assert_se(ascii_strcasecmp_nn("aaaa", 4, "bbbb", 4) < 0); + assert_se(ascii_strcasecmp_nn("aaAA", 4, "BBbb", 4) < 0); + assert_se(ascii_strcasecmp_nn("BBbb", 4, "aaaa", 4) > 0); +} + int main(int argc, char *argv[]) { test_string_erase(); + test_ascii_strcasecmp_n(); + test_ascii_strcasecmp_nn(); return 0; } diff --git a/src/test/test-strip-tab-ansi.c b/src/test/test-strip-tab-ansi.c index 10fc98ced..72b0f6fc1 100644 --- a/src/test/test-strip-tab-ansi.c +++ b/src/test/test-strip-tab-ansi.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-strv.c b/src/test/test-strv.c index c27f15283..2b2f76cc7 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c index e411d479a..9bea77013 100644 --- a/src/test/test-strxcpyx.c +++ b/src/test/test-strxcpyx.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-time.c b/src/test/test-time.c index 8896b2c92..9062c3f3c 100644 --- a/src/test/test-time.c +++ b/src/test/test-time.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -176,12 +174,36 @@ static void test_get_timezones(void) { r = get_timezones(&zones); assert_se(r == 0); - STRV_FOREACH(zone, zones) { + STRV_FOREACH(zone, zones) assert_se(timezone_is_valid(*zone)); - } +} + +static void test_usec_add(void) { + assert_se(usec_add(0, 0) == 0); + assert_se(usec_add(1, 4) == 5); + assert_se(usec_add(USEC_INFINITY, 5) == USEC_INFINITY); + assert_se(usec_add(5, USEC_INFINITY) == USEC_INFINITY); + assert_se(usec_add(USEC_INFINITY-5, 2) == USEC_INFINITY-3); + assert_se(usec_add(USEC_INFINITY-2, 2) == USEC_INFINITY); + assert_se(usec_add(USEC_INFINITY-1, 2) == USEC_INFINITY); + assert_se(usec_add(USEC_INFINITY, 2) == USEC_INFINITY); +} + +static void test_usec_sub(void) { + assert_se(usec_sub(0, 0) == 0); + assert_se(usec_sub(4, 1) == 3); + assert_se(usec_sub(4, 4) == 0); + assert_se(usec_sub(4, 5) == 0); + assert_se(usec_sub(USEC_INFINITY-3, -3) == USEC_INFINITY); + assert_se(usec_sub(USEC_INFINITY-3, -3) == USEC_INFINITY); + assert_se(usec_sub(USEC_INFINITY-3, -4) == USEC_INFINITY); + assert_se(usec_sub(USEC_INFINITY-3, -5) == USEC_INFINITY); + assert_se(usec_sub(USEC_INFINITY, 5) == USEC_INFINITY); } int main(int argc, char *argv[]) { + uintmax_t x; + test_parse_sec(); test_parse_time(); test_parse_nsec(); @@ -190,6 +212,16 @@ int main(int argc, char *argv[]) { test_format_timespan(USEC_PER_SEC); test_timezone_is_valid(); test_get_timezones(); + test_usec_add(); + test_usec_sub(); + + /* Ensure time_t is signed */ + assert_cc((time_t) -1 < (time_t) 1); + + /* Ensure TIME_T_MAX works correctly */ + x = (uintmax_t) TIME_T_MAX; + x ++; + assert((time_t) x < 0); return 0; } diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c index a8bd722e4..d7223dd2b 100644 --- a/src/test/test-tmpfiles.c +++ b/src/test/test-tmpfiles.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -28,6 +26,8 @@ #include "fd-util.h" #include "fileio.h" #include "formats-util.h" +#include "fs-util.h" +#include "log.h" #include "string-util.h" #include "util.h" @@ -35,20 +35,29 @@ int main(int argc, char** argv) { const char *p = argv[1] ?: "/tmp"; char *pattern = strjoina(p, "/systemd-test-XXXXXX"); _cleanup_close_ int fd, fd2; - _cleanup_free_ char *cmd, *cmd2; + _cleanup_free_ char *cmd, *cmd2, *ans, *ans2; + + log_set_max_level(LOG_DEBUG); + log_parse_environment(); fd = open_tmpfile(p, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); assert_se(asprintf(&cmd, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd) > 0); - system(cmd); + (void) system(cmd); + assert_se(readlink_malloc(cmd + 6, &ans) >= 0); + log_debug("link1: %s", ans); + assert_se(endswith(ans, " (deleted)")); fd2 = mkostemp_safe(pattern, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); assert_se(unlink(pattern) == 0); assert_se(asprintf(&cmd2, "ls -l /proc/"PID_FMT"/fd/%d", getpid(), fd2) > 0); - system(cmd2); + (void) system(cmd2); + assert_se(readlink_malloc(cmd2 + 6, &ans2) >= 0); + log_debug("link2: %s", ans2); + assert_se(endswith(ans2, " (deleted)")); return 0; } diff --git a/src/test/test-uid-range.c b/src/test/test-uid-range.c index 4dcf10e26..41f06a5ce 100644 --- a/src/test/test-uid-range.c +++ b/src/test/test-uid-range.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index c3973a316..b0c343590 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -28,6 +26,7 @@ #include #include "alloc-util.h" +#include "capability-util.h" #include "fd-util.h" #include "fileio.h" #include "hashmap.h" @@ -111,17 +110,30 @@ static void test_config_parse_exec(void) { ExecCommand *c = NULL, *c1; const char *ccc; + Manager *m = NULL; + Unit *u = NULL; + + r = manager_new(MANAGER_USER, true, &m); + if (MANAGER_SKIP_TEST(r)) { + printf("Skipping test: manager_new: %s\n", strerror(-r)); + return; + } + + assert_se(r >= 0); + assert_se(manager_startup(m, NULL, NULL) >= 0); + + assert_se(u = unit_new(m, sizeof(Service))); log_info("/* basic test */"); r = config_parse_exec(NULL, "fake", 1, "section", 1, "LValue", 0, "/RValue r1", - &c, NULL); + &c, u); assert_se(r >= 0); check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false); r = config_parse_exec(NULL, "fake", 2, "section", 1, "LValue", 0, "/RValue///slashes r1///", - &c, NULL); + &c, u); log_info("/* test slashes */"); assert_se(r >= 0); @@ -131,14 +143,14 @@ static void test_config_parse_exec(void) { log_info("/* trailing slash */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/RValue/ argv0 r1", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* honour_argv0 */"); r = config_parse_exec(NULL, "fake", 3, "section", 1, "LValue", 0, "@/RValue///slashes2 ///argv0 r1", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false); @@ -146,21 +158,21 @@ static void test_config_parse_exec(void) { log_info("/* honour_argv0, no args */"); r = config_parse_exec(NULL, "fake", 3, "section", 1, "LValue", 0, "@/RValue", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* no command, whitespace only, reset */"); r = config_parse_exec(NULL, "fake", 3, "section", 1, "LValue", 0, " ", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c == NULL); log_info("/* ignore && honour_argv0 */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "-@/RValue///slashes3 argv0a r1", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c; check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true); @@ -168,7 +180,7 @@ static void test_config_parse_exec(void) { log_info("/* ignore && honour_argv0 */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "@-/RValue///slashes4 argv0b r1", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true); @@ -176,14 +188,14 @@ static void test_config_parse_exec(void) { log_info("/* ignore && ignore */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "--/RValue argv0 r1", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* ignore && ignore (2) */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "-@-/RValue argv0 r1", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); @@ -192,7 +204,7 @@ static void test_config_parse_exec(void) { "LValue", 0, "-@/RValue argv0 r1 ; " "/goo/goo boo", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); @@ -205,7 +217,7 @@ static void test_config_parse_exec(void) { "LValue", 0, "-@/RValue argv0 r1 ; ; " "/goo/goo boo", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); @@ -217,7 +229,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "-@/RValue argv0 r1 ; ", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); @@ -228,7 +240,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "-@/RValue argv0 r1 ;", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); @@ -239,7 +251,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "-@/RValue argv0 r1 ';'", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/RValue", "argv0", "r1", ";", true); @@ -248,7 +260,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/bin/find \\;", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); @@ -257,7 +269,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/sbin/find \\; /x", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -267,7 +279,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/sbin/find \\;x", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -277,7 +289,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/bin/find \\073", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); @@ -286,7 +298,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/bin/find \";\"", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); @@ -295,7 +307,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/sbin/find \";\" /x", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -305,7 +317,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH WITH SPACES/daemon\" -1 -2", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -315,7 +327,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH WITH SPACES/daemon -1 -2\"", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -325,7 +337,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -335,7 +347,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -345,7 +357,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, @@ -359,7 +371,7 @@ static void test_config_parse_exec(void) { log_info("/* invalid character: \\%c */", *ccc); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, path, - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); } @@ -367,7 +379,7 @@ static void test_config_parse_exec(void) { log_info("/* valid character: \\s */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/path\\s", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/path ", NULL, NULL, NULL, false); @@ -376,7 +388,7 @@ static void test_config_parse_exec(void) { r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "/bin/grep '\\w+\\K'", - &c, NULL); + &c, u); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, "/bin/grep", NULL, "\\w+\\K", NULL, false); @@ -386,46 +398,49 @@ static void test_config_parse_exec(void) { /* backslash is invalid */ r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/path\\", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* missing ending ' */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/path 'foo", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* missing ending ' with trailing backslash */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "/path 'foo\\", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* invalid space between modifiers */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "- /path", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* only modifiers, no path */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "-", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c1->command_next == NULL); log_info("/* empty argument, reset */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "", - &c, NULL); + &c, u); assert_se(r == 0); assert_se(c == NULL); exec_command_free_list(c); + + unit_free(u); + manager_free(m); } #define env_file_1 \ @@ -625,8 +640,8 @@ static uint64_t make_cap(int cap) { return ((uint64_t) 1ULL << (uint64_t) cap); } -static void test_config_parse_bounding_set(void) { - /* int config_parse_bounding_set( +static void test_config_parse_capability_set(void) { + /* int config_parse_capability_set( const char *unit, const char *filename, unsigned line, @@ -638,38 +653,38 @@ static void test_config_parse_bounding_set(void) { void *data, void *userdata) */ int r; - uint64_t capability_bounding_set_drop = 0; + uint64_t capability_bounding_set = 0; - r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, "CapabilityBoundingSet", 0, "CAP_NET_RAW", - &capability_bounding_set_drop, NULL); + &capability_bounding_set, NULL); assert_se(r >= 0); - assert_se(capability_bounding_set_drop == ~make_cap(CAP_NET_RAW)); + assert_se(capability_bounding_set == make_cap(CAP_NET_RAW)); - r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, "CapabilityBoundingSet", 0, "CAP_NET_ADMIN", - &capability_bounding_set_drop, NULL); + &capability_bounding_set, NULL); assert_se(r >= 0); - assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); + assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); - r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, "CapabilityBoundingSet", 0, "", - &capability_bounding_set_drop, NULL); + &capability_bounding_set, NULL); assert_se(r >= 0); - assert_se(capability_bounding_set_drop == ~((uint64_t) 0ULL)); + assert_se(capability_bounding_set == UINT64_C(0)); - r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, "CapabilityBoundingSet", 0, "~", - &capability_bounding_set_drop, NULL); + &capability_bounding_set, NULL); assert_se(r >= 0); - assert_se(capability_bounding_set_drop == (uint64_t) 0ULL); + assert_se(cap_test_all(capability_bounding_set)); - capability_bounding_set_drop = 0; - r = config_parse_bounding_set(NULL, "fake", 1, "section", 1, + capability_bounding_set = 0; + r = config_parse_capability_set(NULL, "fake", 1, "section", 1, "CapabilityBoundingSet", 0, " 'CAP_NET_RAW' WAT_CAP??? CAP_NET_ADMIN CAP'_trailing_garbage", - &capability_bounding_set_drop, NULL); + &capability_bounding_set, NULL); assert_se(r >= 0); - assert_se(capability_bounding_set_drop == ~(make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); + assert_se(capability_bounding_set == (make_cap(CAP_NET_RAW) | make_cap(CAP_NET_ADMIN))); } static void test_config_parse_rlimit(void) { @@ -680,51 +695,105 @@ 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); + + rl[RLIMIT_NOFILE]->rlim_cur = 10; + 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, "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); + + 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); + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "56", rl, NULL) >= 0); assert_se(rl[RLIMIT_CPU]); assert_se(rl[RLIMIT_CPU]->rlim_cur == 56); 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, "57s", rl, NULL) >= 0); + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "57s", rl, NULL) >= 0); assert_se(rl[RLIMIT_CPU]); 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, "infinity", rl, NULL) >= 0); + assert_se(config_parse_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_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); 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, "1234ms", rl, NULL) >= 0); + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitCPU", RLIMIT_CPU, "1234ms", rl, NULL) >= 0); assert_se(rl[RLIMIT_CPU]); assert_se(rl[RLIMIT_CPU]->rlim_cur == 2); assert_se(rl[RLIMIT_CPU]->rlim_cur == rl[RLIMIT_CPU]->rlim_max); rl[RLIMIT_CPU] = mfree(rl[RLIMIT_CPU]); - assert_se(config_parse_usec_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); + assert_se(config_parse_limit(NULL, "fake", 1, "section", 1, "LimitRTTIME", RLIMIT_RTTIME, "58", rl, NULL) >= 0); assert_se(rl[RLIMIT_RTTIME]); 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, "59s", rl, NULL) >= 0); + assert_se(config_parse_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_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, "infinity", rl, NULL) >= 0); + assert_se(config_parse_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_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, "2345ms", rl, NULL) >= 0); + assert_se(config_parse_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_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); assert_se(rl[RLIMIT_RTTIME]->rlim_cur == rl[RLIMIT_RTTIME]->rlim_max); @@ -778,7 +847,7 @@ int main(int argc, char *argv[]) { r = test_unit_file_get_set(); test_config_parse_exec(); - test_config_parse_bounding_set(); + test_config_parse_capability_set(); test_config_parse_rlimit(); test_config_parse_pass_environ(); test_load_env_file_1(); diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index 842ca4010..3de94ef42 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -27,6 +25,7 @@ #include #include "alloc-util.h" +#include "glob-util.h" #include "hostname-util.h" #include "macro.h" #include "manager.h" @@ -66,26 +65,26 @@ static void test_unit_name_is_valid(void) { assert_se(!unit_name_is_valid("@piep.service", UNIT_NAME_ANY)); } -static void test_u_n_r_i_one(const char *pattern, const char *repl, const char *expected, int ret) { +static void test_unit_name_replace_instance_one(const char *pattern, const char *repl, const char *expected, int ret) { _cleanup_free_ char *t = NULL; assert_se(unit_name_replace_instance(pattern, repl, &t) == ret); puts(strna(t)); assert_se(streq_ptr(t, expected)); } -static void test_u_n_r_i(void) { +static void test_unit_name_replace_instance(void) { puts("-------------------------------------------------"); - test_u_n_r_i_one("foo@.service", "waldo", "foo@waldo.service", 0); - test_u_n_r_i_one("foo@xyz.service", "waldo", "foo@waldo.service", 0); - test_u_n_r_i_one("xyz", "waldo", NULL, -EINVAL); - test_u_n_r_i_one("", "waldo", NULL, -EINVAL); - test_u_n_r_i_one("foo.service", "waldo", NULL, -EINVAL); - test_u_n_r_i_one(".service", "waldo", NULL, -EINVAL); - test_u_n_r_i_one("foo@", "waldo", NULL, -EINVAL); - test_u_n_r_i_one("@bar", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("foo@.service", "waldo", "foo@waldo.service", 0); + test_unit_name_replace_instance_one("foo@xyz.service", "waldo", "foo@waldo.service", 0); + test_unit_name_replace_instance_one("xyz", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("foo.service", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one(".service", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("foo@", "waldo", NULL, -EINVAL); + test_unit_name_replace_instance_one("@bar", "waldo", NULL, -EINVAL); } -static void test_u_n_f_p_one(const char *path, const char *suffix, const char *expected, int ret) { +static void test_unit_name_from_path_one(const char *path, const char *suffix, const char *expected, int ret) { _cleanup_free_ char *t = NULL; assert_se(unit_name_from_path(path, suffix, &t) == ret); @@ -100,19 +99,19 @@ static void test_u_n_f_p_one(const char *path, const char *suffix, const char *e } } -static void test_u_n_f_p(void) { +static void test_unit_name_from_path(void) { puts("-------------------------------------------------"); - test_u_n_f_p_one("/waldo", ".mount", "waldo.mount", 0); - test_u_n_f_p_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0); - test_u_n_f_p_one("/waldo/quuix/", ".mount", "waldo-quuix.mount", 0); - test_u_n_f_p_one("", ".mount", "-.mount", 0); - test_u_n_f_p_one("/", ".mount", "-.mount", 0); - test_u_n_f_p_one("///", ".mount", "-.mount", 0); - test_u_n_f_p_one("/foo/../bar", ".mount", NULL, -EINVAL); - test_u_n_f_p_one("/foo/./bar", ".mount", NULL, -EINVAL); + test_unit_name_from_path_one("/waldo", ".mount", "waldo.mount", 0); + test_unit_name_from_path_one("/waldo/quuix", ".mount", "waldo-quuix.mount", 0); + test_unit_name_from_path_one("/waldo/quuix/", ".mount", "waldo-quuix.mount", 0); + test_unit_name_from_path_one("", ".mount", "-.mount", 0); + test_unit_name_from_path_one("/", ".mount", "-.mount", 0); + test_unit_name_from_path_one("///", ".mount", "-.mount", 0); + test_unit_name_from_path_one("/foo/../bar", ".mount", NULL, -EINVAL); + test_unit_name_from_path_one("/foo/./bar", ".mount", NULL, -EINVAL); } -static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) { +static void test_unit_name_from_path_instance_one(const char *pattern, const char *path, const char *suffix, const char *expected, int ret) { _cleanup_free_ char *t = NULL; assert_se(unit_name_from_path_instance(pattern, path, suffix, &t) == ret); @@ -128,65 +127,71 @@ static void test_u_n_f_p_i_one(const char *pattern, const char *path, const char } } -static void test_u_n_f_p_i(void) { +static void test_unit_name_from_path_instance(void) { puts("-------------------------------------------------"); - test_u_n_f_p_i_one("waldo", "/waldo", ".mount", "waldo@waldo.mount", 0); - test_u_n_f_p_i_one("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount", 0); - test_u_n_f_p_i_one("waldo", "/", ".mount", "waldo@-.mount", 0); - test_u_n_f_p_i_one("waldo", "", ".mount", "waldo@-.mount", 0); - test_u_n_f_p_i_one("waldo", "///", ".mount", "waldo@-.mount", 0); - test_u_n_f_p_i_one("waldo", "..", ".mount", NULL, -EINVAL); - test_u_n_f_p_i_one("waldo", "/foo", ".waldi", NULL, -EINVAL); - test_u_n_f_p_i_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0); + test_unit_name_from_path_instance_one("waldo", "/waldo", ".mount", "waldo@waldo.mount", 0); + test_unit_name_from_path_instance_one("waldo", "/waldo////quuix////", ".mount", "waldo@waldo-quuix.mount", 0); + test_unit_name_from_path_instance_one("waldo", "/", ".mount", "waldo@-.mount", 0); + test_unit_name_from_path_instance_one("waldo", "", ".mount", "waldo@-.mount", 0); + test_unit_name_from_path_instance_one("waldo", "///", ".mount", "waldo@-.mount", 0); + test_unit_name_from_path_instance_one("waldo", "..", ".mount", NULL, -EINVAL); + test_unit_name_from_path_instance_one("waldo", "/foo", ".waldi", NULL, -EINVAL); + test_unit_name_from_path_instance_one("wa--ldo", "/--", ".mount", "wa--ldo@\\x2d\\x2d.mount", 0); } -static void test_u_n_t_p_one(const char *unit, const char *path, int ret) { +static void test_unit_name_to_path_one(const char *unit, const char *path, int ret) { _cleanup_free_ char *p = NULL; assert_se(unit_name_to_path(unit, &p) == ret); assert_se(streq_ptr(path, p)); } -static void test_u_n_t_p(void) { - test_u_n_t_p_one("home.mount", "/home", 0); - test_u_n_t_p_one("home-lennart.mount", "/home/lennart", 0); - test_u_n_t_p_one("home-lennart-.mount", NULL, -EINVAL); - test_u_n_t_p_one("-home-lennart.mount", NULL, -EINVAL); - test_u_n_t_p_one("-home--lennart.mount", NULL, -EINVAL); - test_u_n_t_p_one("home-..-lennart.mount", NULL, -EINVAL); - test_u_n_t_p_one("", NULL, -EINVAL); - test_u_n_t_p_one("home/foo", NULL, -EINVAL); +static void test_unit_name_to_path(void) { + test_unit_name_to_path_one("home.mount", "/home", 0); + test_unit_name_to_path_one("home-lennart.mount", "/home/lennart", 0); + test_unit_name_to_path_one("home-lennart-.mount", NULL, -EINVAL); + test_unit_name_to_path_one("-home-lennart.mount", NULL, -EINVAL); + test_unit_name_to_path_one("-home--lennart.mount", NULL, -EINVAL); + test_unit_name_to_path_one("home-..-lennart.mount", NULL, -EINVAL); + test_unit_name_to_path_one("", NULL, -EINVAL); + test_unit_name_to_path_one("home/foo", NULL, -EINVAL); } -static void test_u_n_m_one(const char *pattern, const char *expect, int ret) { +static void test_unit_name_mangle_one(UnitNameMangle allow_globs, const char *pattern, const char *expect, int ret) { _cleanup_free_ char *t = NULL; - assert_se(unit_name_mangle(pattern, UNIT_NAME_NOGLOB, &t) == ret); + assert_se(unit_name_mangle(pattern, allow_globs, &t) == ret); puts(strna(t)); assert_se(streq_ptr(t, expect)); if (t) { _cleanup_free_ char *k = NULL; - assert_se(unit_name_is_valid(t, UNIT_NAME_ANY)); + assert_se(unit_name_is_valid(t, UNIT_NAME_ANY) || + (allow_globs == UNIT_NAME_GLOB && string_is_glob(t))); - assert_se(unit_name_mangle(t, UNIT_NAME_NOGLOB, &k) == 0); + assert_se(unit_name_mangle(t, allow_globs, &k) == 0); assert_se(streq_ptr(t, k)); } } -static void test_u_n_m(void) { +static void test_unit_name_mangle(void) { puts("-------------------------------------------------"); - test_u_n_m_one("foo.service", "foo.service", 0); - test_u_n_m_one("/home", "home.mount", 1); - test_u_n_m_one("/dev/sda", "dev-sda.device", 1); - test_u_n_m_one("üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1); - test_u_n_m_one("foobar-meh...waldi.service", "foobar-meh...waldi.service", 0); - test_u_n_m_one("_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1); - test_u_n_m_one("_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1); - test_u_n_m_one("xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1); - test_u_n_m_one("", NULL, -EINVAL); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "foo.service", "foo.service", 0); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "/home", "home.mount", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "/dev/sda", "dev-sda.device", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "üxknürz.service", "\\xc3\\xbcxkn\\xc3\\xbcrz.service", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "foobar-meh...waldi.service", "foobar-meh...waldi.service", 0); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "_____####----.....service", "_____\\x23\\x23\\x23\\x23----.....service", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "_____##@;;;,,,##----.....service", "_____\\x23\\x23@\\x3b\\x3b\\x3b\\x2c\\x2c\\x2c\\x23\\x23----.....service", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "xxx@@@@/////\\\\\\\\\\yyy.service", "xxx@@@@-----\\\\\\\\\\yyy.service", 1); + test_unit_name_mangle_one(UNIT_NAME_NOGLOB, "", NULL, -EINVAL); + + test_unit_name_mangle_one(UNIT_NAME_GLOB, "foo.service", "foo.service", 0); + test_unit_name_mangle_one(UNIT_NAME_GLOB, "foo", "foo.service", 1); + test_unit_name_mangle_one(UNIT_NAME_GLOB, "foo*", "foo*", 0); + test_unit_name_mangle_one(UNIT_NAME_GLOB, "ü*", "\\xc3\\xbc*", 1); } static int test_unit_printf(void) { @@ -460,11 +465,11 @@ static void test_unit_name_path_unescape(void) { int main(int argc, char* argv[]) { int rc = 0; test_unit_name_is_valid(); - test_u_n_r_i(); - test_u_n_f_p(); - test_u_n_f_p_i(); - test_u_n_m(); - test_u_n_t_p(); + test_unit_name_replace_instance(); + test_unit_name_from_path(); + test_unit_name_from_path_instance(); + test_unit_name_mangle(); + test_unit_name_to_path(); TEST_REQ_RUNNING_SYSTEMD(rc = test_unit_printf()); test_unit_instance_is_valid(); test_unit_prefix_is_valid(); diff --git a/src/test/test-user-util.c b/src/test/test-user-util.c index 09d37087e..42c6a8d5e 100644 --- a/src/test/test-user-util.c +++ b/src/test/test-user-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index e98be5763..1ce5a5a24 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-util.c b/src/test/test-util.c index f6ed55878..9a8a26579 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -545,38 +543,31 @@ static void test_unbase32hexmem(void) { static void test_base64mem(void) { char *b64; - b64 = base64mem("", strlen("")); - assert_se(b64); + assert_se(base64mem("", strlen(""), &b64) == 0); assert_se(streq(b64, "")); free(b64); - b64 = base64mem("f", strlen("f")); - assert_se(b64); + assert_se(base64mem("f", strlen("f"), &b64) == 4); assert_se(streq(b64, "Zg==")); free(b64); - b64 = base64mem("fo", strlen("fo")); - assert_se(b64); + assert_se(base64mem("fo", strlen("fo"), &b64) == 4); assert_se(streq(b64, "Zm8=")); free(b64); - b64 = base64mem("foo", strlen("foo")); - assert_se(b64); + assert_se(base64mem("foo", strlen("foo"), &b64) == 4); assert_se(streq(b64, "Zm9v")); free(b64); - b64 = base64mem("foob", strlen("foob")); - assert_se(b64); + assert_se(base64mem("foob", strlen("foob"), &b64) == 8); assert_se(streq(b64, "Zm9vYg==")); free(b64); - b64 = base64mem("fooba", strlen("fooba")); - assert_se(b64); + assert_se(base64mem("fooba", strlen("fooba"), &b64) == 8); assert_se(streq(b64, "Zm9vYmE=")); free(b64); - b64 = base64mem("foobar", strlen("foobar")); - assert_se(b64); + assert_se(base64mem("foobar", strlen("foobar"), &b64) == 8); assert_se(streq(b64, "Zm9vYmFy")); free(b64); } diff --git a/src/test/test-watchdog.c b/src/test/test-watchdog.c index d10d9f49a..e3c19647f 100644 --- a/src/test/test-watchdog.c +++ b/src/test/test-watchdog.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/test/test-xml.c b/src/test/test-xml.c index 548d75a3c..b0b72fa78 100644 --- a/src/test/test-xml.c +++ b/src/test/test-xml.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index 564d72773..097963b41 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -193,7 +191,7 @@ static int show_status(sd_bus *bus, char **args, unsigned n) { } static int set_time(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; bool relative = false, interactive = arg_ask_password; usec_t t; int r; @@ -224,7 +222,7 @@ static int set_time(sd_bus *bus, char **args, unsigned n) { } static int set_timezone(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; assert(args); @@ -247,7 +245,7 @@ static int set_timezone(sd_bus *bus, char **args, unsigned n) { } static int set_local_rtc(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r, b; assert(args); @@ -276,7 +274,7 @@ static int set_local_rtc(sd_bus *bus, char **args, unsigned n) { } static int set_ntp(sd_bus *bus, char **args, unsigned n) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int b, r; assert(args); @@ -490,7 +488,7 @@ static int timedatectl_main(sd_bus *bus, int argc, char *argv[]) { } int main(int argc, char *argv[]) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; setlocale(LC_ALL, ""); diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 968ef8a78..2a10135fb 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -33,7 +31,6 @@ #include "bus-util.h" #include "clock-util.h" #include "def.h" -#include "event-util.h" #include "fileio-label.h" #include "fs-util.h" #include "path-util.h" @@ -167,8 +164,8 @@ static int context_write_data_local_rtc(Context *c) { } static int context_read_ntp(Context *c, sd_bus *bus) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; const char *s; int r; @@ -650,7 +647,7 @@ static const sd_bus_vtable timedate_vtable[] = { }; static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; assert(c); @@ -681,8 +678,8 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) { int main(int argc, char *argv[]) { Context context = {}; - _cleanup_event_unref_ sd_event *event = NULL; - _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; log_set_target(LOG_TARGET_AUTO); diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c index 5881bc0c4..20c64a335 100644 --- a/src/timesync/timesyncd-conf.c +++ b/src/timesync/timesyncd-conf.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/timesync/timesyncd-conf.h b/src/timesync/timesyncd-conf.h index 56466fe46..cba0724b1 100644 --- a/src/timesync/timesyncd-conf.h +++ b/src/timesync/timesyncd-conf.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,7 +20,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.c b/src/timesync/timesyncd-manager.c index 8dca538b3..d5e16db3a 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -372,7 +370,8 @@ static int manager_adjust_clock(Manager *m, double offset, int leap_sec) { if (r < 0) return -errno; - touch("/var/lib/systemd/clock"); + /* If touch fails, there isn't much we can do. Maybe it'll work next time. */ + (void) touch("/var/lib/systemd/clock"); m->drift_ppm = tmx.freq / 65536; diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h index 090b2fcba..efe3e60d3 100644 --- a/src/timesync/timesyncd-manager.h +++ b/src/timesync/timesyncd-manager.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -22,8 +20,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.c b/src/timesync/timesyncd-server.c index f98e6b4cf..6bda86fe6 100644 --- a/src/timesync/timesyncd-server.c +++ b/src/timesync/timesyncd-server.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/timesync/timesyncd-server.h b/src/timesync/timesyncd-server.h index 18c44445e..8a19e41d6 100644 --- a/src/timesync/timesyncd-server.h +++ b/src/timesync/timesyncd-server.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - #pragma once /*** @@ -21,8 +19,8 @@ along with systemd; If not, see . ***/ -#include "socket-util.h" #include "list.h" +#include "socket-util.h" typedef struct ServerAddress ServerAddress; typedef struct ServerName ServerName; diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 7f70eaaea..23e19159e 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index f9a759e22..7b105a6bd 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -1075,7 +1073,7 @@ static int item_do_children(Item *i, const char *path, action_t action) { errno = 0; de = readdir(d); if (!de) { - if (errno != 0 && r == 0) + if (errno > 0 && r == 0) r = -errno; break; @@ -1153,6 +1151,7 @@ static int create_item(Item *i) { _cleanup_free_ char *resolved = NULL; struct stat st; int r = 0; + int q = 0; CreationMode creation; assert(i); @@ -1279,27 +1278,23 @@ static int create_item(Item *i) { if (IN_SET(i->type, CREATE_SUBVOLUME_NEW_QUOTA, CREATE_SUBVOLUME_INHERIT_QUOTA)) { r = btrfs_subvol_auto_qgroup(i->path, 0, i->type == CREATE_SUBVOLUME_NEW_QUOTA); - if (r == -ENOTTY) { + if (r == -ENOTTY) log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of unsupported file system or because directory is not a subvolume: %m", i->path); - return 0; - } - if (r == -EROFS) { + else if (r == -EROFS) log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because of read-only file system: %m", i->path); - return 0; - } - if (r == -ENOPROTOOPT) { + else if (r == -ENOPROTOOPT) log_debug_errno(r, "Couldn't adjust quota for subvolume \"%s\" because quota support is disabled: %m", i->path); - return 0; - } - if (r < 0) - return log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path); - if (r > 0) + else if (r < 0) + q = log_error_errno(r, "Failed to adjust quota for subvolume \"%s\": %m", i->path); + else if (r > 0) log_debug("Adjusted quota for subvolume \"%s\".", i->path); - if (r == 0) + else if (r == 0) log_debug("Quota for subvolume \"%s\" already in place, no change made.", i->path); } r = path_set_perms(i, i->path); + if (q < 0) + return q; if (r < 0) return r; diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 8cfe10330..7b67831e5 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -240,10 +238,50 @@ finish: return r; } +static int send_passwords(const char *socket_name, char **passwords) { + _cleanup_free_ char *packet = NULL; + _cleanup_close_ int socket_fd = -1; + union sockaddr_union sa = { .un.sun_family = AF_UNIX }; + size_t packet_length = 1; + char **p, *d; + int r; + + assert(socket_name); + + STRV_FOREACH(p, passwords) + packet_length += strlen(*p) + 1; + + packet = new(char, packet_length); + if (!packet) + return -ENOMEM; + + packet[0] = '+'; + + d = packet + 1; + STRV_FOREACH(p, passwords) + d = stpcpy(d, *p) + 1; + + socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); + if (socket_fd < 0) { + r = log_debug_errno(errno, "socket(): %m"); + goto finish; + } + + strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); + + r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, + offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)); + if (r < 0) + r = log_debug_errno(errno, "sendto(): %m"); + +finish: + memory_erase(packet, packet_length); + return r; +} + static int parse_password(const char *filename, char **wall) { - _cleanup_free_ char *socket_name = NULL, *message = NULL, *packet = NULL; + _cleanup_free_ char *socket_name = NULL, *message = NULL; bool accept_cached = false, echo = false; - size_t packet_length = 0; uint64_t not_after = 0; unsigned pid = 0; @@ -298,8 +336,7 @@ static int parse_password(const char *filename, char **wall) { *wall = _wall; } else { - union sockaddr_union sa = {}; - _cleanup_close_ int socket_fd = -1; + _cleanup_strv_free_erase_ char **passwords = NULL; assert(arg_action == ACTION_QUERY || arg_action == ACTION_WATCH); @@ -311,32 +348,10 @@ static int parse_password(const char *filename, char **wall) { return 0; } - if (arg_plymouth) { - _cleanup_strv_free_erase_ char **passwords = NULL; - + if (arg_plymouth) r = ask_password_plymouth(message, not_after, accept_cached ? ASK_PASSWORD_ACCEPT_CACHED : 0, filename, &passwords); - if (r >= 0) { - char **p; - - packet_length = 1; - STRV_FOREACH(p, passwords) - packet_length += strlen(*p) + 1; - - packet = new(char, packet_length); - if (!packet) - r = -ENOMEM; - else { - char *d = packet + 1; - - STRV_FOREACH(p, passwords) - d = stpcpy(d, *p) + 1; - - packet[0] = '+'; - } - } - - } else { - _cleanup_string_free_erase_ char *password = NULL; + else { + char *password = NULL; int tty_fd = -1; if (arg_console) { @@ -356,48 +371,26 @@ static int parse_password(const char *filename, char **wall) { release_terminal(); } - if (r >= 0) { - packet_length = 1 + strlen(password) + 1; - packet = new(char, packet_length); - if (!packet) - r = -ENOMEM; - else { - packet[0] = '+'; - strcpy(packet + 1, password); - } - } + if (r >= 0) + r = strv_push(&passwords, password); + + if (r < 0) + string_free_erase(password); } - if (IN_SET(r, -ETIME, -ENOENT)) { - /* If the query went away, that's OK */ - r = 0; - goto finish; - } - if (r < 0) { - log_error_errno(r, "Failed to query password: %m"); - goto finish; - } + /* If the query went away, that's OK */ + if (IN_SET(r, -ETIME, -ENOENT)) + return 0; - socket_fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); - if (socket_fd < 0) { - r = log_error_errno(errno, "socket(): %m"); - goto finish; - } - - sa.un.sun_family = AF_UNIX; - strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path)); - - r = sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)); - memory_erase(packet, packet_length); if (r < 0) - return log_error_errno(errno, "Failed to send: %m"); + return log_error_errno(r, "Failed to query password: %m"); + + r = send_passwords(socket_name, passwords); + if (r < 0) + return log_error_errno(r, "Failed to send: %m"); } return 0; - -finish: - memory_erase(packet, packet_length); - return r; } static int wall_tty_block(void) { diff --git a/src/udev/collect/collect.c b/src/udev/collect/collect.c index b6c95cd45..349585b63 100644 --- a/src/udev/collect/collect.c +++ b/src/udev/collect/collect.c @@ -27,6 +27,7 @@ #include "alloc-util.h" #include "libudev-private.h" #include "macro.h" +#include "stdio-util.h" #include "string-util.h" #define BUFSIZE 16 @@ -91,7 +92,7 @@ static int prepare(char *dir, char *filename) if (r < 0 && errno != EEXIST) return -errno; - snprintf(buf, sizeof(buf), "%s/%s", dir, filename); + xsprintf(buf, "%s/%s", dir, filename); fd = open(buf,O_RDWR|O_CREAT|O_CLOEXEC, S_IRUSR|S_IWUSR); if (fd < 0) diff --git a/src/udev/net/ethtool-util.c b/src/udev/net/ethtool-util.c index 0647008d9..c00ff7912 100644 --- a/src/udev/net/ethtool-util.c +++ b/src/udev/net/ethtool-util.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/udev/net/ethtool-util.h b/src/udev/net/ethtool-util.h index 690b1a65a..2e6e1d715 100644 --- a/src/udev/net/ethtool-util.h +++ b/src/udev/net/ethtool-util.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index 77d9bf995..15145fc5e 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index 4fcbee8b9..f525fe211 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h index 3f99ae772..3bf1a9420 100644 --- a/src/udev/scsi_id/scsi.h +++ b/src/udev/scsi_id/scsi.h @@ -24,25 +24,25 @@ struct scsi_ioctl_command { /* * Default 5 second timeout */ -#define DEF_TIMEOUT 5000 +#define DEF_TIMEOUT 5000 -#define SENSE_BUFF_LEN 32 +#define SENSE_BUFF_LEN 32 /* * The request buffer size passed to the SCSI INQUIRY commands, use 254, * as this is a nice value for some devices, especially some of the usb * mass storage devices. */ -#define SCSI_INQ_BUFF_LEN 254 +#define SCSI_INQ_BUFF_LEN 254 /* * SCSI INQUIRY vendor and model (really product) lengths. */ -#define VENDOR_LENGTH 8 -#define MODEL_LENGTH 16 +#define VENDOR_LENGTH 8 +#define MODEL_LENGTH 16 -#define INQUIRY_CMD 0x12 -#define INQUIRY_CMDLEN 6 +#define INQUIRY_CMD 0x12 +#define INQUIRY_CMDLEN 6 /* * INQUIRY VPD page 0x83 identifier descriptor related values. Reference the @@ -52,34 +52,34 @@ struct scsi_ioctl_command { /* * id type values of id descriptors. These are assumed to fit in 4 bits. */ -#define SCSI_ID_VENDOR_SPECIFIC 0 -#define SCSI_ID_T10_VENDOR 1 -#define SCSI_ID_EUI_64 2 -#define SCSI_ID_NAA 3 -#define SCSI_ID_RELPORT 4 +#define SCSI_ID_VENDOR_SPECIFIC 0 +#define SCSI_ID_T10_VENDOR 1 +#define SCSI_ID_EUI_64 2 +#define SCSI_ID_NAA 3 +#define SCSI_ID_RELPORT 4 #define SCSI_ID_TGTGROUP 5 #define SCSI_ID_LUNGROUP 6 -#define SCSI_ID_MD5 7 -#define SCSI_ID_NAME 8 +#define SCSI_ID_MD5 7 +#define SCSI_ID_NAME 8 /* * Supported NAA values. These fit in 4 bits, so the "don't care" value * cannot conflict with real values. */ -#define SCSI_ID_NAA_DONT_CARE 0xff -#define SCSI_ID_NAA_IEEE_REG 5 -#define SCSI_ID_NAA_IEEE_REG_EXTENDED 6 +#define SCSI_ID_NAA_DONT_CARE 0xff +#define SCSI_ID_NAA_IEEE_REG 0x05 +#define SCSI_ID_NAA_IEEE_REG_EXTENDED 0x06 /* * Supported Code Set values. */ -#define SCSI_ID_BINARY 1 -#define SCSI_ID_ASCII 2 +#define SCSI_ID_BINARY 1 +#define SCSI_ID_ASCII 2 struct scsi_id_search_values { - u_char id_type; - u_char naa_type; - u_char code_set; + u_char id_type; + u_char naa_type; + u_char code_set; }; /* @@ -87,13 +87,13 @@ struct scsi_id_search_values { * used a 1 bit right and masked version of these. So now CHECK_CONDITION * and friends (in ) are deprecated. */ -#define SCSI_CHECK_CONDITION 0x2 -#define SCSI_CONDITION_MET 0x4 -#define SCSI_BUSY 0x8 -#define SCSI_IMMEDIATE 0x10 +#define SCSI_CHECK_CONDITION 0x02 +#define SCSI_CONDITION_MET 0x04 +#define SCSI_BUSY 0x08 +#define SCSI_IMMEDIATE 0x10 #define SCSI_IMMEDIATE_CONDITION_MET 0x14 -#define SCSI_RESERVATION_CONFLICT 0x18 -#define SCSI_COMMAND_TERMINATED 0x22 -#define SCSI_TASK_SET_FULL 0x28 -#define SCSI_ACA_ACTIVE 0x30 -#define SCSI_TASK_ABORTED 0x40 +#define SCSI_RESERVATION_CONFLICT 0x18 +#define SCSI_COMMAND_TERMINATED 0x22 +#define SCSI_TASK_SET_FULL 0x28 +#define SCSI_ACA_ACTIVE 0x30 +#define SCSI_TASK_ABORTED 0x40 diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c index c7ef78368..e079e2869 100644 --- a/src/udev/scsi_id/scsi_serial.c +++ b/src/udev/scsi_id/scsi_serial.c @@ -50,11 +50,11 @@ * is normally one or some small number of descriptors. */ static const struct scsi_id_search_values id_search_list[] = { - { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII }, + { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_IEEE_REG, SCSI_ID_ASCII }, /* * Devices already exist using NAA values that are now marked * reserved. These should not conflict with other values, or it is @@ -64,14 +64,14 @@ static const struct scsi_id_search_values id_search_list[] = { * non-IEEE descriptors in a random order will get different * names. */ - { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, - { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, - { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, - { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, - { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_NAA, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_EUI_64, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_T10_VENDOR, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, + { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, + { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII }, }; static const char hex_str[]="0123456789abcdef"; @@ -81,21 +81,21 @@ static const char hex_str[]="0123456789abcdef"; * are used here. */ -#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ -#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ -#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ -#define DRIVER_TIMEOUT 0x06 -#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ +#define DID_NO_CONNECT 0x01 /* Unable to connect before timeout */ +#define DID_BUS_BUSY 0x02 /* Bus remain busy until timeout */ +#define DID_TIME_OUT 0x03 /* Timed out for some other reason */ +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_SENSE 0x08 /* Sense_buffer has been set */ /* The following "category" function returns one of the following */ #define SG_ERR_CAT_CLEAN 0 /* No errors or other information */ #define SG_ERR_CAT_MEDIA_CHANGED 1 /* interpreted from sense buffer */ #define SG_ERR_CAT_RESET 2 /* interpreted from sense buffer */ -#define SG_ERR_CAT_TIMEOUT 3 -#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ -#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ -#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ -#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ +#define SG_ERR_CAT_TIMEOUT 3 +#define SG_ERR_CAT_RECOVERED 4 /* Successful command after recovered err */ +#define SG_ERR_CAT_NOTSUPPORTED 5 /* Illegal / unsupported command */ +#define SG_ERR_CAT_SENSE 98 /* Something else in the sense buffer */ +#define SG_ERR_CAT_OTHER 99 /* Some other error/warning */ static int do_scsi_page80_inquiry(struct udev *udev, struct scsi_id_device *dev_scsi, int fd, @@ -212,7 +212,7 @@ static int scsi_dump_sense(struct udev *udev, s = sense_buffer[7] + 8; if (sb_len < s) { log_debug("%s: sense buffer too small %d bytes, %d bytes too short", - dev_scsi->kernel, sb_len, s - sb_len); + dev_scsi->kernel, sb_len, s - sb_len); return -1; } if ((code == 0x0) || (code == 0x1)) { @@ -222,7 +222,7 @@ static int scsi_dump_sense(struct udev *udev, * Possible? */ log_debug("%s: sense result too" " small %d bytes", - dev_scsi->kernel, s); + dev_scsi->kernel, s); return -1; } asc = sense_buffer[12]; @@ -233,15 +233,15 @@ static int scsi_dump_sense(struct udev *udev, ascq = sense_buffer[3]; } else { log_debug("%s: invalid sense code 0x%x", - dev_scsi->kernel, code); + dev_scsi->kernel, code); return -1; } log_debug("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x", - dev_scsi->kernel, sense_key, asc, ascq); + dev_scsi->kernel, sense_key, asc, ascq); } else { if (sb_len < 4) { log_debug("%s: sense buffer too small %d bytes, %d bytes too short", - dev_scsi->kernel, sb_len, 4 - sb_len); + dev_scsi->kernel, sb_len, 4 - sb_len); return -1; } @@ -249,9 +249,9 @@ static int scsi_dump_sense(struct udev *udev, log_debug("%s: old sense key: 0x%x", dev_scsi->kernel, sense_buffer[0] & 0x0f); else log_debug("%s: sense = %2x %2x", - dev_scsi->kernel, sense_buffer[0], sense_buffer[2]); + dev_scsi->kernel, sense_buffer[0], sense_buffer[2]); log_debug("%s: non-extended sense class %d code 0x%0x", - dev_scsi->kernel, sense_class, code); + dev_scsi->kernel, sense_class, code); } @@ -282,7 +282,7 @@ static int scsi_dump(struct udev *udev, } log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x", - dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status); + dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status); if (io->status == SCSI_CHECK_CONDITION) return scsi_dump_sense(udev, dev_scsi, io->sbp, io->sb_len_wr); else @@ -302,8 +302,7 @@ static int scsi_dump_v4(struct udev *udev, } log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x", - dev_scsi->kernel, io->driver_status, io->transport_status, - io->device_status); + dev_scsi->kernel, io->driver_status, io->transport_status, io->device_status); if (io->device_status == SCSI_CHECK_CONDITION) return scsi_dump_sense(udev, dev_scsi, (unsigned char *)(uintptr_t)io->response, io->response_len); @@ -399,7 +398,7 @@ resend: error: if (retval < 0) log_debug("%s: Unable to get INQUIRY vpd %d page 0x%x.", - dev_scsi->kernel, evpd, page); + dev_scsi->kernel, evpd, page); return retval; } @@ -421,7 +420,7 @@ static int do_scsi_page0_inquiry(struct udev *udev, return 1; } if (buffer[3] > len) { - log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, buffer[3]); + log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, buffer[3]); return 1; } @@ -464,7 +463,7 @@ static int prepend_vendor_model(struct udev *udev, */ if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) { log_debug("%s: expected length %d, got length %d", - dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind); + dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind); return -1; } return ind; @@ -529,7 +528,7 @@ static int check_fill_0x83_id(struct udev *udev, if (max_len < len) { log_debug("%s: length %d too short - need %d", - dev_scsi->kernel, max_len, len); + dev_scsi->kernel, max_len, len); return 1; } @@ -785,7 +784,7 @@ static int do_scsi_page80_inquiry(struct udev *udev, len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3]; if (max_len < len) { log_debug("%s: length %d too short - need %d", - dev_scsi->kernel, max_len, len); + dev_scsi->kernel, max_len, len); return 1; } /* diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index d0e47ec6d..ed0ea5ce5 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -122,7 +122,7 @@ static int find_gpt_root(struct udev_device *dev, blkid_probe pr, bool test) { errno = 0; pl = blkid_probe_get_partitions(pr); if (!pl) - return errno ? -errno : -ENOMEM; + return errno > 0 ? -errno : -ENOMEM; nvals = blkid_partlist_numof_partitions(pl); for (i = 0; i < nvals; i++) { diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index fddafbd4d..3a3d8a177 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -31,6 +31,7 @@ #include #include "fd-util.h" +#include "stdio-util.h" #include "string-util.h" #include "udev.h" #include "util.h" @@ -64,8 +65,8 @@ static void extract_info(struct udev_device *dev, const char *devpath, bool test if (xabsinfo.resolution <= 0 || yabsinfo.resolution <= 0) return; - snprintf(width, sizeof(width), "%d", abs_size_mm(&xabsinfo)); - snprintf(height, sizeof(height), "%d", abs_size_mm(&yabsinfo)); + xsprintf(width, "%d", abs_size_mm(&xabsinfo)); + xsprintf(height, "%d", abs_size_mm(&yabsinfo)); udev_builtin_add_property(dev, test, "ID_INPUT_WIDTH_MM", width); udev_builtin_add_property(dev, test, "ID_INPUT_HEIGHT_MM", height); @@ -91,7 +92,7 @@ static void get_cap_mask(struct udev_device *dev, if (!v) v = ""; - snprintf(text, sizeof(text), "%s", v); + xsprintf(text, "%s", v); log_debug("%s raw kernel attribute: %s", attr, text); memzero(bitmask, bitmask_size); @@ -113,7 +114,8 @@ static void get_cap_mask(struct udev_device *dev, if (test) { /* printf pattern with the right unsigned long number of hex chars */ - snprintf(text, sizeof(text), " bit %%4u: %%0%zulX\n", 2 * sizeof(unsigned long)); + xsprintf(text, " bit %%4u: %%0%zulX\n", + 2 * sizeof(unsigned long)); log_debug("%s decoded bit map:", attr); val = bitmask_size / sizeof (unsigned long); /* skip over leading zeros */ @@ -203,12 +205,12 @@ static bool test_pointers(struct udev_device *dev, /* This path is taken by VMware's USB mouse, which has * absolute axes, but no touch/pressure button. */ is_mouse = true; - else if (has_touch) + else if (has_touch || is_direct) is_touchscreen = true; else if (has_joystick_axes_or_buttons) is_joystick = true; } - if (has_mt_coordinates && is_direct) + if (has_mt_coordinates && (is_direct || has_touch)) is_touchscreen = true; if (has_rel_coordinates && has_mouse_button) diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index bf5c9c6b7..8b1bcefe2 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -34,7 +34,7 @@ * * Type of names: * b -- BCMA bus core number - * ccw -- CCW bus group name + * c -- CCW bus group name, without leading zeros [s390] * o[d] -- on-board device index number * s[f][d] -- hotplug slot index number * x -- MAC address @@ -100,9 +100,12 @@ #include "fd-util.h" #include "fileio.h" +#include "stdio-util.h" #include "string-util.h" #include "udev.h" +#define ONBOARD_INDEX_MAX (16*1024-1) + enum netname_type{ NET_UNDEF, NET_PCI, @@ -149,6 +152,13 @@ static int dev_pci_onboard(struct udev_device *dev, struct netnames *names) { if (idx <= 0) return -EINVAL; + /* Some BIOSes report rubbish indexes that are excessively high (2^24-1 is an index VMware likes to report for + * example). Let's define a cut-off where we don't consider the index reliable anymore. We pick some arbitrary + * cut-off, which is somewhere beyond the realistic number of physical network interface a system might + * have. Ideally the kernel would already filter his crap for us, but it doesn't currently. */ + if (idx > ONBOARD_INDEX_MAX) + return -ENOENT; + /* kernel provided port index for multiple ports on a single PCI function */ attr = udev_device_get_sysattr_value(dev, "dev_port"); if (attr) @@ -226,7 +236,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { err = -ENOENT; goto out; } - snprintf(slots, sizeof(slots), "%s/slots", udev_device_get_syspath(pci)); + xsprintf(slots, "%s/slots", udev_device_get_syspath(pci)); dir = opendir(slots); if (!dir) { err = -errno; @@ -245,7 +255,7 @@ static int dev_pci_slot(struct udev_device *dev, struct netnames *names) { continue; if (i < 1) continue; - snprintf(str, sizeof(str), "%s/%s/address", slots, dent->d_name); + xsprintf(str, "%s/%s/address", slots, dent->d_name); if (read_one_line_file(str, &address) >= 0) { /* match slot address with device by stripping the function */ if (strneq(address, udev_device_get_sysname(names->pcidev), strlen(address))) @@ -378,7 +388,7 @@ static int names_bcma(struct udev_device *dev, struct netnames *names) { return -EINVAL; /* suppress the common core == 0 */ if (core > 0) - snprintf(names->bcma_core, sizeof(names->bcma_core), "b%u", core); + xsprintf(names->bcma_core, "b%u", core); names->type = NET_BCMA; return 0; @@ -418,8 +428,15 @@ static int names_ccw(struct udev_device *dev, struct netnames *names) { if (!bus_id_len || bus_id_len < 8 || bus_id_len > 9) return -EINVAL; + /* Strip leading zeros from the bus id for aesthetic purposes. This + * keeps the ccw names stable, yet much shorter in general case of + * bus_id 0.0.0600 -> 600. This is similar to e.g. how PCI domain is + * not prepended when it is zero. + */ + bus_id += strspn(bus_id, ".0"); + /* Store the CCW bus-ID for use as network device name */ - rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "ccw%s", bus_id); + rc = snprintf(names->ccw_group, sizeof(names->ccw_group), "c%s", bus_id); if (rc >= 0 && rc < (int)sizeof(names->ccw_group)) names->type = NET_CCWGROUP; return 0; @@ -467,9 +484,9 @@ static int ieee_oui(struct udev_device *dev, struct netnames *names, bool test) /* skip commonly misused 00:00:00 (Xerox) prefix */ if (memcmp(names->mac, "\0\0\0", 3) == 0) return -EINVAL; - snprintf(str, sizeof(str), "OUI:%02X%02X%02X%02X%02X%02X", - names->mac[0], names->mac[1], names->mac[2], - names->mac[3], names->mac[4], names->mac[5]); + xsprintf(str, "OUI:%02X%02X%02X%02X%02X%02X", names->mac[0], + names->mac[1], names->mac[2], names->mac[3], names->mac[4], + names->mac[5]); udev_builtin_hwdb_lookup(dev, NULL, str, NULL, test); return 0; } @@ -521,7 +538,7 @@ static int builtin_net_id(struct udev_device *dev, int argc, char *argv[], bool if (err >= 0 && names.mac_valid) { char str[IFNAMSIZ]; - snprintf(str, sizeof(str), "%sx%02x%02x%02x%02x%02x%02x", prefix, + xsprintf(str, "%sx%02x%02x%02x%02x%02x%02x", prefix, names.mac[0], names.mac[1], names.mac[2], names.mac[3], names.mac[4], names.mac[5]); udev_builtin_add_property(dev, test, "ID_NET_NAME_MAC", str); diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index f72894b5c..8e4777513 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index aa18c7e42..b6ed45d8b 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -663,6 +663,12 @@ static int builtin_path_id(struct udev_device *dev, int argc, char *argv[], bool path_prepend(&path, "xen-%s", udev_device_get_sysname(parent)); parent = skip_subsystem(parent, "xen"); supported_parent = true; + } else if (streq(subsys, "virtio")) { + while (parent && streq_ptr("virtio", udev_device_get_subsystem(parent))) + parent = udev_device_get_parent(parent); + path_prepend(&path, "virtio-pci-%s", udev_device_get_sysname(parent)); + supported_transport = true; + supported_parent = true; } else if (streq(subsys, "scm")) { path_prepend(&path, "scm-%s", udev_device_get_sysname(parent)); parent = skip_subsystem(parent, "scm"); diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 5d6542d3a..8d601c9c2 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -31,7 +31,6 @@ #include #include "alloc-util.h" -#include "event-util.h" #include "fd-util.h" #include "formats-util.h" #include "netlink-util.h" @@ -638,7 +637,7 @@ static int spawn_wait(struct udev_event *event, .pid = pid, .accept_failure = accept_failure, }; - _cleanup_event_unref_ sd_event *e = NULL; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; int r, ret; r = sd_event_new(&e); @@ -849,11 +848,11 @@ void udev_event_execute_rules(struct udev_event *event, /* disable watch during event processing */ if (major(udev_device_get_devnum(dev)) != 0) udev_watch_end(event->udev, event->dev_db); - } - if (major(udev_device_get_devnum(dev)) == 0 && - streq(udev_device_get_action(dev), "move")) - udev_device_copy_properties(dev, event->dev_db); + if (major(udev_device_get_devnum(dev)) == 0 && + streq(udev_device_get_action(dev), "move")) + udev_device_copy_properties(dev, event->dev_db); + } udev_rules_apply_to_event(rules, event, timeout_usec, timeout_warn_usec, diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index c2edf2c5c..5d2997fd8 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -29,6 +29,7 @@ #include "fs-util.h" #include "selinux-util.h" #include "smack-util.h" +#include "stdio-util.h" #include "string-util.h" #include "udev.h" @@ -346,9 +347,10 @@ void udev_node_add(struct udev_device *dev, bool apply, return; /* always add /dev/{block,char}/$major:$minor */ - snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", + xsprintf(filename, "/dev/%s/%u:%u", streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", - major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); + major(udev_device_get_devnum(dev)), + minor(udev_device_get_devnum(dev))); node_symlink(dev, udev_device_get_devnode(dev), filename); /* create/update symlinks, add symlinks to name index */ @@ -365,8 +367,9 @@ void udev_node_remove(struct udev_device *dev) { link_update(dev, udev_list_entry_get_name(list_entry), false); /* remove /dev/{block,char}/$major:$minor */ - snprintf(filename, sizeof(filename), "/dev/%s/%u:%u", + xsprintf(filename, "/dev/%s/%u:%u", streq(udev_device_get_subsystem(dev), "block") ? "block" : "char", - major(udev_device_get_devnum(dev)), minor(udev_device_get_devnum(dev))); + major(udev_device_get_devnum(dev)), + minor(udev_device_get_devnum(dev))); unlink(filename); } diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index f1fdccaed..9ce5e975d 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -24,6 +24,7 @@ #include #include +#include "stdio-util.h" #include "udev.h" static int inotify_fd = -1; @@ -103,7 +104,7 @@ void udev_watch_begin(struct udev *udev, struct udev_device *dev) { return; } - snprintf(filename, sizeof(filename), "/run/udev/watch/%d", wd); + xsprintf(filename, "/run/udev/watch/%d", wd); mkdir_parents(filename, 0755); unlink(filename); r = symlink(udev_device_get_id_filename(dev), filename); @@ -127,7 +128,7 @@ void udev_watch_end(struct udev *udev, struct udev_device *dev) { log_debug("removing watch on '%s'", udev_device_get_devnode(dev)); inotify_rm_watch(inotify_fd, wd); - snprintf(filename, sizeof(filename), "/run/udev/watch/%d", wd); + xsprintf(filename, "/run/udev/watch/%d", wd); unlink(filename); udev_device_set_watch_handle(dev, -1); @@ -141,7 +142,7 @@ struct udev_device *udev_watch_lookup(struct udev *udev, int wd) { if (inotify_fd < 0 || wd < 0) return NULL; - snprintf(filename, sizeof(filename), "/run/udev/watch/%d", wd); + xsprintf(filename, "/run/udev/watch/%d", wd); len = readlink(filename, device, sizeof(device)); if (len <= 0 || (size_t)len == sizeof(device)) return NULL; diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 031a099d7..948ad0f5a 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -665,7 +665,7 @@ static int adm_hwdb(struct udev *udev, int argc, char *argv[]) { } if (test) { - _cleanup_hwdb_unref_ sd_hwdb *hwdb = NULL; + _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; int r; r = sd_hwdb_new(&hwdb); diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 60f122ebd..7bd2c1ea4 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -1,4 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /* * Copyright (C) 2007-2012 Kay Sievers * diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 6d9d76515..2c1c4a967 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -47,7 +47,6 @@ #include "cgroup-util.h" #include "cpu-set-util.h" #include "dev-setup.h" -#include "event-util.h" #include "fd-util.h" #include "fileio.h" #include "formats-util.h" @@ -350,7 +349,7 @@ static void worker_spawn(Manager *manager, struct event *event) { switch (pid) { case 0: { struct udev_device *dev = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int fd_monitor; _cleanup_close_ int fd_signal = -1, fd_ep = -1; struct epoll_event ep_signal = { .events = EPOLLIN }; @@ -1651,7 +1650,8 @@ exit: int main(int argc, char *argv[]) { _cleanup_free_ char *cgroup = NULL; - int r, fd_ctrl, fd_uevent; + int fd_ctrl = -1, fd_uevent = -1; + int r; log_set_target(LOG_TARGET_AUTO); log_parse_environment(); diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index 4c44d5061..931e58378 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c index d50063cbc..8ae4a8a83 100644 --- a/src/update-utmp/update-utmp.c +++ b/src/update-utmp/update-utmp.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -48,7 +46,7 @@ typedef struct Context { } Context; static usec_t get_startup_time(Context *c) { - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; usec_t t = 0; int r; @@ -85,7 +83,7 @@ static int get_current_runlevel(Context *c) { { '1', SPECIAL_RESCUE_TARGET }, }; - _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; unsigned i; diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index 252cbdb26..8bf44e210 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -23,7 +21,9 @@ #include #include "fileio.h" +#include "fileio-label.h" #include "log.h" +#include "selinux-util.h" #include "string-util.h" #include "util.h" @@ -40,6 +40,8 @@ int main(int argc, char*argv[]) { umask(0022); + mac_selinux_init(NULL); + if (streq(argv[1], "start")) { int r = 0; @@ -65,7 +67,7 @@ int main(int argc, char*argv[]) { } else if (streq(argv[1], "stop")) { int r; - r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); + r = write_string_file_atomic_label("/run/nologin", "System is going down."); if (r < 0) { log_error_errno(r, "Failed to create /run/nologin: %m"); return EXIT_FAILURE; @@ -76,5 +78,7 @@ int main(int argc, char*argv[]) { return EXIT_FAILURE; } + mac_selinux_finish(); + return EXIT_SUCCESS; } diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index a5f4529cf..8a1b824e6 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -1,5 +1,3 @@ -/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ - /*** This file is part of systemd. @@ -39,6 +37,7 @@ #include "log.h" #include "process-util.h" #include "signal-util.h" +#include "stdio-util.h" #include "string-util.h" #include "terminal-util.h" #include "util.h" @@ -215,11 +214,11 @@ static void font_copy_to_all_vcs(int fd) { continue; /* skip non-allocated ttys */ - snprintf(vcname, sizeof(vcname), "/dev/vcs%i", i); + xsprintf(vcname, "/dev/vcs%i", i); if (access(vcname, F_OK) < 0) continue; - snprintf(vcname, sizeof(vcname), "/dev/tty%i", i); + xsprintf(vcname, "/dev/tty%i", i); vcfd = open_terminal(vcname, O_RDWR|O_CLOEXEC); if (vcfd < 0) continue; diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in index 5e04c821b..5a25de451 100644 --- a/sysctl.d/50-coredump.conf.in +++ b/sysctl.d/50-coredump.conf.in @@ -9,4 +9,4 @@ # and systemd-coredump(8) and core(5) for the explanation of the # setting below. -kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %e +kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %e diff --git a/sysusers.d/.gitignore b/sysusers.d/.gitignore index bb3aaaf82..c065034d2 100644 --- a/sysusers.d/.gitignore +++ b/sysusers.d/.gitignore @@ -1,2 +1,3 @@ /basic.conf /systemd.conf +/systemd-remote.conf diff --git a/sysusers.d/basic.conf.in b/sysusers.d/basic.conf.in index 823d6cb20..b2dc5ebd4 100644 --- a/sysusers.d/basic.conf.in +++ b/sysusers.d/basic.conf.in @@ -19,7 +19,6 @@ g wheel - - - # Access to certain kernel and userspace facilities g kmem - - - -g lock - - - g tty @TTY_GID@ - - g utmp - - - diff --git a/sysusers.d/systemd-remote.conf b/sysusers.d/systemd-remote.conf.m4 similarity index 86% rename from sysusers.d/systemd-remote.conf rename to sysusers.d/systemd-remote.conf.m4 index 15969e9a9..0e9d71cdd 100644 --- a/sysusers.d/systemd-remote.conf +++ b/sysusers.d/systemd-remote.conf.m4 @@ -5,6 +5,10 @@ # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. +m4_ifdef(`HAVE_MICROHTTPD', u systemd-journal-gateway - "systemd Journal Gateway" u systemd-journal-remote - "systemd Journal Remote" +)m4_dnl +m4_ifdef(`HAVE_LIBCURL', u systemd-journal-upload - "systemd Journal Upload" +)m4_dnl diff --git a/sysusers.d/systemd.conf.m4 b/sysusers.d/systemd.conf.m4 index 81b1d79c3..317240a9f 100644 --- a/sysusers.d/systemd.conf.m4 +++ b/sysusers.d/systemd.conf.m4 @@ -16,3 +16,6 @@ u systemd-resolve - "systemd Resolver" m4_ifdef(`ENABLE_TIMESYNCD', u systemd-timesync - "systemd Time Synchronization" )m4_dnl +m4_ifdef(`ENABLE_COREDUMP', +u systemd-coredump - "systemd Core Dumper" +)m4_dnl diff --git a/test/README.testsuite b/test/README.testsuite index 5c7aca43a..fa7e73ce3 100644 --- a/test/README.testsuite +++ b/test/README.testsuite @@ -36,7 +36,7 @@ you can even skip the "clean" and "setup" if you want to run the machine again. $ sudo make KERNEL_APPEND="systemd.unit=multi-user.target" run You can specify a different kernel and initramfs with $KERNEL_BIN and $INITRD. -(Fedora's default kernel path and initramfs are used by default) +(Fedora's or Debian's default kernel path and initramfs are used by default) $ sudo make KERNEL_BIN=/boot/vmlinuz-foo INITRD=/boot/initramfs-bar clean check diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh index b6b474393..6963d8c88 100755 --- a/test/TEST-01-BASIC/test.sh +++ b/test/TEST-01-BASIC/test.sh @@ -11,7 +11,7 @@ check_result_qemu() { mount ${LOOPDEV}p1 $TESTDIR/root [[ -e $TESTDIR/root/testok ]] && ret=0 [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR - [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR umount $TESTDIR/root [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed ls -l $TESTDIR/journal/*/*.journal @@ -58,9 +58,16 @@ Type=oneshot EOF setup_testsuite - ) + ) || return 1 setup_nspawn_root + # mask some services that we do not want to run in these tests + ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service + ddebug "umount $TESTDIR/root" umount $TESTDIR/root } diff --git a/test/TEST-02-CRYPTSETUP/test.sh b/test/TEST-02-CRYPTSETUP/test.sh index 2997da06f..242090c76 100755 --- a/test/TEST-02-CRYPTSETUP/test.sh +++ b/test/TEST-02-CRYPTSETUP/test.sh @@ -13,7 +13,7 @@ check_result_qemu() { [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile mount /dev/mapper/varcrypt $TESTDIR/root/var - [[ -f $TESTDIR/root/var/log/journal ]] && cp -a $TESTDIR/root/var/log/journal $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR umount $TESTDIR/root/var umount $TESTDIR/root cryptsetup luksClose /dev/mapper/varcrypt @@ -76,8 +76,7 @@ EOF cat >>$initdir/etc/fstab < /root/list-jobs.txt -grep 'sleep\.service.*running' /root/list-jobs.txt || exit 1 +while ! grep 'sleep\.service.*running' /root/list-jobs.txt; do + systemctl list-jobs > /root/list-jobs.txt +done + grep 'hello\.service.*waiting' /root/list-jobs.txt || exit 1 # This is supposed to finish quickly, not wait for sleep to finish. @@ -47,4 +50,3 @@ systemctl stop --job-mode=replace-irreversibly unstoppable.service || exit 1 systemctl start unstoppable.service || exit 1 touch /testok -exit 0 diff --git a/test/TEST-03-JOBS/test.sh b/test/TEST-03-JOBS/test.sh index 41e02e2c8..83393435f 100755 --- a/test/TEST-03-JOBS/test.sh +++ b/test/TEST-03-JOBS/test.sh @@ -63,7 +63,7 @@ EOF cp test-jobs.sh $initdir/ setup_testsuite - ) + ) || return 1 setup_nspawn_root ddebug "umount $TESTDIR/root" diff --git a/test/TEST-04-JOURNAL/Makefile b/test/TEST-04-JOURNAL/Makefile new file mode 120000 index 000000000..e9f93b110 --- /dev/null +++ b/test/TEST-04-JOURNAL/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-04-JOURNAL/test-journal.sh b/test/TEST-04-JOURNAL/test-journal.sh new file mode 100755 index 000000000..6646eccfa --- /dev/null +++ b/test/TEST-04-JOURNAL/test-journal.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +set -x +set -e +set -o pipefail + +# Test stdout stream + +# Skip empty lines +ID=$(journalctl --new-id128 | sed -n 2p) +>/expected +printf $'\n\n\n' | systemd-cat -t "$ID" --level-prefix false +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +ID=$(journalctl --new-id128 | sed -n 2p) +>/expected +printf $'<5>\n<6>\n<7>\n' | systemd-cat -t "$ID" --level-prefix true +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +# Remove trailing spaces +ID=$(journalctl --new-id128 | sed -n 2p) +printf "Trailing spaces\n">/expected +printf $'<5>Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix true +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +ID=$(journalctl --new-id128 | sed -n 2p) +printf "Trailing spaces\n">/expected +printf $'Trailing spaces \t \n' | systemd-cat -t "$ID" --level-prefix false +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +# Don't remove leading spaces +ID=$(journalctl --new-id128 | sed -n 2p) +printf $' \t Leading spaces\n'>/expected +printf $'<5> \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix true +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +ID=$(journalctl --new-id128 | sed -n 2p) +printf $' \t Leading spaces\n'>/expected +printf $' \t Leading spaces\n' | systemd-cat -t "$ID" --level-prefix false +journalctl --sync +journalctl -b -o cat -t "$ID" >/output +cmp /expected /output + +# Don't lose streams on restart +systemctl start forever-print-hola +sleep 3 +systemctl restart systemd-journald +sleep 3 +systemctl stop forever-print-hola +[[ ! -f "/i-lose-my-logs" ]] + +touch /testok diff --git a/test/TEST-04-JOURNAL/test.sh b/test/TEST-04-JOURNAL/test.sh new file mode 100755 index 000000000..1a14f7606 --- /dev/null +++ b/test/TEST-04-JOURNAL/test.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="Journal-related tests" + +. $TEST_BASE_DIR/test-functions + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + if check_nspawn; then + run_nspawn + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service <$initdir/etc/systemd/system/forever-print-hola.service </dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-05-RLIMITS/Makefile b/test/TEST-05-RLIMITS/Makefile new file mode 120000 index 000000000..e9f93b110 --- /dev/null +++ b/test/TEST-05-RLIMITS/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-05-RLIMITS/test-rlimits.sh b/test/TEST-05-RLIMITS/test-rlimits.sh new file mode 100755 index 000000000..ba665c596 --- /dev/null +++ b/test/TEST-05-RLIMITS/test-rlimits.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -x +set -e +set -o pipefail + +[[ "$(systemctl show -p DefaultLimitNOFILESoft)" = "DefaultLimitNOFILESoft=10000" ]] +[[ "$(systemctl show -p DefaultLimitNOFILE)" = "DefaultLimitNOFILE=16384" ]] + +[[ "$(systemctl show -p LimitNOFILESoft testsuite.service)" = "LimitNOFILESoft=10000" ]] +[[ "$(systemctl show -p LimitNOFILE testsuite.service)" = "LimitNOFILE=16384" ]] + +[[ "$(ulimit -n -S)" = "10000" ]] +[[ "$(ulimit -n -H)" = "16384" ]] + +touch /testok diff --git a/test/TEST-05-RLIMITS/test.sh b/test/TEST-05-RLIMITS/test.sh new file mode 100755 index 000000000..6eaa0b8f3 --- /dev/null +++ b/test/TEST-05-RLIMITS/test.sh @@ -0,0 +1,81 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="Resource limits-related tests" + +. $TEST_BASE_DIR/test-functions + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + if check_nspawn; then + run_nspawn + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + cat >$initdir/etc/systemd/system.conf <$initdir/etc/systemd/system/testsuite.service </dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-06-SELINUX/Makefile b/test/TEST-06-SELINUX/Makefile new file mode 100644 index 000000000..5e89a29ef --- /dev/null +++ b/test/TEST-06-SELINUX/Makefile @@ -0,0 +1,10 @@ +all: + @make -s --no-print-directory -C ../.. all + @basedir=../.. TEST_BASE_DIR=../ ./test.sh --all +setup: + @make --no-print-directory -C ../.. all + @basedir=../.. TEST_BASE_DIR=../ ./test.sh --setup +clean: + @basedir=../.. TEST_BASE_DIR=../ ./test.sh --clean +run: + @basedir=../.. TEST_BASE_DIR=../ ./test.sh --run diff --git a/test/TEST-06-SELINUX/systemd_test.if b/test/TEST-06-SELINUX/systemd_test.if new file mode 100644 index 000000000..25c91adce --- /dev/null +++ b/test/TEST-06-SELINUX/systemd_test.if @@ -0,0 +1,8 @@ +template(`systemd_test_base_template', ` + gen_require(` + attribute systemd_test_domain_type; + ') + + type $1_t, systemd_test_domain_type; + domain_type($1_t) +') diff --git a/test/TEST-06-SELINUX/systemd_test.te b/test/TEST-06-SELINUX/systemd_test.te new file mode 100644 index 000000000..ff01c09b5 --- /dev/null +++ b/test/TEST-06-SELINUX/systemd_test.te @@ -0,0 +1,50 @@ +policy_module(systemd_test, 0.0.1) + +# declarations +attribute systemd_test_domain_type; + +systemd_test_base_template(systemd_test) +systemd_test_base_template(systemd_test_status) +systemd_test_base_template(systemd_test_start) +systemd_test_base_template(systemd_test_stop) +systemd_test_base_template(systemd_test_reload) + +# systemd_test_domain_type + +require { + role system_r; + role unconfined_r; + type bin_t; + type initrc_t; + type systemd_systemctl_exec_t; + type unconfined_service_t; +} + +role system_r types systemd_test_domain_type; +role unconfined_r types systemd_test_domain_type; + +allow systemd_test_domain_type bin_t: file entrypoint; +allow systemd_test_domain_type systemd_systemctl_exec_t: file entrypoint; +allow initrc_t systemd_test_domain_type: process transition; +allow unconfined_service_t systemd_test_domain_type: process transition; +corecmd_exec_bin(systemd_test_domain_type) +init_signal_script(systemd_test_domain_type) +init_sigchld_script(systemd_test_domain_type) +systemd_exec_systemctl(systemd_test_domain_type) +userdom_use_user_ttys(systemd_test_domain_type) +userdom_use_user_ptys(systemd_test_domain_type) + +optional_policy(` + dbus_system_bus_client(systemd_test_domain_type) + init_dbus_chat(systemd_test_domain_type) +') + +# systemd_test_*_t +require { + type systemd_unit_file_t; +} + +allow systemd_test_status_t systemd_unit_file_t: service { status }; +allow systemd_test_start_t systemd_unit_file_t: service { start }; +allow systemd_test_stop_t systemd_unit_file_t: service { stop }; +allow systemd_test_reload_t systemd_unit_file_t: service { reload }; diff --git a/test/TEST-06-SELINUX/test-selinux-checks.sh b/test/TEST-06-SELINUX/test-selinux-checks.sh new file mode 100755 index 000000000..153fab3aa --- /dev/null +++ b/test/TEST-06-SELINUX/test-selinux-checks.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -x +set -e +set -o pipefail + +echo 1 >/sys/fs/selinux/enforce +runcon -t systemd_test_start_t systemctl start hola +runcon -t systemd_test_reload_t systemctl reload hola +runcon -t systemd_test_stop_t systemctl stop hola + +touch /testok diff --git a/test/TEST-06-SELINUX/test.sh b/test/TEST-06-SELINUX/test.sh new file mode 100755 index 000000000..4f5895be6 --- /dev/null +++ b/test/TEST-06-SELINUX/test.sh @@ -0,0 +1,135 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="SELinux tests" + +# Requirements: +# Fedora 23 +# selinux-policy-targeted +# selinux-policy-devel + +. $TEST_BASE_DIR/test-functions +SETUP_SELINUX=yes +KERNEL_APPEND="$KERNEL_APPEND selinux=1" + +check_result_qemu() { + ret=1 + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + [[ -e $TESTDIR/root/testok ]] && ret=0 + [[ -f $TESTDIR/root/failed ]] && cp -a $TESTDIR/root/failed $TESTDIR + cp -a $TESTDIR/root/var/log/journal $TESTDIR + umount $TESTDIR/root + [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed + ls -l $TESTDIR/journal/*/*.journal + test -s $TESTDIR/failed && ret=$(($ret+1)) + return $ret +} + +test_run() { + if run_qemu; then + check_result_qemu || return 1 + else + dwarn "can't run QEMU, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat <$initdir/etc/systemd/system/testsuite.service +[Unit] +Description=Testsuite service +After=multi-user.target + +[Service] +ExecStart=/test-selinux-checks.sh +Type=oneshot +EOF + + cat <$initdir/etc/systemd/system/hola.service +[Service] +Type=oneshot +ExecStart=/bin/echo Start Hola +ExecReload=/bin/echo Reload Hola +ExecStop=/bin/echo Stop Hola +RemainAfterExit=yes +EOF + + setup_testsuite + + cat <$initdir/etc/systemd/system/load-systemd-test-module.service +[Unit] +Description=Load systemd-test module +DefaultDependencies=no +Requires=local-fs.target +Conflicts=shutdown.target +After=local-fs.target +Before=sysinit.target shutdown.target autorelabel.service +ConditionSecurity=selinux +ConditionPathExists=|/.load-systemd-test-module + +[Service] +ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && cd /systemd-test-module && make -f /usr/share/selinux/devel/Makefile load && rm /.load-systemd-test-module' +Type=oneshot +TimeoutSec=0 +RemainAfterExit=yes +EOF + + touch $initdir/.load-systemd-test-module + mkdir -p $initdir/etc/systemd/system/basic.target.wants + ln -fs load-systemd-test-module.service $initdir/etc/systemd/system/basic.target.wants/load-systemd-test-module.service + + local _modules_dir=/var/lib/selinux + rm -rf $initdir/$_modules_dir + if ! cp -ar $_modules_dir $initdir/$_modules_dir; then + dfatal "Failed to copy $_modules_dir" + exit 1 + fi + + local _policy_headers_dir=/usr/share/selinux/devel + rm -rf $initdir/$_policy_headers_dir + inst_dir /usr/share/selinux + if ! cp -ar $_policy_headers_dir $initdir/$_policy_headers_dir; then + dfatal "Failed to copy $_policy_headers_dir" + exit 1 + fi + + mkdir $initdir/systemd-test-module + cp systemd_test.te $initdir/systemd-test-module + cp systemd_test.if $initdir/systemd-test-module + cp test-selinux-checks.sh $initdir + dracut_install -o sesearch + dracut_install runcon + dracut_install checkmodule semodule semodule_package m4 make /usr/libexec/selinux/hll/pp load_policy sefcontext_compile + ) || return 1 + + # mask some services that we do not want to run in these tests + ln -s /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.service + ln -s /dev/null $initdir/etc/systemd/system/systemd-networkd.socket + ln -s /dev/null $initdir/etc/systemd/system/systemd-resolved.service + + ddebug "umount $TESTDIR/root" + umount $TESTDIR/root +} + +test_cleanup() { + umount $TESTDIR/root 2>/dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/TEST-07-ISSUE-1981/Makefile b/test/TEST-07-ISSUE-1981/Makefile new file mode 120000 index 000000000..e9f93b110 --- /dev/null +++ b/test/TEST-07-ISSUE-1981/Makefile @@ -0,0 +1 @@ +../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/TEST-07-ISSUE-1981/test-segfault.sh b/test/TEST-07-ISSUE-1981/test-segfault.sh new file mode 100755 index 000000000..48f05d89f --- /dev/null +++ b/test/TEST-07-ISSUE-1981/test-segfault.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +set -x +set -e + +>/failed + +cat <<'EOL' >/lib/systemd/system/my.service +[Service] +Type=oneshot +ExecStart=/bin/echo Timer runs me +EOL + +cat <<'EOL' >/lib/systemd/system/my.timer +[Timer] +OnBootSec=10s +OnUnitInactiveSec=1h +EOL + +systemctl unmask my.timer + +systemctl start my.timer + +mkdir -p /etc/systemd/system/my.timer.d/ +cat <<'EOL' >/etc/systemd/system/my.timer.d/override.conf +[Timer] +OnBootSec=10s +OnUnitInactiveSec=1h +EOL + +systemctl daemon-reload + +systemctl mask my.timer + +touch /testok +rm /failed diff --git a/test/TEST-07-ISSUE-1981/test.sh b/test/TEST-07-ISSUE-1981/test.sh new file mode 100755 index 000000000..dcb6ece4d --- /dev/null +++ b/test/TEST-07-ISSUE-1981/test.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +TEST_DESCRIPTION="https://github.com/systemd/systemd/issues/1981" + +. $TEST_BASE_DIR/test-functions + +test_run() { + dwarn "skipping QEMU" + if check_nspawn; then + timeout --foreground 30s systemd-nspawn --kill-signal=SIGKILL --boot --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND + check_result_nspawn || return 1 + else + dwarn "can't run systemd-nspawn, skipping" + fi + return 0 +} + +test_setup() { + create_empty_image + mkdir -p $TESTDIR/root + mount ${LOOPDEV}p1 $TESTDIR/root + + # Create what will eventually be our root filesystem onto an overlay + ( + LOG_LEVEL=5 + eval $(udevadm info --export --query=env --name=${LOOPDEV}p2) + + setup_basic_environment + + # setup the testsuite service + cat >$initdir/etc/systemd/system/testsuite.service </dev/null + [[ $LOOPDEV ]] && losetup -d $LOOPDEV + return 0 +} + +do_test "$@" diff --git a/test/networkd-test.py b/test/networkd-test.py new file mode 100755 index 000000000..d76ab507d --- /dev/null +++ b/test/networkd-test.py @@ -0,0 +1,371 @@ +#!/usr/bin/env python3 +# +# networkd integration test +# This uses temporary configuration in /run and temporary veth devices, and +# does not write anything on disk or change any system configuration; +# but it assumes (and checks at the beginning) that networkd is not currently +# running. +# This can be run on a normal installation, in QEMU, nspawn, or LXC. +# ATTENTION: This uses the *installed* networkd, not the one from the built +# source tree. +# +# (C) 2015 Canonical Ltd. +# Author: Martin Pitt +# +# 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 . + +import os +import sys +import time +import unittest +import tempfile +import subprocess +import shutil + +networkd_active = subprocess.call(['systemctl', 'is-active', '--quiet', + 'systemd-networkd']) == 0 +have_dnsmasq = shutil.which('dnsmasq') + + +@unittest.skipIf(networkd_active, + 'networkd is already active') +class ClientTestBase: + def setUp(self): + self.iface = 'test_eth42' + self.if_router = 'router_eth42' + self.workdir_obj = tempfile.TemporaryDirectory() + self.workdir = self.workdir_obj.name + self.config = '/run/systemd/network/test_eth42.network' + os.makedirs(os.path.dirname(self.config), exist_ok=True) + + # avoid "Failed to open /dev/tty" errors in containers + os.environ['SYSTEMD_LOG_TARGET'] = 'journal' + + # determine path to systemd-networkd-wait-online + for p in ['/usr/lib/systemd/systemd-networkd-wait-online', + '/lib/systemd/systemd-networkd-wait-online']: + if os.path.exists(p): + self.networkd_wait_online = p + break + else: + self.fail('systemd-networkd-wait-online not found') + + # get current journal cursor + out = subprocess.check_output(['journalctl', '-b', '--quiet', + '--no-pager', '-n0', '--show-cursor'], + universal_newlines=True) + self.assertTrue(out.startswith('-- cursor:')) + self.journal_cursor = out.split()[-1] + + def tearDown(self): + self.shutdown_iface() + if os.path.exists(self.config): + os.unlink(self.config) + subprocess.call(['systemctl', 'stop', 'systemd-networkd']) + + def show_journal(self, unit): + '''Show journal of given unit since start of the test''' + + print('---- %s ----' % unit) + sys.stdout.flush() + subprocess.call(['journalctl', '-b', '--no-pager', '--quiet', + '--cursor', self.journal_cursor, '-u', unit]) + + def create_iface(self, ipv6=False): + '''Create test interface with DHCP server behind it''' + + raise NotImplementedError('must be implemented by a subclass') + + def shutdown_iface(self): + '''Remove test interface and stop DHCP server''' + + raise NotImplementedError('must be implemented by a subclass') + + def print_server_log(self): + '''Print DHCP server log for debugging failures''' + + raise NotImplementedError('must be implemented by a subclass') + + def do_test(self, coldplug=True, ipv6=False, extra_opts='', + online_timeout=10, dhcp_mode='yes'): + with open(self.config, 'w') as f: + f.write('''[Match] +Name=%s +[Network] +DHCP=%s +%s''' % (self.iface, dhcp_mode, extra_opts)) + + if coldplug: + # create interface first, then start networkd + self.create_iface(ipv6=ipv6) + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + else: + # start networkd first, then create interface + subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) + self.create_iface(ipv6=ipv6) + + try: + subprocess.check_call([self.networkd_wait_online, '--interface', + self.iface, '--timeout=%i' % online_timeout]) + + if ipv6: + # check iface state and IP 6 address; FIXME: we need to wait a bit + # longer, as the iface is "configured" already with IPv4 *or* + # IPv6, but we want to wait for both + for timeout in range(10): + out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.iface]) + if b'state UP' in out and b'inet6 2600' in out and b'inet 192.168' in out: + break + time.sleep(1) + else: + self.fail('timed out waiting for IPv6 configuration') + + self.assertRegex(out, b'inet6 2600::.* scope global .*dynamic') + self.assertRegex(out, b'inet6 fe80::.* scope link') + else: + # should have link-local address on IPv6 only + out = subprocess.check_output(['ip', '-6', 'a', 'show', 'dev', self.iface]) + self.assertRegex(out, b'inet6 fe80::.* scope link') + self.assertNotIn(b'scope global', out) + + # should have IPv4 address + out = subprocess.check_output(['ip', '-4', 'a', 'show', 'dev', self.iface]) + self.assertIn(b'state UP', out) + self.assertRegex(out, b'inet 192.168.5.\d+/.* scope global dynamic') + + # check networkctl state + out = subprocess.check_output(['networkctl']) + self.assertRegex(out, ('%s\s+ether\s+routable\s+unmanaged' % self.if_router).encode()) + self.assertRegex(out, ('%s\s+ether\s+routable\s+configured' % self.iface).encode()) + + out = subprocess.check_output(['networkctl', 'status', self.iface]) + self.assertRegex(out, b'Type:\s+ether') + self.assertRegex(out, b'State:\s+routable.*configured') + self.assertRegex(out, b'Address:\s+192.168.5.\d+') + if ipv6: + self.assertRegex(out, b'2600::') + else: + self.assertNotIn(b'2600::', out) + self.assertRegex(out, b'fe80::') + self.assertRegex(out, b'Gateway:\s+192.168.5.1') + self.assertRegex(out, b'DNS:\s+192.168.5.1') + except (AssertionError, subprocess.CalledProcessError): + # show networkd status, journal, and DHCP server log on failure + with open(self.config) as f: + print('\n---- %s ----\n%s' % (self.config, f.read())) + print('---- interface status ----') + sys.stdout.flush() + subprocess.call(['ip', 'a', 'show', 'dev', self.iface]) + print('---- networkctl status %s ----' % self.iface) + sys.stdout.flush() + subprocess.call(['networkctl', 'status', self.iface]) + self.show_journal('systemd-networkd.service') + self.print_server_log() + raise + + # verify resolv.conf if it gets dynamically managed + if os.path.islink('/etc/resolv.conf'): + for timeout in range(50): + with open('/etc/resolv.conf') as f: + contents = f.read() + if 'nameserver 192.168.5.1\n' in contents: + break + # resolv.conf can have at most three nameservers; if we already + # have three different ones, that's also okay + if contents.count('nameserver ') >= 3: + break + time.sleep(0.1) + else: + self.fail('nameserver 192.168.5.1 not found in /etc/resolv.conf') + + if not coldplug: + # check post-down.d hook + self.shutdown_iface() + + def test_coldplug_dhcp_yes_ip4(self): + # we have a 12s timeout on RA, so we need to wait longer + self.do_test(coldplug=True, ipv6=False, online_timeout=15) + + def test_coldplug_dhcp_yes_ip4_no_ra(self): + # with disabling RA explicitly things should be fast + self.do_test(coldplug=True, ipv6=False, + extra_opts='IPv6AcceptRouterAdvertisements=False') + + def test_coldplug_dhcp_ip4_only(self): + # we have a 12s timeout on RA, so we need to wait longer + self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4', + online_timeout=15) + + def test_coldplug_dhcp_ip4_only_no_ra(self): + # with disabling RA explicitly things should be fast + self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4', + extra_opts='IPv6AcceptRouterAdvertisements=False') + + def test_coldplug_dhcp_ip6(self): + self.do_test(coldplug=True, ipv6=True) + + def test_hotplug_dhcp_ip4(self): + # With IPv4 only we have a 12s timeout on RA, so we need to wait longer + self.do_test(coldplug=False, ipv6=False, online_timeout=15) + + def test_hotplug_dhcp_ip6(self): + self.do_test(coldplug=False, ipv6=True) + + +@unittest.skipUnless(have_dnsmasq, 'dnsmasq not installed') +class DnsmasqClientTest(ClientTestBase, unittest.TestCase): + '''Test networkd client against dnsmasq''' + + def setUp(self): + super().setUp() + self.dnsmasq = None + + def create_iface(self, ipv6=False): + '''Create test interface with DHCP server behind it''' + + # add veth pair + subprocess.check_call(['ip', 'link', 'add', 'name', self.iface, 'type', + 'veth', 'peer', 'name', self.if_router]) + + # give our router an IP + subprocess.check_call(['ip', 'a', 'flush', 'dev', self.if_router]) + subprocess.check_call(['ip', 'a', 'add', '192.168.5.1/24', 'dev', self.if_router]) + if ipv6: + subprocess.check_call(['ip', 'a', 'add', '2600::1/64', 'dev', self.if_router]) + subprocess.check_call(['ip', 'link', 'set', self.if_router, 'up']) + + # add DHCP server + self.dnsmasq_log = os.path.join(self.workdir, 'dnsmasq.log') + lease_file = os.path.join(self.workdir, 'dnsmasq.leases') + if ipv6: + extra_opts = ['--enable-ra', '--dhcp-range=2600::10,2600::20'] + else: + extra_opts = [] + self.dnsmasq = subprocess.Popen( + ['dnsmasq', '--keep-in-foreground', '--log-queries', + '--log-facility=' + self.dnsmasq_log, '--conf-file=/dev/null', + '--dhcp-leasefile=' + lease_file, '--bind-interfaces', + '--interface=' + self.if_router, '--except-interface=lo', + '--dhcp-range=192.168.5.10,192.168.5.200'] + extra_opts) + + def shutdown_iface(self): + '''Remove test interface and stop DHCP server''' + + if self.if_router: + subprocess.check_call(['ip', 'link', 'del', 'dev', self.if_router]) + self.if_router = None + if self.dnsmasq: + self.dnsmasq.kill() + self.dnsmasq.wait() + self.dnsmasq = None + + def print_server_log(self): + '''Print DHCP server log for debugging failures''' + + with open(self.dnsmasq_log) as f: + sys.stdout.write('\n\n---- dnsmasq log ----\n%s\n------\n\n' % f.read()) + + +class NetworkdClientTest(ClientTestBase, unittest.TestCase): + '''Test networkd client against networkd server''' + + def setUp(self): + super().setUp() + self.dnsmasq = None + + def create_iface(self, ipv6=False): + '''Create test interface with DHCP server behind it''' + + # run "router-side" networkd in own mount namespace to shield it from + # "client-side" configuration and networkd + (fd, script) = tempfile.mkstemp(prefix='networkd-router.sh') + self.addCleanup(os.remove, script) + with os.fdopen(fd, 'w+') as f: + f.write('''#!/bin/sh -eu +mkdir -p /run/systemd/network +mkdir -p /run/systemd/netif +mount -t tmpfs none /run/systemd/network +mount -t tmpfs none /run/systemd/netif +[ ! -e /run/dbus ] || mount -t tmpfs none /run/dbus +# create router/client veth pair +cat << EOF > /run/systemd/network/test.netdev +[NetDev] +Name=%(ifr)s +Kind=veth + +[Peer] +Name=%(ifc)s +EOF + +cat << EOF > /run/systemd/network/test.network +[Match] +Name=%(ifr)s + +[Network] +Address=192.168.5.1/24 +%(addr6)s +DHCPServer=yes + +[DHCPServer] +PoolOffset=10 +PoolSize=50 +DNS=192.168.5.1 +EOF + +# run networkd as in systemd-networkd.service +exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ { s/^.*=//; p}') +''' % {'ifr': self.if_router, 'ifc': self.iface, 'addr6': ipv6 and 'Address=2600::1/64' or ''}) + + os.fchmod(fd, 0o755) + + subprocess.check_call(['systemd-run', '--unit=networkd-test-router.service', + '-p', 'InaccessibleDirectories=-/etc/systemd/network', + '-p', 'InaccessibleDirectories=-/run/systemd/network', + '-p', 'InaccessibleDirectories=-/run/systemd/netif', + '--service-type=notify', script]) + + # wait until devices got created + for timeout in range(50): + out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.if_router]) + if b'state UP' in out and b'scope global' in out: + break + time.sleep(0.1) + + def shutdown_iface(self): + '''Remove test interface and stop DHCP server''' + + if self.if_router: + subprocess.check_call(['systemctl', 'stop', 'networkd-test-router.service']) + # ensure failed transient unit does not stay around + subprocess.call(['systemctl', 'reset-failed', 'networkd-test-router.service']) + subprocess.call(['ip', 'link', 'del', 'dev', self.if_router]) + self.if_router = None + + def print_server_log(self): + '''Print DHCP server log for debugging failures''' + + self.show_journal('networkd-test-router.service') + + @unittest.skip('networkd does not have DHCPv6 server support') + def test_hotplug_dhcp_ip6(self): + pass + + @unittest.skip('networkd does not have DHCPv6 server support') + def test_coldplug_dhcp_ip6(self): + pass + + +if __name__ == '__main__': + unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, + verbosity=2)) diff --git a/test/sys.tar.xz b/test/sys.tar.xz index 49ee8027b2e1cba42a8312d56de4bb65d4a2d470..052c77d182a2eba730d3aeaf52b1ab90d937f006 100644 GIT binary patch literal 261380 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 M_&SPq@yDc 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

)s)Y#*P{y8yiwugPIMaq3 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 J00004Sz00+A-wv?rN~uw$QGMs1W~ZOV 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 TF~f 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

ylNCyuY~M#6!2O4!)bC)+ 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 Y)C2$k0M%KP*c2B#FarPp000D8T01=OssI20 diff --git a/test/sysv-generator-test.py b/test/sysv-generator-test.py index 721e53a4e..aca5f1eec 100644 --- a/test/sysv-generator-test.py +++ b/test/sysv-generator-test.py @@ -23,6 +23,7 @@ import subprocess import tempfile import shutil from glob import glob +import collections try: from configparser import RawConfigParser @@ -32,6 +33,12 @@ except ImportError: sysv_generator = os.path.join(os.environ.get('builddir', '.'), 'systemd-sysv-generator') +class MultiDict(collections.OrderedDict): + def __setitem__(self, key, value): + if isinstance(value, list) and key in self: + self[key].extend(value) + else: + super(MultiDict, self).__setitem__(key, value) class SysvGeneratorTest(unittest.TestCase): def setUp(self): @@ -77,7 +84,14 @@ class SysvGeneratorTest(unittest.TestCase): for service in glob(self.out_dir + '/*.service'): if os.path.islink(service): continue - cp = RawConfigParser() + try: + # for python3 we need here strict=False to parse multiple + # lines with the same key + cp = RawConfigParser(dict_type=MultiDict, strict=False) + except TypeError: + # RawConfigParser in python2 does not have the strict option + # but it allows multiple lines with the same key by default + cp = RawConfigParser(dict_type=MultiDict) cp.optionxform = lambda o: o # don't lower-case option names with open(service) as f: cp.readfp(f) @@ -224,7 +238,7 @@ class SysvGeneratorTest(unittest.TestCase): s = self.run_generator()[1]['foo.service'] self.assertEqual(set(s.options('Unit')), set(['Documentation', 'SourcePath', 'Description', 'After'])) - self.assertEqual(s.get('Unit', 'After'), 'nss-lookup.target rpcbind.target') + self.assertEqual(s.get('Unit', 'After').split(), ['nss-lookup.target', 'rpcbind.target']) def test_lsb_deps(self): '''LSB header dependencies to other services''' diff --git a/test/test-execute/exec-capabilityambientset-merge.service b/test/test-execute/exec-capabilityambientset-merge.service new file mode 100644 index 000000000..64964380e --- /dev/null +++ b/test/test-execute/exec-capabilityambientset-merge.service @@ -0,0 +1,9 @@ +[Unit] +Description=Test for AmbientCapabilities + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' +Type=oneshot +User=nobody +AmbientCapabilities=CAP_NET_ADMIN +AmbientCapabilities=CAP_NET_RAW diff --git a/test/test-execute/exec-capabilityambientset.service b/test/test-execute/exec-capabilityambientset.service new file mode 100644 index 000000000..d63f884ef --- /dev/null +++ b/test/test-execute/exec-capabilityambientset.service @@ -0,0 +1,8 @@ +[Unit] +Description=Test for AmbientCapabilities + +[Service] +ExecStart=/bin/sh -x -c 'c=$$(grep "CapAmb:" /proc/self/status); test "$$c" = "CapAmb: 0000000000003000"' +Type=oneshot +User=nobody +AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW diff --git a/test/test-functions b/test/test-functions index a6eea662f..6667e0524 100644 --- a/test/test-functions +++ b/test/test-functions @@ -13,8 +13,8 @@ if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then ROOTLIBDIR=/usr/lib/systemd fi -BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe" -DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname" +BASICTOOLS="sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm" +DEBUGTOOLS="df free ls stty cat ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find" function find_qemu_bin() { # SUSE and Red Hat call the binary qemu-kvm @@ -51,8 +51,11 @@ run_qemu() { && KERNEL_BIN="/boot/$MACHINE_ID/$KERNEL_VER/linux" fi + default_fedora_initrd=/boot/initramfs-${KERNEL_VER}.img + default_debian_initrd=/boot/initrd.img-${KERNEL_VER} [ "$KERNEL_BIN" ] || KERNEL_BIN=/boot/vmlinuz-$KERNEL_VER - [ "$INITRD" ] || INITRD=/boot/initramfs-${KERNEL_VER}.img + [ "$INITRD" ] || { [ -e "$default_fedora_initrd" ] && INITRD=$default_fedora_initrd; } + [ "$INITRD" ] || { [ "$LOOKS_LIKE_DEBIAN" ] && [ -e "$default_debian_initrd" ] && INITRD=$default_debian_initrd; } [ "$QEMU_SMP" ] || QEMU_SMP=1 find_qemu_bin || return 1 @@ -68,8 +71,7 @@ selinux=0 \ $KERNEL_APPEND \ " - QEMU_OPTIONS="-machine accel=kvm:tcg \ --smp $QEMU_SMP \ + QEMU_OPTIONS="-smp $QEMU_SMP \ -net none \ -m 512M \ -nographic \ @@ -80,13 +82,17 @@ $KERNEL_APPEND \ QEMU_OPTIONS="$QEMU_OPTIONS -initrd $INITRD" fi + if [ -c /dev/kvm ]; then + QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host" + fi + ( set -x $QEMU_BIN $QEMU_OPTIONS -append "$KERNEL_APPEND" $TESTDIR/rootdisk.img ) || return 1 } run_nspawn() { set -x - ../../systemd-nspawn --boot --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND + ../../systemd-nspawn --register=no --directory=$TESTDIR/nspawn-root $ROOTLIBDIR/systemd $KERNEL_APPEND } setup_basic_environment() { @@ -105,21 +111,105 @@ setup_basic_environment() { install_keymaps install_terminfo install_execs + install_fsck install_plymouth install_debug_tools install_ld_so_conf + setup_selinux strip_binaries install_depmod_files generate_module_dependencies - # softlink mtab - ln -fs /proc/self/mounts $initdir/etc/mtab +} + +setup_selinux() { + # don't forget KERNEL_APPEND='... selinux=1 ...' + if [[ "$SETUP_SELINUX" != "yes" ]]; then + ddebug "Don't setup SELinux" + return 0 + fi + ddebug "Setup SELinux" + local _conf_dir=/etc/selinux + local _fixfiles_tools="bash uname cat sort uniq awk grep egrep head expr find rm secon setfiles" + + rm -rf $initdir/$_conf_dir + if ! cp -ar $_conf_dir $initdir/$_conf_dir; then + dfatal "Failed to copy $_conf_dir" + exit 1 + fi + + cat <$initdir/etc/systemd/system/autorelabel.service +[Unit] +Description=Relabel all filesystems +DefaultDependencies=no +Requires=local-fs.target +Conflicts=shutdown.target +After=local-fs.target +Before=sysinit.target shutdown.target +ConditionSecurity=selinux +ConditionPathExists=|/.autorelabel + +[Service] +ExecStart=/bin/sh -x -c 'echo 0 >/sys/fs/selinux/enforce && fixfiles -f -F relabel && rm /.autorelabel && systemctl --force reboot' +Type=oneshot +TimeoutSec=0 +RemainAfterExit=yes +EOF + + touch $initdir/.autorelabel + mkdir -p $initdir/etc/systemd/system/basic.target.wants + ln -fs autorelabel.service $initdir/etc/systemd/system/basic.target.wants/autorelabel.service + + dracut_install $_fixfiles_tools + dracut_install fixfiles + dracut_install sestatus +} + +install_valgrind() { + if ! type -p valgrind; then + dfatal "Failed to install valgrind" + exit 1 + fi + + local _valgrind_bins=$(strace -e execve valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if /^execve\("([^"]+)"/') + dracut_install $_valgrind_bins + + local _valgrind_libs=$(LD_DEBUG=files valgrind /bin/true 2>&1 >/dev/null | perl -lne 'print $1 if m{calling init: (/.*vgpreload_.*)}') + dracut_install $_valgrind_libs + + local _valgrind_dbg_and_supp=$( + strace -e open valgrind /bin/true 2>&1 >/dev/null | + perl -lne 'if (my ($fname) = /^open\("([^"]+).*= (?!-)\d+/) { print $fname if $fname =~ /debug|\.supp$/ }' + ) + dracut_install $_valgrind_dbg_and_supp +} + +create_valgrind_wrapper() { + local _valgrind_wrapper=$initdir/$ROOTLIBDIR/systemd-under-valgrind + ddebug "Create $_valgrind_wrapper" + cat >$_valgrind_wrapper </dev/null && dracut_install dmeventd inst_libdir_file "libdevmapper-event.so*" - inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules + if [[ "$LOOKS_LIKE_DEBIAN" ]]; then + # dmsetup installs 55-dm and 60-persistent-storage-dm on Debian/Ubuntu + # see https://anonscm.debian.org/cgit/pkg-lvm/lvm2.git/tree/debian/patches/0007-udev.patch + inst_rules 55-dm.rules 60-persistent-storage-dm.rules + else + inst_rules 10-dm.rules 13-dm-disk.rules 95-dm-notify.rules + fi } install_systemd() { @@ -142,12 +232,12 @@ install_missing_libraries() { create_empty_image() { rm -f "$TESTDIR/rootdisk.img" # Create the blank file to use as a root filesystem - dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=300 + dd if=/dev/null of="$TESTDIR/rootdisk.img" bs=1M seek=400 LOOPDEV=$(losetup --show -P -f $TESTDIR/rootdisk.img) [ -b "$LOOPDEV" ] || return 1 echo "LOOPDEV=$LOOPDEV" >> $STATEFILE sfdisk "$LOOPDEV" < "big major number test", devpath => "/devices/virtual/misc/misc-fake1", exp_name => "node", - exp_majorminor => "4095:1", + exp_majorminor => "511:1", rules => < "big major and big minor number test", devpath => "/devices/virtual/misc/misc-fake89999", exp_name => "node", - exp_majorminor => "4095:89999", + exp_majorminor => "511:89999", rules => <