Merge v242 into tizen
authorŁukasz Stelmach <l.stelmach@samsung.com>
Thu, 25 Jan 2024 12:38:58 +0000 (13:38 +0100)
committerŁukasz Stelmach <l.stelmach@samsung.com>
Thu, 25 Jan 2024 12:38:58 +0000 (13:38 +0100)
Change-Id: I6ce1712eb0f06cfa50cda3d157cfc678f6a6ac41
Signed-off-by: Łukasz Stelmach <l.stelmach@samsung.com>
1208 files changed:
.ctags [new file with mode: 0644]
.dir-locals.el
.lgtm/cpp-queries/PotentiallyDangerousFunction.ql [new file with mode: 0644]
.lgtm/cpp-queries/fgets.ql [deleted file]
.mailmap
.mkosi/mkosi.arch
NEWS
README
README.md
TODO
coccinelle/empty-or-dash.cocci [new file with mode: 0644]
coccinelle/log-json.cocci [new file with mode: 0644]
docs/BOOT_LOADER_SPECIFICATION.md
docs/DISTRO_PORTING.md
docs/ENVIRONMENT.md
docs/PORTABLE_SERVICES.md
docs/RELEASE.md
docs/TEMPORARY_DIRECTORIES.md [new file with mode: 0644]
docs/TRANSIENT-SETTINGS.md
hwdb/20-OUI.hwdb
hwdb/20-acpi-vendor.hwdb
hwdb/20-acpi-vendor.hwdb.patch
hwdb/20-pci-vendor-model.hwdb
hwdb/20-usb-vendor-model.hwdb
hwdb/60-evdev.hwdb
hwdb/60-input-id.hwdb
hwdb/60-keyboard.hwdb
hwdb/60-sensor.hwdb
hwdb/70-mouse.hwdb
hwdb/70-touchpad.hwdb
hwdb/acpi-update.py
hwdb/ids_parser.py
hwdb/ma-large.txt
hwdb/ma-medium.txt
hwdb/ma-small.txt
hwdb/pci.ids
hwdb/usb.ids
man/binfmt.d.xml
man/bootctl.xml
man/bootup.xml
man/busctl.xml
man/coredump.conf.xml
man/coredumpctl.xml
man/crypttab.xml
man/daemon.xml
man/dnssec-trust-anchors.d.xml
man/environment.d.xml
man/file-hierarchy.xml
man/halt.xml
man/hostname.xml
man/hostnamectl.xml
man/hwdb.xml
man/journal-remote.conf.xml
man/journal-upload.conf.xml
man/journalctl.xml
man/journald.conf.xml
man/kernel-command-line.xml
man/kernel-install.xml
man/less-variables.xml
man/libsystemd-pkgconfig.xml
man/libudev.xml
man/loader.conf.xml
man/locale.conf.xml
man/localectl.xml
man/localtime.xml
man/loginctl.xml
man/logind.conf.xml
man/machine-id.xml
man/machine-info.xml
man/machinectl.xml
man/meson.build
man/modules-load.d.xml
man/networkctl.xml
man/networkd.conf.xml
man/nss-myhostname.xml
man/nss-mymachines.xml
man/nss-resolve.xml
man/nss-systemd.xml
man/os-release.xml
man/pam_systemd.xml
man/portablectl.xml
man/resolvectl.xml
man/resolved.conf.xml
man/rules/meson.build
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
man/sd_booted.xml
man/sd_bus_add_match.xml
man/sd_bus_attach_event.xml
man/sd_bus_close.xml
man/sd_bus_creds_get_pid.xml
man/sd_bus_creds_new_from_pid.xml
man/sd_bus_default.xml
man/sd_bus_error.xml
man/sd_bus_error_add_map.xml
man/sd_bus_get_fd.xml
man/sd_bus_get_n_queued_read.xml
man/sd_bus_is_open.xml
man/sd_bus_message_append.xml
man/sd_bus_message_append_array.xml
man/sd_bus_message_append_basic.xml
man/sd_bus_message_append_string_memfd.xml
man/sd_bus_message_append_strv.xml
man/sd_bus_message_copy.xml
man/sd_bus_message_get_cookie.xml
man/sd_bus_message_get_monotonic_usec.xml
man/sd_bus_message_get_signature.xml
man/sd_bus_message_get_type.xml
man/sd_bus_message_new.xml
man/sd_bus_message_new_method_call.xml
man/sd_bus_message_new_method_error.xml
man/sd_bus_message_new_signal.xml
man/sd_bus_message_read.xml
man/sd_bus_message_read_array.xml
man/sd_bus_message_read_basic.xml
man/sd_bus_message_rewind.xml
man/sd_bus_message_set_destination.xml
man/sd_bus_message_set_expect_reply.xml
man/sd_bus_message_skip.xml
man/sd_bus_message_verify_type.xml
man/sd_bus_negotiate_fds.xml
man/sd_bus_new.xml
man/sd_bus_path_encode.xml
man/sd_bus_process.xml
man/sd_bus_reply_method_error.xml
man/sd_bus_request_name.xml
man/sd_bus_set_close_on_exit.xml
man/sd_bus_set_connected_signal.xml
man/sd_bus_set_description.xml
man/sd_bus_set_sender.xml
man/sd_bus_set_watch_bind.xml
man/sd_bus_slot_ref.xml
man/sd_bus_slot_set_description.xml
man/sd_bus_slot_set_destroy_callback.xml
man/sd_bus_slot_set_floating.xml
man/sd_bus_slot_set_userdata.xml
man/sd_bus_track_add_name.xml
man/sd_bus_track_new.xml
man/sd_bus_wait.xml
man/sd_event_add_child.xml
man/sd_event_add_defer.xml
man/sd_event_add_inotify.xml
man/sd_event_add_io.xml
man/sd_event_add_signal.xml
man/sd_event_add_time.xml
man/sd_event_exit.xml
man/sd_event_get_fd.xml
man/sd_event_new.xml
man/sd_event_now.xml
man/sd_event_run.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_destroy_callback.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
man/sd_id128_randomize.xml
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
man/sd_journal_get_data.xml
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
man/sd_journal_query_unique.xml
man/sd_journal_seek_head.xml
man/sd_journal_stream_fd.xml
man/sd_listen_fds.xml
man/sd_login_monitor_new.xml
man/sd_machine_get_class.xml
man/sd_notify.xml
man/sd_pid_get_owner_uid.xml
man/sd_seat_get_active.xml
man/sd_session_is_active.xml
man/sd_uid_get_state.xml
man/sd_watchdog_enabled.xml
man/shutdown.xml
man/standard-conf.xml
man/standard-options.xml
man/sysctl.d.xml
man/system-only.xml [new file with mode: 0644]
man/systemctl.xml
man/systemd-analyze.xml
man/systemd-ask-password-console.service.xml
man/systemd-ask-password.xml
man/systemd-backlight@.service.xml
man/systemd-binfmt.service.xml
man/systemd-bless-boot-generator.xml
man/systemd-bless-boot.service.xml
man/systemd-boot-check-no-failures.service.xml
man/systemd-boot.xml
man/systemd-cat.xml
man/systemd-cgls.xml
man/systemd-cgtop.xml
man/systemd-coredump.xml
man/systemd-cryptsetup-generator.xml
man/systemd-cryptsetup@.service.xml
man/systemd-debug-generator.xml
man/systemd-delta.xml
man/systemd-detect-virt.xml
man/systemd-environment-d-generator.xml
man/systemd-escape.xml
man/systemd-firstboot.xml
man/systemd-fsck@.service.xml
man/systemd-fstab-generator.xml
man/systemd-getty-generator.xml
man/systemd-gpt-auto-generator.xml
man/systemd-halt.service.xml
man/systemd-hibernate-resume-generator.xml
man/systemd-hibernate-resume@.service.xml
man/systemd-hostnamed.service.xml
man/systemd-hwdb.xml
man/systemd-id128.xml
man/systemd-importd.service.xml
man/systemd-inhibit.xml
man/systemd-initctl.service.xml
man/systemd-journal-gatewayd.service.xml
man/systemd-journal-remote.service.xml
man/systemd-journal-upload.service.xml
man/systemd-journald.service.xml
man/systemd-localed.service.xml
man/systemd-logind.service.xml
man/systemd-machine-id-commit.service.xml
man/systemd-machine-id-setup.xml
man/systemd-machined.service.xml
man/systemd-makefs@.service.xml
man/systemd-modules-load.service.xml
man/systemd-mount.xml
man/systemd-networkd-wait-online.service.xml
man/systemd-networkd.service.xml
man/systemd-notify.xml
man/systemd-nspawn.xml
man/systemd-path.xml
man/systemd-portabled.service.xml
man/systemd-quotacheck.service.xml
man/systemd-random-seed.service.xml
man/systemd-rc-local-generator.xml
man/systemd-remount-fs.service.xml
man/systemd-resolved.service.xml
man/systemd-rfkill.service.xml
man/systemd-run-generator.xml
man/systemd-run.xml
man/systemd-sleep.conf.xml
man/systemd-socket-activate.xml
man/systemd-socket-proxyd.xml
man/systemd-suspend.service.xml
man/systemd-sysctl.service.xml
man/systemd-system-update-generator.xml
man/systemd-system.conf.xml
man/systemd-sysusers.xml
man/systemd-sysv-generator.xml
man/systemd-time-wait-sync.service.xml
man/systemd-timedated.service.xml
man/systemd-timesyncd.service.xml
man/systemd-tmpfiles.xml
man/systemd-tty-ask-password-agent.xml
man/systemd-udevd.service.xml
man/systemd-update-done.service.xml
man/systemd-update-utmp.service.xml
man/systemd-user-sessions.service.xml
man/systemd-vconsole-setup.service.xml
man/systemd-veritysetup-generator.xml
man/systemd-veritysetup@.service.xml
man/systemd-volatile-root.service.xml
man/systemd.automount.xml
man/systemd.device.xml
man/systemd.dnssd.xml
man/systemd.environment-generator.xml
man/systemd.exec.xml
man/systemd.generator.xml
man/systemd.journal-fields.xml
man/systemd.kill.xml
man/systemd.link.xml
man/systemd.mount.xml
man/systemd.netdev.xml
man/systemd.network.xml
man/systemd.nspawn.xml
man/systemd.offline-updates.xml
man/systemd.path.xml
man/systemd.preset.xml
man/systemd.resource-control.xml
man/systemd.scope.xml
man/systemd.service.xml
man/systemd.slice.xml
man/systemd.socket.xml
man/systemd.special.xml
man/systemd.swap.xml
man/systemd.syntax.xml
man/systemd.target.xml
man/systemd.time.xml
man/systemd.timer.xml
man/systemd.unit.xml
man/systemd.xml
man/sysusers.d.xml
man/telinit.xml
man/threads-aware.xml
man/timedatectl.xml
man/timesyncd.conf.xml
man/tmpfiles.d.xml
man/udev.conf.xml
man/udev.xml
man/udev_device_get_syspath.xml
man/udev_device_has_tag.xml
man/udev_device_new_from_syspath.xml
man/udev_enumerate_add_match_subsystem.xml
man/udev_enumerate_new.xml
man/udev_enumerate_scan_devices.xml
man/udev_list_entry.xml
man/udev_monitor_filter_update.xml
man/udev_monitor_new_from_netlink.xml
man/udev_monitor_receive_device.xml
man/udev_new.xml
man/udevadm.xml
man/user-system-options.xml
man/user@.service.xml
man/vconsole.conf.xml
meson.build
meson_options.txt
mkosi.build
packaging/systemd.spec
po/fr.po
po/ja.po
po/lt.po
po/pl.po
rules/60-block.rules
rules/99-systemd.rules.in
semaphoreci/gcc-compilation.sh
semaphoreci/setup.sh
shell-completion/bash/busctl
shell-completion/bash/journalctl
shell-completion/bash/systemctl.in
shell-completion/bash/systemd-id128 [new file with mode: 0644]
shell-completion/zsh/_journalctl
src/activate/activate.c
src/analyze/analyze-security.c
src/analyze/analyze-verify.c
src/analyze/analyze.c
src/backlight/backlight.c
src/basic/alloc-util.c
src/basic/alloc-util.h
src/basic/async.c
src/basic/btrfs-util.c
src/basic/capability-util.c
src/basic/capability-util.h
src/basic/cgroup-util.c
src/basic/cgroup-util.h
src/basic/chattr-util.h
src/basic/conf-files.c
src/basic/copy.c
src/basic/copy.h
src/basic/def.h
src/basic/device-nodes.c
src/basic/env-file.c
src/basic/errno-util.h [new file with mode: 0644]
src/basic/fd-util.c
src/basic/fd-util.h
src/basic/fileio.c
src/basic/fileio.h
src/basic/fs-util.c
src/basic/fs-util.h
src/basic/gcrypt-util.c
src/basic/glob-util.c
src/basic/hashmap.c
src/basic/hashmap.h
src/basic/hexdecoct.c
src/basic/hexdecoct.h
src/basic/in-addr-util.c
src/basic/in-addr-util.h
src/basic/kbd-util.c [new file with mode: 0644]
src/basic/kbd-util.h [new file with mode: 0644]
src/basic/limits-util.c [new file with mode: 0644]
src/basic/limits-util.h [new file with mode: 0644]
src/basic/locale-util.c
src/basic/locale-util.h
src/basic/log.c
src/basic/log.h
src/basic/memory-util.c [new file with mode: 0644]
src/basic/memory-util.h [new file with mode: 0644]
src/basic/mempool.c
src/basic/meson.build
src/basic/missing_fs.h
src/basic/missing_socket.h
src/basic/mkdir.c
src/basic/namespace-util.c [new file with mode: 0644]
src/basic/namespace-util.h [new file with mode: 0644]
src/basic/nulstr-util.c [new file with mode: 0644]
src/basic/nulstr-util.h [new file with mode: 0644]
src/basic/ordered-set.c
src/basic/ordered-set.h
src/basic/path-util.c
src/basic/plymouth-util.c [new file with mode: 0644]
src/basic/plymouth-util.h [new file with mode: 0644]
src/basic/process-util.c
src/basic/process-util.h
src/basic/random-util.c
src/basic/refcnt.h [deleted file]
src/basic/rm-rf.c
src/basic/rm-rf.h
src/basic/selinux-util.c
src/basic/sigbus.c
src/basic/socket-label.c
src/basic/socket-util.c
src/basic/socket-util.h
src/basic/sort-util.c [new file with mode: 0644]
src/basic/sort-util.h [new file with mode: 0644]
src/basic/special.h
src/basic/stat-util.c
src/basic/stat-util.h
src/basic/stdio-util.h
src/basic/strbuf.c
src/basic/string-table.h
src/basic/string-util.c
src/basic/string-util.h
src/basic/strv.c
src/basic/strv.h
src/basic/terminal-util.c
src/basic/time-util.c
src/basic/time-util.h
src/basic/user-util.c
src/basic/utf8.c
src/basic/utf8.h
src/basic/util.c
src/basic/util.h
src/basic/virt.c
src/basic/virt.h
src/basic/xattr-util.c
src/binfmt/binfmt.c
src/boot/bless-boot.c
src/boot/bootctl.c
src/boot/efi/boot.c
src/boot/efi/crc32.c [new file with mode: 0644]
src/boot/efi/crc32.h [new file with mode: 0644]
src/boot/efi/linux.c
src/boot/efi/linux.h
src/boot/efi/meson.build
src/boot/efi/stub.c
src/boot/efi/util.c
src/boot/efi/util.h
src/busctl/busctl.c
src/cgls/cgls.c
src/cgtop/cgtop.c
src/core/automount.c
src/core/bpf-firewall.c
src/core/busname.c
src/core/cgroup.c
src/core/cgroup.h
src/core/chown-recursive.c
src/core/chown-recursive.h
src/core/dbus-cgroup.c
src/core/dbus-execute.c
src/core/dbus-manager.c
src/core/dbus-scope.c
src/core/dbus-service.c
src/core/dbus-timer.c
src/core/dbus-unit.c
src/core/dbus-unit.h
src/core/dbus.c
src/core/device.c
src/core/dynamic-user.c
src/core/dynamic-user.h
src/core/emergency-action.c
src/core/emergency-action.h
src/core/execute.c
src/core/execute.h
src/core/ima-setup.c
src/core/job.c
src/core/kill.h
src/core/load-fragment-gperf.gperf.m4
src/core/load-fragment.c
src/core/loopback-setup.c
src/core/machine-id-setup.c
src/core/macros.systemd.in
src/core/main.c
src/core/manager.c
src/core/manager.h
src/core/meson.build
src/core/mount-setup.c
src/core/mount.c
src/core/namespace.c
src/core/namespace.h
src/core/path.c
src/core/scope.c
src/core/selinux-access.c
src/core/selinux-setup.c
src/core/service.c
src/core/service.h
src/core/show-status.c
src/core/smack-setup.c
src/core/socket.c
src/core/swap.c
src/core/systemd.pc.in
src/core/timer.c
src/core/timer.h
src/core/transaction.c
src/core/transaction.h
src/core/unit.c
src/core/unit.h
src/coredump/coredump-vacuum.c
src/coredump/coredump.c
src/coredump/coredumpctl.c
src/coredump/stacktrace.c
src/cryptsetup/cryptsetup-generator.c
src/cryptsetup/cryptsetup.c
src/dbus1-generator/dbus1-generator.c
src/debug-generator/debug-generator.c
src/delta/delta.c
src/environment-d-generator/environment-d-generator.c
src/firstboot/firstboot.c
src/fsck/fsck.c
src/fstab-generator/fstab-generator.c
src/fuzz/fuzz-bus-label.c [new file with mode: 0644]
src/fuzz/fuzz-calendarspec.c [new file with mode: 0644]
src/fuzz/fuzz-dhcp-server.c
src/fuzz/fuzz-dhcp6-client.c
src/fuzz/fuzz-dhcp6-client.options [new file with mode: 0644]
src/fuzz/fuzz-dns-packet.c
src/fuzz/fuzz-env-file.c [new file with mode: 0644]
src/fuzz/fuzz-env-file.options [new file with mode: 0644]
src/fuzz/fuzz-hostname-util.c [new file with mode: 0644]
src/fuzz/fuzz-journald-stream.c
src/fuzz/fuzz-journald-stream.options [new file with mode: 0644]
src/fuzz/fuzz-lldp.c
src/fuzz/fuzz-lldp.options [new file with mode: 0644]
src/fuzz/fuzz-ndisc-rs.c
src/fuzz/fuzz-ndisc-rs.options [new file with mode: 0644]
src/fuzz/fuzz-nspawn-oci.c [new file with mode: 0644]
src/fuzz/fuzz-nspawn-settings.c [new file with mode: 0644]
src/fuzz/fuzz-time-util.c [new file with mode: 0644]
src/fuzz/fuzz-udev-database.c [new file with mode: 0644]
src/fuzz/fuzz-unit-file.c
src/fuzz/meson.build
src/gpt-auto-generator/gpt-auto-generator.c
src/hibernate-resume/hibernate-resume-generator.c
src/hostname/hostnamed.c
src/id128/id128.c
src/import/curl-util.c
src/import/curl-util.h
src/import/export-raw.c
src/import/export.c
src/import/import-common.c
src/import/import-fs.c
src/import/import-raw.c
src/import/import.c
src/import/pull-job.c
src/import/pull-raw.c
src/import/pull-tar.c
src/import/pull.c
src/import/test-qcow2.c
src/initctl/initctl.c
src/journal-remote/journal-gatewayd.c
src/journal-remote/journal-remote-main.c
src/journal-remote/journal-remote-parse.c
src/journal-remote/journal-remote-write.c
src/journal-remote/journal-remote-write.h
src/journal-remote/journal-remote.c
src/journal-remote/journal-upload.c
src/journal/catalog.c
src/journal/catalog.h
src/journal/compress.c
src/journal/fsprg.c
src/journal/journal-authenticate.c
src/journal/journal-file.c
src/journal/journal-file.h
src/journal/journal-send.c
src/journal/journal-vacuum.c
src/journal/journal-verify.c
src/journal/journalctl.c
src/journal/journald-context.h
src/journal/journald-native.c
src/journal/journald-rate-limit.c
src/journal/journald-rate-limit.h
src/journal/journald-server.h
src/journal/journald-stream.c
src/journal/journald-wall.h
src/journal/mmap-cache.c
src/journal/sd-journal.c
src/journal/test-compress-benchmark.c
src/journal/test-compress.c
src/journal/test-journal-flush.c
src/journal/test-journal-init.c
src/journal/test-journal-interleaving.c
src/journal/test-journal-stream.c
src/journal/test-journal-verify.c
src/journal/test-journal.c
src/kernel-install/00-entry-directory.install [new file with mode: 0644]
src/kernel-install/50-depmod.install
src/kernel-install/90-loaderentry.install
src/kernel-install/kernel-install
src/kernel-install/meson.build
src/libsystemd-network/dhcp-identifier.c
src/libsystemd-network/dhcp-lease-internal.h
src/libsystemd-network/dhcp-network.c
src/libsystemd-network/dhcp-option.c
src/libsystemd-network/dhcp-server-internal.h
src/libsystemd-network/dhcp6-option.c
src/libsystemd-network/icmp6-util.c
src/libsystemd-network/lldp-neighbor.c
src/libsystemd-network/ndisc-internal.h
src/libsystemd-network/ndisc-router.c
src/libsystemd-network/network-internal.c
src/libsystemd-network/network-internal.h
src/libsystemd-network/sd-dhcp-client.c
src/libsystemd-network/sd-dhcp-lease.c
src/libsystemd-network/sd-dhcp6-client.c
src/libsystemd-network/sd-ipv4acd.c
src/libsystemd-network/sd-ipv4ll.c
src/libsystemd-network/sd-lldp.c
src/libsystemd-network/sd-ndisc.c
src/libsystemd-network/sd-radv.c
src/libsystemd-network/test-dhcp-client.c
src/libsystemd-network/test-dhcp-option.c
src/libsystemd-network/test-dhcp6-client.c
src/libsystemd-network/test-lldp.c
src/libsystemd-network/test-ndisc-ra.c
src/libsystemd-network/test-ndisc-rs.c
src/libsystemd/sd-bus/bus-container.c
src/libsystemd/sd-bus/bus-control-kernel.c
src/libsystemd/sd-bus/bus-control.c
src/libsystemd/sd-bus/bus-convenience.c
src/libsystemd/sd-bus/bus-error.c
src/libsystemd/sd-bus/bus-internal.c
src/libsystemd/sd-bus/bus-internal.h
src/libsystemd/sd-bus/bus-introspect.c
src/libsystemd/sd-bus/bus-kernel.c
src/libsystemd/sd-bus/bus-match.c
src/libsystemd/sd-bus/bus-message.c
src/libsystemd/sd-bus/bus-message.h
src/libsystemd/sd-bus/bus-objects.c
src/libsystemd/sd-bus/bus-objects.h
src/libsystemd/sd-bus/bus-signature.c
src/libsystemd/sd-bus/bus-slot.c
src/libsystemd/sd-bus/bus-socket.c
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-bus/test-bus-address.c
src/libsystemd/sd-bus/test-bus-benchmark.c
src/libsystemd/sd-bus/test-bus-cleanup.c
src/libsystemd/sd-bus/test-bus-introspect.c
src/libsystemd/sd-bus/test-bus-match.c
src/libsystemd/sd-bus/test-bus-queue-ref-cycle.c [new file with mode: 0644]
src/libsystemd/sd-bus/test-bus-server.c
src/libsystemd/sd-bus/test-bus-vtable.c
src/libsystemd/sd-bus/test-bus-watch-bind.c
src/libsystemd/sd-device/device-enumerator-private.h
src/libsystemd/sd-device/device-enumerator.c
src/libsystemd/sd-device/device-internal.h
src/libsystemd/sd-device/device-private.c
src/libsystemd/sd-device/device-private.h
src/libsystemd/sd-device/sd-device.c
src/libsystemd/sd-device/test-sd-device.c
src/libsystemd/sd-event/sd-event.c
src/libsystemd/sd-hwdb/hwdb-util.c
src/libsystemd/sd-hwdb/sd-hwdb.c
src/libsystemd/sd-id128/sd-id128.c
src/libsystemd/sd-login/sd-login.c
src/libsystemd/sd-login/test-login.c
src/libsystemd/sd-netlink/generic-netlink.c
src/libsystemd/sd-netlink/local-addresses.c
src/libsystemd/sd-netlink/netlink-internal.h
src/libsystemd/sd-netlink/netlink-message.c
src/libsystemd/sd-netlink/netlink-socket.c
src/libsystemd/sd-netlink/netlink-types.c
src/libsystemd/sd-netlink/netlink-util.c
src/libsystemd/sd-netlink/netlink-util.h
src/libsystemd/sd-netlink/rtnl-message.c
src/libsystemd/sd-netlink/sd-netlink.c
src/libsystemd/sd-netlink/test-local-addresses.c
src/libsystemd/sd-network/network-util.c
src/libsystemd/sd-network/network-util.h
src/libsystemd/sd-network/sd-network.c
src/libsystemd/sd-resolve/sd-resolve.c
src/libudev/libudev-device.c
src/libudev/libudev-enumerate.c
src/libudev/libudev-list.c
src/libudev/libudev-util.c
src/locale/keymap-util.c
src/locale/localectl.c
src/locale/localed.c
src/locale/test-keymap-util.c
src/login/70-uaccess.rules.m4
src/login/71-seat.rules.in
src/login/inhibit.c
src/login/loginctl.c
src/login/logind-core.c
src/login/logind-dbus.c
src/login/logind-inhibit.c
src/login/logind-seat.c
src/login/logind-session-device.c
src/login/logind-session.c
src/login/logind-user.c
src/login/logind.c
src/login/logind.h
src/login/org.freedesktop.login1.conf
src/login/org.freedesktop.login1.policy
src/login/pam_systemd.c
src/login/test-inhibit.c
src/login/user-runtime-dir.c
src/machine/machine-dbus.c
src/machine/machine.c
src/machine/machine.h
src/machine/machinectl.c
src/machine/machined.c
src/mount/mount-tool.c
src/network/fuzz-netdev-parser.c
src/network/fuzz-network-parser.c
src/network/fuzz-network-parser.options [new file with mode: 0644]
src/network/meson.build
src/network/netdev/bond.c
src/network/netdev/fou-tunnel.c
src/network/netdev/fou-tunnel.h
src/network/netdev/geneve.c
src/network/netdev/l2tp-tunnel.c [new file with mode: 0644]
src/network/netdev/l2tp-tunnel.h [new file with mode: 0644]
src/network/netdev/netdev-gperf.gperf
src/network/netdev/netdev.c
src/network/netdev/netdev.h
src/network/netdev/tunnel.c
src/network/netdev/tunnel.h
src/network/netdev/vxlan.c
src/network/netdev/wireguard.c
src/network/netdev/wireguard.h
src/network/networkctl.c
src/network/networkd-address-label.c
src/network/networkd-address-label.h
src/network/networkd-address-pool.c
src/network/networkd-address-pool.h
src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-dhcp4.c
src/network/networkd-dhcp6.c
src/network/networkd-fdb.c
src/network/networkd-fdb.h
src/network/networkd-ipv4ll.c
src/network/networkd-ipv6-proxy-ndp.c
src/network/networkd-ipv6-proxy-ndp.h
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-ndisc.c
src/network/networkd-ndisc.h
src/network/networkd-neighbor.c
src/network/networkd-neighbor.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/networkd-radv.c
src/network/networkd-radv.h
src/network/networkd-route.c
src/network/networkd-route.h
src/network/networkd-routing-policy-rule.c
src/network/networkd-routing-policy-rule.h
src/network/networkd-util.c
src/network/networkd-util.h
src/network/networkd.c
src/network/test-networkd-conf.c
src/network/wait-online/link.c
src/network/wait-online/link.h
src/network/wait-online/manager.c
src/network/wait-online/manager.h
src/network/wait-online/wait-online.c
src/nspawn/meson.build
src/nspawn/nspawn-cgroup.c
src/nspawn/nspawn-gperf.gperf
src/nspawn/nspawn-mount.c
src/nspawn/nspawn-mount.h
src/nspawn/nspawn-oci.c [new file with mode: 0644]
src/nspawn/nspawn-oci.h [new file with mode: 0644]
src/nspawn/nspawn-patch-uid.c
src/nspawn/nspawn-register.c
src/nspawn/nspawn-register.h
src/nspawn/nspawn-seccomp.c
src/nspawn/nspawn-settings.c
src/nspawn/nspawn-settings.h
src/nspawn/nspawn-setuid.c
src/nspawn/nspawn-setuid.h
src/nspawn/nspawn-stub-pid1.c
src/nspawn/nspawn.c
src/nss-myhostname/nss-myhostname.c
src/nss-mymachines/nss-mymachines.c
src/nss-resolve/nss-resolve.c
src/nss-systemd/nss-systemd.c
src/partition/growfs.c
src/portable/org.freedesktop.portable1.conf
src/portable/portable.c
src/portable/portabled-bus.c
src/portable/portabled-image-bus.c
src/portable/portabled.c
src/quotacheck/quotacheck.c
src/random-seed/random-seed.c
src/remount-fs/remount-fs.c
src/reply-password/reply-password.c
src/resolve/resolvectl.c
src/resolve/resolved-bus.c
src/resolve/resolved-dns-answer.c
src/resolve/resolved-dns-dnssec.c
src/resolve/resolved-dns-packet.c
src/resolve/resolved-dns-packet.h
src/resolve/resolved-dns-query.c
src/resolve/resolved-dns-question.c
src/resolve/resolved-dns-question.h
src/resolve/resolved-dns-rr.c
src/resolve/resolved-dns-rr.h
src/resolve/resolved-dns-stream.c
src/resolve/resolved-dns-stream.h
src/resolve/resolved-dns-stub.c
src/resolve/resolved-dns-transaction.c
src/resolve/resolved-dns-trust-anchor.c
src/resolve/resolved-dnssd.c
src/resolve/resolved-etc-hosts.c
src/resolve/resolved-llmnr.c
src/resolve/resolved-manager.c
src/resolve/resolved-manager.h
src/resolve/resolved-mdns.c
src/resolve/resolved-resolv-conf.c
src/resolve/resolved.c
src/resolve/test-resolved-etc-hosts.c
src/resolve/test-resolved-packet.c
src/rfkill/rfkill.c
src/run-generator/run-generator.c
src/run/run.c
src/shared/acl-util.c
src/shared/ask-password-api.c
src/shared/base-filesystem.c
src/shared/bitmap.c
src/shared/bootspec.c
src/shared/bootspec.h
src/shared/bpf-program.c
src/shared/bus-unit-procs.c [new file with mode: 0644]
src/shared/bus-unit-procs.h [new file with mode: 0644]
src/shared/bus-unit-util.c
src/shared/bus-unit-util.h
src/shared/bus-util.c
src/shared/bus-util.h
src/shared/bus-wait-for-jobs.c [new file with mode: 0644]
src/shared/bus-wait-for-jobs.h [new file with mode: 0644]
src/shared/calendarspec.c
src/shared/cgroup-show.c
src/shared/clock-util.c
src/shared/condition.c
src/shared/condition.h
src/shared/conf-parser.c
src/shared/conf-parser.h
src/shared/crypt-util.h
src/shared/dev-setup.c
src/shared/dissect-image.c
src/shared/dissect-image.h
src/shared/efivars.c
src/shared/efivars.h
src/shared/exec-util.c
src/shared/exec-util.h
src/shared/fdset.c
src/shared/fdset.h
src/shared/format-table.c
src/shared/fstab-util.c
src/shared/fstab-util.h
src/shared/generator.c
src/shared/generator.h
src/shared/gpt.h
src/shared/import-util.c
src/shared/install.c
src/shared/json.c
src/shared/json.h
src/shared/libmount-util.h [new file with mode: 0644]
src/shared/log-link.h [new file with mode: 0644]
src/shared/logs-show.c
src/shared/machine-image.c
src/shared/main-func.h
src/shared/meson.build
src/shared/mount-util.c
src/shared/mount-util.h
src/shared/pager.c
src/shared/pe-header.h [new file with mode: 0644]
src/shared/pretty-print.c
src/shared/reboot-util.c
src/shared/reboot-util.h
src/shared/seccomp-util.c
src/shared/seccomp-util.h
src/shared/serialize.h
src/shared/sleep-config.c
src/shared/specifier.c
src/shared/sysctl-util.c
src/shared/sysctl-util.h
src/shared/udev-util.c
src/shared/udev-util.h
src/shared/uid-range.c
src/shared/utmp-wtmp.c
src/shared/volatile-util.c
src/shared/volatile-util.h
src/shutdown/meson.build [new file with mode: 0644]
src/shutdown/shutdown.c [moved from src/core/shutdown.c with 97% similarity]
src/shutdown/umount.c [moved from src/core/umount.c with 95% similarity]
src/shutdown/umount.h [moved from src/core/umount.h with 100% similarity]
src/sleep/sleep.c
src/socket-proxy/socket-proxyd.c
src/stdio-bridge/stdio-bridge.c
src/sysctl/sysctl.c
src/systemctl/systemctl.c
src/systemctl/sysv-compat.c [new file with mode: 0644]
src/systemctl/sysv-compat.h [new file with mode: 0644]
src/systemd/sd-bus-vtable.h
src/systemd/sd-bus.h
src/systemd/sd-dhcp-lease.h
src/systemd/sd-event.h
src/systemd/sd-netlink.h
src/systemd/sd-network.h
src/sysusers/sysusers.c
src/test/meson.build
src/test/test-alloc-util.c
src/test/test-async.c
src/test/test-barrier.c
src/test/test-boot-timestamps.c
src/test/test-cap-list.c
src/test/test-capability.c
src/test/test-cgroup-cpu.c [new file with mode: 0644]
src/test/test-chown-rec.c
src/test/test-condition.c
src/test/test-copy.c
src/test/test-daemon.c
src/test/test-date.c
src/test/test-engine.c
src/test/test-exec-util.c
src/test/test-execute.c
src/test/test-fd-util.c
src/test/test-fileio.c
src/test/test-fs-util.c
src/test/test-fstab-util.c
src/test/test-hashmap-plain.c
src/test/test-hostname-util.c
src/test/test-id128.c
src/test/test-in-addr-util.c
src/test/test-install-root.c
src/test/test-json.c
src/test/test-libmount.c [new file with mode: 0644]
src/test/test-libudev.c
src/test/test-locale-util.c
src/test/test-log.c
src/test/test-mountpoint-util.c
src/test/test-namespace.c
src/test/test-nss.c
src/test/test-ordered-set.c [new file with mode: 0644]
src/test/test-path-util.c
src/test/test-pretty-print.c
src/test/test-prioq.c
src/test/test-proc-cmdline.c
src/test/test-process-util.c
src/test/test-replace-var.c
src/test/test-rlimit-util.c
src/test/test-seccomp.c
src/test/test-set.c
src/test/test-sigbus.c
src/test/test-siphash24.c
src/test/test-sleep.c
src/test/test-socket-util.c
src/test/test-stat-util.c
src/test/test-string-util.c
src/test/test-strv.c
src/test/test-tables.c
src/test/test-terminal-util.c
src/test/test-time-util.c
src/test/test-unaligned.c
src/test/test-unit-file.c
src/test/test-unit-name.c
src/test/test-user-util.c
src/test/test-utf8.c
src/test/test-util.c
src/test/test-verbs.c
src/test/test-watch-pid.c
src/timedate/timedatectl.c
src/timedate/timedated.c
src/timesync/timesyncd-manager.c
src/timesync/timesyncd.c
src/tmpfiles/tmpfiles.c
src/tty-ask-password-agent/tty-ask-password-agent.c
src/udev/ata_id/ata_id.c
src/udev/cdrom_id/cdrom_id.c
src/udev/meson.build
src/udev/net/ethtool-util.c
src/udev/net/fuzz-link-parser.c [new file with mode: 0644]
src/udev/net/fuzz-link-parser.options [new file with mode: 0644]
src/udev/net/link-config-gperf.gperf
src/udev/net/link-config.c
src/udev/net/link-config.h
src/udev/scsi_id/scsi_serial.c
src/udev/udev-builtin-usb_id.c
src/udev/udev-builtin.c
src/udev/udev-ctrl.c
src/udev/udev-ctrl.h
src/udev/udev-event.c
src/udev/udev-node.c
src/udev/udev-node.h
src/udev/udev-rules.c
src/udev/udev.h
src/udev/udevadm-control.c
src/udev/udevadm-info.c
src/udev/udevadm-monitor.c
src/udev/udevadm-settle.c
src/udev/udevadm-test.c
src/udev/udevadm-trigger.c
src/udev/udevadm.c
src/udev/udevd.c
src/udev/v4l_id/v4l_id.c
src/update-done/update-done.c
src/update-utmp/update-utmp.c
src/user-sessions/user-sessions.c
src/vconsole/vconsole-setup.c
src/volatile-root/volatile-root.c
test/README.testsuite
test/TEST-02-CRYPTSETUP/test.sh
test/TEST-03-JOBS/test-jobs.sh
test/TEST-04-JOURNAL/test-journal.sh
test/TEST-11-ISSUE-3166/test.sh
test/TEST-20-MAINPIDGAMES/testsuite.sh
test/TEST-22-TMPFILES/test-08.sh [new file with mode: 0755]
test/TEST-23-TYPE-EXEC/testsuite.sh
test/TEST-24-UNIT-TESTS/test.sh
test/TEST-24-UNIT-TESTS/testsuite.sh
test/TEST-27-STDOUTFILE/testsuite.sh
test/TEST-29-UDEV-ID_RENAMING/Makefile [new symlink]
test/TEST-29-UDEV-ID_RENAMING/test.sh [new file with mode: 0755]
test/TEST-29-UDEV-ID_RENAMING/testsuite.sh [new file with mode: 0755]
test/TEST-30-ONCLOCKCHANGE/Makefile [new symlink]
test/TEST-30-ONCLOCKCHANGE/test.sh [new file with mode: 0755]
test/TEST-30-ONCLOCKCHANGE/testsuite.sh [new file with mode: 0755]
test/TEST-31-DEVICE-ENUMERATION/Makefile [new symlink]
test/TEST-31-DEVICE-ENUMERATION/test.sh [new file with mode: 0755]
test/TEST-31-DEVICE-ENUMERATION/testsuite.sh [new file with mode: 0755]
test/fuzz/fuzz-bus-message/oss-fuzz-14016 [new file with mode: 0644]
test/fuzz/fuzz-calendarspec/oss-fuzz-14108 [new file with mode: 0644]
test/fuzz/fuzz-dns-packet/oss-fuzz-13422 [new file with mode: 0644]
test/fuzz/fuzz-env-file/simple-env-file [new file with mode: 0644]
test/fuzz/fuzz-journal-remote/oss-fuzz-9341 [new file with mode: 0644]
test/fuzz/fuzz-link-parser/99-default.link [new file with mode: 0644]
test/fuzz/fuzz-link-parser/advertise-segv.link [new file with mode: 0644]
test/fuzz/fuzz-link-parser/condition-memleak.link [new file with mode: 0644]
test/fuzz/fuzz-link-parser/directives.link [new file with mode: 0644]
test/fuzz/fuzz-link-parser/oss-fuzz-13878 [new file with mode: 0644]
test/fuzz/fuzz-link-parser/oss-fuzz-13882 [new file with mode: 0644]
test/fuzz/fuzz-netdev-parser/directives.netdev
test/fuzz/fuzz-netdev-parser/oss-fuzz-13719 [new file with mode: 0644]
test/fuzz/fuzz-netdev-parser/oss-fuzz-13884 [new file with mode: 0644]
test/fuzz/fuzz-netdev-parser/oss-fuzz-13886 [new file with mode: 0644]
test/fuzz/fuzz-netdev-parser/oss-fuzz-14157 [new file with mode: 0644]
test/fuzz/fuzz-netdev-parser/oss-fuzz-14158 [new file with mode: 0644]
test/fuzz/fuzz-network-parser/directives.network
test/fuzz/fuzz-network-parser/oss-fuzz-13059 [new file with mode: 0644]
test/fuzz/fuzz-network-parser/oss-fuzz-13354 [new file with mode: 0644]
test/fuzz/fuzz-network-parser/oss-fuzz-13433 [new file with mode: 0644]
test/fuzz/fuzz-network-parser/oss-fuzz-13888 [new file with mode: 0644]
test/fuzz/fuzz-nspawn-oci/basic.json [new file with mode: 0644]
test/fuzz/fuzz-nspawn-oci/crash-bffbd2085d4e95c47e9749b3f4a2dbc0580c20d3 [new file with mode: 0644]
test/fuzz/fuzz-nspawn-oci/crash-db0595479ee2e625fa5419a821009b5eb4d809b7 [new file with mode: 0644]
test/fuzz/fuzz-nspawn-settings/basic-config [new file with mode: 0644]
test/fuzz/fuzz-nspawn-settings/leak-4ff0e2498f596a77ea68d185c61e9e9ff9bb657f [new file with mode: 0644]
test/fuzz/fuzz-nspawn-settings/oss-fuzz-13691 [new file with mode: 0644]
test/fuzz/fuzz-udev-database/sample.txt [new file with mode: 0644]
test/fuzz/fuzz-unit-file/directives.service
test/fuzz/fuzz-unit-file/oss-fuzz-13125 [new file with mode: 0644]
test/fuzz/fuzz-unit-file/systemd-machined.service
test/fuzz/meson.build
test/meson.build
test/networkd-test.py
test/test-execute/exec-environment-no-substitute.service [new file with mode: 0644]
test/test-execute/exec-inaccessiblepaths-sys.service [moved from test/test-execute/exec-inaccessiblepaths-proc.service with 63% similarity]
test/test-execute/exec-protecthome-tmpfs-vs-protectsystem-strict.service [new file with mode: 0644]
test/test-functions
test/test-network/conf/11-dummy.network [new file with mode: 0644]
test/test-network/conf/15-name-conflict-test.netdev [new file with mode: 0644]
test/test-network/conf/21-macvlan.netdev
test/test-network/conf/21-vlan-test1.network [new file with mode: 0644]
test/test-network/conf/21-vlan-test1.network.d/override.conf [new file with mode: 0644]
test/test-network/conf/21-vlan.netdev.d/override.conf
test/test-network/conf/21-vlan.network
test/test-network/conf/21-vlan.network.d/override.conf [deleted file]
test/test-network/conf/25-address-preferred-lifetime-zero-ipv6.network [new file with mode: 0644]
test/test-network/conf/25-address-section-miscellaneous.network [deleted file]
test/test-network/conf/25-address-section.network [deleted file]
test/test-network/conf/25-address-static.network [new file with mode: 0644]
test/test-network/conf/25-bind-carrier.network [new file with mode: 0644]
test/test-network/conf/25-bridge.network [new file with mode: 0644]
test/test-network/conf/25-erspan-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-erspan-tunnel.netdev
test/test-network/conf/25-fou-gre.netdev [new file with mode: 0644]
test/test-network/conf/25-fou-gretap.netdev [new file with mode: 0644]
test/test-network/conf/25-fou-ipip.netdev [new file with mode: 0644]
test/test-network/conf/25-fou-ipproto-gre.netdev [new file with mode: 0644]
test/test-network/conf/25-fou-ipproto-ipip.netdev [new file with mode: 0644]
test/test-network/conf/25-fou-sit.netdev [new file with mode: 0644]
test/test-network/conf/25-gre-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-gre-tunnel-remote-any.netdev [new file with mode: 0644]
test/test-network/conf/25-gre-tunnel.netdev
test/test-network/conf/25-gretap-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-gretap-tunnel.netdev
test/test-network/conf/25-ip6gre-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-ip6gre-tunnel-remote-any.netdev [new file with mode: 0644]
test/test-network/conf/25-ip6gre-tunnel.netdev
test/test-network/conf/25-ip6gretap-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-ip6gretap-tunnel.netdev [new file with mode: 0644]
test/test-network/conf/25-ip6tnl-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-ip6tnl-tunnel-remote-any.netdev [new file with mode: 0644]
test/test-network/conf/25-ipip-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-ipip-tunnel-remote-any.netdev [new file with mode: 0644]
test/test-network/conf/25-l2tp-dummy.network [new file with mode: 0644]
test/test-network/conf/25-l2tp-ip.netdev [new file with mode: 0644]
test/test-network/conf/25-l2tp-udp.netdev [new file with mode: 0644]
test/test-network/conf/25-link-local-addressing-yes.network
test/test-network/conf/25-route-gateway-on-link.network [deleted file]
test/test-network/conf/25-route-gateway.network [deleted file]
test/test-network/conf/25-route-reverse-order.network [deleted file]
test/test-network/conf/25-route-section.network [deleted file]
test/test-network/conf/25-route-static.network [new file with mode: 0644]
test/test-network/conf/25-route-tcp-window-settings.network [deleted file]
test/test-network/conf/25-route-type.network [deleted file]
test/test-network/conf/25-sit-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-sit-tunnel-remote-any.netdev [new file with mode: 0644]
test/test-network/conf/25-sysctl-disable-ipv6.network [new file with mode: 0644]
test/test-network/conf/25-sysctl.network
test/test-network/conf/25-vrf.network [new file with mode: 0644]
test/test-network/conf/25-vti-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-vti-tunnel-remote-any.netdev [new file with mode: 0644]
test/test-network/conf/25-vti6-tunnel-local-any.netdev [new file with mode: 0644]
test/test-network/conf/25-vti6-tunnel-remote-any.netdev [new file with mode: 0644]
test/test-network/conf/25-wireguard-23-peers.netdev
test/test-network/conf/25-wireguard-preshared-key.txt [new file with mode: 0644]
test/test-network/conf/25-wireguard-private-key.txt [new file with mode: 0644]
test/test-network/conf/25-wireguard.netdev.d/peer.conf [new file with mode: 0644]
test/test-network/conf/25-wireguard.network [new file with mode: 0644]
test/test-network/conf/26-bridge-slave-interface-1.network
test/test-network/conf/bond-slave.network [new file with mode: 0644]
test/test-network/conf/bond99.network [new file with mode: 0644]
test/test-network/conf/bridge99-ignore-carrier-loss.network [new file with mode: 0644]
test/test-network/conf/bridge99.network
test/test-network/conf/dhcp-client-gateway-onlink-implicit.network [new file with mode: 0644]
test/test-network/conf/dhcp-client-ipv4-dhcp-settings.network
test/test-network/conf/dhcp-client-vrf.network [new file with mode: 0644]
test/test-network/conf/dhcp-server.network
test/test-network/conf/erspan.network [new file with mode: 0644]
test/test-network/conf/gretap.network
test/test-network/conf/gretun.network
test/test-network/conf/ip6gretap.network
test/test-network/conf/ip6gretun.network [new file with mode: 0644]
test/test-network/conf/ip6tnl.network
test/test-network/conf/ipip.network
test/test-network/conf/routing-policy-rule-dummy98.network [new file with mode: 0644]
test/test-network/conf/routing-policy-rule-test1.network [moved from test/test-network/conf/routing-policy-rule.network with 100% similarity]
test/test-network/conf/sit.network
test/test-network/conf/test-static.network [deleted file]
test/test-network/conf/vlan6.netdev [new file with mode: 0644]
test/test-network/conf/vlan6.network [new file with mode: 0644]
test/test-network/conf/vti.network
test/test-network/conf/vti6.network
test/test-network/systemd-networkd-tests.py
test/udev-test.pl
tools/check-directives.sh
tools/meson-hwdb-update.sh
travis-ci/managers/debian.sh
units/dev-mqueue.mount
units/meson.build
units/proc-sys-fs-binfmt_misc.mount
units/sys-fs-fuse-connections.mount
units/sys-kernel-config.mount
units/sys-kernel-debug.mount
units/system-update-cleanup.service
units/systemd-coredump@.service.in
units/systemd-hostnamed.service.in
units/systemd-importd.service.in
units/systemd-journal-catalog-update.service.in
units/systemd-journal-gatewayd.service.in
units/systemd-journal-remote.service.in
units/systemd-journal-upload.service.in
units/systemd-journald.service.in
units/systemd-localed.service.in
units/systemd-logind.service.in
units/systemd-machined.service.in
units/systemd-networkd.service.in
units/systemd-portabled.service.in
units/systemd-remount-fs.service.in
units/systemd-resolved.service.in
units/systemd-timedated.service.in
units/systemd-timesyncd.service.in
units/systemd-tmpfiles-clean.service.in
units/systemd-udevd.service.in
units/time-set.target [new file with mode: 0644]
units/time-sync.target
units/tmp.mount.m4
units/usb-gadget.target [new file with mode: 0644]
units/user/default.target
units/user@.service.in

diff --git a/.ctags b/.ctags
new file mode 100644 (file)
index 0000000..a75e12e
--- /dev/null
+++ b/.ctags
@@ -0,0 +1 @@
+--links=no
index 676d755..815afe1 100644 (file)
@@ -15,7 +15,8 @@
             (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))))
+            (eval . (c-set-offset 'arglist-close 0))
+            (eval . (c-set-offset 'arglist-cont-nonempty '(c-lineup-gcc-asm-reg c-lineup-arglist)))))
  (nxml-mode . ((nxml-child-indent . 2)
                (fill-column . 109)))
  (meson-mode . ((meson-indent-basic . 8)))
diff --git a/.lgtm/cpp-queries/PotentiallyDangerousFunction.ql b/.lgtm/cpp-queries/PotentiallyDangerousFunction.ql
new file mode 100644 (file)
index 0000000..8653304
--- /dev/null
@@ -0,0 +1,54 @@
+/**
+ * @name Use of potentially dangerous function
+ * @description Certain standard library functions are dangerous to call.
+ * @kind problem
+ * @problem.severity error
+ * @precision high
+ * @id cpp/potentially-dangerous-function
+ * @tags reliability
+ *       security
+ *
+ * Borrowed from
+ * https://github.com/Semmle/ql/blob/master/cpp/ql/src/Security/CWE/CWE-676/PotentiallyDangerousFunction.ql
+ */
+import cpp
+
+predicate potentiallyDangerousFunction(Function f, string message) {
+  (
+    f.getQualifiedName() = "fgets" and
+    message = "Call to fgets() is potentially dangerous. Use read_line() instead."
+  ) or (
+    f.getQualifiedName() = "strtok" and
+    message = "Call to strtok() is potentially dangerous. Use extract_first_word() instead."
+  ) or (
+    f.getQualifiedName() = "strsep" and
+    message = "Call to strsep() is potentially dangerous. Use extract_first_word() instead."
+  ) or (
+    f.getQualifiedName() = "dup" and
+    message = "Call to dup() is potentially dangerous. Use fcntl(fd, FD_DUPFD_CLOEXEC, 3) instead."
+  ) or (
+    f.getQualifiedName() = "htonl" and
+    message = "Call to htonl() is confusing. Use htobe32() instead."
+  ) or (
+    f.getQualifiedName() = "htons" and
+    message = "Call to htons() is confusing. Use htobe16() instead."
+  ) or (
+    f.getQualifiedName() = "ntohl" and
+    message = "Call to ntohl() is confusing. Use be32toh() instead."
+  ) or (
+    f.getQualifiedName() = "ntohs" and
+    message = "Call to ntohs() is confusing. Use be16toh() instead."
+  ) or (
+    f.getQualifiedName() = "strerror" and
+    message = "Call to strerror() is not thread-safe. Use strerror_r() or printf()'s %m format string instead."
+  ) or (
+    f.getQualifiedName() = "accept" and
+    message = "Call to accept() is not O_CLOEXEC-safe. Use accept4() instead."
+  )
+}
+
+from FunctionCall call, Function target, string message
+where
+  call.getTarget() = target and
+  potentiallyDangerousFunction(target, message)
+select call, message
diff --git a/.lgtm/cpp-queries/fgets.ql b/.lgtm/cpp-queries/fgets.ql
deleted file mode 100644 (file)
index a4181e4..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * @name Use of fgets()
- * @description fgets() is dangerous to call. Use read_line() instead.
- * @kind problem
- * @problem.severity error
- * @precision high
- * @id cpp/fgets
- * @tags reliability
- *       security
- */
-import cpp
-
-predicate dangerousFunction(Function function) {
-  exists (string name | name = function.getQualifiedName() |
-    name = "fgets")
-}
-
-from FunctionCall call, Function target
-where call.getTarget() = target
-  and dangerousFunction(target)
-select call, target.getQualifiedName() + " is potentially dangerous"
index abde31e..4764ad6 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -198,3 +198,5 @@ David Santamaría Rogado <howl.nsp@gmail.com>
 Mike Auty <mike.auty@gmail.com>
 Roger James <roger@beardandsandals.co.uk>
 Stephan Edel <se@se-it.eu>
+Andrey Yashkin <38919268+AndreyYashkin@users.noreply.github.com>
+Ronald Tschalär <ronald@innovation.ch>
index aabfd52..0561fec 100644 (file)
@@ -13,7 +13,7 @@ Format=raw_btrfs
 Bootable=yes
 
 [Partitions]
-RootSize=2G
+RootSize=3G
 
 [Packages]
 Cache=/var/cache/pacman/pkg/
diff --git a/NEWS b/NEWS
index cd81d9c..98d5a16 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,268 @@
 systemd System and Service Manager
 
+CHANGES WITH 242:
+
+        * In .link files, MACAddressPolicy=persistent (the default) is changed
+          to cover more devices. For devices like bridges, tun, tap, bond, and
+          similar interfaces that do not have other identifying information,
+          the interface name is used as the basis for persistent seed for MAC
+          and IPv4LL addresses. The way that devices that were handled
+          previously is not changed, and this change is about covering more
+          devices then previously by the "persistent" policy.
+
+          MACAddressPolicy=random may be used to force randomized MACs and
+          IPv4LL addresses for a device if desired.
+
+          Hint: the log output from udev (at debug level) was enhanced to
+          clarify what policy is followed and which attributes are used.
+          `SYSTEMD_LOG_LEVEL=debug udevadm test-builtin net_setup_link /sys/class/net/<name>`
+          may be used to view this.
+
+        * The .device units generated by systemd-fstab-generator and other
+          generators do not automatically pull in the corresponding .mount unit
+          as a Wants= dependency. This means that simply plugging in the device
+          will not cause the mount unit to be started automatically. But please
+          note that the mount unit may be started for other reasons, in
+          particular if it is part of local-fs.target, and any unit which
+          (transitively) depends on local-fs.target is started.
+
+        * networkctl list/status/lldp now accept globbing wildcards for network
+          interface names to match against all existing interfaces.
+
+        * The $PIDFILE environment variable is set to point the absolute path
+          configured with PIDFile= for processes of that service.
+
+        * The fallback DNS server list was augmented with Cloudflare public DNS
+          servers. Use `-Ddns-servers=` to set a different fallback.
+
+        * A new special target usb-gadget.target will be started automatically
+          when a USB Device Controller is detected (which means that the system
+          is a USB peripheral).
+
+        * A new unit setting CPUQuotaPeriodSec= assigns the time period
+          relatively to which the CPU time quota specified by CPUQuota= is
+          measured.
+
+        * A new unit setting ProtectHostname= may be used to prevent services
+          from modifying hostname information (even if they otherwise would
+          have privileges to do so).
+
+        * A new unit setting NetworkNamespacePath= may be used to specify a
+          namespace for service or socket units through a path referring to a
+          Linux network namespace pseudo-file.
+
+        * The PrivateNetwork= setting and JoinsNamespaceOf= dependencies now
+          have an effect on .socket units: when used the listening socket is
+          created within the configured network namespace instead of the host
+          namespace.
+
+        * ExecStart= command lines in unit files may now be prefixed with ':'
+          in which case environment variable substitution is
+          disabled. (Supported for the other ExecXYZ= settings, too.)
+
+        * .timer units gained two new boolean settings OnClockChange= and
+          OnTimezoneChange= which may be used to also trigger a unit when the
+          system clock is changed or the local timezone is
+          modified. systemd-run has been updated to make these options easily
+          accessible from the command line for transient timers.
+
+        * Two new conditions for units have been added: ConditionMemory= may be
+          used to conditionalize a unit based on installed system
+          RAM. ConditionCPUs= may be used to conditionalize a unit based on
+          install CPU cores.
+
+        * The @default system call filter group understood by SystemCallFilter=
+          has been updated to include the new rseq() system call introduced in
+          kernel 4.15.
+
+        * A new time-set.target has been added that indicates that the system
+          time has been set from a local source (possibly imprecise). The
+          existing time-sync.target is stronger and indicates that the time has
+          been synchronized with a precise external source. Services where
+          approximate time is sufficient should use the new target.
+
+        * "systemctl start" (and related commands) learnt a new
+          --show-transaction option. If specified brief information about all
+          jobs queued because of the requested operation is shown.
+
+        * systemd-networkd recognizes a new operation state 'enslaved', used
+          (instead of 'degraded' or 'carrier') for interfaces which form a
+          bridge, bond, or similar, and an new 'degraded-carrier' operational
+          state used for the bond or bridge master interface when one of the
+          enslaved devices is not operational.
+
+        * .network files learnt the new IgnoreCarrierLoss= option for leaving
+          networks configured even if the carrier is lost.
+
+        * The RequiredForOnline= setting in .network files may now specify a
+          minimum operational state required for the interface to be considered
+          "online" by systemd-networkd-wait-online. Related to this
+          systemd-networkd-wait-online gained a new option --operational-state=
+          to configure the same, and its --interface= option was updated to
+          optionally also take an operational state specific for an interface.
+
+        * systemd-networkd-wait-online gained a new setting --any for waiting
+          for only one of the requested interfaces instead of all of them.
+
+        * systemd-networkd now implements L2TP tunnels.
+
+        * Two new .network settings UseAutonomousPrefix= and UseOnLinkPrefix=
+          may be used to cause autonomous and onlink prefixes received in IPv6
+          Router Advertisements to be ignored.
+
+        * New MulticastFlood=, NeighborSuppression=, and Learning= .network
+          file settings may be used to tweak bridge behaviour.
+
+        * The new TripleSampling= option in .network files may be used to
+          configure CAN triple sampling.
+
+        * A new .netdev settings PrivateKeyFile= and PresharedKeyFile= may be
+          used to point to private or preshared key for a WireGuard interface.
+
+        * /etc/crypttab now supports the same-cpu-crypt and
+          submit-from-crypt-cpus options to tweak encryption work scheduling
+          details.
+
+        * systemd-tmpfiles will now take a BSD file lock before operating on a
+          contents of directory. This may be used to temporarily exclude
+          directories from aging by taking the same lock (useful for example
+          when extracting a tarball into /tmp or /var/tmp as a privileged user,
+          which might create files with really old timestamps, which
+          nevertheless should not be deleted). For further details, see:
+
+          https://systemd.io/TEMPORARY_DIRECTORIES
+
+        * systemd-tmpfiles' h line type gained support for the
+          FS_PROJINHERIT_FL ('P') file attribute (introduced in kernel 4.5),
+          controlling project quota inheritance.
+
+        * sd-boot and bootctl now implement support for an Extended Boot Loader
+          (XBOOTLDR) partition, that is intended to be mounted to /boot, in
+          addition to the ESP partition mounted to /efi or /boot/efi.
+          Configuration file fragments, kernels, initrds and other EFI images
+          to boot will be loaded from both the ESP and XBOOTLDR partitions.
+          The XBOOTLDR partition was previously described by the Boot Loader
+          Specification, but implementation was missing in sd-boot. Support for
+          this concept allows using the sd-boot boot loader in more
+          conservative scenarios where the boot loader itself is placed in the
+          ESP but the kernels to boot (and their metadata) in a separate
+          partition.
+
+        * A system may now be booted with systemd.volatile=overlay on the
+          kernel command line, which causes the root file system to be set up
+          an overlayfs mount combining the root-only root directory with a
+          writable tmpfs. In this setup, the underlying root device is not
+          modified, and any changes are lost at reboot.
+
+        * Similar, systemd-nspawn can now boot containers with a volatile
+          overlayfs root with the new --volatile=overlay switch.
+
+        * systemd-nspawn can now consume OCI runtime bundles using a new
+          --oci-bundle= option. This implementation is fully usable, with most
+          features in the specification implemented, but since this a lot of
+          new code and functionality, this feature should most likely not
+          be used in production yet.
+
+        * systemd-nspawn now supports various options described by the OCI
+          runtime specification on the command-line and in .nspawn files:
+          --inaccessible=/Inaccessible= may be used to mask parts of the file
+          system tree, --console=/--pipe may be used to configure how standard
+          input, output, and error are set up.
+
+        * busctl learned the `emit` verb to generate D-Bus signals.
+
+        * systemd-analyze cat-config may be used to gather and display
+          configuration spread over multiple files, for example system and user
+          presets, tmpfiles.d, sysusers.d, udev rules, etc.
+
+        * systemd-analyze calendar now takes an optional new parameter
+          --iterations= which may be used to show a maximum number of iterations
+          the specified expression will elapse next.
+
+        * The sd-bus C API gained support for naming method parameters in the
+          introspection data.
+
+        * systemd-logind gained D-Bus APIs to specify the "reboot parameter"
+          the reboot() system call expects.
+
+        * journalctl learnt a new --cursor-file= option that points to a file
+          from which a cursor should be loaded in the beginning and to which
+          the updated cursor should be stored at the end.
+
+        * ACRN hypervisor and Windows Subsystem for Linux (WSL) are now
+          detected by systemd-detect-virt (and may also be used in
+          ConditionVirtualization=).
+
+        * The behaviour of systemd-logind may now be modified with environment
+          variables $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP,
+          $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU, and
+          $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY. They cause logind to either
+          skip the relevant operation completely (when set to false), or to
+          create a flag file in /run/systemd (when set to true), instead of
+          actually commencing the real operation when requested. The presence
+          of /run/systemd/reboot-to-firmware-setup,
+          /run/systemd/reboot-to-boot-loader-menu, and
+          /run/systemd/reboot-to-boot-loader-entry, may be used by alternative
+          boot loader implementations to replace some steps logind performs
+          during reboot with their own operations.
+
+        * systemctl can be used to request a reboot into the boot loader menu
+          or a specific boot loader entry with the new --boot-load-menu= and
+          --boot-loader-entry= options to a reboot command. (This requires a
+          boot loader that supports this, for example sd-boot.)
+
+        * kernel-install will no longer unconditionally create the output
+          directory (e.g. /efi/<machine-id>/<kernel-version>) for boot loader
+          snippets, but will do only if the machine-specific parent directory
+          (i.e. /efi/<machine-id>/) already exists. bootctl has been modified
+          to create this parent directory during sd-boot installation.
+
+          This makes it easier to use kernel-install with plugins which support
+          a different layout of the bootloader partitions (for example grub2).
+
+        * During package installation (with `ninja install`), we would create
+          symlinks for systemd-networkd.service, systemd-networkd.socket,
+          systemd-resolved.service, remote-cryptsetup.target, remote-fs.target,
+          systemd-networkd-wait-online.service, and systemd-timesyncd.service
+          in /etc, as if `systemctl enable` was called for those units, to make
+          the system usable immediately after installation. Now this is not
+          done anymore, and instead calling `systemctl preset-all` is
+          recommended after the first installation of systemd.
+
+        * A new boolean sandboxing option RestrictSUIDSGID= has been added that
+          is built on seccomp. When turned on creation of SUID/SGID files is
+          prohibited.
+
+        * The NoNewPrivileges= and the new RestrictSUIDSGID= options are now
+          implied if DynamicUser= is turned on for a service. This hardens
+          these services, so that they neither can benefit from nor create
+          SUID/SGID executables. This is a minor compatibility breakage, given
+          that when DynamicUser= was first introduced SUID/SGID behaviour was
+          unaffected. However, the security benefit of these two options is
+          substantial, and the setting is still relatively new, hence we opted
+          to make it mandatory for services with dynamic users.
+
+        Contributions from: Adam Jackson, Alexander Tsoy, Andrey Yashkin,
+        Andrzej Pietrasiewicz, Anita Zhang, Balint Reczey, Beniamino Galvani,
+        Ben Iofel, Benjamin Berg, Benjamin Dahlhoff, Chris, Chris Morin,
+        Christopher Wong, Claudius Ellsel, Clemens Gruber, dana, Daniel Black,
+        Davide Cavalca, David Michael, David Rheinsberg, emersion, Evgeny
+        Vereshchagin, Filipe Brandenburger, Franck Bui, Frantisek Sumsal,
+        Giacinto Cifelli, Hans de Goede, Hugo Kindel, Ignat Korchagin, Insun
+        Pyo, Jan Engelhardt, Jonas Dorel, Jonathan Lebon, Jonathon Kowalski,
+        Jörg Sommer, Jörg Thalheim, Jussi Pakkanen, Kai-Heng Feng, Lennart
+        Poettering, Lubomir Rintel, Luís Ferreira, Martin Pitt, Matthias
+        Klumpp, Michael Biebl, Michael Niewöhner, Michael Olbrich, Michal
+        Sekletar, Mike Lothian, Paul Menzel, Piotr Drąg, Riccardo Schirone,
+        Robin Elvedi, Roman Kulikov, Ronald Tschalär, Ross Burton, Ryan
+        Gonzalez, Sebastian Krzyszkowiak, Stephane Chazelas, StKob, Susant
+        Sahani, Sylvain Plantefève, Szabolcs Fruhwald, Taro Yamada, Theo
+        Ouzhinski, Thomas Haller, Tobias Jungel, Tom Yan, Tony Asleson, Topi
+        Miettinen, unixsysadmin, Van Laser, Vesa Jääskeläinen, Yu, Li-Yu,
+        Yu Watanabe, Zbigniew Jędrzejewski-Szmek
+
+        — Warsaw, 2019-04-11
+
 CHANGES WITH 241:
 
         * The default locale can now be configured at compile time. Otherwise,
@@ -83,6 +346,9 @@ CHANGES WITH 241:
         * udevadm control learnt a new option for --ping for testing whether a
           systemd-udevd instance is running and reacting.
 
+        * udevadm trigger learnt a new option for --wait-daemon for waiting
+          systemd-udevd daemon to be initialized.
+
         Contributions from: Aaron Plattner, Alberts Muktupāvels, Alex Mayer,
         Ayman Bagabas, Beniamino Galvani, Burt P, Chris Down, Chris Lamb, Chris
         Morin, Christian Hesse, Claudius Ellsel, dana, Daniel Axtens, Daniele
@@ -101,7 +367,7 @@ CHANGES WITH 241:
         Miettinen, YiFei Zhu, YmrDtnJu, YunQiang Su, Yu Watanabe, Zbigniew
         Jędrzejewski-Szmek, zsergeant77, Дамјан Георгиевски
 
-        — Berlin, 2018-02-14
+        — Berlin, 2019-02-14
 
 CHANGES WITH 240:
 
@@ -1954,12 +2220,14 @@ CHANGES WITH 234:
           systemd-logind to be safe. See
           https://cgit.freedesktop.org/xorg/xserver/commit/?id=dc48bd653c7e101.)
 
-        * All kernel install plugins are called with the environment variable
+        * All kernel-install plugins are called with the environment variable
           KERNEL_INSTALL_MACHINE_ID which is set to the machine ID given by
-          /etc/machine-id. If the file is missing or empty, the variable is
-          empty and BOOT_DIR_ABS is the path of a temporary directory which is
-          removed after all the plugins exit. So, if KERNEL_INSTALL_MACHINE_ID
-          is empty, all plugins should not put anything in BOOT_DIR_ABS.
+          /etc/machine-id. If the machine ID could not be determined,
+          $KERNEL_INSTALL_MACHINE_ID will be empty. Plugins should not put
+          anything in the entry directory (passed as the second argument) if
+          $KERNEL_INSTALL_MACHINE_ID is empty. For backwards compatiblity, a
+          temporary directory is passed as the entry directory and removed
+          after all the plugins exit.
 
         Contributions from: Adrian Heine né Lang, Aggelos Avgerinos, Alexander
         Kurtz, Alexandros Frantzis, Alexey Brodkin, Alex Lu, Amir Pakdel, Amir
@@ -5743,7 +6011,7 @@ CHANGES WITH 214:
         * Socket units gained a new Symlinks= setting. It takes a list
           of symlinks to create to file system sockets or FIFOs
           created by the specific Unix sockets. This is useful to
-          manage symlinks to socket nodes with the same life-cycle as
+          manage symlinks to socket nodes with the same lifecycle as
           the socket itself.
 
         * The /dev/log socket and /dev/initctl FIFO have been moved to
@@ -6051,7 +6319,7 @@ CHANGES WITH 212:
           users who are logged out cannot continue to consume IPC
           resources. This covers SysV memory, semaphores and message
           queues as well as POSIX shared memory and message
-          queues. Traditionally, SysV and POSIX IPC had no life-cycle
+          queues. Traditionally, SysV and POSIX IPC had no lifecycle
           limits. With this functionality, that is corrected. This may
           be turned off by using the RemoveIPC= switch of logind.conf.
 
@@ -6201,7 +6469,7 @@ CHANGES WITH 211:
           systemd-networkd.
 
         * The sd-bus.h bus API gained a new sd_bus_track object for
-          tracking the life-cycle of bus peers. Note that sd-bus.h is
+          tracking the lifecycle of bus peers. Note that sd-bus.h is
           still not a public API though (unless you specify
           --enable-kdbus on the configure command line, which however
           voids your warranty and you get no API stability guarantee).
diff --git a/README b/README
index 419f0ad..c652319 100644 (file)
--- a/README
+++ b/README
@@ -158,6 +158,7 @@ REQUIREMENTS:
         openssl >= 1.1.0 (optional, required to support DNS-over-TLS with openssl)
         elfutils >= 158 (optional)
         polkit (optional)
+        tzdata >= 2014f (optional)
         pkg-config
         gperf
         docbook-xsl (optional, required for documentation)
@@ -316,8 +317,7 @@ WARNINGS:
         that valgrind generates nice output only on exit(), hence on shutdown
         we don't execve() systemd-shutdown.
 
-STABLE BRANCHES AND BACKPORTS
-
+STABLE BRANCHES AND BACKPORTS:
        Stable branches with backported patches are available in the
        systemd-stable repo at https://github.com/systemd/systemd-stable.
 
index 31d5307..72484f6 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
 <a href="https://in.waw.pl/systemd-github-state/systemd-systemd-issues.svg"><img align="right" src="https://in.waw.pl/systemd-github-state/systemd-systemd-issues-small.svg" alt="Count of open issues over time"></a>
 <a href="https://in.waw.pl/systemd-github-state/systemd-systemd-pull-requests.svg"><img align="right" src="https://in.waw.pl/systemd-github-state/systemd-systemd-pull-requests-small.svg" alt="Count of open pull requests over time"></a>
 [![Semaphore CI Build Status](https://semaphoreci.com/api/v1/projects/28a5a3ca-3c56-4078-8b5e-7ed6ef912e14/443470/shields_badge.svg)](https://semaphoreci.com/systemd/systemd)<br/>
+[![Coverity Scan Status](https://scan.coverity.com/projects/350/badge.svg)](https://scan.coverity.com/projects/350)<br/>
 [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1369/badge)](https://bestpractices.coreinfrastructure.org/projects/1369)<br/>
 [![Travis CI Build Status](https://travis-ci.org/systemd/systemd.svg?branch=master)](https://travis-ci.org/systemd/systemd)<br/>
 [![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/systemd/systemd.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/systemd/systemd/context:cpp)<br/>
diff --git a/TODO b/TODO
index 981b3dd..e94ea01 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,13 +1,9 @@
 Bugfixes:
 
-* copy.c: set the right chattrs before copying files and others after
-
 * Many manager configuration settings that are only applicable to user
   manager or system manager can be always set. It would be better to reject
   them when parsing config.
 
-* Clarify what IPAddress* matches (source, destination, both?)
-
 External:
 
 * Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros.
@@ -23,6 +19,19 @@ Janitorial Clean-ups:
 
 Features:
 
+* tweak journald context caching. In addition to caching per-process attributes
+  keyed by PID, cache per-cgroup attributes (i.e. the various xattrs we read)
+  keyed by cgroup path, and guarded by ctime changes. This should provide us
+  with a nice speed-up on services that have many processes running in the same
+  cgroup.
+
+* clean up sleep.c:
+  - Use CLOCK_BOOTTIME_ALARM for waking up s2h instead of RTC ioctls
+  - Parse sleep.conf only once, and parse its whole contents so that we don't
+    have to parse it again and again in s2h
+  - Make sure resume= and resume_offset= on the kernel cmdline always take
+    precedence
+
 * make MAINPID= message reception checks even stricter: if service uses User=,
   then check sending UID and ignore message if it doesn't match the user or
   root.
@@ -51,13 +60,8 @@ Features:
 * When logind.conf contains HandleLidSwitch=suspend-then-hibernate and we can't
   hibernate because the swap partition isn't large enough, still suspend
 
-* bootctl: implement Type #2 boot loader entry discovery
-
 * bootctl,sd-boot: actually honour the "architecture" key
 
-* when a socket unit is spawned with an AF_UNIX path in /var/run, complain and
-  patch it to use /run instead
-
 * set memory.oom.group in cgroup v2 for all leaf cgroups (kernel v4.19+)
 
 * add a new syscall group "@esoteric" for more esoteric stuff such as bpf() and
@@ -65,7 +69,7 @@ Features:
 
 * paranoia: whenever we process passwords, call mlock() on the memory
   first. i.e. look for all places we use string_erase()/string_free_erase() and
-  augment them with mlock()
+  augment them with mlock(). Also use MADV_DONTDUMP
 
 * whenever oom_kill memory.event event is triggered print a nice log message
 
@@ -77,8 +81,6 @@ Features:
 * maybe implicitly attach monotonic+realtime timestamps to outgoing messages in
   log.c and sd-journal-send
 
-* chown() tty a service is attached to after the service goes down
-
 * optionally: turn on cgroup delegation for per-session scope units
 
 * introduce per-unit (i.e. per-slice, per-service) journal log size limits.
@@ -90,23 +92,12 @@ Features:
   show state of these flags, and optionally trigger such a factory reset on
   next boot by setting the flag.
 
-* sd-boot: search drop-ins in $BOOT, too
-
-* sd-boot: add "oneshot boot timeout" variable support
-
 * sd-boot: automatically load EFI modules from some drop-in dir, so that people
   can add in file system drivers and such
 
-* esp generator: also mount $BOOT if found
-
 * sd-boot: optionally, show boot menu when previous default boot item has
   non-zero "tries done" count
 
-* logind: add "boot into bootmenu" API, and possibly even "boot into windows"
-  and "boot into macos".
-
-* bootspec.c: also enumerate EFI unified kernel images.
-
 * maybe set a special xattr on cgroups that have delegate=yes set, to make it
   easy to mark cut points
 
@@ -150,9 +141,6 @@ Features:
 * When reloading configuration PID 1 should reset all its properties to the
   original defaults before calling parse_config()
 
-* Add OnTimezoneChange= and OnTimeChange= stanzas to .timer units in order to
-  schedule events based on time and timezone changes.
-
 * nspawn: greater control over selinux label?
 
 * hibernate/s2h: make this robust and safe to enable in Fedora by default.
@@ -268,8 +256,6 @@ Features:
 
 * support projid-based quota in machinectl for containers
 
-* Add NetworkNamespacePath= to specify a path to a network namespace
-
 * maybe use SOURCE_DATE_EPOCH (i.e. the env var the reproducible builds folks
   introduced) as the RTC epoch, instead of the mtime of NEWS.
 
@@ -449,8 +435,6 @@ Features:
 
 * optionally, also require WATCHDOG=1 notifications during service start-up and shutdown
 
-* resolved: when routing queries, make sure only look for the *longest* suffix...
-
 * 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
 
@@ -597,12 +581,6 @@ Features:
   service instances processing the listening socket, and open this up
   for ReusePort=
 
-* socket units: support creating sockets in different namespace,
-  opening it up for JoinsNamespaceOf=. This would require to fork off
-  a tiny process that joins the namespace and creates/binds the socket
-  and passes this back to PID1 via SCM_RIGHTS. This also could be used
-  to allow Chown/chgrp on sockets without requiring NSS in PID 1.
-
 * introduce bus call FreezeUnit(s, b), as well as "systemctl freeze
   $UNIT" and "systemctl thaw $UNIT" as wrappers around this. The calls
   should SIGSTOP all unit processes in a loop until all processes of
@@ -643,9 +621,6 @@ Features:
 
 * load .d/*.conf dropins for device units
 
-* allow implementation of InaccessibleDirectories=/ plus
-  ReadOnlyDirectories=... for whitelisting files for a service.
-
 * sd-bus:
   - EBADSLT handling
   - GetAllProperties() on a non-existing object does not result in a failure currently
@@ -716,6 +691,10 @@ Features:
   - honor language efi variables for default language selection (if there are any?)
   - honor timezone efi variables for default timezone selection (if there are any?)
   - change bootctl to be backed by systemd-bootd to control temporary and persistent default boot goal plus efi variables
+* bootctl
+  - verify that the files boot entries point to exist
+  - recognize the case when not booted on EFI
+  - specify paths for boot entries
 
 * maybe do not install getty@tty1.service symlink in /etc but in /usr?
 
@@ -748,8 +727,6 @@ Features:
   - follow PropertiesChanged state more closely, to deal with quick logouts and
     relogins
 
-* exec: when deinitializating a tty device fix the perms and group, too, not only when initializing. Set access mode/gid to 0620/tty.
-
 * journal:
   - consider introducing implicit _TTY= + _PPID= + _EUID= + _EGID= + _FSUID= + _FSGID= fields
   - import and delete pstore filesystem content at startup
@@ -831,6 +808,7 @@ Features:
   - man: document the very specific env the shutdown drop-in tools live in
   - man: add more examples to man pages
   - man: maybe sort directives in man pages, and take sections from --help and apply them to man too
+  - document root=gpt-auto properly
 
 * systemctl:
   - add systemctl switch to dump transaction without executing it
@@ -850,9 +828,7 @@ Features:
 
 * timer units:
   - timer units should get the ability to trigger when:
-    o CLOCK_REALTIME makes jumps (TFD_TIMER_CANCEL_ON_SET)
     o DST changes
-    o timezone changes
   - Modulate timer frequency based on battery state
 
 * add libsystemd-password or so to query passwords during boot using the password agent logic
diff --git a/coccinelle/empty-or-dash.cocci b/coccinelle/empty-or-dash.cocci
new file mode 100644 (file)
index 0000000..bebaead
--- /dev/null
@@ -0,0 +1,5 @@
+@@
+expression s;
+@@
+- (isempty(s) || streq(s, "-"))
++ empty_or_dash(s)
diff --git a/coccinelle/log-json.cocci b/coccinelle/log-json.cocci
new file mode 100644 (file)
index 0000000..3730fd6
--- /dev/null
@@ -0,0 +1,8 @@
+@@
+expression e, v, flags;
+expression list args;
+@@
++ return
+- json_log(v, flags, 0, args);
++ json_log(v, flags, SYNTHETIC_ERRNO(e), args);
+- return -e;
index 3612ff1..55a9fef 100644 (file)
@@ -4,20 +4,33 @@ title: The Boot Loader Specification
 
 # The Boot Loader Specification
 
-_TL;DR: Currently there's little cooperation between multiple distributions in dual-boot (or triple, ... multi-boot) setups, and we'd like to improve this situation by getting everybody to commit to a single boot configuration format that is based on drop-in files, and thus is robust, simple, works without rewriting configuration files and is free of namespace clashes._
-
-The Boot Loader Specification defines a scheme how different operating systems can cooperatively manage a boot loader configuration directory, that accepts drop-in files for boot menu items that are defined in a format that is shared between various boot loader implementations, operating systems, and userspace programs. The target audience for this specification is:
+_TL;DR: Currently there's no common boot scheme across architectures and
+platforms for open-source operating systems. There's also little cooperation
+between multiple distributions in dual-boot (or triple, … multi-boot)
+setups. We'd like to improve this situation by getting everybody to commit to a
+single boot configuration format that is based on drop-in files, and thus is
+robust, simple, works without rewriting configuration files and is free of
+namespace clashes._
+
+The Boot Loader Specification defines a scheme how different operating systems
+can cooperatively manage a boot loader configuration directory, that accepts
+drop-in files for boot menu items that are defined in a format that is shared
+between various boot loader implementations, operating systems, and userspace
+programs. The same scheme can be used to prepare OS media for cases where the
+firmware includes a boot loader. The target audience for this specification is:
 
 * Boot loader developers, to write a boot loader that directly reads its configuration at runtime from these drop-in snippets
+* Firmware developers, to add generic boot loading support directly to the firmware itself
 * Distribution and Core OS developers, in order to create these snippets at OS/kernel package installation time
 * UI developers, for implementing a user interface that discovers the available boot options
-* OS Installer developers, for setting up the initial drop-in directory
+* OS Installer developers, to prepare their installation media and for setting up the initial drop-in directory
 
 ## Why is there a need for this specification?
 
 Of course, without this specification things already work mostly fine. But here's why we think this specification is needed:
 
 * To make the boot more robust, as no explicit rewriting of configuration files is required any more
+* To allow an out of the box boot experience on any platform without the need of traditional firmware mechanisms (e.g. BIOS calls, UEFI Boot Services)
 * To improve dual-boot scenarios. Currently, multiple Linux installations tend to fight over which boot loader becomes the primary one in possession of the MBR, and only that one installation can then update the boot loader configuration of it freely. Other Linux installs have to be manually configured to never touch the MBR and instead install a chain-loaded boot loader in their own partition headers. In this new scheme as all installations share a loader directory no manual configuration has to take place, and all participants implicitly cooperate due to removal of name collisions and can install/remove their own boot menu entries at free will, without interfering with the entries of other installed operating systems.
 * Drop-in directories are otherwise now pretty ubiquitous on Linux as an easy way to extend configuration without having to edit, regenerate or manipulate configuration files. For the sake of uniformity, we should do the same for extending the boot menu.
 * Userspace code can sanely parse boot loader configuration which is essential with modern BIOSes which do not necessarily initialize USB keyboards anymore during boot, which makes boot menus hard to reach for the user. If userspace code can parse the boot loader configuration, too, this allows for UIs that can select a boot menu item to boot into, before rebooting the machine, thus not requiring interactivity during early boot.
@@ -26,7 +39,9 @@ Of course, without this specification things already work mostly fine. But here'
 
 ## Why not simply rely on the EFI boot menu logic?
 
-The EFI specification provides a boot options logic that can offer similar functionality. Here's why we think that it is not enough for our uses:
+EFI is not ubiquitous, especially not in embedded systems. If you have an EFI
+system, it provides a boot options logic that can offer similar
+functionality. Here's why we think that it is not enough for our uses:
 
 * The various EFI implementations implement the boot order/boot item logic to different levels. Some firmware implementations do not offer a boot menu at all and instead unconditionally follow the EFI boot order, booting the first item that is working.
 * If the firmware setup is used to reset all data usually all EFI boot entries are lost, making the system entirely unbootable, as the firmware setups generally do not offer a UI to define additional boot items. By placing the menu item information on disk, it is always available, regardless if the BIOS setup data is lost.
@@ -42,16 +57,21 @@ Everything described below is located on a placeholder file system `$BOOT`. The
   * If the OS is installed on a disk with MBR disk label, and a partition with the MBR type id of 0xEA already exists it should be used as `$BOOT`.
   * Otherwise, if the OS is installed on a disk with MBR disk label, a new partition with MBR type id of 0xEA shall be created, of a suitable size (let's say 500MB), and it should be used as `$BOOT`.
 * On disks with GPT disk labels
-  * If the OS is installed on a disk with GPT disk label, and a partition with the GPT type GUID of bc13c2ff-59e6-4262-a352-b275fd6f7172 already exists, it should be used as `$BOOT`.
-  * Otherwise, if the OS is installed on a disk with GPT disk label, and an ESP partition (i.e. with the GPT type UID of c12a7328-f81f-11d2-ba4b-00a0c93ec93b) already exists and is large enough (let's say 250MB) and otherwise qualifies, it should be used as `$BOOT`.
-  * Otherwise, if the OS is installed on a disk with GPT disk label, and if the ESP partition already exists but is too small, a new suitably sized (let's say 500MB) partition with GPT type GUID of bc13c2ff-59e6-4262-a352-b275fd6f7172 shall be created and it should be used as `$BOOT`.
+  * If the OS is installed on a disk with GPT disk label, and a partition with the GPT type GUID of `bc13c2ff-59e6-4262-a352-b275fd6f7172` already exists, it should be used as `$BOOT`.
+  * Otherwise, if the OS is installed on a disk with GPT disk label, and an ESP partition (i.e. with the GPT type UID of `c12a7328-f81f-11d2-ba4b-00a0c93ec93b`) already exists and is large enough (let's say 250MB`) and otherwise qualifies, it should be used as `$BOOT`.
+  * Otherwise, if the OS is installed on a disk with GPT disk label, and if the ESP partition already exists but is too small, a new suitably sized (let's say 500MB) partition with GPT type GUID of `bc13c2ff-59e6-4262-a352-b275fd6f7172` shall be created and it should be used as `$BOOT`.
   * Otherwise, if the OS is installed on a disk with GPT disk label, and no ESP partition exists yet, a new suitably sized (let's say 500MB) ESP should be created and should be used as `$BOOT`.
 
 This placeholder file system shall be determined during _installation time_, and an fstab entry may be created. It should be mounted to either `/boot/` or `/efi/`. Additional locations like `/boot/efi/`, with `/boot/` being a separate file system, might be supported by implementations. This is not recommended because the mounting of `$BOOT` is then dependent on and requires the mounting of the intermediate file system.
 
 **Note:** _`$BOOT` should be considered **shared** among all OS installations of a system. Instead of maintaining one `$BOOT` per installed OS (as `/boot/` was traditionally handled), all installed OS share the same place to drop in their boot-time configuration._
 
-For systems where the firmware is able to read file systems directly, `$BOOT` must be a file system readable by the firmware. For other systems, `$BOOT` must be a VFAT (16 or 32) file system. Applications accessing `$BOOT` should hence not assume that fancier file system features such as symlinks, hardlinks, access control or case sensitivity are supported.
+For systems where the firmware is able to read file systems directly, `$BOOT`
+must be a file system readable by the firmware. For other systems and generic
+installation and live media, `$BOOT` must be a VFAT (16 or 32) file
+system. Applications accessing `$BOOT` should hence not assume that fancier
+file system features such as symlinks, hardlinks, access control or case
+sensitivity are supported.
 
 This specification defines two types of boot loader entries. The first type is
 text based, very simple and suitable for a variety of firmware, architecture
@@ -80,7 +100,7 @@ We define two directories below `$BOOT`:
 
 Inside the `$BOOT/loader/entries/` directory each OS vendor may drop one or more configuration snippets with the suffix ".conf", one for each boot menu item. The file name of the file is used for identification of the boot item but shall never be presented to the user in the UI. The file name may be chosen freely but should be unique enough to avoid clashes between OS installations. More specifically it is suggested to include the machine ID (`/etc/machine-id` or the D-Bus machine ID for OSes that lack `/etc/machine-id`), the kernel version (as returned by `uname -r`) and an OS identifier (The ID field of `/etc/os-release`). Example: `$BOOT/loader/entries/6a9857a393724b7a981ebb5b8495b9ea-3.8.0-2.fc19.x86_64.conf`.
 
-These configuration snippets shall be Unix-style text files (i.e. line separation with a single newline character), in the UTF-8 encoding. The configuration snippets are loosely inspired on Grub1's configuration syntax. Lines beginning with '#' shall be ignored and used for commenting. The first word of a line is used as key and shall be separated by a space from its value. The following keys are known:
+These configuration snippets shall be Unix-style text files (i.e. line separation with a single newline character), in the UTF-8 encoding. The configuration snippets are loosely inspired on Grub1's configuration syntax. Lines beginning with '#' shall be ignored and used for commenting. The first word of a line is used as key and shall be separated by one or more spaces from its value. The following keys are known:
 
 * `title` shall contain a human readable title string for this menu item. This will be displayed in the boot menu for the item. It is a good idea to initialize this from the `PRETTY_NAME` of `/etc/os-release`. This name should be descriptive and does not have to be unique. If a boot loader discovers two entries with the same title it is a good idea to show more than just the raw title in the UI, for example by appending the `version` field. This field is optional. Example: "Fedora 18 (Spherical Cow)".
 * `version` shall contain a human readable version string for this menu item. This is usually the kernel version and is intended for use by OSes to install multiple kernel versions at the same time with the same `title` field. This field shall be in a syntax that is useful for Debian-style version sorts, so that the boot loader UI can determine the newest version easily and show it first or preselect it automatically. This field is optional. Example: `3.7.2-201.fc18.x86_64`.
@@ -105,7 +125,16 @@ Each configuration drop-in snippet must include at least a `linux` or an `efi` k
     linux        /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/linux
     initrd       /6a9857a393724b7a981ebb5b8495b9ea/3.8.0-2.fc19.x86_64/initrd
 
-On EFI systems all Linux kernel images should be EFI images. In order to increase compatibility with EFI systems it is highly recommended only to install EFI kernel images, even on non-EFI systems, if that's applicable and supported on the specific architecture.
+On EFI systems all Linux kernel images should be EFI images. In order to
+increase compatibility with EFI systems it is highly recommended only to
+install EFI kernel images, even on non-EFI systems, if that's applicable and
+supported on the specific architecture.
+
+Conversely, in order to increase compatibility it is recommended to install
+generic kernel images that make few assumptions about the firmware they run on,
+i.e. it is a good idea that both images shipped as UEFI PE images and those
+which are not don't make unnecessary assumption on the underlying firmware,
+i.e. don't hard depend on legacy BIOS calls or UEFI boot services.
 
 Note that these configuration snippets may only reference kernels (and EFI programs) that reside on the same file system as the configuration snippets, i.e. everything referenced must be contained in the same file system. This is by design, as referencing other partitions or devices would require a non-trivial language for denoting device paths. If kernels/initrds are to be read from other partitions/disks the boot loader can do this in its own native configuration, using its own specific device path language, and this is out of focus for this specification. More specifically, on non-EFI systems configuration snippets following this specification cannot be used to spawn other operating systems (such as Windows).
 
index f8b98bc..620e47e 100644 (file)
@@ -31,6 +31,20 @@ distribution:
    print the initial transaction it would execute during boot-up.
    This will also inform you about ordering loops and suchlike.
 
+## Compilation options
+
+The default configuration does not enable any optimization or hardening
+options. This is suitable for development and testing, but not for end-user
+installations.
+
+For deployment, optimization (`-O2` or `-O3` compiler options), link time
+optimization (`-Db_lto=true` meson option), and hardening (e.g.
+`-D_FORTIFY_SOURCE=2`, `-fstack-protector-strong`, `-fstack-clash-protection`,
+`-fcf-protection`, `-pie` compiler options, and `-z relro`, `-z now`,
+`--as-needed` linker options) are recommended. The most appropriate set of
+options depends on the architecture and distribution specifics so no default is
+provided.
+
 ## NTP Pool
 
 By default, systemd-timesyncd uses the Google Public NTP servers
@@ -49,8 +63,8 @@ NTP servers.
 
 ## DNS Servers
 
-By default, systemd-resolved uses the Google Public DNS servers
-`8.8.8.8`, `8.8.4.4`, `2001:4860:4860::8888`, `2001:4860:4860::8844`
+By default, systemd-resolved uses Cloudflare and Google Public DNS servers
+`1.1.1.1`, `8.8.8.8`, `1.0.0.1`, `8.8.4.4`, `2606:4700:4700::1111`, `2001:4860:4860::8888`, `2606:4700:4700::1001`, `2001:4860:4860::8844`
 as fallback, if no other DNS configuration is available.
 
 Use `-Ddns-servers=` to direct systemd-resolved to different fallback
index 99b5b03..f72ed20 100644 (file)
@@ -107,6 +107,51 @@ systemd-udevd:
   with `:` in which case the kernel command line option takes precedence, if it
   is specified as well.
 
+* `$SYSTEMD_REBOOT_TO_FIRMWARE_SETUP` — if set overrides systemd-logind's
+  built-in EFI logic of requesting a reboot into the firmware. Takes a
+  boolean. If set to false the functionality is turned off entirely. If set to
+  true instead of requesting a reboot into the firmware setup UI through EFI a
+  file `/run/systemd/reboot-to-firmware-setup` is created whenever this is
+  requested. This file may be checked for by services run during system
+  shutdown in order to request the appropriate operation from the firmware in
+  an alternative fashion.
+
+* `$SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU` — similar to the above, allows
+  overriding of systemd-logind's built-in EFI logic of requesting a reboot into
+  the boot loader menu. Takes a boolean. If set to false the functionality is
+  turned off entirely. If set to true instead of requesting a reboot into the
+  boot loader menu through EFI a file `/run/systemd/reboot-to-boot-loader-menu`
+  is created whenever this is requested. The file contains the requested boot
+  loader menu timeout in µs, formatted in ASCII decimals, or zero in case no
+  time-out is requested. This file may be checked for by services run during
+  system shutdown in order to request the appropriate operation from the boot
+  loader in an alternative fashion.
+
+* `$SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY` — similar to the above, allows
+  overriding of systemd-logind's built-in EFI logic of requesting a reboot into
+  a specific boot loader entry. Takes a boolean. If set to false the
+  functionality is turned off entirely. If set to true instead of requesting a
+  reboot into a specific boot loader entry through EFI a file
+  `/run/systemd/reboot-to-boot-loader-entry` is created whenever this is
+  requested. The file contains the requested boot loader entry identifier. This
+  file may be checked for by services run during system shutdown in order to
+  request the appropriate operation from the boot loader in an alternative
+  fashion. Note that by default only boot loader entries which follow the [Boot
+  Loader Specification](https://systemd.io/BOOT_LOADER_SPECIFICATION) and are
+  placed in the ESP or the Extended Boot Loader partition may be selected this
+  way. However, if a directory `/run/boot-loader-entries/` exists, the entries
+  are loaded from there instead. The directory should contain the usual
+  directory hierarchy mandated by the Boot Loader Specification, i.e. the entry
+  drop-ins should be placed in
+  `/run/boot-loader-entries/loader/entries/*.conf`, and the files referenced by
+  the drop-ins (including the kernels and initrds) somewhere else below
+  `/run/boot-loader-entries/`. Note that all these files may be (and are
+  supposed to be) symlinks. systemd-logind will load these files on-demand,
+  these files can hence be updated (ideally atomically) whenever the boot
+  loader configuration changes. A foreign boot loader installer script should
+  hence synthesize drop-in snippets and symlinks for all boot entries at boot
+  or whenever they change if it wants to integrate with systemd-logind's APIs.
+
 installed systemd tests:
 
 * `$SYSTEMD_TEST_DATA` — override the location of test data. This is useful if
index 5b6c085..194ef5b 100644 (file)
@@ -153,9 +153,9 @@ images should just work the way they are. Specifically, the following
 requirements are made for an image that can be attached/detached with
 `portablectl`.
 
-1. It must contain a binary (and its dependencies) that shall be invoked,
-   including all its dependencies. If binary code, the code needs to be
-   compiled for an architecture compatible with the host.
+1. It must contain an executable that shall be invoked, along with all its
+   dependencies. If binary code, the code needs to be compiled for an
+   architecture compatible with the host.
 
 2. The image must either be a plain sub-directory (or btrfs subvolume)
    containing the binaries and its dependencies in a classic Linux OS tree, or
@@ -177,15 +177,35 @@ requirements are made for an image that can be attached/detached with
 5. The image must contain the files `/etc/resolv.conf` and `/etc/machine-id`
    (empty files are ok), they will be bind mounted from the host at runtime.
 
-Note that generally images created by tools such as `debootstrap`, `dnf
---installroot=` or `mkosi` qualify for all of the above in one way or
-another. If you wonder what the most minimal image would be that complies with
-the requirements above, it could consist of this:
+6. The image must contain directories `/proc/`, `/sys/`, `/dev/`, `/run/`,
+   `/tmp/`, `/var/tmp/` that can be mounted over with the corresponding version
+   from the host.
+
+7. The OS might require other files or directories to be in place. For example,
+   if the image is built based on glibc, the dynamic loader needs to be
+   available in `/lib/ld-linux.so.2` or `/lib64/ld-linux-x86-64.so.2` (or
+   similar, depending on architecture), and if the distribution implements a
+   merged `/usr/` tree, this means `/lib` and/or `/lib64` need to be symlinks
+   to their respective counterparts below `/usr/`. For details see your
+   distribution's documentation.
+
+Note that images created by tools such as `debootstrap`, `dnf --installroot=`
+or `mkosi` generally qualify for all of the above in one way or another. If you
+wonder what the most minimal image would be that complies with the requirements
+above, it could consist of this:
 
 ```
-/usr/bin/minimald                        # a statically compiled binary
-/usr/lib/systemd/minimal-test.service    # the unit file for the service, with ExecStart=/usr/bin/minimald
-/usr/lib/os-release                      # an os-release file explaining what this is
+/usr/bin/minimald                            # a statically compiled binary
+/usr/lib/systemd/system/minimal-test.service # the unit file for the service, with ExecStart=/usr/bin/minimald
+/usr/lib/os-release                          # an os-release file explaining what this is
+/etc/resolv.conf                             # empty file to mount over with host's version
+/etc/machine-id                              # ditto
+/proc/                                       # empty directory to use as mount point for host's API fs
+/sys/                                        # ditto
+/dev/                                        # ditto
+/run/                                        # ditto
+/tmp/                                        # ditto
+/var/tmp/                                    # ditto
 ```
 
 And that's it.
@@ -195,6 +215,11 @@ own. If they do, it's fine, it will be ignored by the portable service logic,
 but they generally don't have to, and it might make sense to avoid any, to keep
 images minimal.
 
+If the image is writable, and some of the files or directories that are
+overmounted from the host do not exist yet they are automatically created. On
+read-only, immutable images (e.g. squashfs images) all files and directories to
+over-mount must exist already.
+
 Note that as no new image format or metadata is defined, it's very
 straight-forward to define images than can be made use of it a number of
 different ways. For example, by using `mkosi -b` you can trivially build a
index 4bf5ab8..d842afc 100644 (file)
@@ -5,12 +5,15 @@ title: Steps to a Successful Release
 # Steps to a Successful Release
 
 1. Add all items to NEWS
-2. Update the contributors list in NEWS ("make git-contrib")
+2. Update the contributors list in NEWS (`ninja -C build git-contrib`)
 3. Update the time and place in NEWS
-4. Update version in configure.ac and library numbers in Makefile.am
-5. Check that "make distcheck" works
-6. Tag the release ("make git-tag")
-7. Upload the documentation ("make doc-sync")
-8. Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
-9. Send announcement to systemd-devel, with a copy&paste from NEWS
-10. Update IRC topic ("/msg chanserv TOPIC #systemd Version NNN released")
+4. Update version and library numbers in `meson.build`
+5. Tag the release: `version=vXXX-rcY && git tag -s "${version}" -m "systemd ${version}"`
+6. Do `ninja -C build`
+7. Make sure that the version string and package string match: `build/systemctl --version`
+8. Upload the documentation: `ninja -C build doc-sync`
+9. [After final release] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
+10. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
+11. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
+12. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released`)
+13. [After final release] Also push commits to stable, create an empty -stable branch: `git push systemd-stable origin/master:master origin/master:v${version}-stable`, and change the default branch to latest release (https://github.com/systemd/systemd-stable/settings/branches).
diff --git a/docs/TEMPORARY_DIRECTORIES.md b/docs/TEMPORARY_DIRECTORIES.md
new file mode 100644 (file)
index 0000000..0ea88f8
--- /dev/null
@@ -0,0 +1,220 @@
+---
+title: Using /tmp/ And /var/tmp/ Safely
+---
+
+# Using `/tmp/` And `/var/tmp/` Safely
+
+`/tmp/` and `/var/tmp/` are two world-writable directories Linux systems
+provide for temporary files. The former is typically on `tmpfs` and thus
+backed by RAM/swap, and flushed out on each reboot. The latter is typically a
+proper, persistent file system, and thus backed by physical storage. This
+means:
+
+1. `/tmp/` should be used for smaller, size-bounded files only; `/var/tmp/`
+   should be used for everything else.
+
+2. Data that shall survive a boot cycle shouldn't be placed in `/tmp/`.
+
+If the `$TMPDIR` environment variable is set, use that path, and neither use
+`/tmp/` nor `/var/tmp/` directly.
+
+See
+[file-hierarchy(7)](https://www.freedesktop.org/software/systemd/man/file-hierarchy.html)
+for details about these two (and most other) directories of a Linux system.
+
+## Common Namespace
+
+Note that `/tmp/` and `/var/tmp/` each define a common namespace shared by all
+local software. This means guessable file or directory names below either
+directory directly translate into a 🚨 Denial-of-Service (DoS) 🚨 vulnerability
+or worse: if some software creates a file or directory `/tmp/foo` then any
+other software that wants to create the same file or directory `/tmp/foo`
+either will fail (as the file already exists) or might be tricked into using
+untrusted files. Hence: do not use guessable names in `/tmp/` or `/var/tmp/` —
+if you do you open yourself up to a local DoS exploit or worse. (You can get
+away with using guessable names, if you pre-create subdirectories below `/tmp/`
+for them, like X11 does with `/tmp/.X11-unix/` through `tmpfiles.d/`
+drop-ins. However this is not recommended, as it is fully safe only if these
+directories are pre-created during early boot, and thus problematic if package
+installation during runtime is permitted.)
+
+To protect yourself against these kinds of attacks Linux provides a couple of
+APIs that help you avoiding guessable names. Specifically:
+
+1. Use [`mkstemp()`](http://man7.org/linux/man-pages/man3/mkstemp.3.html)
+   (POSIX), `mkostemp()` (glibc),
+   [`mkdtemp()`](http://man7.org/linux/man-pages/man3/mkdtemp.3.html) (POSIX),
+   [`tmpfile()`](http://man7.org/linux/man-pages/man3/tmpfile.3.html) (C89)
+
+2. Use [`open()`](http://man7.org/linux/man-pages/man2/open.2.html) with
+   `O_TMPFILE` (Linux)
+
+3. [`memfd_create()`](http://man7.org/linux/man-pages/man2/memfd_create.2.html)
+   (Linux; this doesn't bother with `/tmp/` or `/var/tmp/` at all, but uses the
+   same RAM/swap backing as `tmpfs` uses, hence is very similar to `/tmp/`
+   semantics.)
+
+For system services systemd provides the `PrivateTmp=` boolean setting. If
+turned on for a service (👍 which is highly recommended), `/tmp/` and
+`/var/tmp/` are replaced by private sub-directories, implemented through Linux
+file system namespacing and bind mounts. This means from the service's point of
+view `/tmp/` and `/var/tmp/` look and behave like they normally do, but in
+reality they are private sub-directories of the host's real `/tmp/` and
+`/var/tmp/`, and thus not system-wide locations anymore, but service-specific
+ones. This reduces the surface for local DoS attacks substantially. While it is
+recommended to turn this option on, it's highly recommended for applications
+not to rely on this solely to avoid DoS vulnerabilities, because this option is
+not available in environments where file system namespaces are prohibited, for
+example in certain container environments. This option is hence an extra line
+of defense, but should not be used as an excuse to rely on guessable names in
+`/tmp/` and `/var/tmp/`. When this option is used, the per-service temporary
+directories are removed whenever the service shuts down, hence the lifecycle of
+temporary files stored in it is substantially different from the case where
+this option is not used. Also note that some applications use `/tmp/` and
+`/var/tmp/` for sharing files and directories. If this option is turned on this
+is not possible anymore as after all each service gets its own instances of
+both directories.
+
+## Automatic Clean-Up
+
+By default, `systemd-tmpfiles` will apply a concept of ⚠️ "ageing" to all files
+and directories stored in `/tmp/` and `/var/tmp/`. This means that files that
+have neither been changed nor read within a specific time frame are
+automatically removed in regular intervals. (This concept is not new to
+`systemd-tmpfiles` btw, it's inherited from previous subsystems such as
+`tmpwatch`.) By default files in `/tmp/` are cleaned up after 10 days, and
+those in `/var/tmp` after 30 days.
+
+This automatic clean-up is important to ensure disk usage of these temporary
+directories doesn't grow without bounds, even when programs abort unexpectedly
+or otherwise don't clean up the temporary files/directories they create. On the
+other hand it creates problems for long-running software that does not expect
+temporary files it operates on to be suddenly removed. There are a couple of
+strategies to avoid these issues:
+
+1. Make sure to always keep a file descriptor to the temporary files you
+   operate on open, and only access the files through them. This way it doesn't
+   matter whether the files have been unlinked from the file system: as long as
+   you have the file descriptor open you can still access the file for both
+   reading and writing. When operating this way it is recommended to delete the
+   files right after creating them to ensure that on unexpected program
+   termination the files or directories are implicitly released by the kernel.
+
+2. 🥇 Use `memfd_create()` or `O_TMPFILE`. This is an extension of the
+   suggestion above: files created this way are never linked under a filename
+   in the file system. This means they are not subject to ageing (as they come
+   unlinked out of the box), and there's no time window where a directory entry
+   for the file exists in the file system, and thus behaviour is fully robust
+   towards unexpected program termination as there are never files on disk that
+   need to be explicitly deleted.
+
+3. 🥇 Operate below a sub-directory of `/tmp/` and `/var/tmp/` you created, and
+   take a BSD file lock ([`flock(dir_fd,
+   LOCK_SH)`](http://man7.org/linux/man-pages/man2/flock.2.html)) on that
+   sub-directory. This is particularly interesting when operating on more than
+   a single file, or on file nodes that are not plain regular files, for
+   example when extracting a tarball to a temporary directory. The ageing
+   algorithm will skip all directories (and everything below them) that are
+   locked through a BSD file lock. As BSD file locks are automatically released
+   when the file descriptor they are taken on is closed, and all file
+   descriptors opened by a process are implicitly closed when it exits, this is
+   a robust mechanism that ensures all temporary files are subject to ageing
+   when the program that owns them dies, but not while it is still running. Use
+   this when decompressing tarballs that contain files with old
+   modification/access times, as extracted files are otherwise immediately
+   candidates for deletion by the ageing algorithm. The
+   [`flock`](http://man7.org/linux/man-pages/man1/flock.1.html) tool of the
+   `util-linux` packages makes this concept available to shell scripts. Note
+   that `systemd-tmpfiles` only checks for BSD file locks on directories, locks
+   on other types of file nodes (including regular files) are not considered.
+
+4. Keep the access time of all temporary files created current. In regular
+   intervals, use `utimensat()` or a related call to update the access time
+   ("atime") of all files that shall be kept around. Since the ageing algorithm
+   looks at the access time of files when deciding whether to delete them, it's
+   sufficient to update their access times in sufficiently frequent intervals to
+   ensure the files are not deleted. Since most applications (and tools such as
+   `ls`) primarily care for the modification time (rather than the access time)
+   using the access time for this purpose should be acceptable.
+
+5. Set the "sticky" bit on regular files. The ageing logic skips deletion of
+   all regular files that have the sticky bit (`chmod +t`) set. This is
+   honoured for regular files only however, and has no effect on directories as
+   the sticky bit has a different meaning for them.
+
+6. Don't use `/tmp/` or `/var/tmp/`, but use your own sub-directory under
+   `/run/` or `$XDG_RUNTIME_DIRECTORY` (the former if privileged, the latter if
+   unprivileged), or `/var/lib/` and `~/.config/` (similar, but with
+   persistency and suitable for larger data). The two temporary directories
+   `/tmp/` and `/var/tmp/` come with the implicit clean-up semantics described
+   above. When this is not desired, it's possible to create private per-package
+   runtime or state directories, and place all temporary files there. However,
+   do note that this means opting out of any kind of automatic clean-up, and it
+   is hence particularly essential that the program cleans up generated files
+   in these directories when they are no longer needed, in particular when the
+   program dies unexpectedly. Note: this strategy is only really suitable for
+   packages that operate in a "system wide singleton" fashion with "long"
+   persistance of its data or state, i.e. as opposed to programs that run in
+   multiple parallel or short-living instances. This is because a private
+   directory under `/run` (and the other mentioned directories) is itself
+   system and package specific singleton with greater longevity.
+
+5. Exclude your temporary files from clean-ups via a `tmpfiles.d/` drop-in
+   (which includes drop-ins in the runtime-only directory
+   `/run/tmpfiles.d/`). The `x`/`X` line types may be used to exclude files
+   matching the specified globbing patterns from the ageing logic. If this is
+   used, automatic clean-up is not done for matching files and directory, and
+   much like with the previous option it's hence essential that the program
+   generating these temporary files carefully removes the temporary files it
+   creates again, and in particular so if it dies unexpectedly.
+
+🥇 The semantics of options 2 (in case you only deal with temporary files, not
+directories) and 3 (in case you deal with both) in the list above are in most
+cases the most preferable. It is thus recommended to stick to these two
+options.
+
+While the ageing logic is very useful as a safety concept to ensure unused
+files and directories are eventually removed a well written program avoids even
+creating files that need such a clean-up. In particular:
+
+1. Use `memfd_create()` or `O_TMPFILE` when creating temporary files.
+
+2. `unlink()` temporary files right after creating them. This is very similar
+   to `O_TMPFILE` behaviour: consider deleting temporary files right after
+   creating them, while keeping open a file descriptor to them. Unlike
+   `O_TMPFILE` this method also works on older Linux systems and other OSes
+   that do not implement `O_TMPFILE`.
+
+## Disk Quota
+
+Generally, files allocated from `/tmp/` and `/var/tmp/` are allocated from a
+pool shared by all local users. Moreover the space available in `/tmp/` is
+generally more restricted than `/var/tmp/`. This means, that in particular in
+`/tmp/` space should be considered scarce, and programs need to be prepared
+that no space is available. Essential programs might require a fallback logic
+using a different location for storing temporary files hence. Non-essential
+programs at least need to be prepared for `ENOSPC` errors and generate useful,
+actionable error messages.
+
+Some setups employ per-user quota on `/var/tmp/` and possibly `/tmp/`, to make
+`ENOSPC` situations less likely, and harder to trigger from unprivileged
+users. However, in the general case no such per-user quota is implemented
+though, in particular not when `tmpfs` is used as backing file system, because
+— even today — `tmpfs` still provides no native quota support in the kernel.
+
+## Early Boot Considerations
+
+Both `/tmp/` and `/var/tmp/` are not necessarily available during early boot,
+or — if they are available early — are not writable. This means software that
+is intended to run during early boot (i.e. before `basic.target` — or more
+specifically `local-fs.target` — is up) should not attempt to make use of
+either. Interfaces such as `memfd_create()` or files below a package-specific
+directory in `/run/` are much better options in this case. (Note that some
+packages instead use `/dev/shm/` for temporary files during early boot; this is
+not advisable however, as it offers no benefits over a private directory in
+`/run/` as both are backed by the same concept: `tmpfs`. The directory
+`/dev/shm/` exists to back POSIX shared memory (see
+[`shm_open()`](http://man7.org/linux/man-pages/man3/shm_open.3.html) and
+related calls), and not as a place for temporary files. `/dev/shm` is
+problematic as it is world-writable and there's no automatic clean-up logic in
+place.)
index 0ac77f0..f081fdb 100644 (file)
@@ -155,6 +155,7 @@ All execution-related settings are available for transient units.
 ✓ MemoryDenyWriteExecute=
 ✓ RestrictNamespaces=
 ✓ RestrictRealtime=
+✓ RestrictSUIDSGID=
 ✓ RestrictAddressFamilies=
 ✓ LockPersonality=
 ✓ LimitCPU=
@@ -224,6 +225,7 @@ All cgroup/resource control settings are available for transient units
 ✓ CPUShares=
 ✓ StartupCPUShares=
 ✓ CPUQuota=
+✓ CPUQuotaPeriodSec=
 ✓ MemoryAccounting=
 ✓ MemoryMin=
 ✓ MemoryLow=
@@ -334,10 +336,12 @@ All automount unit setting is available to transient units:
 Most timer unit settings are available to transient units.
 
 ```
-✓ OnCalendar=
 ✓ OnActiveSec=
 ✓ OnBootSec=
+✓ OnCalendar=
+✓ OnClockChange=
 ✓ OnStartupSec=
+✓ OnTimezoneChange
 ✓ OnUnitActiveSec=
 ✓ OnUnitInactiveSec=
 ✓ Persistent=
index d65cd6d..769404a 100644 (file)
@@ -3666,7 +3666,7 @@ OUI:0004C3*
  ID_OUI_FROM_DATABASE=CASTOR Informatique
 
 OUI:0004C4*
- ID_OUI_FROM_DATABASE=Allen & Heath Limited
+ ID_OUI_FROM_DATABASE=Audiotonix Group Limited
 
 OUI:0004C5*
  ID_OUI_FROM_DATABASE=ASE Technologies, USA
@@ -6348,7 +6348,7 @@ OUI:00085C*
  ID_OUI_FROM_DATABASE=Shanghai Dare Technologies Co. Ltd.
 
 OUI:00085D*
- ID_OUI_FROM_DATABASE=Aastra
+ ID_OUI_FROM_DATABASE=Mitel Corporation
 
 OUI:00085E*
  ID_OUI_FROM_DATABASE=PCO AG
@@ -9462,7 +9462,7 @@ OUI:000C6B*
  ID_OUI_FROM_DATABASE=Kurz Industrie-Elektronik GmbH
 
 OUI:000C6C*
- ID_OUI_FROM_DATABASE=Elgato Systems LLC
+ ID_OUI_FROM_DATABASE=Eve Systems GmbH
 
 OUI:000C6D*
  ID_OUI_FROM_DATABASE=Edwards Ltd.
@@ -9903,7 +9903,7 @@ OUI:000CFE*
  ID_OUI_FROM_DATABASE=Grand Electronic Co., Ltd
 
 OUI:000CFF*
- ID_OUI_FROM_DATABASE=MRO-TEK LIMITED
+ ID_OUI_FROM_DATABASE=MRO-TEK Realty Limited
 
 OUI:000D00*
  ID_OUI_FROM_DATABASE=Seaway Networks Inc.
@@ -24579,7 +24579,7 @@ OUI:001F52*
  ID_OUI_FROM_DATABASE=UVT Unternehmensberatung fur Verkehr und Technik GmbH
 
 OUI:001F53*
- ID_OUI_FROM_DATABASE=GEMAC Gesellschaft für Mikroelektronikanwendung Chemnitz mbH
+ ID_OUI_FROM_DATABASE=GEMAC Chemnitz GmbH
 
 OUI:001F54*
  ID_OUI_FROM_DATABASE=Lorex Technology Inc.
@@ -29301,7 +29301,7 @@ OUI:00257D*
  ID_OUI_FROM_DATABASE=PointRed Telecom Private Ltd.
 
 OUI:00257E*
- ID_OUI_FROM_DATABASE=NEW POS Technology Limited
+ ID_OUI_FROM_DATABASE=NEW POS TECHNOLOGY LIMITED
 
 OUI:00257F*
  ID_OUI_FROM_DATABASE=CallTechSolution Co.,Ltd
@@ -31397,6 +31397,9 @@ OUI:003532*
 OUI:003560*
  ID_OUI_FROM_DATABASE=Rosen Aviation
 
+OUI:0035FF*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:003676*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
@@ -31698,7 +31701,7 @@ OUI:004050*
  ID_OUI_FROM_DATABASE=IRONICS, INCORPORATED
 
 OUI:004051*
- ID_OUI_FROM_DATABASE=GRACILIS, INC.
+ ID_OUI_FROM_DATABASE=Garbee and Garbee
 
 OUI:004052*
  ID_OUI_FROM_DATABASE=STAR TECHNOLOGIES, INC.
@@ -33968,6 +33971,9 @@ OUI:0076B1*
 OUI:00778D*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:0077E4*
+ ID_OUI_FROM_DATABASE=Nokia
+
 OUI:007888*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -34416,7 +34422,7 @@ OUI:00808B*
  ID_OUI_FROM_DATABASE=DACOLL LIMITED
 
 OUI:00808C*
- ID_OUI_FROM_DATABASE=NetScout Systems, Inc.
+ ID_OUI_FROM_DATABASE=NetAlly
 
 OUI:00808D*
  ID_OUI_FROM_DATABASE=WESTCOAST TECHNOLOGY B.V.
@@ -35673,7 +35679,7 @@ OUI:00A00D*
  ID_OUI_FROM_DATABASE=THE PANDA PROJECT
 
 OUI:00A00E*
- ID_OUI_FROM_DATABASE=NetScout Systems, Inc.
+ ID_OUI_FROM_DATABASE=NetAlly
 
 OUI:00A00F*
  ID_OUI_FROM_DATABASE=Broadband Technologies
@@ -36461,6 +36467,9 @@ OUI:00ACE0*
 OUI:00AD24*
  ID_OUI_FROM_DATABASE=D-Link International
 
+OUI:00AD63*
+ ID_OUI_FROM_DATABASE=Dedicated Micros Malta LTD
+
 OUI:00AECD*
  ID_OUI_FROM_DATABASE=Pensando Systems
 
@@ -36750,7 +36759,7 @@ OUI:00C016*
  ID_OUI_FROM_DATABASE=ELECTRONIC THEATRE CONTROLS
 
 OUI:00C017*
- ID_OUI_FROM_DATABASE=NetScout Systems, Inc.
+ ID_OUI_FROM_DATABASE=NetAlly
 
 OUI:00C018*
  ID_OUI_FROM_DATABASE=LANART CORPORATION
@@ -39170,6 +39179,9 @@ OUI:00EBD5*
 OUI:00EC0A*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
+OUI:00EDB8*
+ ID_OUI_FROM_DATABASE=KYOCERA Corporation
+
 OUI:00EEAB*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -39200,6 +39212,9 @@ OUI:00F48D*
 OUI:00F4B9*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:00F620*
+ ID_OUI_FROM_DATABASE=Google, Inc.
+
 OUI:00F663*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -39218,6 +39233,9 @@ OUI:00F860*
 OUI:00F871*
  ID_OUI_FROM_DATABASE=DGS Denmark A/S
 
+OUI:00FA21*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:00FA3B*
  ID_OUI_FROM_DATABASE=CLOOS ELECTRONIC GMBH
 
@@ -39497,6 +39515,9 @@ OUI:045A95*
 OUI:045C06*
  ID_OUI_FROM_DATABASE=Zmodo Technology Corporation
 
+OUI:045C6C*
+ ID_OUI_FROM_DATABASE=Juniper Networks
+
 OUI:045C8E*
  ID_OUI_FROM_DATABASE=gosund GROUP CO.,LTD
 
@@ -39632,6 +39653,9 @@ OUI:0481AE*
 OUI:04848A*
  ID_OUI_FROM_DATABASE=7INOVA TECHNOLOGY LIMITED
 
+OUI:04885F*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:04888C*
  ID_OUI_FROM_DATABASE=Eifelwerk Butler Systeme GmbH
 
@@ -39696,7 +39720,7 @@ OUI:049F06*
  ID_OUI_FROM_DATABASE=Smobile Co., Ltd.
 
 OUI:049F81*
- ID_OUI_FROM_DATABASE=NetScout Systems, Inc.
+ ID_OUI_FROM_DATABASE=NetAlly
 
 OUI:049FCA*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
@@ -39866,6 +39890,9 @@ OUI:04D437*
 OUI:04D4C4*
  ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
 
+OUI:04D590*
+ ID_OUI_FROM_DATABASE=Fortinet, Inc.
+
 OUI:04D6AA*
  ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND)
 
@@ -39875,6 +39902,9 @@ OUI:04D783*
 OUI:04D7A5*
  ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd
 
+OUI:04D9F5*
+ ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
+
 OUI:04DAD2*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -40556,6 +40586,9 @@ OUI:08379C*
 OUI:0838A5*
  ID_OUI_FROM_DATABASE=Funkwerk plettac electronic GmbH
 
+OUI:083A2F*
+ ID_OUI_FROM_DATABASE=Guangzhou Juan Intelligent Tech Joint Stock Co.,Ltd
+
 OUI:083A5C*
  ID_OUI_FROM_DATABASE=Junilab, Inc.
 
@@ -40593,7 +40626,7 @@ OUI:084656*
  ID_OUI_FROM_DATABASE=VEO-LABS
 
 OUI:0847D0*
- ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co. Ltd.)
+ ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co., Ltd.
 
 OUI:08482C*
  ID_OUI_FROM_DATABASE=Raycore Taiwan Co., LTD.
@@ -40607,6 +40640,9 @@ OUI:084E1C*
 OUI:084EBF*
  ID_OUI_FROM_DATABASE=Broad Net Mux Corporation
 
+OUI:084F0A*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:085114*
  ID_OUI_FROM_DATABASE=QINGDAO TOPSCOMM COMMUNICATION CO., LTD
 
@@ -40706,6 +40742,9 @@ OUI:087CBE*
 OUI:087D21*
  ID_OUI_FROM_DATABASE=Altasec technology corporation
 
+OUI:087E64*
+ ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
+
 OUI:087F98*
  ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
 
@@ -40767,7 +40806,7 @@ OUI:089B4B*
  ID_OUI_FROM_DATABASE=iKuai Networks
 
 OUI:089C86*
- ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co. Ltd.)
+ ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co., Ltd.
 
 OUI:089E01*
  ID_OUI_FROM_DATABASE=QUANTA COMPUTER INC.
@@ -40979,6 +41018,9 @@ OUI:08ED02E*
 OUI:08EDB9*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
+OUI:08EDED*
+ ID_OUI_FROM_DATABASE=Zhejiang Dahua Technology Co., Ltd.
+
 OUI:08EE8B*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -41495,6 +41537,9 @@ OUI:0CB5DE*
 OUI:0CB6D2*
  ID_OUI_FROM_DATABASE=D-Link International
 
+OUI:0CB771*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:0CB912*
  ID_OUI_FROM_DATABASE=JM-DATA GmbH
 
@@ -42683,6 +42728,9 @@ OUI:144146*
 OUI:1441E2*
  ID_OUI_FROM_DATABASE=Monaco Enterprises, Inc.
 
+OUI:1442FC*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:144319*
  ID_OUI_FROM_DATABASE=Creative&Link Technology Limited
 
@@ -42701,6 +42749,9 @@ OUI:14488B*
 OUI:144978*
  ID_OUI_FROM_DATABASE=Digital Control Incorporated
 
+OUI:1449BC*
+ ID_OUI_FROM_DATABASE=DrayTek Corp.
+
 OUI:1449E0*
  ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND)
 
@@ -42857,6 +42908,9 @@ OUI:147DC5*
 OUI:14825B*
  ID_OUI_FROM_DATABASE=Hefei Radio Communication Technology Co., Ltd
 
+OUI:148430*
+ ID_OUI_FROM_DATABASE=MITAC COMPUTING TECHNOLOGY CORPORATION
+
 OUI:148692*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
@@ -42929,6 +42983,9 @@ OUI:149FE8*
 OUI:14A0F8*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:14A2A0*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:14A364*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -42956,6 +43013,9 @@ OUI:14ABC5*
 OUI:14ABF0*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:14ADCA*
+ ID_OUI_FROM_DATABASE=China Mobile Iot Limited company
+
 OUI:14AEDB*
  ID_OUI_FROM_DATABASE=VTech Telecommunications Ltd.
 
@@ -42995,6 +43055,9 @@ OUI:14BB6E*
 OUI:14BD61*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:14C03E*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:14C089*
  ID_OUI_FROM_DATABASE=DUNE HD LTD
 
@@ -43190,6 +43253,9 @@ OUI:181725*
 OUI:18193F*
  ID_OUI_FROM_DATABASE=Tamtron Oy
 
+OUI:1819D6*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:181BEB*
  ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc
 
@@ -43628,6 +43694,9 @@ OUI:18A99B*
 OUI:18AA45*
  ID_OUI_FROM_DATABASE=Fon Technology
 
+OUI:18AACA*
+ ID_OUI_FROM_DATABASE=Sichuan tianyi kanghe communications co., LTD
+
 OUI:18ABF5*
  ID_OUI_FROM_DATABASE=Ultra Electronics Electrics
 
@@ -43664,6 +43733,9 @@ OUI:18B430*
 OUI:18B591*
  ID_OUI_FROM_DATABASE=I-Storm
 
+OUI:18B6F7*
+ ID_OUI_FROM_DATABASE=NEW POS TECHNOLOGY LIMITED
+
 OUI:18B79E*
  ID_OUI_FROM_DATABASE=Invoxia
 
@@ -43712,6 +43784,9 @@ OUI:18CC23*
 OUI:18CC88*
  ID_OUI_FROM_DATABASE=Hitachi Johnson Controls Air
 
+OUI:18CF24*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:18CF5E*
  ID_OUI_FROM_DATABASE=Liteon Technology Corporation
 
@@ -43913,6 +43988,9 @@ OUI:1C1EE3*
 OUI:1C1FD4*
  ID_OUI_FROM_DATABASE=LifeBEAM Technologies LTD
 
+OUI:1C20DB*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:1C21D10*
  ID_OUI_FROM_DATABASE=Toyo System CO.,LTD.
 
@@ -44012,6 +44090,9 @@ OUI:1C398A*
 OUI:1C3A4F*
  ID_OUI_FROM_DATABASE=AccuSpec Electronics, LLC
 
+OUI:1C3A60*
+ ID_OUI_FROM_DATABASE=Ruckus Wireless
+
 OUI:1C3ADE*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -44126,6 +44207,9 @@ OUI:1C62B8*
 OUI:1C63B7*
  ID_OUI_FROM_DATABASE=OpenProducts 237 AB
 
+OUI:1C6499*
+ ID_OUI_FROM_DATABASE=Comtrend Corporation
+
 OUI:1C659D*
  ID_OUI_FROM_DATABASE=Liteon Technology Corporation
 
@@ -44210,6 +44294,51 @@ OUI:1C7EE5*
 OUI:1C7F2C*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:1C82590*
+ ID_OUI_FROM_DATABASE=Shandong Luneng Intelligence Technology CO., Ltd
+
+OUI:1C82591*
+ ID_OUI_FROM_DATABASE=3xLOGIC Inc.
+
+OUI:1C82592*
+ ID_OUI_FROM_DATABASE=Diatrend Corporation
+
+OUI:1C82593*
+ ID_OUI_FROM_DATABASE=C&A Marketing, INC.
+
+OUI:1C82594*
+ ID_OUI_FROM_DATABASE=winsun AG
+
+OUI:1C82595*
+ ID_OUI_FROM_DATABASE=Fagus-GreCon Greten GmbH & Co. KG
+
+OUI:1C82596*
+ ID_OUI_FROM_DATABASE=CGI IT UK LIMITED
+
+OUI:1C82597*
+ ID_OUI_FROM_DATABASE=Jump Trading
+
+OUI:1C82598*
+ ID_OUI_FROM_DATABASE=SHENZHEN AOA TECHNOLOGY CO.,LTD
+
+OUI:1C82599*
+ ID_OUI_FROM_DATABASE=Shanghai Xiaoyan Technology Co., Ltd.
+
+OUI:1C8259A*
+ ID_OUI_FROM_DATABASE=ESTec Corporation
+
+OUI:1C8259B*
+ ID_OUI_FROM_DATABASE=KeyWest Networks, Inc
+
+OUI:1C8259C*
+ ID_OUI_FROM_DATABASE=Evondos Oy
+
+OUI:1C8259D*
+ ID_OUI_FROM_DATABASE=Applied Concepts, Inc.
+
+OUI:1C8259E*
+ ID_OUI_FROM_DATABASE=Microtronics Engineering GmbH
+
 OUI:1C8341*
  ID_OUI_FROM_DATABASE=Hefei Bitland Information Technology Co.Ltd
 
@@ -44552,6 +44681,9 @@ OUI:1CB3E9*
 OUI:1CB72C*
  ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
 
+OUI:1CB796*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:1CB857*
  ID_OUI_FROM_DATABASE=Becon Technologies Co,.Ltd.
 
@@ -44876,6 +45008,9 @@ OUI:2016B9*
 OUI:2016D8*
  ID_OUI_FROM_DATABASE=Liteon Technology Corporation
 
+OUI:201742*
+ ID_OUI_FROM_DATABASE=LG Electronics
+
 OUI:20180E*
  ID_OUI_FROM_DATABASE=Shenzhen Sunchip Technology Co., Ltd
 
@@ -45386,6 +45521,9 @@ OUI:20F41B*
 OUI:20F452*
  ID_OUI_FROM_DATABASE=Shanghai IUV Software Development Co. Ltd
 
+OUI:20F478*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:20F510*
  ID_OUI_FROM_DATABASE=Codex Digital Limited
 
@@ -45473,6 +45611,9 @@ OUI:241148*
 OUI:2411D0*
  ID_OUI_FROM_DATABASE=Chongqing Ehs Science and Technology Development Co.,Ltd.
 
+OUI:24166D*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:24181D*
  ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND)
 
@@ -45665,6 +45806,9 @@ OUI:24615A*
 OUI:246278*
  ID_OUI_FROM_DATABASE=sysmocom - systems for mobile communications GmbH
 
+OUI:2462AB*
+ ID_OUI_FROM_DATABASE=Espressif Inc.
+
 OUI:2464EF*
  ID_OUI_FROM_DATABASE=CYG SUNRI CO.,LTD.
 
@@ -45992,6 +46136,9 @@ OUI:24ECD6*
 OUI:24EE3A*
  ID_OUI_FROM_DATABASE=Chengdu Yingji Electronic Hi-tech Co Ltd
 
+OUI:24EE9A*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:24F094*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -46292,6 +46439,9 @@ OUI:28401A*
 OUI:284121*
  ID_OUI_FROM_DATABASE=OptiSense Network, LLC
 
+OUI:2841C6*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:284430*
  ID_OUI_FROM_DATABASE=GenesisTechnical Systems (UK) Ltd
 
@@ -46460,6 +46610,9 @@ OUI:28987B*
 OUI:28993A*
  ID_OUI_FROM_DATABASE=Arista Networks
 
+OUI:2899C7*
+ ID_OUI_FROM_DATABASE=LINDSAY BROADBAND INC
+
 OUI:289A4B*
  ID_OUI_FROM_DATABASE=SteelSeries ApS
 
@@ -46631,6 +46784,9 @@ OUI:28D0CB*
 OUI:28D1AF*
  ID_OUI_FROM_DATABASE=Nokia Corporation
 
+OUI:28D1B7*
+ ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd
+
 OUI:28D244*
  ID_OUI_FROM_DATABASE=LCFC(HeFei) Electronics Technology Co., Ltd.
 
@@ -46916,6 +47072,9 @@ OUI:2C1CF6*
 OUI:2C1DB8*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:2C1E4F*
+ ID_OUI_FROM_DATABASE=Chengdu Qianli Network Technology Co., Ltd.
+
 OUI:2C1EEA*
  ID_OUI_FROM_DATABASE=AERODEV
 
@@ -47201,6 +47360,9 @@ OUI:2C4D54*
 OUI:2C4D79*
  ID_OUI_FROM_DATABASE=WEIFANG GOERTEK ELECTRONICS CO.,LTD
 
+OUI:2C4F52*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:2C5089*
  ID_OUI_FROM_DATABASE=Shenzhen Kaixuan Visual Technology Co.,Limited
 
@@ -47702,6 +47864,9 @@ OUI:2CFDAB*
 OUI:2CFF65*
  ID_OUI_FROM_DATABASE=Oki Electric Industry Co., Ltd.
 
+OUI:2CFFEE*
+ ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
+
 OUI:30053F*
  ID_OUI_FROM_DATABASE=JTI Co.,Ltd.
 
@@ -47921,6 +48086,9 @@ OUI:3029BE*
 OUI:302DE8*
  ID_OUI_FROM_DATABASE=JDA, LLC (JDA Systems)
 
+OUI:30317D*
+ ID_OUI_FROM_DATABASE=Hosiden Corporation
+
 OUI:303294*
  ID_OUI_FROM_DATABASE=W-IE-NE-R Plein & Baus GmbH
 
@@ -49274,6 +49442,9 @@ OUI:34FCEF*
 OUI:380025*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:380118*
+ ID_OUI_FROM_DATABASE=ULVAC,Inc.
+
 OUI:380195*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -49349,6 +49520,9 @@ OUI:3817E1*
 OUI:38192F*
  ID_OUI_FROM_DATABASE=Nokia Corporation
 
+OUI:381A52*
+ ID_OUI_FROM_DATABASE=Seiko Epson Corporation
+
 OUI:381C1A*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -49466,6 +49640,9 @@ OUI:383A21D*
 OUI:383A21E*
  ID_OUI_FROM_DATABASE=SDNware technology co.,LTD
 
+OUI:383B26*
+ ID_OUI_FROM_DATABASE=Jiangsu Qinheng Co., Ltd.
+
 OUI:383BC8*
  ID_OUI_FROM_DATABASE=2Wire Inc
 
@@ -49496,6 +49673,9 @@ OUI:38458C*
 OUI:384608*
  ID_OUI_FROM_DATABASE=zte corporation
 
+OUI:3847BC*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:38484C*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -49697,6 +49877,9 @@ OUI:389496*
 OUI:3894E0*
  ID_OUI_FROM_DATABASE=Syrotech Networks. Ltd.
 
+OUI:3894ED*
+ ID_OUI_FROM_DATABASE=NETGEAR
+
 OUI:389592*
  ID_OUI_FROM_DATABASE=Beijing Tendyron Corporation
 
@@ -50003,6 +50186,9 @@ OUI:38ED18*
 OUI:38EE9D*
  ID_OUI_FROM_DATABASE=Anedo Ltd.
 
+OUI:38EFE3*
+ ID_OUI_FROM_DATABASE=INGENICO TERMINALS SAS
+
 OUI:38F098*
  ID_OUI_FROM_DATABASE=Vapor Stone Rail Systems
 
@@ -50750,6 +50936,9 @@ OUI:3CB6B7*
 OUI:3CB72B*
  ID_OUI_FROM_DATABASE=PLUMgrid Inc
 
+OUI:3CB74B*
+ ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
+
 OUI:3CB792*
  ID_OUI_FROM_DATABASE=Hitachi Maxell, Ltd., Optronics Division
 
@@ -51017,6 +51206,9 @@ OUI:40270B*
 OUI:402814*
  ID_OUI_FROM_DATABASE=RFI Engineering
 
+OUI:402B50*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:402BA1*
  ID_OUI_FROM_DATABASE=Sony Mobile Communications Inc
 
@@ -51173,6 +51365,9 @@ OUI:405662*
 OUI:405A9B*
  ID_OUI_FROM_DATABASE=ANOVO
 
+OUI:405BD8*
+ ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD.
+
 OUI:405CFD*
  ID_OUI_FROM_DATABASE=Dell Inc.
 
@@ -51719,6 +51914,9 @@ OUI:440010*
 OUI:440049*
  ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
 
+OUI:44004D*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:44032C*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
@@ -51746,6 +51944,9 @@ OUI:4411C2*
 OUI:441319*
  ID_OUI_FROM_DATABASE=WKK TECHNOLOGY LTD.
 
+OUI:4413D0*
+ ID_OUI_FROM_DATABASE=zte corporation
+
 OUI:441441*
  ID_OUI_FROM_DATABASE=AudioControl Inc.
 
@@ -51917,6 +52118,9 @@ OUI:445829*
 OUI:44599F*
  ID_OUI_FROM_DATABASE=Criticare Systems, Inc
 
+OUI:4459E3*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:445D5E*
  ID_OUI_FROM_DATABASE=SHENZHEN Coolkit Technology CO.,LTD
 
@@ -52499,6 +52703,9 @@ OUI:484D7E*
 OUI:485073*
  ID_OUI_FROM_DATABASE=Microsoft Corporation
 
+OUI:485169*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:4851B7*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
@@ -52637,6 +52844,9 @@ OUI:487583*
 OUI:487604*
  ID_OUI_FROM_DATABASE=Private
 
+OUI:487746*
+ ID_OUI_FROM_DATABASE=Calix Inc.
+
 OUI:487A55*
  ID_OUI_FROM_DATABASE=ALE International
 
@@ -52748,6 +52958,9 @@ OUI:48A6B8*
 OUI:48A6D2*
  ID_OUI_FROM_DATABASE=GJsun Optical Science and Tech Co.,Ltd.
 
+OUI:48A73C*
+ ID_OUI_FROM_DATABASE=Sichuan tianyi kanghe communications co., LTD
+
 OUI:48A74E*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -52895,6 +53108,9 @@ OUI:48DF37*
 OUI:48E1AF*
  ID_OUI_FROM_DATABASE=Vity
 
+OUI:48E1E9*
+ ID_OUI_FROM_DATABASE=Chengdu Meross Technology Co., Ltd.
+
 OUI:48E244*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
@@ -53660,6 +53876,9 @@ OUI:4CE676*
 OUI:4CE933*
  ID_OUI_FROM_DATABASE=RailComm, LLC
 
+OUI:4CE9E4*
+ ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd
+
 OUI:4CEB42*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
@@ -53816,6 +54035,9 @@ OUI:501AA5*
 OUI:501AC5*
  ID_OUI_FROM_DATABASE=Microsoft
 
+OUI:501B32*
+ ID_OUI_FROM_DATABASE=Taicang T&W Electronics
+
 OUI:501CB0*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -54167,6 +54389,9 @@ OUI:50934F*
 OUI:509551*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:509744*
+ ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd.
+
 OUI:509772*
  ID_OUI_FROM_DATABASE=Westinghouse Digital
 
@@ -54284,6 +54509,9 @@ OUI:50AD92*
 OUI:50ADD5*
  ID_OUI_FROM_DATABASE=Dynalec Corporation
 
+OUI:50AF4D*
+ ID_OUI_FROM_DATABASE=zte corporation
+
 OUI:50AF73*
  ID_OUI_FROM_DATABASE=Shenzhen Bitland Information Technology Co., Ltd.
 
@@ -54353,6 +54581,9 @@ OUI:50D274*
 OUI:50D37F*
  ID_OUI_FROM_DATABASE=Yu Fly Mikly Way Science and Technology Co., Ltd.
 
+OUI:50D4F7*
+ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+
 OUI:50D59C*
  ID_OUI_FROM_DATABASE=Thai Habel Industrial Co., Ltd.
 
@@ -54380,6 +54611,9 @@ OUI:50DD4F*
 OUI:50DF95*
  ID_OUI_FROM_DATABASE=Lytx
 
+OUI:50E085*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:50E0C7*
  ID_OUI_FROM_DATABASE=TurControlSystme AG
 
@@ -54437,6 +54671,9 @@ OUI:50F61A*
 OUI:50F722*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:50F8A5*
+ ID_OUI_FROM_DATABASE=eWBM Co., Ltd.
+
 OUI:50FA84*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
@@ -54812,6 +55049,9 @@ OUI:548998*
 OUI:548CA0*
  ID_OUI_FROM_DATABASE=Liteon Technology Corporation
 
+OUI:549209*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:5492BE*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -54959,6 +55199,9 @@ OUI:54B802*
 OUI:54B80A*
  ID_OUI_FROM_DATABASE=D-Link International
 
+OUI:54BAD6*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:54BD79*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -55031,6 +55274,9 @@ OUI:54DF24*
 OUI:54DF63*
  ID_OUI_FROM_DATABASE=Intrakey technologies GmbH
 
+OUI:54E019*
+ ID_OUI_FROM_DATABASE=Ring LLC
+
 OUI:54E032*
  ID_OUI_FROM_DATABASE=Juniper Networks
 
@@ -55070,12 +55316,18 @@ OUI:54E6FC*
 OUI:54EAA8*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:54EC2F*
+ ID_OUI_FROM_DATABASE=Ruckus Wireless
+
 OUI:54EDA3*
  ID_OUI_FROM_DATABASE=Navdy, Inc.
 
 OUI:54EE75*
  ID_OUI_FROM_DATABASE=Wistron InfoComm(Kunshan)Co.,Ltd.
 
+OUI:54EF44*
+ ID_OUI_FROM_DATABASE=Lumi United Technology Co., Ltd
+
 OUI:54EF92*
  ID_OUI_FROM_DATABASE=Shenzhen Elink Technology Co., LTD
 
@@ -55949,6 +56201,9 @@ OUI:5C5819*
 OUI:5C5948*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:5C5AC7*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:5C5AEA*
  ID_OUI_FROM_DATABASE=FORD
 
@@ -56030,6 +56285,9 @@ OUI:5C86C1*
 OUI:5C8778*
  ID_OUI_FROM_DATABASE=Cybertelbridge co.,ltd
 
+OUI:5C879C*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
 OUI:5C8816*
  ID_OUI_FROM_DATABASE=Rockwell Automation
 
@@ -56360,6 +56618,9 @@ OUI:5CF9DD*
 OUI:5CF9F0*
  ID_OUI_FROM_DATABASE=Atomos Engineering P/L
 
+OUI:5CFAFB*
+ ID_OUI_FROM_DATABASE=Acubit
+
 OUI:5CFB7C*
  ID_OUI_FROM_DATABASE=Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd
 
@@ -56474,6 +56735,9 @@ OUI:6024C1*
 OUI:60271C*
  ID_OUI_FROM_DATABASE=VIDEOR E. Hartig GmbH
 
+OUI:6029D5*
+ ID_OUI_FROM_DATABASE=DAVOLINK Inc.
+
 OUI:602A54*
  ID_OUI_FROM_DATABASE=CardioTek B.V.
 
@@ -56519,6 +56783,9 @@ OUI:6038E0*
 OUI:60391F*
  ID_OUI_FROM_DATABASE=ABB Ltd
 
+OUI:603A7C*
+ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+
 OUI:603D26*
  ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
 
@@ -56723,6 +56990,51 @@ OUI:609217*
 OUI:6092F5*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
+OUI:6095CE0*
+ ID_OUI_FROM_DATABASE=Siema Applications
+
+OUI:6095CE1*
+ ID_OUI_FROM_DATABASE=Ponoor Experiments Inc.
+
+OUI:6095CE2*
+ ID_OUI_FROM_DATABASE=Q-SENTECH Co.,Ltd.
+
+OUI:6095CE3*
+ ID_OUI_FROM_DATABASE=Robot S.A.
+
+OUI:6095CE4*
+ ID_OUI_FROM_DATABASE=Untangle, Inc.
+
+OUI:6095CE5*
+ ID_OUI_FROM_DATABASE=AdvanWISE Corporation
+
+OUI:6095CE6*
+ ID_OUI_FROM_DATABASE=Xiamen Sigmastar Technology Ltd.
+
+OUI:6095CE7*
+ ID_OUI_FROM_DATABASE=Cadmo Soluciones SAC
+
+OUI:6095CE8*
+ ID_OUI_FROM_DATABASE=Trophy SAS
+
+OUI:6095CE9*
+ ID_OUI_FROM_DATABASE=Jlztlink Industry(ShenZhen)Co.,Ltd.
+
+OUI:6095CEA*
+ ID_OUI_FROM_DATABASE=(UN)MANNED
+
+OUI:6095CEB*
+ ID_OUI_FROM_DATABASE=Beijing Sinomedisite Bio-tech Co.,Ltd
+
+OUI:6095CEC*
+ ID_OUI_FROM_DATABASE=Synamedia
+
+OUI:6095CED*
+ ID_OUI_FROM_DATABASE=GovComm
+
+OUI:6095CEE*
+ ID_OUI_FROM_DATABASE=VNS Inc.
+
 OUI:609620*
  ID_OUI_FROM_DATABASE=Private
 
@@ -56873,6 +57185,9 @@ OUI:60D1AA*
 OUI:60D21C*
  ID_OUI_FROM_DATABASE=Sunnovo International Limited
 
+OUI:60D248*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:60D262*
  ID_OUI_FROM_DATABASE=Tzukuri Pty Ltd
 
@@ -57836,6 +58151,9 @@ OUI:683E34*
 OUI:683EEC*
  ID_OUI_FROM_DATABASE=ERECA
 
+OUI:683F1E*
+ ID_OUI_FROM_DATABASE=EFFECT Photonics B.V.
+
 OUI:684352*
  ID_OUI_FROM_DATABASE=Bhuu Limited
 
@@ -57920,6 +58238,9 @@ OUI:686975*
 OUI:6869F2*
  ID_OUI_FROM_DATABASE=ComAp s.r.o.
 
+OUI:686DBC*
+ ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd.
+
 OUI:686E23*
  ID_OUI_FROM_DATABASE=Wi3 Inc.
 
@@ -57953,6 +58274,9 @@ OUI:687CC8*
 OUI:687CD5*
  ID_OUI_FROM_DATABASE=Y Soft Corporation, a.s.
 
+OUI:687D6B*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:687F74*
  ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC
 
@@ -58218,7 +58542,7 @@ OUI:68DB54*
  ID_OUI_FROM_DATABASE=Phicomm (Shanghai) Co., Ltd.
 
 OUI:68DB67*
- ID_OUI_FROM_DATABASE=Nantong Coship Electronics Co., Ltd
+ ID_OUI_FROM_DATABASE=Nantong Coship Electronics Co., Ltd.
 
 OUI:68DB96*
  ID_OUI_FROM_DATABASE=OPWILL Technologies CO .,LTD
@@ -58388,6 +58712,9 @@ OUI:6C25B9*
 OUI:6C2779*
  ID_OUI_FROM_DATABASE=Microsoft Mobile Oy
 
+OUI:6C2990*
+ ID_OUI_FROM_DATABASE=WiZ Connected Lighting Company Limited
+
 OUI:6C2995*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
@@ -58562,6 +58889,9 @@ OUI:6C5CDE*
 OUI:6C5D63*
  ID_OUI_FROM_DATABASE=ShenZhen Rapoo Technology Co., Ltd.
 
+OUI:6C5E3B*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:6C5E7A*
  ID_OUI_FROM_DATABASE=Ubiquitous Internet Telecom Co., Ltd
 
@@ -58628,6 +58958,9 @@ OUI:6C8686*
 OUI:6C8814*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:6C8AEC*
+ ID_OUI_FROM_DATABASE=Nantong Coship Electronics Co., Ltd.
+
 OUI:6C8B2F*
  ID_OUI_FROM_DATABASE=zte corporation
 
@@ -58721,6 +59054,9 @@ OUI:6CA96F*
 OUI:6CAAB3*
  ID_OUI_FROM_DATABASE=Ruckus Wireless
 
+OUI:6CAB05*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:6CAB31*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -58812,7 +59148,7 @@ OUI:6CD032*
  ID_OUI_FROM_DATABASE=LG Electronics
 
 OUI:6CD146*
- ID_OUI_FROM_DATABASE=Smartek d.o.o.
+ ID_OUI_FROM_DATABASE=FRAMOS GmbH
 
 OUI:6CD1B0*
  ID_OUI_FROM_DATABASE=WING SING ELECTRONICS HONG KONG LIMITED
@@ -58913,6 +59249,9 @@ OUI:6CEFC6*
 OUI:6CF049*
  ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD.
 
+OUI:6CF17E*
+ ID_OUI_FROM_DATABASE=Zhejiang Uniview Technologies Co.,Ltd.
+
 OUI:6CF373*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -58955,6 +59294,9 @@ OUI:700258*
 OUI:70037E*
  ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
 
+OUI:700433*
+ ID_OUI_FROM_DATABASE=California Things Inc.
+
 OUI:700514*
  ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications)
 
@@ -59594,6 +59936,9 @@ OUI:70B3D5015*
 OUI:70B3D5016*
  ID_OUI_FROM_DATABASE=Guardian Controls International Ltd
 
+OUI:70B3D5019*
+ ID_OUI_FROM_DATABASE=Transit Solutions, LLC.
+
 OUI:70B3D501A*
  ID_OUI_FROM_DATABASE=Cubro Acronet GesmbH
 
@@ -59741,6 +60086,9 @@ OUI:70B3D5059*
 OUI:70B3D505A*
  ID_OUI_FROM_DATABASE=Uni Control System Sp. z o. o.
 
+OUI:70B3D505B*
+ ID_OUI_FROM_DATABASE=PAL Inc.
+
 OUI:70B3D505C*
  ID_OUI_FROM_DATABASE=Amber Kinetics Inc
 
@@ -59765,6 +60113,9 @@ OUI:70B3D5063*
 OUI:70B3D5066*
  ID_OUI_FROM_DATABASE=North Pole Engineering, Inc.
 
+OUI:70B3D5068*
+ ID_OUI_FROM_DATABASE=Onethinx BV
+
 OUI:70B3D5069*
  ID_OUI_FROM_DATABASE=ONDEMAND LABORATORY Co., Ltd.
 
@@ -59816,6 +60167,9 @@ OUI:70B3D507E*
 OUI:70B3D507F*
  ID_OUI_FROM_DATABASE=Abalance Corporation
 
+OUI:70B3D5080*
+ ID_OUI_FROM_DATABASE=ABB
+
 OUI:70B3D5081*
  ID_OUI_FROM_DATABASE=IST Technologies (SHENZHEN) Limited
 
@@ -59864,6 +60218,9 @@ OUI:70B3D5091*
 OUI:70B3D5092*
  ID_OUI_FROM_DATABASE=inomed Medizintechnik GmbH
 
+OUI:70B3D5093*
+ ID_OUI_FROM_DATABASE=Legrand Electric Ltd
+
 OUI:70B3D5094*
  ID_OUI_FROM_DATABASE=Circuitlink Pty Ltd
 
@@ -60008,6 +60365,9 @@ OUI:70B3D50C8*
 OUI:70B3D50C9*
  ID_OUI_FROM_DATABASE=LINEAGE POWER PVT LTD.,
 
+OUI:70B3D50CA*
+ ID_OUI_FROM_DATABASE=VITEC
+
 OUI:70B3D50CD*
  ID_OUI_FROM_DATABASE=AML Oceanographic
 
@@ -60128,6 +60488,9 @@ OUI:70B3D50FF*
 OUI:70B3D5100*
  ID_OUI_FROM_DATABASE=Gupsy GmbH
 
+OUI:70B3D5102*
+ ID_OUI_FROM_DATABASE=Oxford Monitoring Solutions Ltd
+
 OUI:70B3D5103*
  ID_OUI_FROM_DATABASE=HANYOUNG NUX CO.,LTD
 
@@ -60161,6 +60524,9 @@ OUI:70B3D510E*
 OUI:70B3D510F*
  ID_OUI_FROM_DATABASE=neQis
 
+OUI:70B3D5111*
+ ID_OUI_FROM_DATABASE=Leonardo Sistemi Integrati S.r.l.
+
 OUI:70B3D5112*
  ID_OUI_FROM_DATABASE=DiTEST Fahrzeugdiagnose GmbH
 
@@ -60311,6 +60677,9 @@ OUI:70B3D514F*
 OUI:70B3D5150*
  ID_OUI_FROM_DATABASE=YUYAMA MFG Co.,Ltd
 
+OUI:70B3D5151*
+ ID_OUI_FROM_DATABASE=Virsae Group Ltd
+
 OUI:70B3D5152*
  ID_OUI_FROM_DATABASE=Xped Corporation Pty Ltd
 
@@ -60650,9 +61019,15 @@ OUI:70B3D51F4*
 OUI:70B3D51F5*
  ID_OUI_FROM_DATABASE=Martec S.p.A.
 
+OUI:70B3D51F7*
+ ID_OUI_FROM_DATABASE=Morgan Schaffer Inc.
+
 OUI:70B3D51F8*
  ID_OUI_FROM_DATABASE=Convergent Design
 
+OUI:70B3D51F9*
+ ID_OUI_FROM_DATABASE=Automata GmbH & Co. KG
+
 OUI:70B3D51FD*
  ID_OUI_FROM_DATABASE=BRS Sistemas Eletrônicos
 
@@ -60701,6 +61076,9 @@ OUI:70B3D520E*
 OUI:70B3D520F*
  ID_OUI_FROM_DATABASE=Tieline Research Pty Ltd
 
+OUI:70B3D5210*
+ ID_OUI_FROM_DATABASE=Eastone Century Technology Co.,Ltd.
+
 OUI:70B3D5211*
  ID_OUI_FROM_DATABASE=Fracarro srl
 
@@ -60797,6 +61175,9 @@ OUI:70B3D5235*
 OUI:70B3D5236*
  ID_OUI_FROM_DATABASE=Monnit Corporation
 
+OUI:70B3D5237*
+ ID_OUI_FROM_DATABASE=Sikom AS
+
 OUI:70B3D5238*
  ID_OUI_FROM_DATABASE=Arete Associates
 
@@ -60842,6 +61223,9 @@ OUI:70B3D524A*
 OUI:70B3D524B*
  ID_OUI_FROM_DATABASE=TOSEI ENGINEERING CORP.
 
+OUI:70B3D524C*
+ ID_OUI_FROM_DATABASE=Astronomical Research Cameras, Inc.
+
 OUI:70B3D524D*
  ID_OUI_FROM_DATABASE=INFO CREATIVE (HK) LTD
 
@@ -60872,6 +61256,9 @@ OUI:70B3D5255*
 OUI:70B3D5257*
  ID_OUI_FROM_DATABASE=LG Electronics
 
+OUI:70B3D5258*
+ ID_OUI_FROM_DATABASE=BAYKON Endüstriyel Kontrol Sistemleri San. ve Tic. A.Ş.
+
 OUI:70B3D5259*
  ID_OUI_FROM_DATABASE=Zebra Elektronik A.S.
 
@@ -61106,12 +61493,18 @@ OUI:70B3D52BE*
 OUI:70B3D52BF*
  ID_OUI_FROM_DATABASE=FOSHAN VOHOM
 
+OUI:70B3D52C0*
+ ID_OUI_FROM_DATABASE=Sensative AB
+
 OUI:70B3D52C2*
  ID_OUI_FROM_DATABASE=Quantum Detectors
 
 OUI:70B3D52C3*
  ID_OUI_FROM_DATABASE=Proterra
 
+OUI:70B3D52C7*
+ ID_OUI_FROM_DATABASE=Worldsensing
+
 OUI:70B3D52C9*
  ID_OUI_FROM_DATABASE=SEASON DESIGN TECHNOLOGY
 
@@ -61145,6 +61538,9 @@ OUI:70B3D52D5*
 OUI:70B3D52D6*
  ID_OUI_FROM_DATABASE=Kvazar LLC
 
+OUI:70B3D52D7*
+ ID_OUI_FROM_DATABASE=Private
+
 OUI:70B3D52DA*
  ID_OUI_FROM_DATABASE=Skywave Networks Private Limited
 
@@ -61292,6 +61688,9 @@ OUI:70B3D531B*
 OUI:70B3D531C*
  ID_OUI_FROM_DATABASE=FINANCIERE DE L'OMBREE (eolane)
 
+OUI:70B3D531D*
+ ID_OUI_FROM_DATABASE=AVA Monitoring AB
+
 OUI:70B3D531E*
  ID_OUI_FROM_DATABASE=GILLAM-FEI S.A.
 
@@ -61508,6 +61907,9 @@ OUI:70B3D537C*
 OUI:70B3D537D*
  ID_OUI_FROM_DATABASE=The DX Shop Limited
 
+OUI:70B3D537E*
+ ID_OUI_FROM_DATABASE=ELINKGATE JSC
+
 OUI:70B3D537F*
  ID_OUI_FROM_DATABASE=IDS Innomic GmbH
 
@@ -61628,6 +62030,9 @@ OUI:70B3D53BB*
 OUI:70B3D53BC*
  ID_OUI_FROM_DATABASE=SciTronix
 
+OUI:70B3D53BD*
+ ID_OUI_FROM_DATABASE=DAO QIN TECHNOLOGY CO.LTD.
+
 OUI:70B3D53BE*
  ID_OUI_FROM_DATABASE=MyDefence Communication ApS
 
@@ -61661,6 +62066,9 @@ OUI:70B3D53C9*
 OUI:70B3D53CA*
  ID_OUI_FROM_DATABASE=TTI Ltd
 
+OUI:70B3D53CB*
+ ID_OUI_FROM_DATABASE=GeoSpectrum Technologies Inc
+
 OUI:70B3D53CC*
  ID_OUI_FROM_DATABASE=TerOpta Ltd
 
@@ -61802,6 +62210,9 @@ OUI:70B3D5408*
 OUI:70B3D540A*
  ID_OUI_FROM_DATABASE=Monroe Electronics, Inc.
 
+OUI:70B3D540B*
+ ID_OUI_FROM_DATABASE=QUERCUS TECHNOLOGIES, S.L.
+
 OUI:70B3D540E*
  ID_OUI_FROM_DATABASE=Liaoyun Information Technology Co., Ltd.
 
@@ -61854,7 +62265,7 @@ OUI:70B3D542C*
  ID_OUI_FROM_DATABASE=D.Marchiori Srl
 
 OUI:70B3D542D*
- ID_OUI_FROM_DATABASE=RCH Italia SpA
+ ID_OUI_FROM_DATABASE=RCH ITALIA SPA
 
 OUI:70B3D542E*
  ID_OUI_FROM_DATABASE=Dr. Zinngrebe GmbH
@@ -61913,6 +62324,9 @@ OUI:70B3D5442*
 OUI:70B3D5443*
  ID_OUI_FROM_DATABASE=Slot3 GmbH
 
+OUI:70B3D5444*
+ ID_OUI_FROM_DATABASE=AMS Controls, Inc.
+
 OUI:70B3D5445*
  ID_OUI_FROM_DATABASE=Advanced Devices SpA
 
@@ -61934,6 +62348,9 @@ OUI:70B3D544E*
 OUI:70B3D5455*
  ID_OUI_FROM_DATABASE=Heartlandmicropayments
 
+OUI:70B3D5456*
+ ID_OUI_FROM_DATABASE=Technological Application and Production One Member Liability Company (Tecapro company)
+
 OUI:70B3D5457*
  ID_OUI_FROM_DATABASE=Vivaldi Clima Srl
 
@@ -61964,6 +62381,9 @@ OUI:70B3D5461*
 OUI:70B3D5462*
  ID_OUI_FROM_DATABASE=EarTex
 
+OUI:70B3D5463*
+ ID_OUI_FROM_DATABASE=WARECUBE,INC
+
 OUI:70B3D5465*
  ID_OUI_FROM_DATABASE=ENERGISME
 
@@ -62006,6 +62426,9 @@ OUI:70B3D5478*
 OUI:70B3D5479*
  ID_OUI_FROM_DATABASE=LINEAGE POWER PVT LTD.,
 
+OUI:70B3D547A*
+ ID_OUI_FROM_DATABASE=GlooVir Inc.
+
 OUI:70B3D547C*
  ID_OUI_FROM_DATABASE=Par-Tech, Inc.
 
@@ -62099,6 +62522,9 @@ OUI:70B3D54A6*
 OUI:70B3D54A7*
  ID_OUI_FROM_DATABASE=aelettronica group srl
 
+OUI:70B3D54A8*
+ ID_OUI_FROM_DATABASE=Acrodea, Inc.
+
 OUI:70B3D54A9*
  ID_OUI_FROM_DATABASE=WARECUBE,INC
 
@@ -62183,6 +62609,9 @@ OUI:70B3D54C7*
 OUI:70B3D54C8*
  ID_OUI_FROM_DATABASE=Hosokawa Micron Powder Systems
 
+OUI:70B3D54CC*
+ ID_OUI_FROM_DATABASE=FRESENIUS MEDICAL CARE
+
 OUI:70B3D54CD*
  ID_OUI_FROM_DATABASE=Power Electronics Espana, S.L.
 
@@ -62273,6 +62702,9 @@ OUI:70B3D54F8*
 OUI:70B3D54F9*
  ID_OUI_FROM_DATABASE=OptoPrecision GmbH
 
+OUI:70B3D54FA*
+ ID_OUI_FROM_DATABASE=Thruvision Limited
+
 OUI:70B3D54FC*
  ID_OUI_FROM_DATABASE=Mettler Toledo
 
@@ -62297,12 +62729,18 @@ OUI:70B3D5504*
 OUI:70B3D5505*
  ID_OUI_FROM_DATABASE=MC2-Technologies
 
+OUI:70B3D5506*
+ ID_OUI_FROM_DATABASE=Tonbo Imaging Pte Ltd
+
 OUI:70B3D5507*
  ID_OUI_FROM_DATABASE=Human Oriented Technology, Inc.
 
 OUI:70B3D5508*
  ID_OUI_FROM_DATABASE=INSEVIS GmbH
 
+OUI:70B3D550A*
+ ID_OUI_FROM_DATABASE=AMEDTEC Medizintechnik Aue GmbH
+
 OUI:70B3D550E*
  ID_OUI_FROM_DATABASE=Micro Trend Automation Co., LTD
 
@@ -62453,6 +62891,9 @@ OUI:70B3D5554*
 OUI:70B3D5555*
  ID_OUI_FROM_DATABASE=SoftLab-NSK
 
+OUI:70B3D5556*
+ ID_OUI_FROM_DATABASE=OHASHI ENGINEERING CO.,LTD.
+
 OUI:70B3D5557*
  ID_OUI_FROM_DATABASE=HEITEC AG
 
@@ -62498,6 +62939,9 @@ OUI:70B3D556C*
 OUI:70B3D5570*
  ID_OUI_FROM_DATABASE=Bayern Engineering GmbH & Co. KG
 
+OUI:70B3D5571*
+ ID_OUI_FROM_DATABASE=Echogear
+
 OUI:70B3D5572*
  ID_OUI_FROM_DATABASE=CRDE
 
@@ -62525,6 +62969,9 @@ OUI:70B3D557C*
 OUI:70B3D557D*
  ID_OUI_FROM_DATABASE=WICOM1 GmbH
 
+OUI:70B3D557E*
+ ID_OUI_FROM_DATABASE=Ascon Tecnologic S.r.l.
+
 OUI:70B3D557F*
  ID_OUI_FROM_DATABASE=MBio Diagnostics, Inc.
 
@@ -62612,6 +63059,9 @@ OUI:70B3D55A3*
 OUI:70B3D55A5*
  ID_OUI_FROM_DATABASE=Rehwork GmbH
 
+OUI:70B3D55A6*
+ ID_OUI_FROM_DATABASE=TimeMachines Inc.
+
 OUI:70B3D55A7*
  ID_OUI_FROM_DATABASE=ABB S.p.A.
 
@@ -62642,6 +63092,9 @@ OUI:70B3D55B6*
 OUI:70B3D55B8*
  ID_OUI_FROM_DATABASE=Hella Gutmann Solutions GmbH
 
+OUI:70B3D55BA*
+ ID_OUI_FROM_DATABASE=INFRASAFE/ ADVANTOR SYSTEMS
+
 OUI:70B3D55BC*
  ID_OUI_FROM_DATABASE=LAMTEC Meß- und Regeltechnik für Feuerungen GmbH & Co. KG
 
@@ -62708,6 +63161,9 @@ OUI:70B3D55DE*
 OUI:70B3D55E0*
  ID_OUI_FROM_DATABASE=Hexagon Metrology SAS
 
+OUI:70B3D55E1*
+ ID_OUI_FROM_DATABASE=Arevita
+
 OUI:70B3D55E2*
  ID_OUI_FROM_DATABASE=Grossenbacher Systeme AG
 
@@ -62984,6 +63440,9 @@ OUI:70B3D565C*
 OUI:70B3D565D*
  ID_OUI_FROM_DATABASE=GEGA ELECTRONIQUE
 
+OUI:70B3D565E*
+ ID_OUI_FROM_DATABASE=Season Electronics Ltd
+
 OUI:70B3D5660*
  ID_OUI_FROM_DATABASE=Smart Service Technologies CO., LTD
 
@@ -63287,6 +63746,9 @@ OUI:70B3D56FC*
 OUI:70B3D56FD*
  ID_OUI_FROM_DATABASE=Core Akıllı Ev Sistemleri
 
+OUI:70B3D56FE*
+ ID_OUI_FROM_DATABASE=NTO IRE-POLUS
+
 OUI:70B3D56FF*
  ID_OUI_FROM_DATABASE=AKEO PLUS
 
@@ -63371,6 +63833,9 @@ OUI:70B3D5723*
 OUI:70B3D5724*
  ID_OUI_FROM_DATABASE=Quan International Co., Ltd.
 
+OUI:70B3D5726*
+ ID_OUI_FROM_DATABASE=ATGS
+
 OUI:70B3D5727*
  ID_OUI_FROM_DATABASE=LP Technologies Inc.
 
@@ -63755,6 +64220,9 @@ OUI:70B3D57C8*
 OUI:70B3D57C9*
  ID_OUI_FROM_DATABASE=Council Rock
 
+OUI:70B3D57CB*
+ ID_OUI_FROM_DATABASE=KeyW Corporation
+
 OUI:70B3D57CD*
  ID_OUI_FROM_DATABASE=Molekuler Goruntuleme A.S.
 
@@ -63876,7 +64344,7 @@ OUI:70B3D57FD*
  ID_OUI_FROM_DATABASE=SYS TEC electronic GmbH
 
 OUI:70B3D57FE*
- ID_OUI_FROM_DATABASE=RCH Italia SpA
+ ID_OUI_FROM_DATABASE=RCH ITALIA SPA
 
 OUI:70B3D5800*
  ID_OUI_FROM_DATABASE=HeadsafeIP PTY LTD
@@ -63953,6 +64421,9 @@ OUI:70B3D5820*
 OUI:70B3D5821*
  ID_OUI_FROM_DATABASE=HL2 group
 
+OUI:70B3D5822*
+ ID_OUI_FROM_DATABASE=Angora Networks
+
 OUI:70B3D5823*
  ID_OUI_FROM_DATABASE=SP Controls
 
@@ -63998,6 +64469,9 @@ OUI:70B3D5838*
 OUI:70B3D5839*
  ID_OUI_FROM_DATABASE=Rockwell Collins Canada
 
+OUI:70B3D583A*
+ ID_OUI_FROM_DATABASE=EMDEP CENTRO TECNOLOGICO MEXICO
+
 OUI:70B3D583B*
  ID_OUI_FROM_DATABASE=Telefonix Incorporated
 
@@ -64065,7 +64539,7 @@ OUI:70B3D5855*
  ID_OUI_FROM_DATABASE=CRDE
 
 OUI:70B3D5857*
- ID_OUI_FROM_DATABASE=RCH Italia SpA
+ ID_OUI_FROM_DATABASE=RCH ITALIA SPA
 
 OUI:70B3D585A*
  ID_OUI_FROM_DATABASE=BRUSHIES
@@ -64163,6 +64637,9 @@ OUI:70B3D5881*
 OUI:70B3D5882*
  ID_OUI_FROM_DATABASE=SIMON TECH, S.L.
 
+OUI:70B3D5884*
+ ID_OUI_FROM_DATABASE=LG Electronics
+
 OUI:70B3D5885*
  ID_OUI_FROM_DATABASE=QuirkLogic
 
@@ -64283,6 +64760,9 @@ OUI:70B3D58C2*
 OUI:70B3D58C3*
  ID_OUI_FROM_DATABASE=Wyebot, Inc.
 
+OUI:70B3D58C4*
+ ID_OUI_FROM_DATABASE=APE GmbH
+
 OUI:70B3D58C5*
  ID_OUI_FROM_DATABASE=HMicro Inc
 
@@ -64331,6 +64811,9 @@ OUI:70B3D58DB*
 OUI:70B3D58DC*
  ID_OUI_FROM_DATABASE=Niveo International BV
 
+OUI:70B3D58DF*
+ ID_OUI_FROM_DATABASE=DORLET SAU
+
 OUI:70B3D58E0*
  ID_OUI_FROM_DATABASE=SOUDAX EQUIPEMENTS
 
@@ -64352,6 +64835,9 @@ OUI:70B3D58EB*
 OUI:70B3D58EC*
  ID_OUI_FROM_DATABASE=Rudy Tellert
 
+OUI:70B3D58ED*
+ ID_OUI_FROM_DATABASE=NanoSense
+
 OUI:70B3D58EE*
  ID_OUI_FROM_DATABASE=Network Additions
 
@@ -64667,6 +65153,9 @@ OUI:70B3D597F*
 OUI:70B3D5981*
  ID_OUI_FROM_DATABASE=Zamir Recognition Systems Ltd.
 
+OUI:70B3D5982*
+ ID_OUI_FROM_DATABASE=3S - Sensors, Signal Processing, Systems GmbH
+
 OUI:70B3D5984*
  ID_OUI_FROM_DATABASE=Sanmina Israel
 
@@ -64724,6 +65213,9 @@ OUI:70B3D5999*
 OUI:70B3D599A*
  ID_OUI_FROM_DATABASE=KEVIC. inc,
 
+OUI:70B3D599B*
+ ID_OUI_FROM_DATABASE=RCH ITALIA SPA
+
 OUI:70B3D599C*
  ID_OUI_FROM_DATABASE=Enerwise Solutions Ltd.
 
@@ -64796,6 +65288,9 @@ OUI:70B3D59BD*
 OUI:70B3D59BE*
  ID_OUI_FROM_DATABASE=Izome
 
+OUI:70B3D59BF*
+ ID_OUI_FROM_DATABASE=Xiris Automation Inc.
+
 OUI:70B3D59C0*
  ID_OUI_FROM_DATABASE=Schneider Displaytechnik GmbH
 
@@ -64859,6 +65354,9 @@ OUI:70B3D59D7*
 OUI:70B3D59D9*
  ID_OUI_FROM_DATABASE=ATX Networks Corp
 
+OUI:70B3D59DA*
+ ID_OUI_FROM_DATABASE=Blake UK
+
 OUI:70B3D59DB*
  ID_OUI_FROM_DATABASE=CAS Medical Systems, Inc
 
@@ -65033,6 +65531,9 @@ OUI:70B3D5A29*
 OUI:70B3D5A2A*
  ID_OUI_FROM_DATABASE=Redwood Systems
 
+OUI:70B3D5A2B*
+ ID_OUI_FROM_DATABASE=Clever Devices
+
 OUI:70B3D5A2C*
  ID_OUI_FROM_DATABASE=TLV CO., LTD.
 
@@ -65078,12 +65579,18 @@ OUI:70B3D5A3F*
 OUI:70B3D5A40*
  ID_OUI_FROM_DATABASE=STRACK LIFT AUTOMATION GmbH
 
+OUI:70B3D5A42*
+ ID_OUI_FROM_DATABASE=iMAR Navigation GmbH
+
 OUI:70B3D5A43*
  ID_OUI_FROM_DATABASE=OLEDCOMM
 
 OUI:70B3D5A44*
  ID_OUI_FROM_DATABASE=FSR Inc
 
+OUI:70B3D5A45*
+ ID_OUI_FROM_DATABASE=Viper Innovations Ltd
+
 OUI:70B3D5A46*
  ID_OUI_FROM_DATABASE=Foxconn 4Tech
 
@@ -65102,6 +65609,9 @@ OUI:70B3D5A4B*
 OUI:70B3D5A4C*
  ID_OUI_FROM_DATABASE=Alere Technologies AS
 
+OUI:70B3D5A4D*
+ ID_OUI_FROM_DATABASE=LANSITEC TECHNOLOGY CO., LTD
+
 OUI:70B3D5A4E*
  ID_OUI_FROM_DATABASE=Array Technologies Inc.
 
@@ -65360,12 +65870,18 @@ OUI:70B3D5ABB*
 OUI:70B3D5ABC*
  ID_OUI_FROM_DATABASE=BKM-Micronic Richtfunkanlagen GmbH
 
+OUI:70B3D5ABD*
+ ID_OUI_FROM_DATABASE=wtec GmbH
+
 OUI:70B3D5ABE*
  ID_OUI_FROM_DATABASE=MART NETWORK SOLUTIONS LTD
 
 OUI:70B3D5ABF*
  ID_OUI_FROM_DATABASE=AGR International
 
+OUI:70B3D5AC0*
+ ID_OUI_FROM_DATABASE=RITEC
+
 OUI:70B3D5AC1*
  ID_OUI_FROM_DATABASE=AEM Singapore Pte. Ltd.
 
@@ -65525,6 +66041,9 @@ OUI:70B3D5B04*
 OUI:70B3D5B05*
  ID_OUI_FROM_DATABASE=E-PLUS TECHNOLOGY CO., LTD
 
+OUI:70B3D5B06*
+ ID_OUI_FROM_DATABASE=MULTIVOICE LLC
+
 OUI:70B3D5B07*
  ID_OUI_FROM_DATABASE=Arrowvale Electronics
 
@@ -65576,6 +66095,9 @@ OUI:70B3D5B1E*
 OUI:70B3D5B1F*
  ID_OUI_FROM_DATABASE=TECNOWATT
 
+OUI:70B3D5B20*
+ ID_OUI_FROM_DATABASE=ICT BUSINESS GROUP of Humanrights Center for disabled people
+
 OUI:70B3D5B21*
  ID_OUI_FROM_DATABASE=TATTILE SRL
 
@@ -65606,6 +66128,9 @@ OUI:70B3D5B2D*
 OUI:70B3D5B2E*
  ID_OUI_FROM_DATABASE=Green Access Ltd
 
+OUI:70B3D5B2F*
+ ID_OUI_FROM_DATABASE=Hermann Automation GmbH
+
 OUI:70B3D5B30*
  ID_OUI_FROM_DATABASE=Systolé Hardware B.V.
 
@@ -65681,6 +66206,9 @@ OUI:70B3D5B50*
 OUI:70B3D5B51*
  ID_OUI_FROM_DATABASE=Critical Link LLC
 
+OUI:70B3D5B52*
+ ID_OUI_FROM_DATABASE=AEye, Inc.
+
 OUI:70B3D5B53*
  ID_OUI_FROM_DATABASE=Revolution Retail Systems, LLC
 
@@ -65690,6 +66218,9 @@ OUI:70B3D5B55*
 OUI:70B3D5B56*
  ID_OUI_FROM_DATABASE=Power Electronics Espana, S.L.
 
+OUI:70B3D5B58*
+ ID_OUI_FROM_DATABASE=INTERNET PROTOCOLO LOGICA SL
+
 OUI:70B3D5B59*
  ID_OUI_FROM_DATABASE=FutureTechnologyLaboratories INC.
 
@@ -65735,6 +66266,9 @@ OUI:70B3D5B71*
 OUI:70B3D5B72*
  ID_OUI_FROM_DATABASE=UB330.net d.o.o.
 
+OUI:70B3D5B73*
+ ID_OUI_FROM_DATABASE=Cetto Industries
+
 OUI:70B3D5B74*
  ID_OUI_FROM_DATABASE=OnYield Inc Ltd
 
@@ -65882,6 +66416,9 @@ OUI:70B3D5BB3*
 OUI:70B3D5BB4*
  ID_OUI_FROM_DATABASE=Integritech
 
+OUI:70B3D5BB5*
+ ID_OUI_FROM_DATABASE=Grossenbacher Systeme AG
+
 OUI:70B3D5BB6*
  ID_OUI_FROM_DATABASE=Franke Aquarotter GmbH
 
@@ -65924,6 +66461,9 @@ OUI:70B3D5BC5*
 OUI:70B3D5BC6*
  ID_OUI_FROM_DATABASE=Hatteland Display AS
 
+OUI:70B3D5BC9*
+ ID_OUI_FROM_DATABASE=Yite technology
+
 OUI:70B3D5BCA*
  ID_OUI_FROM_DATABASE=Deymed Diagnostic
 
@@ -65987,6 +66527,9 @@ OUI:70B3D5BE5*
 OUI:70B3D5BE6*
  ID_OUI_FROM_DATABASE=CCII Systems (Pty) Ltd
 
+OUI:70B3D5BE7*
+ ID_OUI_FROM_DATABASE=Syscom Instruments SA
+
 OUI:70B3D5BE8*
  ID_OUI_FROM_DATABASE=AndFun Co.,Ltd.
 
@@ -66035,12 +66578,18 @@ OUI:70B3D5BFB*
 OUI:70B3D5BFE*
  ID_OUI_FROM_DATABASE=Aplex Technology Inc.
 
+OUI:70B3D5C00*
+ ID_OUI_FROM_DATABASE=BESO sp. z o.o.
+
 OUI:70B3D5C01*
  ID_OUI_FROM_DATABASE=SmartGuard LLC
 
 OUI:70B3D5C03*
  ID_OUI_FROM_DATABASE=XAVi Technologies Corp.
 
+OUI:70B3D5C04*
+ ID_OUI_FROM_DATABASE=Prolan Zrt.
+
 OUI:70B3D5C05*
  ID_OUI_FROM_DATABASE=KST technology
 
@@ -66209,6 +66758,9 @@ OUI:70B3D5C4D*
 OUI:70B3D5C4F*
  ID_OUI_FROM_DATABASE=AE Van de Vliet BVBA
 
+OUI:70B3D5C51*
+ ID_OUI_FROM_DATABASE=Innotas Elektronik GmbH
+
 OUI:70B3D5C53*
  ID_OUI_FROM_DATABASE=S Labs sp. z o.o.
 
@@ -66236,6 +66788,9 @@ OUI:70B3D5C5C*
 OUI:70B3D5C5D*
  ID_OUI_FROM_DATABASE=FOSHAN SHILANTIAN NETWORK S.T. CO., LTD.
 
+OUI:70B3D5C5F*
+ ID_OUI_FROM_DATABASE=Clean-Lasersysteme GmbH
+
 OUI:70B3D5C60*
  ID_OUI_FROM_DATABASE=Gogo BA
 
@@ -66443,6 +66998,9 @@ OUI:70B3D5CC3*
 OUI:70B3D5CC5*
  ID_OUI_FROM_DATABASE=Intecom
 
+OUI:70B3D5CC6*
+ ID_OUI_FROM_DATABASE=MB connect line GmbH Fernwartungssysteme
+
 OUI:70B3D5CC8*
  ID_OUI_FROM_DATABASE=PROFEN COMMUNICATIONS
 
@@ -66485,6 +67043,9 @@ OUI:70B3D5CD5*
 OUI:70B3D5CD6*
  ID_OUI_FROM_DATABASE=VideoRay LLC
 
+OUI:70B3D5CD7*
+ ID_OUI_FROM_DATABASE=AutomationX GmbH
+
 OUI:70B3D5CD9*
  ID_OUI_FROM_DATABASE=Peter Huber Kaeltemaschinenbau GmbH
 
@@ -66548,6 +67109,9 @@ OUI:70B3D5CF5*
 OUI:70B3D5CF6*
  ID_OUI_FROM_DATABASE=Tornado Modular Systems
 
+OUI:70B3D5CF8*
+ ID_OUI_FROM_DATABASE=Idneo Technologies S.A.U.
+
 OUI:70B3D5CFD*
  ID_OUI_FROM_DATABASE=iLOQ Oy
 
@@ -66695,6 +67259,9 @@ OUI:70B3D5D47*
 OUI:70B3D5D48*
  ID_OUI_FROM_DATABASE=HEADROOM Broadcast GmbH
 
+OUI:70B3D5D49*
+ ID_OUI_FROM_DATABASE=Sicon srl
+
 OUI:70B3D5D4A*
  ID_OUI_FROM_DATABASE=OÜ ELIKO Tehnoloogia Arenduskeskus
 
@@ -66725,6 +67292,9 @@ OUI:70B3D5D54*
 OUI:70B3D5D55*
  ID_OUI_FROM_DATABASE=WM Design s.r.o
 
+OUI:70B3D5D56*
+ ID_OUI_FROM_DATABASE=KRONOTECH SRL
+
 OUI:70B3D5D57*
  ID_OUI_FROM_DATABASE=TRIUMPH BOARD a.s.
 
@@ -66965,6 +67535,9 @@ OUI:70B3D5DC0*
 OUI:70B3D5DC2*
  ID_OUI_FROM_DATABASE=SwineTech, Inc.
 
+OUI:70B3D5DC3*
+ ID_OUI_FROM_DATABASE=Fath Mechatronics
+
 OUI:70B3D5DC5*
  ID_OUI_FROM_DATABASE=Excel Medical Electronics LLC
 
@@ -67064,6 +67637,9 @@ OUI:70B3D5DF2*
 OUI:70B3D5DF3*
  ID_OUI_FROM_DATABASE=SPC Bioclinicum
 
+OUI:70B3D5DF4*
+ ID_OUI_FROM_DATABASE=Heim- & Bürokommunikation Ilmert e.K.
+
 OUI:70B3D5DF5*
  ID_OUI_FROM_DATABASE=Beijing Huanyu Zhilian Science &Technology Co., Ltd.
 
@@ -67082,12 +67658,18 @@ OUI:70B3D5DF9*
 OUI:70B3D5DFA*
  ID_OUI_FROM_DATABASE=Newtouch Electronics (Shanghai) Co.,Ltd.
 
+OUI:70B3D5DFB*
+ ID_OUI_FROM_DATABASE=Yamamoto Works Ltd.
+
 OUI:70B3D5DFC*
  ID_OUI_FROM_DATABASE=ELECTRONIC SYSTEMS DESIGN SPRL
 
 OUI:70B3D5DFD*
  ID_OUI_FROM_DATABASE=Contiweb
 
+OUI:70B3D5DFE*
+ ID_OUI_FROM_DATABASE=microtec Sicherheitstechnik GmbH
+
 OUI:70B3D5DFF*
  ID_OUI_FROM_DATABASE=Spanawave Corporation
 
@@ -67121,6 +67703,9 @@ OUI:70B3D5E0D*
 OUI:70B3D5E0F*
  ID_OUI_FROM_DATABASE=Vtron Pty Ltd
 
+OUI:70B3D5E14*
+ ID_OUI_FROM_DATABASE=Automata Spa
+
 OUI:70B3D5E15*
  ID_OUI_FROM_DATABASE=Benetel
 
@@ -67142,6 +67727,9 @@ OUI:70B3D5E1B*
 OUI:70B3D5E1C*
  ID_OUI_FROM_DATABASE=Xcenter AS
 
+OUI:70B3D5E1E*
+ ID_OUI_FROM_DATABASE=Umano Medical Inc.
+
 OUI:70B3D5E1F*
  ID_OUI_FROM_DATABASE=THETA432
 
@@ -67157,6 +67745,9 @@ OUI:70B3D5E22*
 OUI:70B3D5E23*
  ID_OUI_FROM_DATABASE=Smith Meter, Inc.
 
+OUI:70B3D5E25*
+ ID_OUI_FROM_DATABASE=GJD Manufacturing
+
 OUI:70B3D5E26*
  ID_OUI_FROM_DATABASE=FEITIAN CO.,LTD.
 
@@ -67259,6 +67850,9 @@ OUI:70B3D5E52*
 OUI:70B3D5E53*
  ID_OUI_FROM_DATABASE=MI INC.
 
+OUI:70B3D5E54*
+ ID_OUI_FROM_DATABASE=Beijing PanGu Company
+
 OUI:70B3D5E55*
  ID_OUI_FROM_DATABASE=BELT S.r.l.
 
@@ -67352,6 +67946,9 @@ OUI:70B3D5E86*
 OUI:70B3D5E88*
  ID_OUI_FROM_DATABASE=Breas Medical AB
 
+OUI:70B3D5E8A*
+ ID_OUI_FROM_DATABASE=Melecs EWS GmbH
+
 OUI:70B3D5E8C*
  ID_OUI_FROM_DATABASE=Fracarro srl
 
@@ -67397,6 +67994,9 @@ OUI:70B3D5E9B*
 OUI:70B3D5E9C*
  ID_OUI_FROM_DATABASE=ATG UV Technology
 
+OUI:70B3D5E9D*
+ ID_OUI_FROM_DATABASE=INTECH
+
 OUI:70B3D5E9E*
  ID_OUI_FROM_DATABASE=MSB Elektronik und Gerätebau GmbH
 
@@ -67430,6 +68030,9 @@ OUI:70B3D5EAB*
 OUI:70B3D5EAC*
  ID_OUI_FROM_DATABASE=Kentech Instruments Limited
 
+OUI:70B3D5EAD*
+ ID_OUI_FROM_DATABASE=Cobo, Inc.
+
 OUI:70B3D5EAE*
  ID_OUI_FROM_DATABASE=Orlaco Products B.V.
 
@@ -67598,6 +68201,9 @@ OUI:70B3D5EFB*
 OUI:70B3D5EFE*
  ID_OUI_FROM_DATABASE=MEIDEN SYSTEM SOLUTIONS
 
+OUI:70B3D5EFF*
+ ID_OUI_FROM_DATABASE=Carlo Gavazzi Industri
+
 OUI:70B3D5F00*
  ID_OUI_FROM_DATABASE=Aplex Technology Inc.
 
@@ -67688,6 +68294,9 @@ OUI:70B3D5F25*
 OUI:70B3D5F27*
  ID_OUI_FROM_DATABASE=NIRIT- Xinwei  Telecom Technology Co., Ltd.
 
+OUI:70B3D5F29*
+ ID_OUI_FROM_DATABASE=SamabaNova Systems
+
 OUI:70B3D5F2A*
  ID_OUI_FROM_DATABASE=WIBOND Informationssysteme GmbH
 
@@ -67982,6 +68591,9 @@ OUI:70B3D5FB6*
 OUI:70B3D5FB7*
  ID_OUI_FROM_DATABASE=SAICE
 
+OUI:70B3D5FB9*
+ ID_OUI_FROM_DATABASE=EYEDEA
+
 OUI:70B3D5FBA*
  ID_OUI_FROM_DATABASE=Apogee Applied Research, Inc.
 
@@ -68051,6 +68663,9 @@ OUI:70B3D5FD3*
 OUI:70B3D5FD4*
  ID_OUI_FROM_DATABASE=GETRALINE
 
+OUI:70B3D5FD5*
+ ID_OUI_FROM_DATABASE=OCEANCCTV LTD
+
 OUI:70B3D5FD6*
  ID_OUI_FROM_DATABASE=Visual Fan
 
@@ -68186,6 +68801,9 @@ OUI:70C6AC*
 OUI:70C76F*
  ID_OUI_FROM_DATABASE=INNO S
 
+OUI:70C7F2*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:70C833*
  ID_OUI_FROM_DATABASE=Wirepas Oy
 
@@ -68384,6 +69002,9 @@ OUI:70F96D*
 OUI:70FC8C*
  ID_OUI_FROM_DATABASE=OneAccess SA
 
+OUI:70FC8F*
+ ID_OUI_FROM_DATABASE=FREEBOX SAS
+
 OUI:70FD46*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -68573,6 +69194,9 @@ OUI:743256*
 OUI:743400*
  ID_OUI_FROM_DATABASE=MTG Co., Ltd.
 
+OUI:7434AE*
+ ID_OUI_FROM_DATABASE=this is engineering Inc.
+
 OUI:74366D*
  ID_OUI_FROM_DATABASE=Vodafone Italia S.p.A.
 
@@ -68585,6 +69209,9 @@ OUI:74373B*
 OUI:743889*
  ID_OUI_FROM_DATABASE=ANNAX Anzeigesysteme GmbH
 
+OUI:7438B7*
+ ID_OUI_FROM_DATABASE=CANON INC.
+
 OUI:743A65*
  ID_OUI_FROM_DATABASE=NEC Corporation
 
@@ -68606,6 +69233,9 @@ OUI:744401*
 OUI:74458A*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:7445CE*
+ ID_OUI_FROM_DATABASE=CRESYN
+
 OUI:7446A0*
  ID_OUI_FROM_DATABASE=Hewlett Packard
 
@@ -68639,6 +69269,9 @@ OUI:745612*
 OUI:745798*
  ID_OUI_FROM_DATABASE=TRUMPF Laser GmbH + Co. KG
 
+OUI:745909*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:745933*
  ID_OUI_FROM_DATABASE=Danal Entertainment
 
@@ -69158,6 +69791,9 @@ OUI:74EC42*
 OUI:74ECF1*
  ID_OUI_FROM_DATABASE=Acumen
 
+OUI:74EE2A*
+ ID_OUI_FROM_DATABASE=SHENZHEN BILIAN ELECTRONIC CO.,LTD
+
 OUI:74F06D*
  ID_OUI_FROM_DATABASE=AzureWave Technology Inc.
 
@@ -69818,6 +70454,9 @@ OUI:78C2C0E*
 OUI:78C2C0F*
  ID_OUI_FROM_DATABASE=Private
 
+OUI:78C313*
+ ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd.
+
 OUI:78C3E9*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -69893,6 +70532,9 @@ OUI:78CB33*
 OUI:78CB68*
  ID_OUI_FROM_DATABASE=DAEHAP HYPER-TECH
 
+OUI:78CC2B*
+ ID_OUI_FROM_DATABASE=SINEWY TECHNOLOGY CO., LTD
+
 OUI:78CD8E*
  ID_OUI_FROM_DATABASE=SMC Networks Inc
 
@@ -69905,6 +70547,9 @@ OUI:78D129*
 OUI:78D294*
  ID_OUI_FROM_DATABASE=NETGEAR
 
+OUI:78D347*
+ ID_OUI_FROM_DATABASE=Ericsson AB
+
 OUI:78D34F*
  ID_OUI_FROM_DATABASE=Pace-O-Matic, Inc.
 
@@ -70199,6 +70844,9 @@ OUI:7C2048*
 OUI:7C2064*
  ID_OUI_FROM_DATABASE=Alcatel-Lucent IPD
 
+OUI:7C2302*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:7C240C*
  ID_OUI_FROM_DATABASE=Telechips, Inc.
 
@@ -70553,6 +71201,9 @@ OUI:7C8274*
 OUI:7C8306*
  ID_OUI_FROM_DATABASE=Glen Dimplex Nordic as
 
+OUI:7C8956*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:7C89C1*
  ID_OUI_FROM_DATABASE=Palo Alto Networks
 
@@ -70571,6 +71222,9 @@ OUI:7C8EE4*
 OUI:7C9122*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:7C942A*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:7C94B2*
  ID_OUI_FROM_DATABASE=Philips Healthcare PCCI
 
@@ -70649,6 +71303,9 @@ OUI:7CB25C*
 OUI:7CB542*
  ID_OUI_FROM_DATABASE=ACES Technology
 
+OUI:7CB59B*
+ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+
 OUI:7CB733*
  ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP
 
@@ -70931,6 +71588,9 @@ OUI:7CEBEA*
 OUI:7CEC79*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
+OUI:7CEC9B*
+ ID_OUI_FROM_DATABASE=Fuzhou Teraway Information Technology Co.,Ltd
+
 OUI:7CED8D*
  ID_OUI_FROM_DATABASE=Microsoft
 
@@ -71313,7 +71973,7 @@ OUI:807ABF*
  ID_OUI_FROM_DATABASE=HTC Corporation
 
 OUI:807B1E*
- ID_OUI_FROM_DATABASE=Corsair Components
+ ID_OUI_FROM_DATABASE=Corsair Memory, Inc.
 
 OUI:807B850*
  ID_OUI_FROM_DATABASE=Shiroshita Industrial Co., Ltd.
@@ -71411,6 +72071,9 @@ OUI:808F1D*
 OUI:80912A*
  ID_OUI_FROM_DATABASE=Lih Rong electronic Enterprise Co., Ltd.
 
+OUI:809133*
+ ID_OUI_FROM_DATABASE=AzureWave Technology Inc.
+
 OUI:8091C0*
  ID_OUI_FROM_DATABASE=AgileMesh, Inc.
 
@@ -71726,6 +72389,9 @@ OUI:8404D2*
 OUI:840B2D*
  ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO MECHANICS CO., LTD.
 
+OUI:840B7C*
+ ID_OUI_FROM_DATABASE=Hitron Technologies. Inc
+
 OUI:840D8E*
  ID_OUI_FROM_DATABASE=Espressif Inc.
 
@@ -72122,6 +72788,45 @@ OUI:8489ECE*
 OUI:848A8D*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:848BCD0*
+ ID_OUI_FROM_DATABASE=SouXin Corporate
+
+OUI:848BCD1*
+ ID_OUI_FROM_DATABASE=Shenzhen LTIME In-Vehicle Entertainment System Company Limited
+
+OUI:848BCD2*
+ ID_OUI_FROM_DATABASE=CCX Technologies Inc.
+
+OUI:848BCD3*
+ ID_OUI_FROM_DATABASE=Annapurna labs
+
+OUI:848BCD4*
+ ID_OUI_FROM_DATABASE=Logic Supply
+
+OUI:848BCD5*
+ ID_OUI_FROM_DATABASE=exodraft a/s
+
+OUI:848BCD6*
+ ID_OUI_FROM_DATABASE=TWTG R&D B.V.
+
+OUI:848BCD7*
+ ID_OUI_FROM_DATABASE=Smart Code (Shenzhen) Technology Co.,Ltd
+
+OUI:848BCD9*
+ ID_OUI_FROM_DATABASE=NORALSY
+
+OUI:848BCDA*
+ ID_OUI_FROM_DATABASE=Sphera Telecom
+
+OUI:848BCDB*
+ ID_OUI_FROM_DATABASE=CHONGQING HUAYI KANGDAO TECHNOLOGY CO.,LTD.
+
+OUI:848BCDD*
+ ID_OUI_FROM_DATABASE=ENGISAT LDA
+
+OUI:848BCDE*
+ ID_OUI_FROM_DATABASE=Emotiv Inc
+
 OUI:848D84*
  ID_OUI_FROM_DATABASE=Rajant Corporation
 
@@ -72548,6 +73253,9 @@ OUI:8828B3*
 OUI:882950*
  ID_OUI_FROM_DATABASE=Netmoon Technology Co., Ltd
 
+OUI:88299C*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:882BD7*
  ID_OUI_FROM_DATABASE=ADDÉNERGIE  TECHNOLOGIES
 
@@ -72941,9 +73649,15 @@ OUI:889B39*
 OUI:889CA6*
  ID_OUI_FROM_DATABASE=BTB Korea INC
 
+OUI:889E33*
+ ID_OUI_FROM_DATABASE=TCT mobile ltd
+
 OUI:889F6F*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:889FAA*
+ ID_OUI_FROM_DATABASE=Hella Gutmann Solutions GmbH
+
 OUI:889FFA*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
@@ -73041,7 +73755,10 @@ OUI:88B291*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
 OUI:88B362*
- ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co. Ltd.)
+ ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co., Ltd.
+
+OUI:88B436*
+ ID_OUI_FROM_DATABASE=Private
 
 OUI:88B4A6*
  ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
@@ -73214,6 +73931,9 @@ OUI:88E9FE*
 OUI:88ED1C*
  ID_OUI_FROM_DATABASE=Cudo Communication Co., Ltd.
 
+OUI:88EF16*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:88F031*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
@@ -73247,6 +73967,9 @@ OUI:88FED6*
 OUI:8C006D*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:8C04BA*
+ ID_OUI_FROM_DATABASE=Dell Inc.
+
 OUI:8C04FF*
  ID_OUI_FROM_DATABASE=Technicolor CH USA Inc.
 
@@ -73559,6 +74282,33 @@ OUI:8C57FD*
 OUI:8C5877*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:8C593C1*
+ ID_OUI_FROM_DATABASE=Future Robot Technology Co., Limited
+
+OUI:8C593C2*
+ ID_OUI_FROM_DATABASE=Beida Jade Bird Universal Fire Alarm Device CO.,LTD.
+
+OUI:8C593C3*
+ ID_OUI_FROM_DATABASE=Chongqing beimoting technology co.ltd
+
+OUI:8C593C5*
+ ID_OUI_FROM_DATABASE=Spectranetix
+
+OUI:8C593C6*
+ ID_OUI_FROM_DATABASE=Qbic Technology Co., Ltd
+
+OUI:8C593C7*
+ ID_OUI_FROM_DATABASE=OBO Pro.2 Inc.
+
+OUI:8C593C8*
+ ID_OUI_FROM_DATABASE=Nanonord A/S
+
+OUI:8C593C9*
+ ID_OUI_FROM_DATABASE=GENIS
+
+OUI:8C593CD*
+ ID_OUI_FROM_DATABASE=IDRO-ELETTRICA S.P.A.
+
 OUI:8C5973*
  ID_OUI_FROM_DATABASE=Zyxel Communications Corporation
 
@@ -73766,6 +74516,9 @@ OUI:8CA5A1*
 OUI:8CA6DF*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
+OUI:8CA96F*
+ ID_OUI_FROM_DATABASE=D&M Holdings Inc.
+
 OUI:8CA982*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
@@ -73928,6 +74681,9 @@ OUI:8CE2DA*
 OUI:8CE38E*
  ID_OUI_FROM_DATABASE=Toshiba Memory Corporation
 
+OUI:8CE5C0*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:8CE748*
  ID_OUI_FROM_DATABASE=Private
 
@@ -73979,6 +74735,9 @@ OUI:8CFABA*
 OUI:8CFCA0*
  ID_OUI_FROM_DATABASE=Shenzhen Smart Device Technology Co., LTD.
 
+OUI:8CFD18*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:8CFDF0*
  ID_OUI_FROM_DATABASE=Qualcomm Inc.
 
@@ -74351,9 +75110,15 @@ OUI:907240*
 OUI:907282*
  ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS
 
+OUI:90735A*
+ ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
+
 OUI:907841*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
+OUI:9078B2*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:907910*
  ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd.
 
@@ -74759,6 +75524,9 @@ OUI:9405B6*
 OUI:940937*
  ID_OUI_FROM_DATABASE=HUMAX Co., Ltd.
 
+OUI:940B19*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:940B2D*
  ID_OUI_FROM_DATABASE=NetView Technologies(Shenzhen) Co., Ltd
 
@@ -75455,6 +76223,9 @@ OUI:980CA5*
 OUI:980D2E*
  ID_OUI_FROM_DATABASE=HTC Corporation
 
+OUI:980D67*
+ ID_OUI_FROM_DATABASE=Zyxel Communications Corporation
+
 OUI:980EE4*
  ID_OUI_FROM_DATABASE=Private
 
@@ -75542,6 +76313,9 @@ OUI:983571*
 OUI:9835B8*
  ID_OUI_FROM_DATABASE=Assembled Products Corporation
 
+OUI:9835ED*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:983713*
  ID_OUI_FROM_DATABASE=PT.Navicom Indonesia
 
@@ -75740,6 +76514,9 @@ OUI:988389*
 OUI:9884E3*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
+OUI:98865D*
+ ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co., Ltd.
+
 OUI:9886B1*
  ID_OUI_FROM_DATABASE=Flyaudio corporation (China)
 
@@ -76463,6 +77240,9 @@ OUI:9C7A03*
 OUI:9C7BD2*
  ID_OUI_FROM_DATABASE=NEOLAB Convergence
 
+OUI:9C7BEF*
+ ID_OUI_FROM_DATABASE=Hewlett Packard
+
 OUI:9C7DA3*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -76541,6 +77321,9 @@ OUI:9C9811*
 OUI:9C99A0*
  ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
 
+OUI:9C99CD*
+ ID_OUI_FROM_DATABASE=Voippartners
+
 OUI:9C9C1D*
  ID_OUI_FROM_DATABASE=Starkey Labs Inc.
 
@@ -77711,6 +78494,9 @@ OUI:A0FE61*
 OUI:A0FE91*
  ID_OUI_FROM_DATABASE=AVAT Automation GmbH
 
+OUI:A400E2*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:A40130*
  ID_OUI_FROM_DATABASE=ABIsystems Co., LTD
 
@@ -78275,6 +79061,9 @@ OUI:A4975C*
 OUI:A497BB*
  ID_OUI_FROM_DATABASE=Hitachi Industrial Equipment Systems Co.,Ltd
 
+OUI:A49813*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:A49947*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -78305,6 +79094,9 @@ OUI:A49F85*
 OUI:A49F89*
  ID_OUI_FROM_DATABASE=Shanghai Rui Rui Communication Technology Co.Ltd.
 
+OUI:A4A179*
+ ID_OUI_FROM_DATABASE=Nanjing dianyan electric power automation co. LTD
+
 OUI:A4A1C2*
  ID_OUI_FROM_DATABASE=Ericsson AB
 
@@ -78329,6 +79121,9 @@ OUI:A4AD00*
 OUI:A4ADB8*
  ID_OUI_FROM_DATABASE=Vitec Group, Camera Dynamics Ltd
 
+OUI:A4AE11*
+ ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd.
+
 OUI:A4AE9A*
  ID_OUI_FROM_DATABASE=Maestro Wireless Solutions ltd.
 
@@ -78818,6 +79613,9 @@ OUI:A845E9*
 OUI:A8474A*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
+OUI:A8494D*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:A849A5*
  ID_OUI_FROM_DATABASE=Lisantech Co., Ltd.
 
@@ -79439,6 +80237,9 @@ OUI:AC40EA*
 OUI:AC4122*
  ID_OUI_FROM_DATABASE=Eclipse Electronic Systems Inc.
 
+OUI:AC4228*
+ ID_OUI_FROM_DATABASE=Parta Networks
+
 OUI:AC4330*
  ID_OUI_FROM_DATABASE=Versa Networks
 
@@ -79508,6 +80309,9 @@ OUI:AC5AEE*
 OUI:AC5D10*
  ID_OUI_FROM_DATABASE=Pace Americas
 
+OUI:AC5D5C*
+ ID_OUI_FROM_DATABASE=FN-LINK TECHNOLOGY LIMITED
+
 OUI:AC5E8C*
  ID_OUI_FROM_DATABASE=Utillink
 
@@ -79649,6 +80453,9 @@ OUI:AC81F3*
 OUI:AC8317*
  ID_OUI_FROM_DATABASE=Shenzhen Furtunetel Communication Co., Ltd
 
+OUI:AC83E9*
+ ID_OUI_FROM_DATABASE=Beijing Zile Technology Co., Ltd
+
 OUI:AC83F0*
  ID_OUI_FROM_DATABASE=ImmediaTV Corporation
 
@@ -79862,6 +80669,9 @@ OUI:ACD657*
 OUI:ACD9D6*
  ID_OUI_FROM_DATABASE=tci GmbH
 
+OUI:ACDB48*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:ACDBDA*
  ID_OUI_FROM_DATABASE=Shenzhen Geniatech Inc, Ltd
 
@@ -79940,6 +80750,9 @@ OUI:ACF1DF*
 OUI:ACF2C5*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:ACF5E6*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:ACF6F7*
  ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications)
 
@@ -80375,6 +81188,9 @@ OUI:B0A2E7*
 OUI:B0A37E*
  ID_OUI_FROM_DATABASE=QING DAO HAIER TELECOM CO.,LTD.
 
+OUI:B0A6F5*
+ ID_OUI_FROM_DATABASE=Xaptum, Inc.
+
 OUI:B0A72A*
  ID_OUI_FROM_DATABASE=Ensemble Designs, Inc.
 
@@ -80420,6 +81236,9 @@ OUI:B0B3AD*
 OUI:B0B448*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
+OUI:B0B5E8*
+ ID_OUI_FROM_DATABASE=Ruroc LTD
+
 OUI:B0B867*
  ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise
 
@@ -80660,15 +81479,36 @@ OUI:B0FC0D*
 OUI:B0FC36*
  ID_OUI_FROM_DATABASE=CyberTAN Technology Inc.
 
+OUI:B0FD0B0*
+ ID_OUI_FROM_DATABASE=TAE HYUNG Industrial Electronics Co., Ltd.
+
+OUI:B0FD0B1*
+ ID_OUI_FROM_DATABASE=IDspire Corporation Ltd.
+
 OUI:B0FD0B2*
  ID_OUI_FROM_DATABASE=Vista Manufacturing
 
 OUI:B0FD0B3*
  ID_OUI_FROM_DATABASE=DMAC Security LLC
 
+OUI:B0FD0B4*
+ ID_OUI_FROM_DATABASE=Fasii Information Technology (Shanghai) Ltd.
+
+OUI:B0FD0B5*
+ ID_OUI_FROM_DATABASE=Taian Yuqi Communication Technology Co., Ltd
+
+OUI:B0FD0B6*
+ ID_OUI_FROM_DATABASE=DNESO TEN Ltd.
+
+OUI:B0FD0B7*
+ ID_OUI_FROM_DATABASE=Everynet Oy
+
 OUI:B0FD0B8*
  ID_OUI_FROM_DATABASE=eSenseLab Ltd.
 
+OUI:B0FD0B9*
+ ID_OUI_FROM_DATABASE=Eagle Acoustics Manufacturing, LLC
+
 OUI:B0FD0BA*
  ID_OUI_FROM_DATABASE=TEMCO JAPAN CO., LTD.
 
@@ -80681,6 +81521,9 @@ OUI:B0FD0BC*
 OUI:B0FD0BD*
  ID_OUI_FROM_DATABASE=Habana Labs LTD
 
+OUI:B0FD0BE*
+ ID_OUI_FROM_DATABASE=Shenzhen FEIBIT Electronic Technology Co.,LTD
+
 OUI:B0FEBD*
  ID_OUI_FROM_DATABASE=Private
 
@@ -80960,6 +81803,12 @@ OUI:B4527D*
 OUI:B4527E*
  ID_OUI_FROM_DATABASE=Sony Mobile Communications Inc
 
+OUI:B452A9*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
+OUI:B45459*
+ ID_OUI_FROM_DATABASE=China Mobile (Hangzhou) Information Technology Co., Ltd.
+
 OUI:B45570*
  ID_OUI_FROM_DATABASE=Borea
 
@@ -80975,6 +81824,9 @@ OUI:B45CA4*
 OUI:B45D50*
  ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company
 
+OUI:B46077*
+ ID_OUI_FROM_DATABASE=Sichuan Changhong Electric Ltd.
+
 OUI:B461FF*
  ID_OUI_FROM_DATABASE=Lumigon A/S
 
@@ -81080,6 +81932,9 @@ OUI:B4994C*
 OUI:B499BA*
  ID_OUI_FROM_DATABASE=Hewlett Packard
 
+OUI:B49A95*
+ ID_OUI_FROM_DATABASE=Shenzhen Boomtech Industrial Corporation
+
 OUI:B49CDF*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -81095,6 +81950,9 @@ OUI:B49EAC*
 OUI:B49EE6*
  ID_OUI_FROM_DATABASE=SHENZHEN TECHNOLOGY CO LTD
 
+OUI:B4A305*
+ ID_OUI_FROM_DATABASE=XIAMEN YAXON NETWORK CO., LTD.
+
 OUI:B4A382*
  ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd.
 
@@ -81194,6 +82052,9 @@ OUI:B4C170*
 OUI:B4C44E*
  ID_OUI_FROM_DATABASE=VXL eTech Pvt Ltd
 
+OUI:B4C4FC*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:B4C62E*
  ID_OUI_FROM_DATABASE=Molex CMS
 
@@ -81227,6 +82088,9 @@ OUI:B4CEFE*
 OUI:B4CFDB*
  ID_OUI_FROM_DATABASE=Shenzhen Jiuzhou Electric Co.,LTD
 
+OUI:B4CFE0*
+ ID_OUI_FROM_DATABASE=Sichuan tianyi kanghe communications co., LTD
+
 OUI:B4D0A9*
  ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd.
 
@@ -81245,6 +82109,9 @@ OUI:B4D8A9*
 OUI:B4D8DE*
  ID_OUI_FROM_DATABASE=iota Computing, Inc.
 
+OUI:B4DC09*
+ ID_OUI_FROM_DATABASE=Guangzhou Dawei Communication Co.,Ltd
+
 OUI:B4DD15*
  ID_OUI_FROM_DATABASE=ControlThings Oy Ab
 
@@ -81329,6 +82196,9 @@ OUI:B4F2E8*
 OUI:B4F323*
  ID_OUI_FROM_DATABASE=PETATEL INC.
 
+OUI:B4F58E*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:B4F61C*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
@@ -81368,6 +82238,9 @@ OUI:B805AB*
 OUI:B80716*
  ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
 
+OUI:B80756*
+ ID_OUI_FROM_DATABASE=Cisco Meraki
+
 OUI:B808CF*
  ID_OUI_FROM_DATABASE=Intel Corporate
 
@@ -81554,6 +82427,9 @@ OUI:B86491*
 OUI:B8653B*
  ID_OUI_FROM_DATABASE=Bolymin, Inc.
 
+OUI:B86685*
+ ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS
+
 OUI:B869C2*
  ID_OUI_FROM_DATABASE=Sunitec Enterprise Co., Ltd.
 
@@ -81659,6 +82535,9 @@ OUI:B88F14*
 OUI:B88FB4*
  ID_OUI_FROM_DATABASE=JABIL CIRCUIT ITALIA S.R.L
 
+OUI:B891C9*
+ ID_OUI_FROM_DATABASE=Handreamnet
+
 OUI:B8921D*
  ID_OUI_FROM_DATABASE=BG T&A
 
@@ -81713,6 +82592,9 @@ OUI:B8A386*
 OUI:B8A3E0*
  ID_OUI_FROM_DATABASE=BenRui Technology Co.,Ltd
 
+OUI:B8A44F*
+ ID_OUI_FROM_DATABASE=Axis Communications AB
+
 OUI:B8A8AF*
  ID_OUI_FROM_DATABASE=Logic S.p.A.
 
@@ -82427,6 +83309,9 @@ OUI:BC79AD*
 OUI:BC7DD1*
  ID_OUI_FROM_DATABASE=Radio Data Comms
 
+OUI:BC7FA4*
+ ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd
+
 OUI:BC811F*
  ID_OUI_FROM_DATABASE=Ingate Systems
 
@@ -82484,9 +83369,60 @@ OUI:BC9325*
 OUI:BC9680*
  ID_OUI_FROM_DATABASE=SHENZHEN GONGJIN ELECTRONICS CO.,LT
 
+OUI:BC97400*
+ ID_OUI_FROM_DATABASE=Alpha ESS Co., Ltd.
+
+OUI:BC97401*
+ ID_OUI_FROM_DATABASE=comtac AG
+
+OUI:BC97402*
+ ID_OUI_FROM_DATABASE=Lattec I/S
+
+OUI:BC97403*
+ ID_OUI_FROM_DATABASE=Precision Galaxy Pvt. Ltd
+
+OUI:BC97404*
+ ID_OUI_FROM_DATABASE=Wind Mobility Technology (Beijing) Co., Ltd
+
+OUI:BC97405*
+ ID_OUI_FROM_DATABASE=Shanghai Laisi Information Technology Co.,Ltd
+
+OUI:BC97406*
+ ID_OUI_FROM_DATABASE=Shenzhen Colorwin Optical Technology Co.,Ltd
+
+OUI:BC97407*
+ ID_OUI_FROM_DATABASE=Airfi Oy AB
+
+OUI:BC97408*
+ ID_OUI_FROM_DATABASE=Gaodi Rus
+
+OUI:BC97409*
+ ID_OUI_FROM_DATABASE=Direct Communication Solutions
+
+OUI:BC9740A*
+ ID_OUI_FROM_DATABASE=Amap Information Technology Co., Ltd
+
+OUI:BC9740B*
+ ID_OUI_FROM_DATABASE=ForoTel
+
+OUI:BC9740C*
+ ID_OUI_FROM_DATABASE=LISTEC GmbH
+
+OUI:BC9740D*
+ ID_OUI_FROM_DATABASE=Rollock Oy
+
+OUI:BC9740E*
+ ID_OUI_FROM_DATABASE=B4ComTechnologies LLC
+
+OUI:BC97E1*
+ ID_OUI_FROM_DATABASE=Broadcom Limited
+
 OUI:BC9889*
  ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD
 
+OUI:BC98DF*
+ ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
+
 OUI:BC9911*
  ID_OUI_FROM_DATABASE=Zyxel Communications Corporation
 
@@ -82505,12 +83441,18 @@ OUI:BC9CC5*
 OUI:BC9DA5*
  ID_OUI_FROM_DATABASE=DASCOM Europe GmbH
 
+OUI:BC9FE4*
+ ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company
+
 OUI:BC9FEF*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
 OUI:BCA042*
  ID_OUI_FROM_DATABASE=SHANGHAI FLYCO ELECTRICAL APPLIANCE CO.,LTD
 
+OUI:BCA13A*
+ ID_OUI_FROM_DATABASE=SES-imagotag
+
 OUI:BCA4E1*
  ID_OUI_FROM_DATABASE=Nabto
 
@@ -83024,6 +83966,9 @@ OUI:C0885B*
 OUI:C08997*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:C089AB*
+ ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
+
 OUI:C08ACD*
  ID_OUI_FROM_DATABASE=Guangzhou Shiyuan Electronic Technology Company Limited
 
@@ -83501,6 +84446,9 @@ OUI:C43DC7*
 OUI:C44044*
  ID_OUI_FROM_DATABASE=RackTop Systems Inc.
 
+OUI:C4411E*
+ ID_OUI_FROM_DATABASE=Belkin International Inc.
+
 OUI:C44202*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -83750,12 +84698,18 @@ OUI:C486E9*
 OUI:C488E5*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
+OUI:C48A5A*
+ ID_OUI_FROM_DATABASE=JFCONTROL
+
 OUI:C48E8F*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
 OUI:C48F07*
  ID_OUI_FROM_DATABASE=Shenzhen Yihao Hulian Science and Technology Co., Ltd.
 
+OUI:C48FC1*
+ ID_OUI_FROM_DATABASE=DEEPTRACK S.L.U.
+
 OUI:C4913A*
  ID_OUI_FROM_DATABASE=Shenzhen Sanland Electronic Co., ltd.
 
@@ -83873,6 +84827,9 @@ OUI:C4C19F*
 OUI:C4C563*
  ID_OUI_FROM_DATABASE=TECNO MOBILE LIMITED
 
+OUI:C4C603*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:C4C755*
  ID_OUI_FROM_DATABASE=Beijing HuaqinWorld Technology Co.,Ltd
 
@@ -83975,6 +84932,9 @@ OUI:C4F57C*
 OUI:C4F5A5*
  ID_OUI_FROM_DATABASE=Kumalift Co., Ltd.
 
+OUI:C4F7D5*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:C4F839*
  ID_OUI_FROM_DATABASE=Actia Automotive
 
@@ -84065,6 +85025,9 @@ OUI:C80AA9*
 OUI:C80CC8*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:C80D32*
+ ID_OUI_FROM_DATABASE=Holoplot GmbH
+
 OUI:C80E14*
  ID_OUI_FROM_DATABASE=AVM Audiovisuelles Marketing und Computersysteme GmbH
 
@@ -84266,6 +85229,9 @@ OUI:C84C75*
 OUI:C84F86*
  ID_OUI_FROM_DATABASE=Sophos Ltd
 
+OUI:C850CE*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:C850E9*
  ID_OUI_FROM_DATABASE=Raisecom Technology CO., LTD
 
@@ -84287,6 +85253,9 @@ OUI:C85663*
 OUI:C85B76*
  ID_OUI_FROM_DATABASE=LCFC(HeFei) Electronics Technology co., ltd
 
+OUI:C85D38*
+ ID_OUI_FROM_DATABASE=HUMAX Co., Ltd.
+
 OUI:C86000*
  ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC.
 
@@ -84521,6 +85490,9 @@ OUI:C8A70A*
 OUI:C8A729*
  ID_OUI_FROM_DATABASE=SYStronics Co., Ltd.
 
+OUI:C8A776*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:C8A823*
  ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
 
@@ -84644,6 +85616,9 @@ OUI:C8D590*
 OUI:C8D5FE*
  ID_OUI_FROM_DATABASE=Shenzhen Zowee Technology Co., Ltd
 
+OUI:C8D69D*
+ ID_OUI_FROM_DATABASE=Arab International Optronics
+
 OUI:C8D719*
  ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC
 
@@ -84695,6 +85670,9 @@ OUI:C8E7D8*
 OUI:C8E7F0*
  ID_OUI_FROM_DATABASE=Juniper Networks
 
+OUI:C8EAF8*
+ ID_OUI_FROM_DATABASE=zte corporation
+
 OUI:C8EE08*
  ID_OUI_FROM_DATABASE=TANGTOP TECHNOLOGY CO.,LTD
 
@@ -85115,6 +86093,9 @@ OUI:CC60BB*
 OUI:CC61E5*
  ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
 
+OUI:CC64A6*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:CC65AD*
  ID_OUI_FROM_DATABASE=ARRIS Group, Inc.
 
@@ -85196,6 +86177,9 @@ OUI:CC82EB*
 OUI:CC856C*
  ID_OUI_FROM_DATABASE=SHENZHEN MDK DIGITAL TECHNOLOGY CO.,LTD
 
+OUI:CC8826*
+ ID_OUI_FROM_DATABASE=LG Innotek
+
 OUI:CC89FD*
  ID_OUI_FROM_DATABASE=Nokia Corporation
 
@@ -85208,6 +86192,9 @@ OUI:CC8CE3*
 OUI:CC8E71*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:CC9070*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
 OUI:CC9093*
  ID_OUI_FROM_DATABASE=Hansong Tehnologies
 
@@ -85727,6 +86714,9 @@ OUI:D03311*
 OUI:D03742*
  ID_OUI_FROM_DATABASE=Yulong Computer Telecommunication Scientific (Shenzhen) Co.,Ltd
 
+OUI:D03745*
+ ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
+
 OUI:D03761*
  ID_OUI_FROM_DATABASE=Texas Instruments
 
@@ -85799,6 +86789,9 @@ OUI:D0577B*
 OUI:D05785*
  ID_OUI_FROM_DATABASE=Pantech Co., Ltd.
 
+OUI:D05794*
+ ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS
+
 OUI:D057A1*
  ID_OUI_FROM_DATABASE=Werma Signaltechnik GmbH & Co. KG
 
@@ -86144,12 +87137,60 @@ OUI:D0C5D8*
 OUI:D0C5F3*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:D0C65B*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:D0C789*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
 OUI:D0C7C0*
  ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD.
 
+OUI:D0C8570*
+ ID_OUI_FROM_DATABASE=YUAN High-Tech Development Co., Ltd.
+
+OUI:D0C8571*
+ ID_OUI_FROM_DATABASE=DALI A/S
+
+OUI:D0C8572*
+ ID_OUI_FROM_DATABASE=FORGAMERS INC.
+
+OUI:D0C8573*
+ ID_OUI_FROM_DATABASE=Mobicon
+
+OUI:D0C8574*
+ ID_OUI_FROM_DATABASE=Imin Technology Pte Ltd
+
+OUI:D0C8575*
+ ID_OUI_FROM_DATABASE=Beijing Inspiry Technology Co., Ltd.
+
+OUI:D0C8576*
+ ID_OUI_FROM_DATABASE=Innovative Industrial(HK)Co., Limited
+
+OUI:D0C8577*
+ ID_OUI_FROM_DATABASE=Eco Mobile
+
+OUI:D0C8578*
+ ID_OUI_FROM_DATABASE=Nanjing Magewell Electronics Co.,Ltd
+
+OUI:D0C8579*
+ ID_OUI_FROM_DATABASE=Shenzhen xiaosha  Intelligence  Technology Co. Ltd
+
+OUI:D0C857A*
+ ID_OUI_FROM_DATABASE=shenzhen cnsun
+
+OUI:D0C857B*
+ ID_OUI_FROM_DATABASE=CHUNGHSIN INTERNATIONAL ELECTRONICS CO.,LTD.
+
+OUI:D0C857C*
+ ID_OUI_FROM_DATABASE=Dante Security Inc.
+
+OUI:D0C857D*
+ ID_OUI_FROM_DATABASE=IFLYTEK CO.,LTD.
+
+OUI:D0C857E*
+ ID_OUI_FROM_DATABASE=E-T-A Elektrotechnische Apparate GmbH
+
 OUI:D0CDE1*
  ID_OUI_FROM_DATABASE=Scientech Electronics
 
@@ -86597,6 +87638,9 @@ OUI:D461DA*
 OUI:D461FE*
  ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited
 
+OUI:D462EA*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:D463C6*
  ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company
 
@@ -87029,6 +88073,9 @@ OUI:D4EE07*
 OUI:D4F027*
  ID_OUI_FROM_DATABASE=Navetas Energy Management
 
+OUI:D4F057*
+ ID_OUI_FROM_DATABASE=Nintendo Co.,Ltd
+
 OUI:D4F0B4*
  ID_OUI_FROM_DATABASE=Napco Security Technologies
 
@@ -87092,6 +88139,9 @@ OUI:D80DE3*
 OUI:D80F99*
  ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd.
 
+OUI:D81399*
+ ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD
+
 OUI:D814D6*
  ID_OUI_FROM_DATABASE=SURE SYSTEM Co Ltd
 
@@ -87608,6 +88658,9 @@ OUI:D8C8E9*
 OUI:D8C99D*
  ID_OUI_FROM_DATABASE=EA DISPLAY LIMITED
 
+OUI:D8CA06*
+ ID_OUI_FROM_DATABASE=Titan DataCenters France
+
 OUI:D8CB8A*
  ID_OUI_FROM_DATABASE=Micro-Star INTL CO., LTD.
 
@@ -87632,6 +88685,9 @@ OUI:D8D385*
 OUI:D8D43C*
  ID_OUI_FROM_DATABASE=Sony Corporation
 
+OUI:D8D4E6*
+ ID_OUI_FROM_DATABASE=Hytec Inter Co., Ltd.
+
 OUI:D8D5B9*
  ID_OUI_FROM_DATABASE=Rainforest Automation, Inc.
 
@@ -87687,7 +88743,7 @@ OUI:D8E56D*
  ID_OUI_FROM_DATABASE=TCT mobile ltd
 
 OUI:D8E72B*
- ID_OUI_FROM_DATABASE=NetScout Systems, Inc.
+ ID_OUI_FROM_DATABASE=NetAlly
 
 OUI:D8E743*
  ID_OUI_FROM_DATABASE=Wush, Inc
@@ -87710,6 +88766,9 @@ OUI:D8EFCD*
 OUI:D8F0F2*
  ID_OUI_FROM_DATABASE=Zeebo Inc
 
+OUI:D8F15B*
+ ID_OUI_FROM_DATABASE=Espressif Inc.
+
 OUI:D8F1F0*
  ID_OUI_FROM_DATABASE=Pepxim International Limited
 
@@ -88007,6 +89066,9 @@ OUI:DC5360*
 OUI:DC537C*
  ID_OUI_FROM_DATABASE=Compal Broadband Networks, Inc.
 
+OUI:DC54D7*
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
+
 OUI:DC5583*
  ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD
 
@@ -88148,6 +89210,9 @@ OUI:DCA4CA*
 OUI:DCA5F4*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:DCA632*
+ ID_OUI_FROM_DATABASE=Raspberry Pi Trading Ltd
+
 OUI:DCA6BD*
  ID_OUI_FROM_DATABASE=Beijing Lanbo Technology Co., Ltd.
 
@@ -89156,12 +90221,18 @@ OUI:E4121D*
 OUI:E41289*
  ID_OUI_FROM_DATABASE=topsystem Systemhaus GmbH
 
+OUI:E415F6*
+ ID_OUI_FROM_DATABASE=Texas Instruments
+
 OUI:E417D8*
  ID_OUI_FROM_DATABASE=8BITDO TECHNOLOGY HK LIMITED
 
 OUI:E4186B*
  ID_OUI_FROM_DATABASE=Zyxel Communications Corporation
 
+OUI:E419C1*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:E41A2C*
  ID_OUI_FROM_DATABASE=ZPE Systems, Inc.
 
@@ -89381,6 +90452,9 @@ OUI:E44F5F*
 OUI:E4509A*
  ID_OUI_FROM_DATABASE=HW Communications Ltd
 
+OUI:E454E8*
+ ID_OUI_FROM_DATABASE=Dell Inc.
+
 OUI:E455EA*
  ID_OUI_FROM_DATABASE=Dedicated Computing
 
@@ -89633,6 +90707,9 @@ OUI:E4AA5D*
 OUI:E4AB46*
  ID_OUI_FROM_DATABASE=UAB Selteka
 
+OUI:E4AB89*
+ ID_OUI_FROM_DATABASE=MitraStar Technology Corp.
+
 OUI:E4AD7D*
  ID_OUI_FROM_DATABASE=SCL Elements
 
@@ -89813,6 +90890,9 @@ OUI:E4FB8F*
 OUI:E4FC82*
  ID_OUI_FROM_DATABASE=Juniper Networks
 
+OUI:E4FDA1*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:E4FED9*
  ID_OUI_FROM_DATABASE=EDMI Europe Ltd
 
@@ -89963,6 +91043,9 @@ OUI:E820E2*
 OUI:E82877*
  ID_OUI_FROM_DATABASE=TMY Co., Ltd.
 
+OUI:E828C1*
+ ID_OUI_FROM_DATABASE=Eltex Enterprise Ltd.
+
 OUI:E828D5*
  ID_OUI_FROM_DATABASE=Cots Technology
 
@@ -90665,6 +91748,9 @@ OUI:EC59E7*
 OUI:EC5A86*
  ID_OUI_FROM_DATABASE=Yulong Computer Telecommunication Scientific (Shenzhen) Co.,Ltd
 
+OUI:EC5B73*
+ ID_OUI_FROM_DATABASE=Advanced & Wise Technology Corp.
+
 OUI:EC5C68*
  ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD.
 
@@ -90869,6 +91955,9 @@ OUI:ECA86B*
 OUI:ECA9FA*
  ID_OUI_FROM_DATABASE=GUANGDONG GENIUS TECHNOLOGY CO., LTD.
 
+OUI:ECAA25*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:ECAAA0*
  ID_OUI_FROM_DATABASE=PEGATRON CORPORATION
 
@@ -91460,6 +92549,9 @@ OUI:F085C1*
 OUI:F08A28*
  ID_OUI_FROM_DATABASE=JIANGSU HENGSION ELECTRONIC S and T CO.,LTD
 
+OUI:F08A76*
+ ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd
+
 OUI:F08BFE*
  ID_OUI_FROM_DATABASE=COSTEL.,CO.LTD
 
@@ -91526,6 +92618,9 @@ OUI:F0A225*
 OUI:F0A764*
  ID_OUI_FROM_DATABASE=GST Co., Ltd.
 
+OUI:F0A968*
+ ID_OUI_FROM_DATABASE=Antailiye Technology Co.,Ltd
+
 OUI:F0AB54*
  ID_OUI_FROM_DATABASE=MITSUMI ELECTRIC CO.,LTD.
 
@@ -91928,6 +93023,9 @@ OUI:F417B8*
 OUI:F41BA1*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:F41D6B*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
 OUI:F41E26*
  ID_OUI_FROM_DATABASE=Simon-Kaloi Engineering
 
@@ -91976,6 +93074,9 @@ OUI:F431C3*
 OUI:F4323D*
  ID_OUI_FROM_DATABASE=Sichuan tianyi kanghe communications co., LTD
 
+OUI:F43328*
+ ID_OUI_FROM_DATABASE=CIMCON Lighting Inc.
+
 OUI:F436E1*
  ID_OUI_FROM_DATABASE=Abilis Systems SARL
 
@@ -92654,6 +93755,9 @@ OUI:F82055*
 OUI:F82285*
  ID_OUI_FROM_DATABASE=Cypress Technology CO., LTD.
 
+OUI:F82387*
+ ID_OUI_FROM_DATABASE=Shenzhen Horn Audio Co.,Ltd.
+
 OUI:F823B2*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
@@ -93038,6 +94142,9 @@ OUI:F8A45F*
 OUI:F8A5C5*
  ID_OUI_FROM_DATABASE=Cisco Systems, Inc
 
+OUI:F8A763*
+ ID_OUI_FROM_DATABASE=Zhejiang Tmall Technology Co., Ltd.
+
 OUI:F8A963*
  ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD.
 
@@ -93056,6 +94163,9 @@ OUI:F8AB05*
 OUI:F8AC6D*
  ID_OUI_FROM_DATABASE=Deltenna Ltd
 
+OUI:F8ADCB*
+ ID_OUI_FROM_DATABASE=HMD Global Oy
+
 OUI:F8B156*
  ID_OUI_FROM_DATABASE=Dell Inc.
 
@@ -93254,6 +94364,9 @@ OUI:F8E61A*
 OUI:F8E71E*
  ID_OUI_FROM_DATABASE=Ruckus Wireless
 
+OUI:F8E7A0*
+ ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
+
 OUI:F8E7B5*
  ID_OUI_FROM_DATABASE=µTech Tecnologia LTDA
 
@@ -93506,6 +94619,9 @@ OUI:FC4596*
 OUI:FC48EF*
  ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
 
+OUI:FC492D*
+ ID_OUI_FROM_DATABASE=Amazon Technologies Inc.
+
 OUI:FC4AE9*
  ID_OUI_FROM_DATABASE=Castlenet Technology Inc.
 
@@ -93761,6 +94877,12 @@ OUI:FCBBA1*
 OUI:FCBC9C*
  ID_OUI_FROM_DATABASE=Vimar Spa
 
+OUI:FCBCD1*
+ ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD
+
+OUI:FCBD67*
+ ID_OUI_FROM_DATABASE=Arista Networks
+
 OUI:FCBE7B*
  ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd.
 
@@ -93899,6 +95021,9 @@ OUI:FCE892*
 OUI:FCE998*
  ID_OUI_FROM_DATABASE=Apple, Inc.
 
+OUI:FCEA50*
+ ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd.
+
 OUI:FCECDA*
  ID_OUI_FROM_DATABASE=Ubiquiti Networks Inc.
 
index 9628207..bd6c106 100644 (file)
@@ -1,8 +1,8 @@
 # This file is part of systemd.
 #
 # Data imported from:
-#     http://www.uefi.org/uefi-pnp-export
-#     http://www.uefi.org/uefi-acpi-export
+#     https://uefi.org/uefi-pnp-export
+#     https://uefi.org/uefi-acpi-export
 #
 # With various additions from other sources
 
index 4a35881..fdd9efc 100644 (file)
@@ -1,9 +1,9 @@
---- 20-acpi-vendor.hwdb.base   2019-02-14 10:59:47.388792656 +0100
-+++ 20-acpi-vendor.hwdb        2019-02-14 10:59:47.398792674 +0100
+--- 20-acpi-vendor.hwdb.base   2019-04-08 11:36:50.727757815 +0200
++++ 20-acpi-vendor.hwdb        2019-04-08 11:36:50.735757868 +0200
 @@ -3,6 +3,8 @@
  # Data imported from:
- #     http://www.uefi.org/uefi-pnp-export
- #     http://www.uefi.org/uefi-acpi-export
+ #     https://uefi.org/uefi-pnp-export
+ #     https://uefi.org/uefi-acpi-export
 +#
 +# With various additions from other sources
  
index 9ca2c7b..c942325 100644 (file)
@@ -579,7 +579,7 @@ pci:v00000F62*
  ID_VENDOR_FROM_DATABASE=Acrox Technologies Co., Ltd.
 
 pci:v00001000*
- ID_VENDOR_FROM_DATABASE=LSI Logic / Symbios Logic
+ ID_VENDOR_FROM_DATABASE=Broadcom / LSI
 
 pci:v00001000d00000001*
  ID_MODEL_FROM_DATABASE=53c810
@@ -716,6 +716,9 @@ pci:v00001000d00000014*
 pci:v00001000d00000014sv00001028sd00001FD4*
  ID_MODEL_FROM_DATABASE=MegaRAID Tri-Mode SAS3516 (PERC H745P MX)
 
+pci:v00001000d00000014sv00001137sd0000020E*
+ ID_MODEL_FROM_DATABASE=MegaRAID Tri-Mode SAS3516 (UCSC-RAID-M5 12G Modular RAID Controller)
+
 pci:v00001000d00000014sv00001D49sd00000602*
  ID_MODEL_FROM_DATABASE=MegaRAID Tri-Mode SAS3516 (ThinkSystem RAID 930-16i 4GB Flash PCIe 12Gb Adapter)
 
@@ -1116,7 +1119,7 @@ pci:v00001000d0000005Bsv00008086sd00003512*
  ID_MODEL_FROM_DATABASE=MegaRAID SAS 2208 [Thunderbolt] (RMT3PB080 RAID Controller)
 
 pci:v00001000d0000005Bsv00008086sd00003513*
- ID_MODEL_FROM_DATABASE=MegaRAID SAS 2208 [Thunderbolt] (RMS25CB080 RAID Controller)
+ ID_MODEL_FROM_DATABASE=MegaRAID SAS 2208 [Thunderbolt] (Integrated RAID Module RMS25CB080)
 
 pci:v00001000d0000005Bsv00008086sd00003514*
  ID_MODEL_FROM_DATABASE=MegaRAID SAS 2208 [Thunderbolt] (RMS25CB040 RAID Controller)
@@ -1352,9 +1355,15 @@ pci:v00001000d00000062sv00001000sd00000062*
 pci:v00001000d00000064*
  ID_MODEL_FROM_DATABASE=SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor]
 
+pci:v00001000d00000064sv00001000sd00003030*
+ ID_MODEL_FROM_DATABASE=SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor] (9200-16e 6Gb/s SAS/SATA PCIe x8 External HBA)
+
 pci:v00001000d00000064sv00001000sd000030C0*
  ID_MODEL_FROM_DATABASE=SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor] (SAS 9201-16i)
 
+pci:v00001000d00000064sv00001000sd000030D0*
+ ID_MODEL_FROM_DATABASE=SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor] (9201-16e 6Gb/s SAS/SATA PCIe x8 External HBA)
+
 pci:v00001000d00000065*
  ID_MODEL_FROM_DATABASE=SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor]
 
@@ -1421,6 +1430,9 @@ pci:v00001000d00000073sv00001000sd000092A0*
 pci:v00001000d00000073sv00001014sd000003B1*
  ID_MODEL_FROM_DATABASE=MegaRAID SAS 2008 [Falcon] (ServeRAID M1015 SAS/SATA Controller)
 
+pci:v00001000d00000073sv00001014sd0000040D*
+ ID_MODEL_FROM_DATABASE=MegaRAID SAS 2008 [Falcon] (ServeRAID M1115 SAS/SATA Controller)
+
 pci:v00001000d00000073sv00001028sd00001F4E*
  ID_MODEL_FROM_DATABASE=MegaRAID SAS 2008 [Falcon] (PERC H310 Adapter)
 
@@ -2372,9 +2384,6 @@ pci:v00001002d00001714*
 pci:v00001002d00001714sv0000103Csd0000168B*
  ID_MODEL_FROM_DATABASE=BeaverCreek HDMI Audio [Radeon HD 6500D and 6400G-6600G series] (ProBook 4535s)
 
-pci:v00001002d00002191*
- ID_MODEL_FROM_DATABASE=TU116M
-
 pci:v00001002d00003150*
  ID_MODEL_FROM_DATABASE=RV380/M24 [Mobility Radeon X600]
 
@@ -7232,6 +7241,9 @@ pci:v00001002d000067DFsv00001462sd00003416*
 pci:v00001002d000067DFsv00001462sd00003418*
  ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 580 Armor 4G OC)
 
+pci:v00001002d000067DFsv00001462sd00008A92*
+ ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 580)
+
 pci:v00001002d000067DFsv0000148Csd00002372*
  ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 480)
 
@@ -7247,6 +7259,9 @@ pci:v00001002d000067DFsv00001682sd00009480*
 pci:v00001002d000067DFsv00001682sd00009588*
  ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 580 XTR)
 
+pci:v00001002d000067DFsv00001682sd0000C570*
+ ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 570)
+
 pci:v00001002d000067DFsv0000174Bsd0000E347*
  ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 470/480)
 
@@ -7319,6 +7334,9 @@ pci:v00001002d000067EB*
 pci:v00001002d000067EF*
  ID_MODEL_FROM_DATABASE=Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X]
 
+pci:v00001002d000067EFsv0000103Csd00003421*
+ ID_MODEL_FROM_DATABASE=Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X] (Radeon RX 460)
+
 pci:v00001002d000067EFsv0000106Bsd00000160*
  ID_MODEL_FROM_DATABASE=Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X] (Radeon Pro 460)
 
@@ -8033,6 +8051,12 @@ pci:v00001002d0000686C*
 pci:v00001002d0000687F*
  ID_MODEL_FROM_DATABASE=Vega 10 XL/XT [Radeon RX Vega 56/64]
 
+pci:v00001002d0000687Fsv00001002sd00000B36*
+ ID_MODEL_FROM_DATABASE=Vega 10 XL/XT [Radeon RX Vega 56/64] (RX Vega64)
+
+pci:v00001002d0000687Fsv00001002sd00006B76*
+ ID_MODEL_FROM_DATABASE=Vega 10 XL/XT [Radeon RX Vega 56/64] (RX Vega56)
+
 pci:v00001002d00006880*
  ID_MODEL_FROM_DATABASE=Lexington [Radeon HD 6550M]
 
@@ -10683,34 +10707,34 @@ pci:v00001002d00009616*
  ID_MODEL_FROM_DATABASE=RS780L [Radeon 3000]
 
 pci:v00001002d00009640*
- ID_MODEL_FROM_DATABASE=BeaverCreek [Radeon HD 6550D]
+ ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6550D]
 
 pci:v00001002d00009641*
- ID_MODEL_FROM_DATABASE=BeaverCreek [Radeon HD 6620G]
+ ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6620G]
 
 pci:v00001002d00009642*
- ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6370D]
+ ID_MODEL_FROM_DATABASE=SuperSumo [Radeon HD 6370D]
 
 pci:v00001002d00009643*
- ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6380G]
+ ID_MODEL_FROM_DATABASE=SuperSumo [Radeon HD 6380G]
 
 pci:v00001002d00009644*
- ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6410D]
+ ID_MODEL_FROM_DATABASE=SuperSumo [Radeon HD 6410D]
 
 pci:v00001002d00009645*
- ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6410D]
+ ID_MODEL_FROM_DATABASE=SuperSumo [Radeon HD 6410D]
 
 pci:v00001002d00009647*
- ID_MODEL_FROM_DATABASE=BeaverCreek [Radeon HD 6520G]
+ ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6520G]
 
 pci:v00001002d00009648*
  ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6480G]
 
 pci:v00001002d00009649*
- ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6480G]
+ ID_MODEL_FROM_DATABASE=SuperSumo [Radeon HD 6480G]
 
 pci:v00001002d0000964A*
- ID_MODEL_FROM_DATABASE=BeaverCreek [Radeon HD 6530D]
+ ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6530D]
 
 pci:v00001002d0000964B*
  ID_MODEL_FROM_DATABASE=Sumo
@@ -11162,6 +11186,9 @@ pci:v00001002d0000AAA0*
 pci:v00001002d0000AAB0*
  ID_MODEL_FROM_DATABASE=Oland/Hainan/Cape Verde/Pitcairn HDMI Audio [Radeon HD 7000 Series]
 
+pci:v00001002d0000AAB8*
+ ID_MODEL_FROM_DATABASE=Tiran HDMI Audio
+
 pci:v00001002d0000AAC0*
  ID_MODEL_FROM_DATABASE=Tobago HDMI Audio [Radeon R7 360 / R9 360 OEM]
 
@@ -12978,7 +13005,7 @@ pci:v00001022d00001437*
  ID_MODEL_FROM_DATABASE=Liverpool I/O Memory Management Unit
 
 pci:v00001022d00001438*
- ID_MODEL_FROM_DATABASE=Liverpool Processor Root Port
+ ID_MODEL_FROM_DATABASE=Liverpool UMI PCIe Dummy Host Bridge
 
 pci:v00001022d00001439*
  ID_MODEL_FROM_DATABASE=Family 16h Processor Functions 5:1
@@ -13077,7 +13104,7 @@ pci:v00001022d0000145E*
  ID_MODEL_FROM_DATABASE=Zeppelin Switch Downstream (PCIE SW.DS)
 
 pci:v00001022d0000145F*
- ID_MODEL_FROM_DATABASE=USB 3.0 Host controller
+ ID_MODEL_FROM_DATABASE=Zeppelin USB 3.0 Host controller
 
 pci:v00001022d00001460*
  ID_MODEL_FROM_DATABASE=Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 0
@@ -19706,6 +19733,9 @@ pci:v0000106Bd00001801*
 pci:v0000106Bd00001802*
  ID_MODEL_FROM_DATABASE=T2 Secure Enclave Processor
 
+pci:v0000106Bd00001803*
+ ID_MODEL_FROM_DATABASE=Apple Audio Device
+
 pci:v0000106Bd00002001*
  ID_MODEL_FROM_DATABASE=S1X NVMe Controller
 
@@ -19931,6 +19961,9 @@ pci:v00001077d00001656sv00001077sd0000E4F6*
 pci:v00001077d00001656sv00001077sd0000E4F7*
  ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series 25GbE Controller (FastLinQ QL45212H 25GbE Adapter)
 
+pci:v00001077d00001656sv00001590sd00000245*
+ ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series 25GbE Controller (10/20/25GbE 2P 4820c CNA)
+
 pci:v00001077d0000165C*
  ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series 10/25/40/50GbE Controller (FCoE)
 
@@ -19943,6 +19976,9 @@ pci:v00001077d0000165Csv00001077sd0000E4F1*
 pci:v00001077d0000165Csv00001077sd0000E4F2*
  ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series 10/25/40/50GbE Controller (FCoE) (FastLinQ QL45461H 40GbE FCoE Adapter)
 
+pci:v00001077d0000165Csv00001590sd00000245*
+ ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series 10/25/40/50GbE Controller (FCoE) (10/20/25GbE 2P 4820c CNA FCoE)
+
 pci:v00001077d0000165E*
  ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series 10/25/40/50GbE Controller (iSCSI)
 
@@ -19955,6 +19991,9 @@ pci:v00001077d0000165Esv00001077sd0000E4F1*
 pci:v00001077d0000165Esv00001077sd0000E4F2*
  ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series 10/25/40/50GbE Controller (iSCSI) (FastLinQ QL45461H 40GbE iSCSI Adapter)
 
+pci:v00001077d0000165Esv00001590sd00000245*
+ ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series 10/25/40/50GbE Controller (iSCSI) (10/20/25GbE 2P 4820c CNA iSCSI)
+
 pci:v00001077d00001664*
  ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF)
 
@@ -19979,6 +20018,9 @@ pci:v00001077d00001664sv00001077sd0000E4F7*
 pci:v00001077d00001664sv00001077sd0000E4F8*
  ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (FastLinQ QL45611H 100GbE Adapter (SR-IOV VF))
 
+pci:v00001077d00001664sv00001590sd00000245*
+ ID_MODEL_FROM_DATABASE=FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF) (10/20/25GbE 2P 4820c CNA SRIOV)
+
 pci:v00001077d00002020*
  ID_MODEL_FROM_DATABASE=ISP2020A Fast!SCSI Basic Adapter
 
@@ -20012,6 +20054,15 @@ pci:v00001077d00002071sv00001077sd000002A2*
 pci:v00001077d00002071sv00001077sd000002AD*
  ID_MODEL_FROM_DATABASE=ISP2714-based 16/32Gb Fibre Channel to PCIe Adapter (QLE2694U Quad Port 16/32Gb Fibre Channel to PCIe Adapter)
 
+pci:v00001077d00002081*
+ ID_MODEL_FROM_DATABASE=ISP2814-based 64/32G Fibre Channel to PCIe Controller
+
+pci:v00001077d00002081sv00001077sd000002E1*
+ ID_MODEL_FROM_DATABASE=ISP2814-based 64/32G Fibre Channel to PCIe Controller (QLE2874 Quad Port 64GFC PCIe Gen4 x16 Adapter)
+
+pci:v00001077d00002081sv00001077sd000002E3*
+ ID_MODEL_FROM_DATABASE=ISP2814-based 64/32G Fibre Channel to PCIe Controller (QLE2774 Quad Port 32GFC PCIe Gen4 x16 Adapter)
+
 pci:v00001077d00002100*
  ID_MODEL_FROM_DATABASE=QLA2100 64-bit Fibre Channel Adapter
 
@@ -20069,6 +20120,21 @@ pci:v00001077d00002261sv00001590sd00000203*
 pci:v00001077d00002261sv00001590sd00000204*
  ID_MODEL_FROM_DATABASE=ISP2722-based 16/32Gb Fibre Channel to PCIe Adapter (StoreFabric SN1600Q 32Gb Dual Port Fibre Channel Host Bus Adapter)
 
+pci:v00001077d00002281*
+ ID_MODEL_FROM_DATABASE=ISP2812-based 64/32G Fibre Channel to PCIe Controller
+
+pci:v00001077d00002281sv00001077sd000002E2*
+ ID_MODEL_FROM_DATABASE=ISP2812-based 64/32G Fibre Channel to PCIe Controller (QLE2872 Dual Port 64GFC PCIe Gen4 x8 Adapter)
+
+pci:v00001077d00002281sv00001077sd000002E4*
+ ID_MODEL_FROM_DATABASE=ISP2812-based 64/32G Fibre Channel to PCIe Controller (QLE2772 Dual Port 32GFC PCIe Gen4 x8 Adapter)
+
+pci:v00001077d00002281sv00001077sd000002EE*
+ ID_MODEL_FROM_DATABASE=ISP2812-based 64/32G Fibre Channel to PCIe Controller (QLE2870 Single Port 64GFC PCIe Gen4 x8 Adapter)
+
+pci:v00001077d00002281sv00001077sd000002F0*
+ ID_MODEL_FROM_DATABASE=ISP2812-based 64/32G Fibre Channel to PCIe Controller (QLE2770 Single Port 32GFC PCIe Gen4 x8 Adapter)
+
 pci:v00001077d00002300*
  ID_MODEL_FROM_DATABASE=QLA2300 64-bit Fibre Channel Adapter
 
@@ -27362,6 +27428,9 @@ pci:v000010DEd00000112*
 pci:v000010DEd00000113*
  ID_MODEL_FROM_DATABASE=NV11GL [Quadro2 MXR/EX/Go]
 
+pci:v000010DEd00000113sv00001028sd000000E5*
+ ID_MODEL_FROM_DATABASE=NV11GL [Quadro2 MXR/EX/Go] (Quadro2 Go)
+
 pci:v000010DEd00000140*
  ID_MODEL_FROM_DATABASE=NV43 [GeForce 6600 GT]
 
@@ -30083,6 +30152,9 @@ pci:v000010DEd000006CB*
 pci:v000010DEd000006CD*
  ID_MODEL_FROM_DATABASE=GF100 [GeForce GTX 470]
 
+pci:v000010DEd000006D0*
+ ID_MODEL_FROM_DATABASE=GF100GL
+
 pci:v000010DEd000006D1*
  ID_MODEL_FROM_DATABASE=GF100GL [Tesla C2050 / C2070]
 
@@ -32133,7 +32205,7 @@ pci:v000010DEd00001023sv000010DEsd0000097E*
  ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K40m] (12GB Computational Accelerator)
 
 pci:v000010DEd00001024*
- ID_MODEL_FROM_DATABASE=GK110BGL [Tesla K40c]
+ ID_MODEL_FROM_DATABASE=GK180GL [Tesla K40c]
 
 pci:v000010DEd00001026*
  ID_MODEL_FROM_DATABASE=GK110GL [Tesla K20s]
@@ -34665,7 +34737,7 @@ pci:v000010DEd00001EB8*
  ID_MODEL_FROM_DATABASE=TU104GL [Tesla T4]
 
 pci:v000010DEd00001ED0*
- ID_MODEL_FROM_DATABASE=TU104M [GeForce RTX 2080 Mobile]
+ ID_MODEL_FROM_DATABASE=TU104BM [GeForce RTX 2080 Mobile]
 
 pci:v000010DEd00001F02*
  ID_MODEL_FROM_DATABASE=TU106 [GeForce RTX 2070]
@@ -34692,22 +34764,22 @@ pci:v000010DEd00001F2E*
  ID_MODEL_FROM_DATABASE=TU106M
 
 pci:v000010DEd00001F50*
- ID_MODEL_FROM_DATABASE=TU106M [GeForce RTX 2070 Mobile]
+ ID_MODEL_FROM_DATABASE=TU106BM [GeForce RTX 2070 Mobile]
 
 pci:v000010DEd00001F51*
- ID_MODEL_FROM_DATABASE=TU106M [GeForce RTX 2060 Mobile]
+ ID_MODEL_FROM_DATABASE=TU106BM [GeForce RTX 2060 Mobile]
 
 pci:v000010DEd00001F82*
- ID_MODEL_FROM_DATABASE=TU107
+ ID_MODEL_FROM_DATABASE=TU107 [GeForce GTX 1650]
 
 pci:v000010DEd00001F92*
- ID_MODEL_FROM_DATABASE=TU107M
+ ID_MODEL_FROM_DATABASE=TU107M [GeForce GTX 1650 Mobile]
 
 pci:v000010DEd00001FBF*
  ID_MODEL_FROM_DATABASE=TU107GL
 
 pci:v000010DEd00002182*
- ID_MODEL_FROM_DATABASE=TU116 [GeForce GTX 1660 Ti Rev. A]
+ ID_MODEL_FROM_DATABASE=TU116 [GeForce GTX 1660 Ti]
 
 pci:v000010DEd00002183*
  ID_MODEL_FROM_DATABASE=TU116
@@ -34716,7 +34788,7 @@ pci:v000010DEd00002184*
  ID_MODEL_FROM_DATABASE=TU116 [GeForce GTX 1660]
 
 pci:v000010DEd00002191*
- ID_MODEL_FROM_DATABASE=TU116M
+ ID_MODEL_FROM_DATABASE=TU116M [GeForce GTX 1660 Mobile]
 
 pci:v000010DEd000021AE*
  ID_MODEL_FROM_DATABASE=TU116GL
@@ -34724,6 +34796,9 @@ pci:v000010DEd000021AE*
 pci:v000010DEd000021BF*
  ID_MODEL_FROM_DATABASE=TU116GL
 
+pci:v000010DEd000021D1*
+ ID_MODEL_FROM_DATABASE=TU116BM [GeForce GTX 1660 Mobile]
+
 pci:v000010DF*
  ID_VENDOR_FROM_DATABASE=Emulex Corporation
 
@@ -35264,6 +35339,9 @@ pci:v000010ECd00005229sv000017AAsd00003832*
 pci:v000010ECd0000522A*
  ID_MODEL_FROM_DATABASE=RTS522A PCI Express Card Reader
 
+pci:v000010ECd0000522Asv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=RTS522A PCI Express Card Reader (EliteBook 840 G3)
+
 pci:v000010ECd00005249*
  ID_MODEL_FROM_DATABASE=RTS5249 PCI Express Card Reader
 
@@ -35288,6 +35366,9 @@ pci:v000010ECd0000525Asv00001028sd000006E4*
 pci:v000010ECd0000525Asv000017AAsd0000224F*
  ID_MODEL_FROM_DATABASE=RTS525A PCI Express Card Reader (ThinkPad X1 Carbon 5th Gen)
 
+pci:v000010ECd00005260*
+ ID_MODEL_FROM_DATABASE=RTS5260 PCI Express Card Reader
+
 pci:v000010ECd00005286*
  ID_MODEL_FROM_DATABASE=RTS5286 PCI Express Card Reader
 
@@ -39107,6 +39188,9 @@ pci:v0000112Fd00000000*
 pci:v0000112Fd00000001*
  ID_MODEL_FROM_DATABASE=MVC IM-PCI Video frame grabber/processor
 
+pci:v0000112Fd00000004*
+ ID_MODEL_FROM_DATABASE=PCDig Digital Image Capture
+
 pci:v0000112Fd00000008*
  ID_MODEL_FROM_DATABASE=PC-CamLink PCI framegrabber
 
@@ -43214,6 +43298,9 @@ pci:v000011ABd00007823*
 pci:v000011ABd00007846*
  ID_MODEL_FROM_DATABASE=88F6820 [Armada 385] ARM SoC
 
+pci:v000011ABd0000D40F*
+ ID_MODEL_FROM_DATABASE=Bobcat3 Ethernet Switch
+
 pci:v000011ABd0000F003*
  ID_MODEL_FROM_DATABASE=GT-64010 Primary Image Piranha Image Generator
 
@@ -54683,6 +54770,9 @@ pci:v000014E4d000016D8*
 pci:v000014E4d000016D8sv00001028sd00001FEB*
  ID_MODEL_FROM_DATABASE=BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller (NetXtreme-E 10Gb SFP+ Adapter)
 
+pci:v000014E4d000016D8sv000014E4sd00004163*
+ ID_MODEL_FROM_DATABASE=BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller (BCM957416M4163C OCP 2x10GBT Type1 wRoCE)
+
 pci:v000014E4d000016D8sv00001590sd0000020C*
  ID_MODEL_FROM_DATABASE=BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller (Ethernet 10Gb 2-port 535T Adapter)
 
@@ -57593,12 +57683,24 @@ pci:v000015B3d00000212*
 pci:v000015B3d00000213*
  ID_MODEL_FROM_DATABASE=MT2892 Family [ConnectX-6 Dx Secure Flash Recovery]
 
+pci:v000015B3d00000214*
+ ID_MODEL_FROM_DATABASE=MT42822 Family [BlueField-2 SoC Flash Recovery]
+
+pci:v000015B3d00000215*
+ ID_MODEL_FROM_DATABASE=MT42822 Family [BlueField-2 Secure Flash Recovery]
+
 pci:v000015B3d0000024E*
  ID_MODEL_FROM_DATABASE=MT53100 [Spectrum-2, Flash recovery mode]
 
 pci:v000015B3d0000024F*
  ID_MODEL_FROM_DATABASE=MT53100 [Spectrum-2, Secure Flash recovery mode]
 
+pci:v000015B3d00000250*
+ ID_MODEL_FROM_DATABASE=Spectrum-3, Flash recovery mode
+
+pci:v000015B3d00000251*
+ ID_MODEL_FROM_DATABASE=Spectrum-3, Secure Flash recovery mode
+
 pci:v000015B3d00000262*
  ID_MODEL_FROM_DATABASE=MT27710 [ConnectX-4 Lx Programmable] EN
 
@@ -57834,7 +57936,7 @@ pci:v000015B3d0000101D*
  ID_MODEL_FROM_DATABASE=MT2892 Family [ConnectX-6 Dx]
 
 pci:v000015B3d0000101E*
- ID_MODEL_FROM_DATABASE=MT2892 Family [ConnectX-6 Dx Virtual Function]
+ ID_MODEL_FROM_DATABASE=ConnectX Family mlx5Gen Virtual Function
 
 pci:v000015B3d0000101F*
  ID_MODEL_FROM_DATABASE=MT28851
@@ -57851,6 +57953,9 @@ pci:v000015B3d00001974*
 pci:v000015B3d00001975*
  ID_MODEL_FROM_DATABASE=MT416842 Family [BlueField SoC PCIe Bridge]
 
+pci:v000015B3d00001978*
+ ID_MODEL_FROM_DATABASE=MT42822 Family [BlueField-2 SoC PCIe Bridge]
+
 pci:v000015B3d00004117*
  ID_MODEL_FROM_DATABASE=MT27712A0-FDCF-AE
 
@@ -57878,6 +57983,9 @@ pci:v000015B3d00005E8C*
 pci:v000015B3d00005E8D*
  ID_MODEL_FROM_DATABASE=MT25204 [InfiniHost III Lx HCA Flash Recovery]
 
+pci:v000015B3d00006001*
+ ID_MODEL_FROM_DATABASE=NVMe SNAP Controller
+
 pci:v000015B3d00006274*
  ID_MODEL_FROM_DATABASE=MT25204 [InfiniHost III Lx HCA]
 
@@ -57995,6 +58103,21 @@ pci:v000015B3d0000A2D2*
 pci:v000015B3d0000A2D3*
  ID_MODEL_FROM_DATABASE=MT416842 BlueField multicore SoC family VF
 
+pci:v000015B3d0000A2D4*
+ ID_MODEL_FROM_DATABASE=MT42822 BlueField-2 SoC Crypto enabled
+
+pci:v000015B3d0000A2D5*
+ ID_MODEL_FROM_DATABASE=MT42822 BlueField-2 SoC Crypto disabled
+
+pci:v000015B3d0000A2D6*
+ ID_MODEL_FROM_DATABASE=MT42822 BlueField-2 integrated ConnectX-6 Dx network controller
+
+pci:v000015B3d0000C2D2*
+ ID_MODEL_FROM_DATABASE=MT416842 BlueField SoC management interfac
+
+pci:v000015B3d0000C2D3*
+ ID_MODEL_FROM_DATABASE=MT42822 BlueField-2 SoC Management Interface
+
 pci:v000015B3d0000C738*
  ID_MODEL_FROM_DATABASE=MT51136
 
@@ -58019,6 +58142,9 @@ pci:v000015B3d0000CF08*
 pci:v000015B3d0000CF6C*
  ID_MODEL_FROM_DATABASE=MT53100 [Spectrum-2]
 
+pci:v000015B3d0000CF70*
+ ID_MODEL_FROM_DATABASE=Spectrum-3
+
 pci:v000015B3d0000D2F0*
  ID_MODEL_FROM_DATABASE=Quantum HDR (200Gbps) switch
 
@@ -61235,6 +61361,12 @@ pci:v000017DFd00001916*
 pci:v000017DFd00001917*
  ID_MODEL_FROM_DATABASE=UltrascalePlus PCIe Accelerator Board [DNPCIe_400G_VU_LL]
 
+pci:v000017DFd00001918*
+ ID_MODEL_FROM_DATABASE=VirtexUS+ ASIC Emulation Board [DNVUPF4A]
+
+pci:v000017DFd00001919*
+ ID_MODEL_FROM_DATABASE=UltrascalePlus PCIe Accelerator Board [DNPCIe_400G_VUP_HBM_LL]
+
 pci:v000017DFd00001A00*
  ID_MODEL_FROM_DATABASE=Virtex6 PCIe DMA Netlist Design
 
@@ -61271,6 +61403,12 @@ pci:v000017DFd00001A0B*
 pci:v000017DFd00001A0C*
  ID_MODEL_FROM_DATABASE=KintexUS PCIe DRAM Packet Capture Design [DNPCIe_40G_KU_LL]
 
+pci:v000017DFd00001A0D*
+ ID_MODEL_FROM_DATABASE=KintexUS PCIe DRAM Packet Capture Design [DNPCIe_40G_KU_LL_2QSFP]
+
+pci:v000017DFd00001A0E*
+ ID_MODEL_FROM_DATABASE=UltrascalePlus PCIe Darklite Design [DNPCIe_400G_VUP_HBM_LL]
+
 pci:v000017E4*
  ID_VENDOR_FROM_DATABASE=Sectra AB
 
@@ -62216,6 +62354,9 @@ pci:v000018F4d00000185*
 pci:v000018F4d000001A5*
  ID_MODEL_FROM_DATABASE=NT200A01 Network Adapter
 
+pci:v000018F4d000001C5*
+ ID_MODEL_FROM_DATABASE=NT200A02 Network Adapter
+
 pci:v000018F6*
  ID_VENDOR_FROM_DATABASE=NextIO
 
@@ -62696,9 +62837,27 @@ pci:v00001924d00000B03sv00001924sd0000801E*
 pci:v00001924d00000B03sv00001924sd00008022*
  ID_MODEL_FROM_DATABASE=XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller (XtremeScale X2522 10G Network Adapter)
 
+pci:v00001924d00000B03sv00001924sd00008024*
+ ID_MODEL_FROM_DATABASE=XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller (XtremeScale X2562 OCP 3.0 Dual Port SFP28)
+
+pci:v00001924d00000B03sv00001924sd00008027*
+ ID_MODEL_FROM_DATABASE=XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller (XtremeScale X2541 PCIe Single Port QSFP28)
+
 pci:v00001924d00000B03sv00001924sd00008028*
  ID_MODEL_FROM_DATABASE=XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller (XtremeScale X2522-25G Network Adapter)
 
+pci:v00001924d00000B03sv00001924sd0000802A*
+ ID_MODEL_FROM_DATABASE=XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller (XtremeScale X2542 PCIe Dual Port QSFP28)
+
+pci:v00001924d00000B03sv00001924sd0000802B*
+ ID_MODEL_FROM_DATABASE=XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller (XtremeScale X2552 OCP 2.0 Dual Port SFP28)
+
+pci:v00001924d00000B03sv00001924sd0000802C*
+ ID_MODEL_FROM_DATABASE=XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller (XtremeScale X2522-25G PCIe Dual Port SFP28)
+
+pci:v00001924d00000B03sv00001924sd0000802D*
+ ID_MODEL_FROM_DATABASE=XtremeScale SFC9250 10/25/40/50/100G Ethernet Controller (XtremeScale X2562 OCP 3.0 Dual Port SFP28)
+
 pci:v00001924d00001803*
  ID_MODEL_FROM_DATABASE=SFC9020 10G Ethernet Controller (Virtual Function)
 
@@ -64637,6 +64796,9 @@ pci:v00001B4Bd00009230sv00001028sd00001FDF*
 pci:v00001B4Bd00009230sv00001028sd00001FE2*
  ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (BOSS-S1 Adapter)
 
+pci:v00001B4Bd00009230sv00001028sd00002010*
+ ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (BOSS-S2 Adapter)
+
 pci:v00001B4Bd00009230sv00001D49sd00000300*
  ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem M.2 with Mirroring Enablement Kit)
 
@@ -64922,6 +65084,9 @@ pci:v00001BF4*
 pci:v00001BF4d00000001*
  ID_MODEL_FROM_DATABASE=SentinelEX
 
+pci:v00001BF4d00007011*
+ ID_MODEL_FROM_DATABASE=RX0xxx
+
 pci:v00001BFD*
  ID_VENDOR_FROM_DATABASE=EeeTOP
 
@@ -64977,7 +65142,7 @@ pci:v00001C28d00000122*
  ID_MODEL_FROM_DATABASE=M6e PCI Express SSD [Marvell 88SS9183]
 
 pci:v00001C2C*
- ID_VENDOR_FROM_DATABASE=Fiberblaze
+ ID_VENDOR_FROM_DATABASE=Silicom Denmark
 
 pci:v00001C2Cd0000000A*
  ID_MODEL_FROM_DATABASE=Capture
@@ -65010,13 +65175,31 @@ pci:v00001C2Cd000000A9*
  ID_MODEL_FROM_DATABASE=FBC2XGHH Capture 2x10Gb
 
 pci:v00001C2Cd000000AD*
- ID_MODEL_FROM_DATABASE=FBC2CGG3HL Capture 2x200Gb
+ ID_MODEL_FROM_DATABASE=FBC2CGG3HL Capture 2x100Gb [Padua]
 
 pci:v00001C2Cd000000AF*
  ID_MODEL_FROM_DATABASE=Capture slave device
 
+pci:v00001C2Cd000000E0*
+ ID_MODEL_FROM_DATABASE=PacketMover 2x100Gb [Savona]
+
+pci:v00001C2Cd000000E1*
+ ID_MODEL_FROM_DATABASE=PacketMover 2x100Gb [Tivoli]
+
 pci:v00001C2Cd0000A001*
- ID_MODEL_FROM_DATABASE=FBC2CGG3 Capture 2x200Gb
+ ID_MODEL_FROM_DATABASE=FBC2CGG3 Capture 2x100Gb [Mango]
+
+pci:v00001C2Cd0000A00E*
+ ID_MODEL_FROM_DATABASE=FB2CG Capture 2x100Gb [Savona]
+
+pci:v00001C2Cd0000A00F*
+ ID_MODEL_FROM_DATABASE=FB2CG Capture 2x40Gb [Savona]
+
+pci:v00001C2Cd0000A011*
+ ID_MODEL_FROM_DATABASE=FB2CG Capture 2x25Gb [Savona]
+
+pci:v00001C2Cd0000A012*
+ ID_MODEL_FROM_DATABASE=FB2CG Capture 8x10Gb [Savona]
 
 pci:v00001C32*
  ID_VENDOR_FROM_DATABASE=Highland Technology, Inc.
@@ -65120,6 +65303,12 @@ pci:v00001CB5d00000002*
 pci:v00001CB8*
  ID_VENDOR_FROM_DATABASE=Dawning Information Industry Co., Ltd.
 
+pci:v00001CC4*
+ ID_VENDOR_FROM_DATABASE=Union Memory (Shenzhen)
+
+pci:v00001CC4d000017AB*
+ ID_MODEL_FROM_DATABASE=NVMe 256G SSD device
+
 pci:v00001CC5*
  ID_VENDOR_FROM_DATABASE=Embedded Intelligence, Inc.
 
@@ -65573,6 +65762,9 @@ pci:v00001D87d00001808*
 pci:v00001D8F*
  ID_VENDOR_FROM_DATABASE=Enyx
 
+pci:v00001D93*
+ ID_VENDOR_FROM_DATABASE=YADRO (KNS Group)
+
 pci:v00001D94*
  ID_VENDOR_FROM_DATABASE=Chengdu Haiguang IC Design Co., Ltd.
 
@@ -65672,12 +65864,27 @@ pci:v00001D95d00000001*
 pci:v00001D95d00000002*
  ID_MODEL_FROM_DATABASE=Colossus GC1 [S1]
 
+pci:v00001D9B*
+ ID_VENDOR_FROM_DATABASE=Facebook, Inc.
+
+pci:v00001D9Bd00000010*
+ ID_MODEL_FROM_DATABASE=Networking DOM Engine
+
+pci:v00001D9Bd00000011*
+ ID_MODEL_FROM_DATABASE=IO Bridge
+
 pci:v00001DA1*
  ID_VENDOR_FROM_DATABASE=Teko Telecom S.r.l.
 
 pci:v00001DA2*
  ID_VENDOR_FROM_DATABASE=Sapphire Technology Limited
 
+pci:v00001DA3*
+ ID_VENDOR_FROM_DATABASE=Habana Labs Ltd.
+
+pci:v00001DA3d00000001*
+ ID_MODEL_FROM_DATABASE=HL-1000 AI Inference Accelerator [Goya]
+
 pci:v00001DBB*
  ID_VENDOR_FROM_DATABASE=NGD Systems, Inc.
 
@@ -65765,6 +65972,9 @@ pci:v00001DF3d00000202sv00001DF3sd00000002*
 pci:v00001DF3d00000203*
  ID_MODEL_FROM_DATABASE=ACE-NIC100 Programmable Network Accelerator
 
+pci:v00001DF3d00000203sv00001DF3sd00000000*
+ ID_MODEL_FROM_DATABASE=ACE-NIC100 Programmable Network Accelerator (Maintenance Mode)
+
 pci:v00001DF3d00000203sv00001DF3sd00000001*
  ID_MODEL_FROM_DATABASE=ACE-NIC100 Programmable Network Accelerator (ENA2080F)
 
@@ -65816,6 +66026,9 @@ pci:v00001E24d0000021F*
 pci:v00001E24d00001525*
  ID_MODEL_FROM_DATABASE=Xilinx BCU-1525
 
+pci:v00001E26*
+ ID_VENDOR_FROM_DATABASE=Fujitsu Client Computing Limited
+
 pci:v00001E38*
  ID_VENDOR_FROM_DATABASE=Thinci, Inc
 
@@ -69566,6 +69779,9 @@ pci:v00008086d00000A54sv0000108Esd00004870*
 pci:v00008086d00000A54sv0000108Esd00004871*
  ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [3DNAND, Beta Rock Controller] (NVMe PCIe 3.0 SSD 6.4TB 2.5-inch (P4600))
 
+pci:v00008086d00000A54sv0000108Esd00004879*
+ ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [3DNAND, Beta Rock Controller] (NVMe PCIe 3.0 SSD v2 6.4TB AIC (P4618))
+
 pci:v00008086d00000A54sv0000108Esd0000487A*
  ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [3DNAND, Beta Rock Controller] (NVMe PCIe 3.0 SSD v2 6.4TB 2.5-inch (P4610))
 
@@ -69902,6 +70118,12 @@ pci:v00008086d00000D26*
 pci:v00008086d00000D36*
  ID_MODEL_FROM_DATABASE=Crystal Well Integrated Graphics Controller
 
+pci:v00008086d00000D4E*
+ ID_MODEL_FROM_DATABASE=Ethernet Connection (10) I219-LM
+
+pci:v00008086d00000D4F*
+ ID_MODEL_FROM_DATABASE=Ethernet Connection (10) I219-V
+
 pci:v00008086d00000D58*
  ID_MODEL_FROM_DATABASE=Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
 
@@ -71942,6 +72164,9 @@ pci:v00008086d000010FBsv0000108Esd00007B11*
 pci:v00008086d000010FBsv00001170sd0000004C*
  ID_MODEL_FROM_DATABASE=82599ES 10-Gigabit SFI/SFP+ Network Connection (82599 DP 10G Mezzanine Adapter)
 
+pci:v00008086d000010FBsv000015D9sd00000611*
+ ID_MODEL_FROM_DATABASE=82599ES 10-Gigabit SFI/SFP+ Network Connection (AOC-STGN-I2S [REV 1.01])
+
 pci:v00008086d000010FBsv00001734sd000011A9*
  ID_MODEL_FROM_DATABASE=82599ES 10-Gigabit SFI/SFP+ Network Connection (10 Gigabit Dual Port Network Connection)
 
@@ -73355,6 +73580,9 @@ pci:v00008086d0000156F*
 pci:v00008086d0000156Fsv00001028sd000006DC*
  ID_MODEL_FROM_DATABASE=Ethernet Connection I219-LM (Latitude E7470)
 
+pci:v00008086d0000156Fsv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Ethernet Connection I219-LM (EliteBook 840 G3)
+
 pci:v00008086d00001570*
  ID_MODEL_FROM_DATABASE=Ethernet Connection I219-V
 
@@ -73694,6 +73922,9 @@ pci:v00008086d0000158Bsv00008086sd00000008*
 pci:v00008086d0000158Bsv00008086sd00000009*
  ID_MODEL_FROM_DATABASE=Ethernet Controller XXV710 for 25GbE SFP28 (Ethernet 25G 2P XXV710 Adapter)
 
+pci:v00008086d0000158Bsv00008086sd0000000A*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller XXV710 for 25GbE SFP28 (Ethernet 25G 2P XXV710 OCP)
+
 pci:v00008086d0000158Bsv00008086sd00004001*
  ID_MODEL_FROM_DATABASE=Ethernet Controller XXV710 for 25GbE SFP28 (Ethernet Network Adapter XXV710-2)
 
@@ -73937,6 +74168,21 @@ pci:v00008086d000015F6*
 pci:v00008086d000015FF*
  ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T
 
+pci:v00008086d000015FFsv00008086sd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (Ethernet Network Adapter X710-TL)
+
+pci:v00008086d000015FFsv00008086sd00000001*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (Ethernet Network Adapter X710-T4L)
+
+pci:v00008086d000015FFsv00008086sd00000002*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (Ethernet Network Adapter X710-T4L)
+
+pci:v00008086d000015FFsv00008086sd00000003*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (Ethernet Network Adapter X710-T2L)
+
+pci:v00008086d000015FFsv00008086sd00000004*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (Ethernet Network Adapter X710-T2L)
+
 pci:v00008086d000015FFsv00008086sd00000005*
  ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (Ethernet 10G 2P X710-T2L-t Adapter)
 
@@ -74096,6 +74342,9 @@ pci:v00008086d00001904sv00001028sd000006DC*
 pci:v00008086d00001904sv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers (Latitude 3570)
 
+pci:v00008086d00001904sv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers (EliteBook 840 G3)
+
 pci:v00008086d00001904sv000017AAsd0000382A*
  ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers (B51-80 Laptop)
 
@@ -74150,6 +74399,9 @@ pci:v00008086d00001916sv00001028sd000006DC*
 pci:v00008086d00001916sv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Skylake GT2 [HD Graphics 520] (Latitude 3570)
 
+pci:v00008086d00001916sv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Skylake GT2 [HD Graphics 520] (EliteBook 840 G3)
+
 pci:v00008086d00001918*
  ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers
 
@@ -75827,6 +76079,9 @@ pci:v00008086d0000208D*
 pci:v00008086d0000208E*
  ID_MODEL_FROM_DATABASE=Sky Lake-E CHA Registers
 
+pci:v00008086d00002241*
+ ID_MODEL_FROM_DATABASE=Larrabee
+
 pci:v00008086d00002250*
  ID_MODEL_FROM_DATABASE=Xeon Phi coprocessor 5100 series
 
@@ -79550,6 +79805,9 @@ pci:v00008086d00002701sv00001028sd00002001*
 pci:v00008086d00002701sv00001028sd00002002*
  ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] (Express Flash NVMe [Optane] 750GB AIC (P4800X))
 
+pci:v00008086d00002701sv00001028sd0000200A*
+ ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] (Express Flash NVMe [Optane] 375GB AIC (P4800X))
+
 pci:v00008086d00002701sv00008086sd00003904*
  ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] (x4 AIC (P4800X))
 
@@ -84755,6 +85013,9 @@ pci:v00008086d0000373F*
 pci:v00008086d000037C8*
  ID_MODEL_FROM_DATABASE=C62x Chipset QuickAssist Technology
 
+pci:v00008086d000037CC*
+ ID_MODEL_FROM_DATABASE=Ethernet Connection X722
+
 pci:v00008086d000037CD*
  ID_MODEL_FROM_DATABASE=Ethernet Virtual Function 700 Series
 
@@ -85982,12 +86243,18 @@ pci:v00008086d00003E92*
 pci:v00008086d00003E93*
  ID_MODEL_FROM_DATABASE=UHD Graphics 610
 
+pci:v00008086d00003E98*
+ ID_MODEL_FROM_DATABASE=UHD Graphics 630 (Desktop 9 Series)
+
 pci:v00008086d00003E9B*
  ID_MODEL_FROM_DATABASE=UHD Graphics 630 (Mobile)
 
 pci:v00008086d00003EA0*
  ID_MODEL_FROM_DATABASE=UHD Graphics 620 (Whiskey Lake)
 
+pci:v00008086d00003EA0sv00001028sd0000089E*
+ ID_MODEL_FROM_DATABASE=UHD Graphics 620 (Whiskey Lake) (Inspiron 5482)
+
 pci:v00008086d00003EA5*
  ID_MODEL_FROM_DATABASE=Iris Plus Graphics 655
 
@@ -87542,6 +87809,9 @@ pci:v00008086d000071A2*
 pci:v00008086d000071A2sv00004C53sd00001000*
  ID_MODEL_FROM_DATABASE=440GX - 82443GX Host bridge (AGP disabled) (CC7/CR7/CP7/VC7/VP7/VR7 mainboard)
 
+pci:v00008086d00007360*
+ ID_MODEL_FROM_DATABASE=XMM7360 LTE Advanced Modem
+
 pci:v00008086d00007600*
  ID_MODEL_FROM_DATABASE=82372FB PIIX5 ISA
 
@@ -88757,6 +89027,9 @@ pci:v00008086d00009D03sv00001028sd000006DC*
 pci:v00008086d00009D03sv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP SATA Controller [AHCI mode] (Latitude 3570)
 
+pci:v00008086d00009D03sv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP SATA Controller [AHCI mode] (EliteBook 840 G3)
+
 pci:v00008086d00009D03sv000017AAsd0000225D*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP SATA Controller [AHCI mode] (ThinkPad T480)
 
@@ -88766,9 +89039,15 @@ pci:v00008086d00009D03sv000017AAsd0000382A*
 pci:v00008086d00009D10*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #1
 
+pci:v00008086d00009D11*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #2
+
 pci:v00008086d00009D12*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #3
 
+pci:v00008086d00009D13*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #4
+
 pci:v00008086d00009D14*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #5
 
@@ -88796,6 +89075,9 @@ pci:v00008086d00009D18sv000017AAsd0000382A*
 pci:v00008086d00009D19*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #10
 
+pci:v00008086d00009D1A*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #11
+
 pci:v00008086d00009D21*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC
 
@@ -88805,6 +89087,9 @@ pci:v00008086d00009D21sv00001028sd000006DC*
 pci:v00008086d00009D21sv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC (Latitude 3570)
 
+pci:v00008086d00009D21sv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC (EliteBook 840 G3)
+
 pci:v00008086d00009D21sv000017AAsd0000224F*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC (ThinkPad X1 Carbon 5th Gen)
 
@@ -88823,6 +89108,9 @@ pci:v00008086d00009D23sv00001028sd000006DC*
 pci:v00008086d00009D23sv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP SMBus (Latitude 3570)
 
+pci:v00008086d00009D23sv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP SMBus (EliteBook 840 G3)
+
 pci:v00008086d00009D23sv000017AAsd00002247*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP SMBus (ThinkPad T570)
 
@@ -88859,6 +89147,9 @@ pci:v00008086d00009D2Fsv00001028sd000006DC*
 pci:v00008086d00009D2Fsv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller (Latitude 3570)
 
+pci:v00008086d00009D2Fsv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller (EliteBook 840 G3)
+
 pci:v00008086d00009D2Fsv000017AAsd00002247*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller (ThinkPad T570)
 
@@ -88877,6 +89168,9 @@ pci:v00008086d00009D31sv00001028sd000006DC*
 pci:v00008086d00009D31sv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP Thermal subsystem (Latitude 3570)
 
+pci:v00008086d00009D31sv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP Thermal subsystem (EliteBook 840 G3)
+
 pci:v00008086d00009D31sv000017AAsd00002247*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP Thermal subsystem (ThinkPad T570)
 
@@ -88901,6 +89195,9 @@ pci:v00008086d00009D3Asv00001028sd000006DC*
 pci:v00008086d00009D3Asv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP CSME HECI #1 (Latitude 3570)
 
+pci:v00008086d00009D3Asv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP CSME HECI #1 (EliteBook 840 G3)
+
 pci:v00008086d00009D3Asv000017AAsd00002247*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP CSME HECI #1 (ThinkPad T570)
 
@@ -88916,6 +89213,9 @@ pci:v00008086d00009D3Asv000017AAsd0000382A*
 pci:v00008086d00009D3D*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP Active Management Technology - SOL
 
+pci:v00008086d00009D3Dsv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP Active Management Technology - SOL (EliteBook 840 G3)
+
 pci:v00008086d00009D43*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP LPC Controller
 
@@ -88931,6 +89231,9 @@ pci:v00008086d00009D48sv00001028sd000006DC*
 pci:v00008086d00009D48sv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP LPC Controller (Latitude 3570)
 
+pci:v00008086d00009D48sv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP LPC Controller (EliteBook 840 G3)
+
 pci:v00008086d00009D4E*
  ID_MODEL_FROM_DATABASE=Sunrise Point LPC Controller/eSPI Controller
 
@@ -88958,6 +89261,9 @@ pci:v00008086d00009D60*
 pci:v00008086d00009D60sv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #0 (Latitude 3570)
 
+pci:v00008086d00009D60sv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #0 (EliteBook 840 G3)
+
 pci:v00008086d00009D60sv000017AAsd0000225D*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #0 (ThinkPad T480)
 
@@ -88991,6 +89297,9 @@ pci:v00008086d00009D70sv00001028sd000006DC*
 pci:v00008086d00009D70sv00001028sd000006F3*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio (Latitude 3570)
 
+pci:v00008086d00009D70sv0000103Csd00008079*
+ ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio (EliteBook 840 G3)
+
 pci:v00008086d00009D70sv000017AAsd0000382A*
  ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio (B51-80 Laptop)
 
@@ -89003,6 +89312,9 @@ pci:v00008086d00009D71sv000017AAsd0000225D*
 pci:v00008086d00009D84*
  ID_MODEL_FROM_DATABASE=Cannon Point-LP LPC Controller
 
+pci:v00008086d00009D84sv00001028sd0000089E*
+ ID_MODEL_FROM_DATABASE=Cannon Point-LP LPC Controller (Inspiron 5482)
+
 pci:v00008086d00009DA3*
  ID_MODEL_FROM_DATABASE=Cannon Point-LP SMBus Controller
 
@@ -89012,6 +89324,12 @@ pci:v00008086d00009DA4*
 pci:v00008086d00009DB0*
  ID_MODEL_FROM_DATABASE=Cannon Point-LP PCI Express Root Port #9
 
+pci:v00008086d00009DB4*
+ ID_MODEL_FROM_DATABASE=Cannon Point-LP PCI Express Root Port #13
+
+pci:v00008086d00009DB4sv00001028sd0000089E*
+ ID_MODEL_FROM_DATABASE=Cannon Point-LP PCI Express Root Port #13 (Inspiron 5482)
+
 pci:v00008086d00009DB6*
  ID_MODEL_FROM_DATABASE=Cannon Point-LP PCI Express Root Port #15
 
@@ -89024,12 +89342,27 @@ pci:v00008086d00009DBC*
 pci:v00008086d00009DC8*
  ID_MODEL_FROM_DATABASE=Cannon Point-LP High Definition Audio Controller
 
+pci:v00008086d00009DC8sv00001028sd0000089E*
+ ID_MODEL_FROM_DATABASE=Cannon Point-LP High Definition Audio Controller (Inspiron 5482)
+
 pci:v00008086d00009DD3*
  ID_MODEL_FROM_DATABASE=Cannon Point-LP SATA Controller [AHCI Mode]
 
 pci:v00008086d00009DE0*
  ID_MODEL_FROM_DATABASE=Cannon Point-LP MEI Controller #1
 
+pci:v00008086d00009DE8*
+ ID_MODEL_FROM_DATABASE=Cannon Point-LP Serial IO I2C Controller #0
+
+pci:v00008086d00009DE8sv00001028sd0000089E*
+ ID_MODEL_FROM_DATABASE=Cannon Point-LP Serial IO I2C Controller #0 (Inspiron 5482)
+
+pci:v00008086d00009DE9*
+ ID_MODEL_FROM_DATABASE=Cannon Point-LP Serial IO I2C Controller #1
+
+pci:v00008086d00009DE9sv00001028sd0000089E*
+ ID_MODEL_FROM_DATABASE=Cannon Point-LP Serial IO I2C Controller #1 (Inspiron 5482)
+
 pci:v00008086d00009DED*
  ID_MODEL_FROM_DATABASE=Cannon Point-LP USB 3.1 xHCI Controller
 
@@ -89042,6 +89375,9 @@ pci:v00008086d00009DF0*
 pci:v00008086d00009DF9*
  ID_MODEL_FROM_DATABASE=Cannon Point-LP Thermal Controller
 
+pci:v00008086d00009DFC*
+ ID_MODEL_FROM_DATABASE=Cannon Point-LP Integrated Sensor Hub
+
 pci:v00008086d0000A000*
  ID_MODEL_FROM_DATABASE=Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge
 
@@ -89999,6 +90335,27 @@ pci:v00008086d0000F1A5*
 pci:v00008086d0000F1A6*
  ID_MODEL_FROM_DATABASE=SSD Pro 7600p/760p/E 6100p Series
 
+pci:v00008086d0000F1A8*
+ ID_MODEL_FROM_DATABASE=SSDPEKNW020T8 [660p, 2TB]
+
+pci:v00008086d0000F1A8sv00008086sd0000390D*
+ ID_MODEL_FROM_DATABASE=SSDPEKNW020T8 [660p, 2TB]
+
+pci:v00008088*
+ ID_VENDOR_FROM_DATABASE=Beijing Wangxun Technology Co., Ltd.
+
+pci:v00008088d00001001*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller RP1000 for 10GbE SFP+
+
+pci:v00008088d00001001sv00008088sd00000000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller RP1000 for 10GbE SFP+ (Ethernet Network Adaptor RP1000 for 10GbE SFP+)
+
+pci:v00008088d00002001*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller RP2000 for 10GbE SFP+
+
+pci:v00008088d00002001sv00008088sd00002000*
+ ID_MODEL_FROM_DATABASE=Ethernet Controller RP2000 for 10GbE SFP+ (Ethernet Network Adaptor RP2000 for 10GbE SFP+)
+
 pci:v000080EE*
  ID_VENDOR_FROM_DATABASE=InnoTek Systemberatung GmbH
 
@@ -91013,6 +91370,15 @@ pci:v00009005d0000028Fsv0000103Csd00001100*
 pci:v00009005d0000028Fsv0000103Csd00001101*
  ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (Smart Array P416ie-m SR G10)
 
+pci:v00009005d0000028Fsv0000105Bsd00001211*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 8238-16i)
+
+pci:v00009005d0000028Fsv0000105Bsd00001321*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA 8242-24i)
+
+pci:v00009005d0000028Fsv000013FEsd00008312*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SKY-9200 MIC-8312BridgeB)
+
 pci:v00009005d0000028Fsv0000152Dsd00008A22*
  ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (QS-8204-8i)
 
@@ -91028,6 +91394,66 @@ pci:v00009005d0000028Fsv0000152Dsd00008A36*
 pci:v00009005d0000028Fsv0000152Dsd00008A37*
  ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (QS-8242-24i)
 
+pci:v00009005d0000028Fsv0000193Dsd00008460*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA H460-M1)
+
+pci:v00009005d0000028Fsv0000193Dsd00008461*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (HBA H460-B1)
+
+pci:v00009005d0000028Fsv0000193Dsd0000C460*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID P460-M2)
+
+pci:v00009005d0000028Fsv0000193Dsd0000C461*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID P460-B2)
+
+pci:v00009005d0000028Fsv0000193Dsd0000F460*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID P460-M4)
+
+pci:v00009005d0000028Fsv0000193Dsd0000F461*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID P460-B4)
+
+pci:v00009005d0000028Fsv000019E5sd0000D227*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartROC-HD SR465C-M 4G)
+
+pci:v00009005d0000028Fsv000019E5sd0000D228*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartROC SR455C-M 2G)
+
+pci:v00009005d0000028Fsv000019E5sd0000D229*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartIOC SR155-M)
+
+pci:v00009005d0000028Fsv000019E5sd0000D22A*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartIOC-HD SR765-M)
+
+pci:v00009005d0000028Fsv000019E5sd0000D22B*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartROC-e SR455C-ME 4G)
+
+pci:v00009005d0000028Fsv000019E5sd0000D22C*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartROC SR455C-M 4G)
+
+pci:v00009005d0000028Fsv00001BD4sd00000045*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SMART-HBA 8242-24i)
+
+pci:v00009005d0000028Fsv00001BD4sd00000046*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID 8236-16i)
+
+pci:v00009005d0000028Fsv00001BD4sd00000047*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID 8240-24i)
+
+pci:v00009005d0000028Fsv00001BD4sd00000048*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SMART-HBA 8238-16i)
+
+pci:v00009005d0000028Fsv00001BD4sd0000004A*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (PM8222-SHBA)
+
+pci:v00009005d0000028Fsv00001BD4sd0000004B*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID PM8204-2GB)
+
+pci:v00009005d0000028Fsv00001BD4sd0000004C*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (RAID PM8204-4GB)
+
+pci:v00009005d0000028Fsv00001BD4sd0000004F*
+ ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (PM8222-HBA)
+
 pci:v00009005d0000028Fsv00009005sd00000608*
  ID_MODEL_FROM_DATABASE=Smart Storage PQI 12G SAS/PCIe 3 (SmartRAID 3162-8i /e)
 
@@ -91679,6 +92105,9 @@ pci:v0000BDBDd0000A148*
 pci:v0000BDBDd0000A14B*
  ID_MODEL_FROM_DATABASE=DeckLink 8K Pro
 
+pci:v0000BDBDd0000A14E*
+ ID_MODEL_FROM_DATABASE=DeckLink Quad HDMI Recorder
+
 pci:v0000BDBDd0000A1FF*
  ID_MODEL_FROM_DATABASE=eGPU RX580
 
@@ -92375,6 +92804,9 @@ pci:v0000F1D0d0000DCAF*
 pci:v0000F1D0d0000DFEE*
  ID_MODEL_FROM_DATABASE=Xena HD-DA
 
+pci:v0000F1D0d0000EB0D*
+ ID_MODEL_FROM_DATABASE=Corvid 88
+
 pci:v0000F1D0d0000EB0E*
  ID_MODEL_FROM_DATABASE=Corvid 44
 
index f14aa70..3bb26ad 100644 (file)
@@ -449,6 +449,9 @@ usb:v03EBp7800*
 usb:v03EBp800C*
  ID_MODEL_FROM_DATABASE=Airspy HF+
 
+usb:v03EBpFF02*
+ ID_MODEL_FROM_DATABASE=WootingTwo
+
 usb:v03EBpFF07*
  ID_MODEL_FROM_DATABASE=Tux Droid fish dongle
 
@@ -512,6 +515,9 @@ usb:v03F0p0024*
 usb:v03F0p002A*
  ID_MODEL_FROM_DATABASE=LaserJet P1102
 
+usb:v03F0p0053*
+ ID_MODEL_FROM_DATABASE=DeskJet 2620 All-in-One Printer
+
 usb:v03F0p0101*
  ID_MODEL_FROM_DATABASE=ScanJet 4100c
 
@@ -674,6 +680,9 @@ usb:v03F0p0517*
 usb:v03F0p051D*
  ID_MODEL_FROM_DATABASE=Bluetooth Interface
 
+usb:v03F0p052A*
+ ID_MODEL_FROM_DATABASE=LaserJet M1212nf MFP
+
 usb:v03F0p0601*
  ID_MODEL_FROM_DATABASE=ScanJet 6300c
 
@@ -3809,6 +3818,9 @@ usb:v0419p0001*
 usb:v0419p0600*
  ID_MODEL_FROM_DATABASE=Desktop Wireless 6000
 
+usb:v0419p2694*
+ ID_MODEL_FROM_DATABASE=Laila
+
 usb:v0419p3001*
  ID_MODEL_FROM_DATABASE=Xerox P1202 Laser Printer
 
@@ -4772,9 +4784,6 @@ usb:v0424p223A*
 usb:v0424p2503*
  ID_MODEL_FROM_DATABASE=USB 2.0 Hub
 
-usb:v0424p2504*
- ID_MODEL_FROM_DATABASE=USB 2.0 Hub
-
 usb:v0424p2507*
  ID_MODEL_FROM_DATABASE=hub
 
@@ -4808,6 +4817,9 @@ usb:v0424p2744*
 usb:v0424p274D*
  ID_MODEL_FROM_DATABASE=HTC Hub Controller
 
+usb:v0424p2807*
+ ID_MODEL_FROM_DATABASE=Hub
+
 usb:v0424p3FCC*
  ID_MODEL_FROM_DATABASE=RME MADIface
 
@@ -4829,6 +4841,9 @@ usb:v0424p5534*
 usb:v0424p5744*
  ID_MODEL_FROM_DATABASE=Hub
 
+usb:v0424p5807*
+ ID_MODEL_FROM_DATABASE=Hub
+
 usb:v0424p7500*
  ID_MODEL_FROM_DATABASE=LAN7500 Ethernet 10/100/1000 Adapter
 
@@ -7154,6 +7169,9 @@ usb:v045Ep07A5*
 usb:v045Ep07B2*
  ID_MODEL_FROM_DATABASE=2.4GHz Transceiver v8.0 used by mouse Wireless Desktop 900
 
+usb:v045Ep07B6*
+ ID_MODEL_FROM_DATABASE=Comfort Curve Keyboard 3000
+
 usb:v045Ep07B9*
  ID_MODEL_FROM_DATABASE=Wired Keyboard 200
 
@@ -9542,6 +9560,9 @@ usb:v0480p0200*
 usb:v0480p0820*
  ID_MODEL_FROM_DATABASE=Canvio Advance Disk
 
+usb:v0480p0821*
+ ID_MODEL_FROM_DATABASE=Canvio Advance 2TB model DTC920
+
 usb:v0480pA006*
  ID_MODEL_FROM_DATABASE=External Disk 1.5TB
 
@@ -9728,6 +9749,9 @@ usb:v0483p5731*
 usb:v0483p5740*
  ID_MODEL_FROM_DATABASE=Virtual COM Port
 
+usb:v0483p5750*
+ ID_MODEL_FROM_DATABASE=LED badge -- mini LED display -- 11x44
+
 usb:v0483p7270*
  ID_MODEL_FROM_DATABASE=ST Micro Serial Bridge
 
@@ -9860,6 +9884,9 @@ usb:v048Dp9507*
 usb:v048Dp9910*
  ID_MODEL_FROM_DATABASE=IT9910 chipset based grabber
 
+usb:v048DpFF59*
+ ID_MODEL_FROM_DATABASE=Hdmi-CEC Bridge
+
 usb:v048F*
  ID_VENDOR_FROM_DATABASE=Eicon Tech.
 
@@ -10061,6 +10088,9 @@ usb:v0499p160F*
 usb:v0499p1613*
  ID_MODEL_FROM_DATABASE=Clavinova CLP535
 
+usb:v0499p1617*
+ ID_MODEL_FROM_DATABASE=PSR-E353 digital keyboard
+
 usb:v0499p1704*
  ID_MODEL_FROM_DATABASE=Steinberg UR44
 
@@ -12821,6 +12851,9 @@ usb:v04B0p0429*
 usb:v04B0p042A*
  ID_MODEL_FROM_DATABASE=D800 (ptp)
 
+usb:v04B0p0430*
+ ID_MODEL_FROM_DATABASE=D7100
+
 usb:v04B0p043F*
  ID_MODEL_FROM_DATABASE=D5600
 
@@ -14549,6 +14582,12 @@ usb:v04D8pC001*
 usb:v04D8pE11C*
  ID_MODEL_FROM_DATABASE=TL866CS EEPROM Programmer [MiniPRO]
 
+usb:v04D8pEDB4*
+ ID_MODEL_FROM_DATABASE=micro PLC (ATSAMD51G19A) [Black Brix ECU II]
+
+usb:v04D8pEDB5*
+ ID_MODEL_FROM_DATABASE=ATMEGA32U4 [Black Brix ECU]
+
 usb:v04D8pF2C4*
  ID_MODEL_FROM_DATABASE=Macareux-labs Hygrometry Temperature Sensor
 
@@ -15470,6 +15509,9 @@ usb:v04E8p342D*
 usb:v04E8p344F*
  ID_MODEL_FROM_DATABASE=SCX-3400 Series
 
+usb:v04E8p347E*
+ ID_MODEL_FROM_DATABASE=C48x Series Color Laser Multifunction Printer
+
 usb:v04E8p3605*
  ID_MODEL_FROM_DATABASE=InkJet Color Printer
 
@@ -15707,6 +15749,9 @@ usb:v04E8p61B5*
 usb:v04E8p61B6*
  ID_MODEL_FROM_DATABASE=M3 Portable Hard Drive 1TB
 
+usb:v04E8p61B7*
+ ID_MODEL_FROM_DATABASE=M3 Portable Hard Drive 4TB
+
 usb:v04E8p61F3*
  ID_MODEL_FROM_DATABASE=Portable SSD T3 (MU-PT250B, MU-PT500B)
 
@@ -15893,6 +15938,9 @@ usb:v04E8p7080*
 usb:v04E8p7081*
  ID_MODEL_FROM_DATABASE=Human Interface Device
 
+usb:v04E8p7301*
+ ID_MODEL_FROM_DATABASE=Fingerprint Device
+
 usb:v04E8p8001*
  ID_MODEL_FROM_DATABASE=Handheld
 
@@ -16319,6 +16367,9 @@ usb:v04F3p0381*
 usb:v04F3p04A0*
  ID_MODEL_FROM_DATABASE=Dream Cheeky Stress/Panic Button
 
+usb:v04F3p2234*
+ ID_MODEL_FROM_DATABASE=Touchscreen
+
 usb:v04F4*
  ID_VENDOR_FROM_DATABASE=Harting Elektronik, Inc.
 
@@ -17855,6 +17906,15 @@ usb:v04F9p2061*
 usb:v04F9p2064*
  ID_MODEL_FROM_DATABASE=PT-P700 P-touch Label Printer RemovableDisk
 
+usb:v04F9p209B*
+ ID_MODEL_FROM_DATABASE=QL-800 P-touch Label Printer
+
+usb:v04F9p209C*
+ ID_MODEL_FROM_DATABASE=QL-810W P-touch Label Printer
+
+usb:v04F9p209D*
+ ID_MODEL_FROM_DATABASE=QL-820NWB P-touch Label Printer
+
 usb:v04F9p2100*
  ID_MODEL_FROM_DATABASE=Card Reader Writer
 
@@ -19103,6 +19163,9 @@ usb:v054Cp0045*
 usb:v054Cp0046*
  ID_MODEL_FROM_DATABASE=Network Walkman
 
+usb:v054Cp0049*
+ ID_MODEL_FROM_DATABASE=UP-D895
+
 usb:v054Cp004A*
  ID_MODEL_FROM_DATABASE=Memory Stick Hi-Fi System
 
@@ -19355,6 +19418,9 @@ usb:v054Cp01D5*
 usb:v054Cp01DE*
  ID_MODEL_FROM_DATABASE=VRD-VC10 [Video Capture]
 
+usb:v054Cp01E7*
+ ID_MODEL_FROM_DATABASE=UP-D897
+
 usb:v054Cp01E8*
  ID_MODEL_FROM_DATABASE=UP-DR150 Photo Printer
 
@@ -20222,6 +20288,12 @@ usb:v056Ap0038*
 usb:v056Ap0039*
  ID_MODEL_FROM_DATABASE=DTU-710
 
+usb:v056Ap003A*
+ ID_MODEL_FROM_DATABASE=DTI-520
+
+usb:v056Ap003B*
+ ID_MODEL_FROM_DATABASE=Integrated Hub
+
 usb:v056Ap003F*
  ID_MODEL_FROM_DATABASE=DTZ-2100 [Cintiq 21UX]
 
@@ -20289,7 +20361,7 @@ usb:v056Ap0081*
  ID_MODEL_FROM_DATABASE=CTE-630BT [Graphire Wireless (6x8)]
 
 usb:v056Ap0084*
- ID_MODEL_FROM_DATABASE=Wireless adapter for Bamboo tablets
+ ID_MODEL_FROM_DATABASE=ACK-40401 [Wireless Accessory Kit]
 
 usb:v056Ap0090*
  ID_MODEL_FROM_DATABASE=TPC90
@@ -20426,6 +20498,9 @@ usb:v056Ap00ED*
 usb:v056Ap00EF*
  ID_MODEL_FROM_DATABASE=TPCEF
 
+usb:v056Ap00F0*
+ ID_MODEL_FROM_DATABASE=DTU-1631
+
 usb:v056Ap00F4*
  ID_MODEL_FROM_DATABASE=DTK-2400 [Cintiq 24HD] tablet
 
@@ -20501,9 +20576,51 @@ usb:v056Ap0317*
 usb:v056Ap0318*
  ID_MODEL_FROM_DATABASE=CTH-301 [Bamboo]
 
+usb:v056Ap0319*
+ ID_MODEL_FROM_DATABASE=CTH-300 [Bamboo Pad wireless]
+
+usb:v056Ap0323*
+ ID_MODEL_FROM_DATABASE=CTL-680 [Intuos Pen (M)]
+
+usb:v056Ap032A*
+ ID_MODEL_FROM_DATABASE=DTK-2700 [Cintiq 27QHD]
+
+usb:v056Ap032B*
+ ID_MODEL_FROM_DATABASE=DTH-2700 [Cintiq 27QHD touch] tablet
+
+usb:v056Ap032C*
+ ID_MODEL_FROM_DATABASE=DTH-2700 [Cintiq 27QHD touch] touchscreen
+
 usb:v056Ap032F*
  ID_MODEL_FROM_DATABASE=DTU-1031X
 
+usb:v056Ap0331*
+ ID_MODEL_FROM_DATABASE=ACK-411050 [ExpressKey Remote]
+
+usb:v056Ap0333*
+ ID_MODEL_FROM_DATABASE=DTH-1300 [Cintiq 13HD Touch] tablet
+
+usb:v056Ap0335*
+ ID_MODEL_FROM_DATABASE=DTH-1300 [Cintiq 13HD Touch] touchscreen
+
+usb:v056Ap0336*
+ ID_MODEL_FROM_DATABASE=DTU-1141
+
+usb:v056Ap033B*
+ ID_MODEL_FROM_DATABASE=CTL-490 [Intuos Draw (S)]
+
+usb:v056Ap033C*
+ ID_MODEL_FROM_DATABASE=CTH-490 [Intuos Art/Photo/Comic (S)]
+
+usb:v056Ap033D*
+ ID_MODEL_FROM_DATABASE=CTL-690 [Intuos Draw (M)]
+
+usb:v056Ap033E*
+ ID_MODEL_FROM_DATABASE=CTH-690 [Intuos Art (M)]
+
+usb:v056Ap0343*
+ ID_MODEL_FROM_DATABASE=DTK-1651
+
 usb:v056Ap0347*
  ID_MODEL_FROM_DATABASE=Integrated Hub
 
@@ -20552,6 +20669,9 @@ usb:v056Ap0357*
 usb:v056Ap0358*
  ID_MODEL_FROM_DATABASE=PTH-860 [Intuos Pro (L)]
 
+usb:v056Ap0359*
+ ID_MODEL_FROM_DATABASE=DTU-1141B
+
 usb:v056Ap035A*
  ID_MODEL_FROM_DATABASE=DTH-1152 tablet
 
@@ -20702,6 +20822,15 @@ usb:v056Ep0075*
 usb:v056Ep0077*
  ID_MODEL_FROM_DATABASE=Laser mouse M-LY2UL
 
+usb:v056Ep0079*
+ ID_MODEL_FROM_DATABASE=Laser mouse M-D21DL
+
+usb:v056Ep007B*
+ ID_MODEL_FROM_DATABASE=Laser mouse M-D20DR
+
+usb:v056Ep007C*
+ ID_MODEL_FROM_DATABASE=Laser Bluetooth mouse M-BT5BL
+
 usb:v056Ep2003*
  ID_MODEL_FROM_DATABASE=JC-U3613M
 
@@ -27992,6 +28121,9 @@ usb:v06F8pA300*
 usb:v06F8pB000*
  ID_MODEL_FROM_DATABASE=Hercules DJ Console
 
+usb:v06F8pB121*
+ ID_MODEL_FROM_DATABASE=Hercules P32 DJ
+
 usb:v06F8pC000*
  ID_MODEL_FROM_DATABASE=Hercules Muse Pocket
 
@@ -36131,6 +36263,15 @@ usb:v0AADp0083*
 usb:v0AADp0095*
  ID_MODEL_FROM_DATABASE=NRP-Z86
 
+usb:v0AADp0117*
+ ID_MODEL_FROM_DATABASE=HMF / HMP / HMS-X / HMO series Oscilloscopes
+
+usb:v0AADp0118*
+ ID_MODEL_FROM_DATABASE=HMF / HMP / HMS-X / HMO series Oscilloscopes
+
+usb:v0AADp0119*
+ ID_MODEL_FROM_DATABASE=HMF / HMP / HMS-X / HMO series Oscilloscopes
+
 usb:v0AAE*
  ID_VENDOR_FROM_DATABASE=NEC infrontia Corp. (Nitsuko)
 
@@ -57092,6 +57233,15 @@ usb:v22B9p0006*
 usb:v22BA*
  ID_VENDOR_FROM_DATABASE=Technology Innovation Holdings, Ltd
 
+usb:v22E0*
+ ID_VENDOR_FROM_DATABASE=secunet Security Networks AG
+
+usb:v22E0p0002*
+ ID_MODEL_FROM_DATABASE=SINA Flash Drive
+
+usb:v22E0p0003*
+ ID_MODEL_FROM_DATABASE=SINA ID Token A
+
 usb:v2304*
  ID_VENDOR_FROM_DATABASE=Pinnacle Systems, Inc.
 
@@ -57500,6 +57650,51 @@ usb:v2676*
 usb:v2676pBA02*
  ID_MODEL_FROM_DATABASE=ace
 
+usb:v2717*
+ ID_VENDOR_FROM_DATABASE=Xiaomi Inc.
+
+usb:v2717p0011*
+ ID_MODEL_FROM_DATABASE=100Mbps Network Card Adapter
+
+usb:v2717p0360*
+ ID_MODEL_FROM_DATABASE=Mi3W
+
+usb:v2717p0368*
+ ID_MODEL_FROM_DATABASE=Mi4 LTE
+
+usb:v2717p3801*
+ ID_MODEL_FROM_DATABASE=Mi ANC & Type-C In-Ear Earphones
+
+usb:v2717p4106*
+ ID_MODEL_FROM_DATABASE=MediaTek MT7601U [MI WiFi]
+
+usb:v2717pFF08*
+ ID_MODEL_FROM_DATABASE=Redmi Note 3 (ADB Interface)
+
+usb:v2717pFF10*
+ ID_MODEL_FROM_DATABASE=Mi/Redmi series (PTP)
+
+usb:v2717pFF18*
+ ID_MODEL_FROM_DATABASE=Mi/Redmi series (PTP + ADB)
+
+usb:v2717pFF40*
+ ID_MODEL_FROM_DATABASE=Mi/Redmi series (MTP)
+
+usb:v2717pFF48*
+ ID_MODEL_FROM_DATABASE=Mi/Redmi series (MTP + ADB)
+
+usb:v2717pFF60*
+ ID_MODEL_FROM_DATABASE=redmi prime 2
+
+usb:v2717pFF68*
+ ID_MODEL_FROM_DATABASE=Mi-4c
+
+usb:v2717pFF80*
+ ID_MODEL_FROM_DATABASE=Mi/Redmi series (RNDIS)
+
+usb:v2717pFF88*
+ ID_MODEL_FROM_DATABASE=Mi/Redmi series (RNDIS + ADB)
+
 usb:v2730*
  ID_VENDOR_FROM_DATABASE=Citizen
 
index 3ebdeb6..4f94342 100644 (file)
@@ -100,6 +100,32 @@ evdev:input:b0003v05ACp025B*
  EVDEV_ABS_35=::94
  EVDEV_ABS_36=::92
 
+# MacBook8,1 (2015), MacBook9,1 (2016), MacBook10,1 (2017)
+evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBook8,1:*
+evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBook9,1:*
+evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBook10,1:*
+ EVDEV_ABS_00=::95
+ EVDEV_ABS_01=::90
+ EVDEV_ABS_35=::95
+ EVDEV_ABS_36=::90
+
+# MacBookPro13,* (Late 2016), MacBookPro14,* (Mid 2017)
+evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBookPro13,1:*
+evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBookPro13,2:*
+evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBookPro14,1:*
+evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBookPro14,2:*
+ EVDEV_ABS_00=::96
+ EVDEV_ABS_01=::94
+ EVDEV_ABS_35=::96
+ EVDEV_ABS_36=::94
+
+evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBookPro13,3:*
+evdev:name:Apple SPI Touchpad:dmi:*:svnAppleInc.:pnMacBookPro14,3:*
+ EVDEV_ABS_00=::96
+ EVDEV_ABS_01=::95
+ EVDEV_ABS_35=::96
+ EVDEV_ABS_36=::95
+
 #########################################
 # ASUS
 #########################################
index 7e9dc99..20c1e7e 100644 (file)
@@ -66,3 +66,7 @@ id-input:modalias:input:b0003v5543p0081*
 # XP-PEN STAR 06
 id-input:modalias:input:b0003v28bdp0078*
  ID_INPUT_TABLET=1
+
+# Lite-On Tech IBM USB Travel Keyboard with Ultra Nav Mouse
+id-input:modalias:input:b0003v04B3p301Ee0100-e0,1,2,4*
+ ID_INPUT_POINTINGSTICK=1
index 3555440..71aecd8 100644 (file)
@@ -188,6 +188,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAcer*:pnAOA*:pvr*
 ###########################################################
 
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*
+ KEYBOARD_KEY_81=f21                                    # Touchpad toggle
  KEYBOARD_KEY_8a=ejectcd
 
 # Alienware/Dell reserves these keys; safe to apply on all their devices
@@ -210,6 +211,10 @@ evdev:name:Eee PC WMI hotkeys:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
 evdev:name:Asus Laptop extra buttons:dmi:bvn*:bvr*:bd*:svnASUS*:pn*:pvr*
  KEYBOARD_KEY_6b=f21                                    # Touchpad Toggle
 
+# USB keyboard in Asus FX503VD
+evdev:input:b0003v0B05p1869*
+ KEYBOARD_KEY_ff31007c=f20                              # Remap micmute to f20
+
 ###########################################################
 # BenQ
 ###########################################################
@@ -499,7 +504,8 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*Pavilion*dv7*Notebook*PC:
  KEYBOARD_KEY_c6=break
  KEYBOARD_KEY_94=reserved
 
-# Pavilion x360 13 (Prevents random airplane mode activation)
+# Pavilion and Spectre x360 13 (Prevents random airplane mode activation)
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[sS][pP][eE][cC][tT][rR][eE]*x360*13*:pvr*
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*[pP][aA][vV][iI][lL][iI][oO][nN]*13*x360*:pvr*
  KEYBOARD_KEY_d7=unknown
 
@@ -802,6 +808,10 @@ evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*IdeaPad*Z370*:pvr*
  KEYBOARD_KEY_ae=!volumedown
  KEYBOARD_KEY_b0=!volumeup
 
+# Lenovo Y50-70
+evdev:atkbd:dmi:bvn*:bvr*:svnLENOVO*:pn*20378*:pvr*
+ KEYBOARD_KEY_f3=f21      # Fn+F6 (toggle touchpad)
+
 # V480
 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnLENOVO*:pn*Lenovo*V480*:pvr*
  KEYBOARD_KEY_f1=f21
index b916add..1a6f2d8 100644 (file)
@@ -71,6 +71,9 @@ sensor:modalias:acpi:INVN6500*:dmi:*svn*Acer*:*pn*AspireSW5-012*
 sensor:modalias:acpi:BMA250E*:dmi:*:svnAcer:pnIconiaW1-810:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
+sensor:modalias:acpi:SMO8500:*:dmi:*Acer*:pnOneS1002*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, -1
+
 sensor:modalias:acpi:KIOX0009*:dmi:*:svnAcer:pnOneS1003:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
@@ -359,12 +362,26 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnLINX*:pnLINX12X64:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
 #########################################
+# Medion
+#########################################
+sensor:modalias:acpi:SMO8500*:dmi:*:svnMEDION:pnAkoyaE2212TMD99720:*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
+
+#########################################
 # MSI
 #########################################
 sensor:modalias:acpi:SMO8500*:dmi:*:svnMicro-StarInternationalCo.,Ltd.:pnS100:*
  ACCEL_MOUNT_MATRIX=0, -1, 0; 1, 0, 0; 0, 0, 1
 
 #########################################
+# MYRIA
+#########################################
+
+# MY8307
+sensor:modalias:acpi:BOSC0200*:dmi:*:svnCompletElectroServ:pnMY8307:*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
+
+#########################################
 # Nuvision (TMax)
 #########################################
 
@@ -459,6 +476,10 @@ sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:bvr5.011:bd11/03/20
 sensor:modalias:acpi:KIOX010A*:dmi:*:svnTECLAST:pnF5:*
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
+# Teclast F6 Pro
+sensor:modalias:acpi:KIOX010A*:dmi:*:svnTECLAST:pnF6Pro:*
+ ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1
+
 #########################################
 # Trekstor
 #########################################
@@ -467,6 +488,7 @@ sensor:modalias:acpi:BMA250*:dmi:*:bvrTREK.G.WI71C.JGBMRBA*:*:svnTrekStor:pnSurf
  ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1
 
 sensor:modalias:acpi:KIOX000A*:dmi:*:svnTREKSTOR:pnPrimetabT13B:*
+sensor:modalias:acpi:BOSC0200*:dmi:*:svnTrekStor*:pnSurfTabtwin11.6:*
  ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1
 
 #########################################
index 9854903..0eb5c9d 100644 (file)
@@ -681,7 +681,7 @@ mouse:usb:v0425p0101:name:G-Tech CHINA    USB Wireless Mouse & KeyBoard V1.01  :
 
 # Razer Abyssus
 mouse:usb:v1532p0042:name:Razer Razer Abyssus:
- MOUSE_DPI=3500@1000
+ MOUSE_DPI=1600@1000
 
 # Razer DeathAdder Black Edition
 mouse:usb:v1532p0029:name:Razer Razer DeathAdder:
index 9796353..b16da96 100644 (file)
@@ -48,3 +48,11 @@ touchpad:bluetooth:*
 touchpad:usb:v056a*
  ID_INPUT_TOUCHPAD_INTEGRATION=external
 
+###########################################################
+# Apple
+###########################################################
+# Magic Trackpad (1 and 2)
+touchpad:usb:v05acp030e:*
+touchpad:usb:v05acp0265:*
+ ID_INPUT_TOUCHPAD_INTEGRATION=external
index 2c23b05..7bdd3f9 100755 (executable)
@@ -72,8 +72,8 @@ b = open("pnp_id_registry.html")
 print('# This file is part of systemd.\n'
       '#\n'
       '# Data imported from:\n'
-      '#     http://www.uefi.org/uefi-pnp-export\n'
-      '#     http://www.uefi.org/uefi-acpi-export')
+      '#     https://uefi.org/uefi-pnp-export\n'
+      '#     https://uefi.org/uefi-acpi-export')
 
 read_table(a)
 read_table(b)
index 61ca0ca..58ecc73 100755 (executable)
@@ -5,6 +5,7 @@ import sys
 from pyparsing import (Word, White, Literal, Regex,
                        LineEnd, SkipTo,
                        ZeroOrMore, OneOrMore, Combine, Optional, Suppress,
+                       Group,
                        stringEnd, pythonStyleComment)
 
 EOL = LineEnd().suppress()
@@ -23,10 +24,10 @@ def klass_grammar():
     subclass_line = TAB + NUM2('subclass') + text_eol('text')
     protocol_line = TAB + TAB + NUM2('protocol') + text_eol('name')
     subclass = (subclass_line('SUBCLASS') -
-                ZeroOrMore(protocol_line('PROTOCOLS*')
+                ZeroOrMore(Group(protocol_line)('PROTOCOLS*')
                            ^ COMMENTLINE.suppress()))
     klass = (klass_line('KLASS') -
-             ZeroOrMore(subclass('SUBCLASSES*')
+             ZeroOrMore(Group(subclass)('SUBCLASSES*')
                         ^ COMMENTLINE.suppress()))
     return klass
 
@@ -34,7 +35,7 @@ def usb_ids_grammar():
     vendor_line = NUM4('vendor') + text_eol('text')
     device_line = TAB + NUM4('device') + text_eol('text')
     vendor = (vendor_line('VENDOR') +
-             ZeroOrMore(device_line('VENDOR_DEV*') ^ COMMENTLINE.suppress()))
+              ZeroOrMore(Group(device_line)('VENDOR_DEV*') ^ COMMENTLINE.suppress()))
 
     klass = klass_grammar()
 
@@ -44,7 +45,8 @@ def usb_ids_grammar():
     other_group = (other_line - ZeroOrMore(TAB + text_eol('text')))
 
     commentgroup = OneOrMore(COMMENTLINE).suppress() ^ EMPTYLINE.suppress()
-    grammar = OneOrMore(vendor('VENDORS*') ^ klass('CLASSES*')
+    grammar = OneOrMore(Group(vendor)('VENDORS*')
+                        ^ Group(klass)('CLASSES*')
                         ^ other_group.suppress() ^ commentgroup) + stringEnd()
 
     grammar.parseWithTabs()
@@ -56,14 +58,15 @@ def pci_ids_grammar():
     subvendor_line = TAB + TAB + NUM4('a') + White(' ') + NUM4('b') + text_eol('name')
 
     device = (device_line('DEVICE') +
-              ZeroOrMore(subvendor_line('SUBVENDORS*') ^ COMMENTLINE.suppress()))
+              ZeroOrMore(Group(subvendor_line)('SUBVENDORS*') ^ COMMENTLINE.suppress()))
     vendor = (vendor_line('VENDOR') +
-              ZeroOrMore(device('DEVICES*') ^ COMMENTLINE.suppress()))
+              ZeroOrMore(Group(device)('DEVICES*') ^ COMMENTLINE.suppress()))
 
     klass = klass_grammar()
 
     commentgroup = OneOrMore(COMMENTLINE).suppress() ^ EMPTYLINE.suppress()
-    grammar = OneOrMore(vendor('VENDORS*') ^ klass('CLASSES*')
+    grammar = OneOrMore(Group(vendor)('VENDORS*')
+                        ^ Group(klass)('CLASSES*')
                         ^ commentgroup) + stringEnd()
 
     grammar.parseWithTabs()
@@ -73,12 +76,14 @@ def sdio_ids_grammar():
     vendor_line = NUM4('vendor') + text_eol('text')
     device_line = TAB + NUM4('device') + text_eol('text')
     vendor = (vendor_line('VENDOR') +
-              ZeroOrMore(device_line('DEVICES*') ^ COMMENTLINE.suppress()))
+              ZeroOrMore(Group(device_line)('DEVICES*') ^ COMMENTLINE.suppress()))
 
     klass = klass_grammar()
 
     commentgroup = OneOrMore(COMMENTLINE).suppress() ^ EMPTYLINE.suppress()
-    grammar = OneOrMore(vendor('VENDORS*') ^ klass('CLASSES*') ^ commentgroup) + stringEnd()
+    grammar = OneOrMore(Group(vendor)('VENDORS*')
+                        ^ Group(klass)('CLASSES*')
+                        ^ commentgroup) + stringEnd()
 
     grammar.parseWithTabs()
     return grammar
@@ -102,7 +107,7 @@ def oui_grammar(type):
 
     grammar = (Literal('OUI') + text_eol('header')
                + text_eol('header') + text_eol('header') + EMPTYLINE
-               + OneOrMore(vendor('VENDORS*')) + stringEnd())
+               + OneOrMore(Group(vendor)('VENDORS*')) + stringEnd())
 
     grammar.parseWithTabs()
     return grammar
@@ -126,8 +131,8 @@ def usb_vendor_model(p):
     items = {}
 
     for vendor_group in p.VENDORS:
-        vendor = vendor_group.VENDOR.vendor.upper()
-        text = vendor_group.VENDOR.text.strip()
+        vendor = vendor_group.vendor.upper()
+        text = vendor_group.text.strip()
         add_item(items, (vendor,), text)
 
         for vendor_dev in vendor_group.VENDOR_DEV:
@@ -152,8 +157,8 @@ def usb_classes(p):
     items = {}
 
     for klass_group in p.CLASSES:
-        klass = klass_group.KLASS.klass.upper()
-        text = klass_group.KLASS.text.strip()
+        klass = klass_group.klass.upper()
+        text = klass_group.text.strip()
 
         if klass != '00' and not re.match(r'(\?|None|Unused)\s*$', text):
             add_item(items, (klass,), text)
@@ -189,8 +194,8 @@ def pci_vendor_model(p):
     items = {}
 
     for vendor_group in p.VENDORS:
-        vendor = vendor_group.VENDOR.vendor.upper()
-        text = vendor_group.VENDOR.text.strip()
+        vendor = vendor_group.vendor.upper()
+        text = vendor_group.text.strip()
         add_item(items, (vendor,), text)
 
         for device_group in vendor_group.DEVICES:
@@ -227,8 +232,8 @@ def pci_classes(p):
     items = {}
 
     for klass_group in p.CLASSES:
-        klass = klass_group.KLASS.klass.upper()
-        text = klass_group.KLASS.text.strip()
+        klass = klass_group.klass.upper()
+        text = klass_group.text.strip()
         add_item(items, (klass,), text)
 
         for subclass_group in klass_group.SUBCLASSES:
@@ -260,8 +265,8 @@ def sdio_vendor_model(p):
     items = {}
 
     for vendor_group in p.VENDORS:
-        vendor = vendor_group.VENDOR.vendor.upper()
-        text = vendor_group.VENDOR.text.strip()
+        vendor = vendor_group.vendor.upper()
+        text = vendor_group.text.strip()
         add_item(items, (vendor,), text)
 
         for device_group in vendor_group.DEVICES:
@@ -286,8 +291,8 @@ def sdio_classes(p):
     items = {}
 
     for klass_group in p.CLASSES:
-        klass = klass_group.KLASS.klass.upper()
-        text = klass_group.KLASS.text.strip()
+        klass = klass_group.klass.upper()
+        text = klass_group.text.strip()
         add_item(items, klass, text)
 
     with open('20-sdio-classes.hwdb', 'wt') as out:
index 044e9db..17e588f 100644 (file)
@@ -3629,12 +3629,6 @@ C05E6F     (base 16)             V. Stonkaus firma Kodinis Raktas
                                  Vilnius  08303\r
                                LT\r
 \r
-6C-D1-46   (hex)               Smartek d.o.o.\r
-6CD146     (base 16)           Smartek d.o.o.\r
-                               B.J.Jelacica 22c\r
-                               Cakovec  Croatia  40000\r
-                               US\r
-\r
 E0-C2-B7   (hex)               Masimo Corporation\r
 E0C2B7     (base 16)           Masimo Corporation\r
                                40 Parker\r
@@ -3767,12 +3761,6 @@ A42C08     (base 16)             Masterwork Automodules
                                Orange  California  92869\r
                                US\r
 \r
-80-7B-1E   (hex)               Corsair Components\r
-807B1E     (base 16)           Corsair Components\r
-                               46221 Landing Parkway\r
-                               Fremont  CA  94538\r
-                               US\r
-\r
 A0-E2-5A   (hex)               Amicus SK, s.r.o.\r
 A0E25A     (base 16)           Amicus SK, s.r.o.\r
                                Koreszkova 9\r
@@ -9179,12 +9167,6 @@ A8CE90     (base 16)             CVC
                                Largo  Florida  33773\r
                                US\r
 \r
-00-1F-53   (hex)               GEMAC Gesellschaft für Mikroelektronikanwendung Chemnitz mbH\r
-001F53     (base 16)           GEMAC Gesellschaft für Mikroelektronikanwendung Chemnitz mbH\r
-                               Zwickauer Straße 227\r
-                               Chemnitz  Sachsen  09116\r
-                               DE\r
-\r
 00-1F-4E   (hex)               ConMed Linvatec\r
 001F4E     (base 16)           ConMed Linvatec\r
                                11311 Concept Blvd.\r
@@ -9197,12 +9179,6 @@ A8CE90     (base 16)             CVC
                                Markham  Ontario  L3R3S1\r
                                CA\r
 \r
-00-1F-47   (hex)               MCS Logic Inc.\r
-001F47     (base 16)           MCS Logic Inc.\r
-                               6F. Samho Center B Bldg., 275-6\r
-                               Seoul    137-941\r
-                               KR\r
-\r
 00-1F-D2   (hex)               COMMTECH TECHNOLOGY MACAO COMMERCIAL OFFSHORE LTD.\r
 001FD2     (base 16)           COMMTECH TECHNOLOGY MACAO COMMERCIAL OFFSHORE LTD.\r
                                31,TAI YIP STREET, 7/F KWUN TONG,\r
@@ -21989,12 +21965,6 @@ D059E4     (base 16)           Samsung Electronics Co.,Ltd
                                Gumi  Gyeongbuk  730-350\r
                                KR\r
 \r
-00-1D-20   (hex)               Comtrend Corporation\r
-001D20     (base 16)           Comtrend Corporation\r
-                               3F-1 10 LANE 609 CHUNG HSIN ROAD, SEC 5, SAN CHUNG CITY, TAIPEI TAIWAN 241\r
-                               TAIPEI    241\r
-                               TW\r
-\r
 14-0C-76   (hex)               FREEBOX SAS\r
 140C76     (base 16)           FREEBOX SAS\r
                                16 rue de la Ville l'Eveque\r
@@ -23669,18 +23639,6 @@ A8A648     (base 16)           Qingdao Hisense Communications Co.,Ltd.
                                London    NW12AA\r
                                GB\r
 \r
-04-9F-81   (hex)               NetScout Systems, Inc.\r
-049F81     (base 16)           NetScout Systems, Inc.\r
-                               310 Littleton Road\r
-                               Westford  MA  01886\r
-                               US\r
-\r
-00-80-8C   (hex)               NetScout Systems, Inc.\r
-00808C     (base 16)           NetScout Systems, Inc.\r
-                               310 Littleton Road\r
-                               Westford  MA  01886\r
-                               US\r
-\r
 C4-F5-A5   (hex)               Kumalift Co., Ltd.\r
 C4F5A5     (base 16)           Kumalift Co., Ltd.\r
                                7-2-6 Saito-Asagi\r
@@ -27005,12 +26963,6 @@ D4E6B7     (base 16)           Samsung Electronics Co.,Ltd
                                anyang  Gyeonggi-do  14042\r
                                KR\r
 \r
-88-B3-62   (hex)               Nokia Shanghai Bell Co. Ltd.)\r
-88B362     (base 16)           Nokia Shanghai Bell Co. Ltd.)\r
-                               No.388 Ning Qiao Road,Jin Qiao Pudong Shanghai 201206,P.R.China\r
-                               Shanghai   Pudong  201206\r
-                               CN\r
-\r
 1C-A0-B8   (hex)               Hon Hai Precision Ind. Co., Ltd.\r
 1CA0B8     (base 16)           Hon Hai Precision Ind. Co., Ltd.\r
                                GuangDongShenZhen\r
@@ -28889,18 +28841,6 @@ F84DFC     (base 16)           Hangzhou Hikvision Digital Technology Co.,Ltd.
                                Brentwood  Essex  08854\r
                                GB\r
 \r
-88-F5-6E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-88F56E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-D8-9B-3B   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-D89B3B     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
 CC-3F-EA   (hex)               BAE Systems, Inc\r
 CC3FEA     (base 16)           BAE Systems, Inc\r
                                1098 Clark St\r
@@ -29003,12 +28943,6 @@ D49234     (base 16)           NEC Corporation
                                Zelenograd  Moscow  124498\r
                                RU\r
 \r
-F0-10-AB   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-F010AB     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-                               No. 1600 Yuhang Tong Road, Wuchang Street, Yuhang District\r
-                               Hangzhou  Zhejiang  310000\r
-                               CN\r
-\r
 80-8F-1D   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
 808F1D     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
                                Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
@@ -31211,16 +31145,22 @@ ACA46E     (base 16)          SHENZHEN GONGJIN ELECTRONICS CO.,LT
                                Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
                                CN\r
 \r
+5C-5B-35   (hex)               Mist Systems, Inc.\r
+5C5B35     (base 16)           Mist Systems, Inc.\r
+                               1601 South De Anza Blvd, Suite 248\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
 DC-B0-82   (hex)               Nokia\r
 DCB082     (base 16)           Nokia\r
                                600 March Road\r
                                Kanata  Ontario  K2K 2E6\r
                                CA\r
 \r
-5C-5B-35   (hex)               Mist Systems, Inc.\r
-5C5B35     (base 16)           Mist Systems, Inc.\r
-                               1601 South De Anza Blvd, Suite 248\r
-                               Cupertino  CA  95014\r
+D0-19-6A   (hex)               Ciena Corporation\r
+D0196A     (base 16)           Ciena Corporation\r
+                               7035 Ridge Road\r
+                               Hanover  MD  21076\r
                                US\r
 \r
 84-FD-D1   (hex)               Intel Corporate\r
@@ -31229,11 +31169,11 @@ DCB082     (base 16)          Nokia
                                Kulim  Kedah  09000\r
                                MY\r
 \r
-D0-19-6A   (hex)               Ciena Corporation\r
-D0196A     (base 16)           Ciena Corporation\r
-                               7035 Ridge Road\r
-                               Hanover  MD  21076\r
-                               US\r
+CC-88-26   (hex)               LG Innotek\r
+CC8826     (base 16)           LG Innotek\r
+                               26, Hanamsandan 5beon-ro\r
+                               Gwangju  Gwangsan-gu  506-731\r
+                               KR\r
 \r
 D4-35-1D   (hex)               Technicolor\r
 D4351D     (base 16)           Technicolor\r
@@ -31247,6 +31187,288 @@ D4351D     (base 16)          Technicolor
                                Thalwil    8800\r
                                CH\r
 \r
+84-8B-CD   (hex)               IEEE Registration Authority\r
+848BCD     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+6C-AB-05   (hex)               Cisco Systems, Inc\r
+6CAB05     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+50-AF-4D   (hex)               zte corporation\r
+50AF4D     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+00-1F-53   (hex)               GEMAC Chemnitz GmbH\r
+001F53     (base 16)           GEMAC Chemnitz GmbH\r
+                               Zwickauer Straße 227\r
+                               Chemnitz  Sachsen  09116\r
+                               DE\r
+\r
+A4-A1-79   (hex)               Nanjing dianyan electric power automation co. LTD\r
+A4A179     (base 16)           Nanjing dianyan electric power automation co. LTD\r
+                               No. 29, liuzhou north road, pukou district\r
+                               Nanjing  Jiangsu  210031\r
+                               CN\r
+\r
+08-7E-64   (hex)               Technicolor CH USA Inc.\r
+087E64     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
+                               US\r
+\r
+14-84-30   (hex)               MITAC COMPUTING TECHNOLOGY CORPORATION\r
+148430     (base 16)           MITAC COMPUTING TECHNOLOGY CORPORATION\r
+                               3F., NO.1, R&D ROAD 2, HSINCHU SCIENCE PARK\r
+                               HSINCHU    30076\r
+                               TW\r
+\r
+68-7D-6B   (hex)               Samsung Electronics Co.,Ltd\r
+687D6B     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+7C-89-56   (hex)               Samsung Electronics Co.,Ltd\r
+7C8956     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+60-95-CE   (hex)               IEEE Registration Authority\r
+6095CE     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+D8-CA-06   (hex)               Titan DataCenters France\r
+D8CA06     (base 16)           Titan DataCenters France\r
+                               E.SpacePark 45 Allee des ormes\r
+                               mougins    06250\r
+                               FR\r
+\r
+C8-A7-76   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+C8A776     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+90-78-B2   (hex)               Xiaomi Communications Co Ltd\r
+9078B2     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+78-C3-13   (hex)               China Mobile Group Device Co.,Ltd.\r
+78C313     (base 16)           China Mobile Group Device Co.,Ltd.\r
+                               32 Xuanwumen West Street,Xicheng District\r
+                               Beijing    100053\r
+                               CN\r
+\r
+B8-91-C9   (hex)               Handreamnet\r
+B891C9     (base 16)           Handreamnet\r
+                               #1203 Ace High-end Tower II, 61, Digital-ro 26-gil, Guro-Gu\r
+                               Seoul    08389\r
+                               KR\r
+\r
+A8-49-4D   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+A8494D     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+FC-BD-67   (hex)               Arista Networks\r
+FCBD67     (base 16)           Arista Networks\r
+                               5453 Great America Parkway\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+14-A2-A0   (hex)               Cisco Systems, Inc\r
+14A2A0     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+6C-D1-46   (hex)               FRAMOS GmbH\r
+6CD146     (base 16)           FRAMOS GmbH\r
+                               Mehlbeerenstr. 2\r
+                               Taufkirchen    82024\r
+                               DE\r
+\r
+88-F5-6E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+88F56E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+D8-9B-3B   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+D89B3B     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+C4-8A-5A   (hex)               JFCONTROL\r
+C48A5A     (base 16)           JFCONTROL\r
+                               1449-37 Seoburo\r
+                               Suwon  Gyunggi-do  16643\r
+                               KR\r
+\r
+88-B3-62   (hex)               Nokia Shanghai Bell Co., Ltd.\r
+88B362     (base 16)           Nokia Shanghai Bell Co., Ltd.\r
+                               No.388 Ning Qiao Road,Jin Qiao Pudong Shanghai 201206,P.R.China\r
+                               Shanghai   Pudong  201206\r
+                               CN\r
+\r
+DC-A6-32   (hex)               Raspberry Pi Trading Ltd\r
+DCA632     (base 16)           Raspberry Pi Trading Ltd\r
+                               Maurice Wilkes Building, Cowley Road\r
+                               Cambridge    CB4 0DS\r
+                               GB\r
+\r
+7C-EC-9B   (hex)               Fuzhou Teraway Information Technology Co.,Ltd\r
+7CEC9B     (base 16)           Fuzhou Teraway Information Technology Co.,Ltd\r
+                               2F, Building 5#, No. 59, Yangqi Road, Cangshan District\r
+                               Fuzhou  Fujian  350000\r
+                               CN\r
+\r
+80-7B-1E   (hex)               Corsair Memory, Inc.\r
+807B1E     (base 16)           Corsair Memory, Inc.\r
+                               47100 Bayside Parkway\r
+                               Fremont  CA  94538\r
+                               US\r
+\r
+FC-BC-D1   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+FCBCD1     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+4C-E9-E4   (hex)               New H3C Technologies Co., Ltd\r
+4CE9E4     (base 16)           New H3C Technologies Co., Ltd\r
+                               466 Changhe Road, Binjiang District\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
+\r
+94-0B-19   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+940B19     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+04-88-5F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+04885F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+00-1F-47   (hex)               MCS Logic Inc.\r
+001F47     (base 16)           MCS Logic Inc.\r
+                               6F. Samho Center B Bldg., 275-6\r
+                               Seoul    137-941\r
+                               KR\r
+\r
+70-04-33   (hex)               California Things Inc.\r
+700433     (base 16)           California Things Inc.\r
+                               650 main st\r
+                               redwood city  CA  94063\r
+                               US\r
+\r
+78-CC-2B   (hex)               SINEWY TECHNOLOGY CO., LTD\r
+78CC2B     (base 16)           SINEWY TECHNOLOGY CO., LTD\r
+                               2F., No.179, Dongmin Rd.\r
+                               Toufen City, Miaoli County    351\r
+                               TW\r
+\r
+C8-0D-32   (hex)               Holoplot GmbH\r
+C80D32     (base 16)           Holoplot GmbH\r
+                               Ringbahnstr. 12, Hof A2\r
+                               Berlin    12099\r
+                               DE\r
+\r
+38-94-ED   (hex)               NETGEAR\r
+3894ED     (base 16)           NETGEAR\r
+                               350 East Plumeria Drive\r
+                               San Jose  CA  95134\r
+                               US\r
+\r
+F0-10-AB   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+F010AB     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+                               No. 1600 Yuhang Tong Road, Wuchang Street, Yuhang District\r
+                               Hangzhou  Zhejiang  310000\r
+                               CN\r
+\r
+C4-C6-03   (hex)               Cisco Systems, Inc\r
+C4C603     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+60-29-D5   (hex)               DAVOLINK Inc.\r
+6029D5     (base 16)           DAVOLINK Inc.\r
+                               112, Beolmal-ro\r
+                               Dongan-gu, Anyang-si  Gyeonggi-do  14057\r
+                               KR\r
+\r
+5C-87-9C   (hex)               Intel Corporate\r
+5C879C     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+50-E0-85   (hex)               Intel Corporate\r
+50E085     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+00-1D-20   (hex)               Comtrend Corporation\r
+001D20     (base 16)           Comtrend Corporation\r
+                               3F-1, 10 Lane 609, Chongxin Road, Section 5, \r
+                               New Taipei City,  Taiwan  24159\r
+                               TW\r
+\r
+00-80-8C   (hex)               NetAlly\r
+00808C     (base 16)           NetAlly\r
+                               310 Littleton Road\r
+                               Westford  MA  01886\r
+                               US\r
+\r
+04-9F-81   (hex)               NetAlly\r
+049F81     (base 16)           NetAlly\r
+                               310 Littleton Road\r
+                               Westford  MA  01886\r
+                               US\r
+\r
+1C-64-99   (hex)               Comtrend Corporation\r
+1C6499     (base 16)           Comtrend Corporation\r
+                               3F-1, 10 Lane 609, Chongxin Road, Section 5, \r
+                               New Taipei City,  Taiwan  24159\r
+                               TW\r
+\r
+DC-54-D7   (hex)               Amazon Technologies Inc.\r
+DC54D7     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+6C-5E-3B   (hex)               Cisco Systems, Inc\r
+6C5E3B     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+7C-94-2A   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+7C942A     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
 0C-6F-9C   (hex)               Shaw Communications Inc.\r
 0C6F9C     (base 16)           Shaw Communications Inc.\r
                                Suite 900, 630 3rd Avenue S.W.\r
@@ -51905,12 +52127,6 @@ D0D286     (base 16)           Beckman Coulter K.K.
                                  UNITED  KINGDOM\r
                                GB\r
 \r
-00-40-51   (hex)               GRACILIS, INC.\r
-004051     (base 16)           GRACILIS, INC.\r
-                               623 PALACE STREET\r
-                               AURORA  IL  60506\r
-                               US\r
-\r
 00-40-64   (hex)               KLA INSTRUMENTS CORPORATION\r
 004064     (base 16)           KLA INSTRUMENTS CORPORATION\r
                                160 RIO ROBLES\r
@@ -53228,12 +53444,6 @@ E09971     (base 16)           Samsung Electronics Co.,Ltd
                                Hsinchu    \r
                                TW\r
 \r
-F8-8E-85   (hex)               Comtrend Corporation\r
-F88E85     (base 16)           Comtrend Corporation\r
-                               3F-1, NO. 10, LANE 609, \r
-                               NEW TAIPEI CITY     24159\r
-                               TW\r
-\r
 30-0D-43   (hex)               Microsoft Mobile Oy\r
 300D43     (base 16)           Microsoft Mobile Oy\r
                                Keilalahdentie 2-4\r
@@ -54644,12 +54854,6 @@ B0F893     (base 16)           Shanghai MXCHIP Information Technology Co., Ltd.
                                Shanghai    200333\r
                                CN\r
 \r
-00-C0-17   (hex)               NetScout Systems, Inc.\r
-00C017     (base 16)           NetScout Systems, Inc.\r
-                               310 Littleton Road\r
-                               Westford  MA  01886\r
-                               US\r
-\r
 D4-9B-5C   (hex)               Chongqing Miedu Technology Co., Ltd.\r
 D49B5C     (base 16)           Chongqing Miedu Technology Co., Ltd.\r
                                7-602 No.118 DaPing Main Street Yuzhong District\r
@@ -57203,554 +57407,1964 @@ C43306     (base 16)               China Mobile Group Device Co.,Ltd.
                                Sunnyvale  CA  94089\r
                                US\r
 \r
-C0-D9-F7   (hex)               ShanDong Domor Intelligent S&T CO.,Ltd\r
-C0D9F7     (base 16)           ShanDong Domor Intelligent S&T CO.,Ltd\r
-                               Jining high-tech zone base of production,education & research\r
-                               Jining  Shandong  272000\r
+E0-46-E5   (hex)               Gosuncn Technology Group Co., Ltd.\r
+E046E5     (base 16)           Gosuncn Technology Group Co., Ltd.\r
+                               6F, 2819 KaiChuang Blvd., Science Town, Huangpu District\r
+                               Guangzhou City   Guangdong  510530\r
                                CN\r
 \r
-94-FB-29   (hex)               Zebra Technologies Inc.\r
-94FB29     (base 16)           Zebra Technologies Inc.\r
-                               ONE ZEBRA PLAZA\r
-                               HOLTSVILLE  NY  11742\r
-                               US\r
+30-13-89   (hex)               Siemens AG, Automations & Drives,\r
+301389     (base 16)           Siemens AG, Automations & Drives,\r
+                               Systems Engineering\r
+                               Fürth  Deutschlang  90766\r
+                               DE\r
 \r
-64-DB-A0   (hex)               Select Comfort\r
-64DBA0     (base 16)           Select Comfort\r
-                               9800 59th Ave N\r
-                               Minneapolis  MN  55442\r
+F4-DB-E6   (hex)               Cisco Systems, Inc\r
+F4DBE6     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
                                US\r
 \r
-58-00-E3   (hex)               Liteon Technology Corporation\r
-5800E3     (base 16)           Liteon Technology Corporation\r
-                               4F, 90, Chien 1 Road\r
-                               New Taipei City  Taiwan  23585\r
-                               TW\r
-\r
-64-77-7D   (hex)               Hitron Technologies. Inc\r
-64777D     (base 16)           Hitron Technologies. Inc\r
-                               No. 1-8, Lising 1st Rd. Hsinchu Science Park, Hsinchu, 300, Taiwan, R.O.C\r
-                               Hsin-chu  Taiwan  300\r
-                               TW\r
+DC-F4-01   (hex)               Dell Inc.\r
+DCF401     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
+                               US\r
 \r
-04-95-E6   (hex)               Tenda Technology Co.,Ltd.Dongguan branch\r
-0495E6     (base 16)           Tenda Technology Co.,Ltd.Dongguan branch\r
-                               Room 79,Yuanyi Road,Dalang Town,Dongguan Guangdong 523770\r
-                               Dongguan  Guangdong  523770\r
+F4-95-1B   (hex)               Hefei Radio Communication Technology Co., Ltd \r
+F4951B     (base 16)           Hefei Radio Communication Technology Co., Ltd \r
+                                No.108, YinXing Road, High-tech Development Zone \r
+                               Hefei  Anhui  230088\r
                                CN\r
 \r
-00-16-D3   (hex)               Wistron Corporation\r
-0016D3     (base 16)           Wistron Corporation\r
-                               21F, 88, Sec.1, Hsin Tai Wu Rd., Hsichih,\r
-                               Taipei Hsien    221\r
-                               TW\r
-\r
-00-1F-16   (hex)               Wistron Corporation\r
-001F16     (base 16)           Wistron Corporation\r
-                               21F, 88, Sec.1, Hsin Tai Wu Rd., Hsichih,\r
-                               Taipei Hsien    221\r
-                               TW\r
-\r
-4C-4E-03   (hex)               TCT mobile ltd\r
-4C4E03     (base 16)           TCT mobile ltd\r
-                               No.86 hechang 7th road, zhongkai, Hi-Tech District\r
-                               Hui Zhou  Guang Dong  516006\r
+D0-92-FA   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+D092FA     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
                                CN\r
 \r
-50-E6-66   (hex)               Shenzhen Techtion Electronics Co., Ltd.\r
-50E666     (base 16)           Shenzhen Techtion Electronics Co., Ltd.\r
-                               Floor 2, C2 Building, Huafeng Industrial Park, Hangcheng Avenue, Gushu, Xixiang, Baoan\r
-                               Shenzhen  Guangdong  518102\r
+E8-5A-D1   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+E85AD1     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
                                CN\r
 \r
-68-31-FE   (hex)               Teladin Co.,Ltd.\r
-6831FE     (base 16)           Teladin Co.,Ltd.\r
-                               Digital-ro 33 gil, Guro-gu\r
-                               Seoul    08377\r
-                               KR\r
+BC-75-96   (hex)               Beijing Broadwit Technology Co., Ltd.\r
+BC7596     (base 16)           Beijing Broadwit Technology Co., Ltd.\r
+                               Beijing Changping District Beijing International Information Industry Base Jizhida Building 3rd Floor Southeast\r
+                               Beijing  Beijing  10000\r
+                               CN\r
 \r
-D4-B1-69   (hex)               Le Shi Zhi Xin Electronic Technology (Tianjin) Limited\r
-D4B169     (base 16)           Le Shi Zhi Xin Electronic Technology (Tianjin) Limited\r
-                               ,Le Shi Building, No.105 Yaojiayuan Road,Chaoyang District,Beijing,China\r
-                               beijing  beijing  100025\r
+CC-72-86   (hex)               Xi'an Fengyu Information Technology Co., Ltd.\r
+CC7286     (base 16)           Xi'an Fengyu Information Technology Co., Ltd.\r
+                               5F, Block A, STRC, No.10, Zhangba 5th Road, Yanta\r
+                               Xi'an  Shaanxi  710077\r
                                CN\r
 \r
-0C-3C-CD   (hex)               Universal Global Scientific Industrial Co., Ltd.\r
-0C3CCD     (base 16)           Universal Global Scientific Industrial Co., Ltd.\r
-                               141, Lane 351, Taiping Road, Sec.1,Tsao Tuen\r
-                               Nan-Tou  Taiwan  54261\r
+04-92-26   (hex)               ASUSTek COMPUTER INC.\r
+049226     (base 16)           ASUSTek COMPUTER INC.\r
+                               15,Li-Te Rd., Peitou, Taipei 112, Taiwan\r
+                               Taipei  Taiwan  112\r
                                TW\r
 \r
-B0-40-89   (hex)               Senient Systems LTD\r
-B04089     (base 16)           Senient Systems LTD\r
-                               152 Morrison St\r
-                               Edinburgh  Other (Non US)  EH3 8EB\r
-                               GB\r
+84-32-6F   (hex)               GUANGZHOU AVA ELECTRONICS TECHNOLOGY CO.,LTD \r
+84326F     (base 16)           GUANGZHOU AVA ELECTRONICS TECHNOLOGY CO.,LTD \r
+                               Science town luogang district guangzhou city branch bead road 232 profit people park 301, building 2\r
+                               guangzhou   guangdong  510000\r
+                               CN\r
 \r
-00-24-45   (hex)               Adtran Inc\r
-002445     (base 16)           Adtran Inc\r
-                               901 Explorer Blvd.\r
-                               Huntsville  AL  35806-2807\r
+00-B8-B3   (hex)               Cisco Systems, Inc\r
+00B8B3     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
                                US\r
 \r
-68-9F-F0   (hex)               zte corporation\r
-689FF0     (base 16)           zte corporation\r
-                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
-                               shenzhen  guangdong  518057\r
+A8-BC-9C   (hex)               Cloud Light Technology Limited\r
+A8BC9C     (base 16)           Cloud Light Technology Limited\r
+                               3/F, 6 Science Park East Avenue Hong Kong Science Park Shatin, N.T., Hong Kong\r
+                               Hong Kong    00000\r
+                               HK\r
+\r
+0C-B4-A4   (hex)               Xintai Automobile Intelligent Network Technology\r
+0CB4A4     (base 16)           Xintai Automobile Intelligent Network Technology\r
+                               Room3703E Changfu Jinmao Building,Shihua Road\r
+                               Futian Duty Free Zone,Fubao Street,Futian District  Shenzhen City  518000\r
                                CN\r
 \r
-7C-C6-C4   (hex)               Kolff Computer Supplies b.v.\r
-7CC6C4     (base 16)           Kolff Computer Supplies b.v.\r
-                               Kuipershaven 22\r
-                               Dordrecht  Zuid-Holland  3311 AL\r
-                               NL\r
+2C-CC-44   (hex)               Sony Interactive Entertainment Inc.\r
+2CCC44     (base 16)           Sony Interactive Entertainment Inc.\r
+                               1-7-1 Konan\r
+                               Minato-ku  Tokyo  108-0075\r
+                               JP\r
 \r
-F0-6E-32   (hex)               MICROTEL INNOVATION S.R.L.\r
-F06E32     (base 16)           MICROTEL INNOVATION S.R.L.\r
-                               Via Armentera 8\r
-                               BORGO VALSUGANA  TN  38051\r
-                               IT\r
+FC-AA-B6   (hex)               Samsung Electronics Co.,Ltd\r
+FCAAB6     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
 \r
-00-E0-22   (hex)               Analog Devices, Inc.\r
-00E022     (base 16)           Analog Devices, Inc.\r
-                               Three Technology Way\r
-                               Norwood   MA  02062-2666\r
-                               US\r
+C0-BD-C8   (hex)               Samsung Electronics Co.,Ltd\r
+C0BDC8     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
 \r
-7C-67-A2   (hex)               Intel Corporate\r
-7C67A2     (base 16)           Intel Corporate\r
-                               Lot 8, Jalan Hi-Tech 2/3\r
-                               Kulim  Kedah  09000\r
-                               MY\r
+A8-87-B3   (hex)               Samsung Electronics Co.,Ltd\r
+A887B3     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
 \r
-00-03-02   (hex)               Charles Industries, Ltd.\r
-000302     (base 16)           Charles Industries, Ltd.\r
-                               5600 Apollo Drive\r
-                               Rolling Meadows  IL  60008\r
+00-D0-2D   (hex)               Resideo\r
+00D02D     (base 16)           Resideo\r
+                               2 Corporate Center Dr.\r
+                               Melville  NY  11747\r
                                US\r
 \r
-08-96-AD   (hex)               Cisco Systems, Inc\r
-0896AD     (base 16)           Cisco Systems, Inc\r
-                               80 West Tasman Drive\r
-                               San Jose  CA  94568\r
-                               US\r
+10-12-B4   (hex)               SICHUAN TIANYI COMHEART TELECOM CO.,LTD\r
+1012B4     (base 16)           SICHUAN TIANYI COMHEART TELECOM CO.,LTD\r
+                               NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, \r
+                               CHENGDU  SICHUAN  611330\r
+                               CN\r
 \r
-8C-F5-A3   (hex)               SAMSUNG ELECTRO-MECHANICS(THAILAND)\r
-8CF5A3     (base 16)           SAMSUNG ELECTRO-MECHANICS(THAILAND)\r
-                               93Moo5T. Bangsamak SEMTHAI, WELLGROW INDUSTRIAL ESTATE\r
-                               Bangpakong  Chachoengsao  24180\r
-                               TH\r
+3C-9B-D6   (hex)               Vizio, Inc\r
+3C9BD6     (base 16)           Vizio, Inc\r
+                               39 Tesla\r
+                               Irvine  CA  92618\r
+                               US\r
 \r
-B8-EA-AA   (hex)               ICG NETWORKS CO.,ltd\r
-B8EAAA     (base 16)           ICG NETWORKS CO.,ltd\r
-                               Room 2030,Block B,Yamei Park,Haidian District\r
-                               BEIJING    100010\r
+74-23-44   (hex)               Xiaomi Communications Co Ltd\r
+742344     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-B8-F8-83   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
-B8F883     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
-                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
-                               Shenzhen  Guangdong  518057\r
+D8-32-E3   (hex)               Xiaomi Communications Co Ltd\r
+D832E3     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-DC-FE-18   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
-DCFE18     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
-                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
-                               Shenzhen  Guangdong  518057\r
+E0-62-67   (hex)               Xiaomi Communications Co Ltd\r
+E06267     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-AC-60-B6   (hex)               Ericsson AB\r
-AC60B6     (base 16)           Ericsson AB\r
-                               Torshamnsgatan 36\r
-                               Stockholm    SE-164 80\r
-                               SE\r
-\r
-3C-19-7D   (hex)               Ericsson AB\r
-3C197D     (base 16)           Ericsson AB\r
-                               Torshamnsgatan 36\r
-                               Stockholm    SE-164 80\r
-                               SE\r
-\r
-74-C9-9A   (hex)               Ericsson AB\r
-74C99A     (base 16)           Ericsson AB\r
-                               Torshamnsgatan 36\r
-                               Stockholm    SE-164 80\r
-                               SE\r
-\r
-00-0F-4F   (hex)               PCS Systemtechnik GmbH\r
-000F4F     (base 16)           PCS Systemtechnik GmbH\r
-                               66 Hillside Rd\r
-                               Auckland    1310\r
-                               NZ\r
-\r
-7C-5A-1C   (hex)               Sophos Ltd\r
-7C5A1C     (base 16)           Sophos Ltd\r
-                               The Pentagon\r
-                               Abingdon  Oxfordshire  OX14 3YP\r
-                               GB\r
-\r
-00-E4-00   (hex)               Sichuan Changhong Electric Ltd.\r
-00E400     (base 16)           Sichuan Changhong Electric Ltd.\r
-                               No.35,East MianXin Road,MianYang,Sichaun,China.\r
-                               MianYang  SiChuan  PRC 621000\r
+48-2C-A0   (hex)               Xiaomi Communications Co Ltd\r
+482CA0     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-00-11-7E   (hex)               Midmark Corp\r
-00117E     (base 16)           Midmark Corp\r
-                               675 Heathrow Drive\r
-                               Lincolnshire  IL  60089\r
-                               US\r
-\r
-10-5A-F7   (hex)               ADB Italia \r
-105AF7     (base 16)           ADB Italia \r
-                               Viale Sarca 222\r
-                               Milan  Italy  20126\r
-                               IT\r
+18-01-F1   (hex)               Xiaomi Communications Co Ltd\r
+1801F1     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
 \r
-70-3A-CB   (hex)               Google, Inc.\r
-703ACB     (base 16)           Google, Inc.\r
-                               1600 Amphitheatre Parkway\r
-                               Mountain View  CA  94043\r
-                               US\r
+70-BB-E9   (hex)               Xiaomi Communications Co Ltd\r
+70BBE9     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
 \r
-D4-81-D7   (hex)               Dell Inc.\r
-D481D7     (base 16)           Dell Inc.\r
-                               One Dell Way\r
-                               Round Rock  TX  78682\r
-                               US\r
+F0-B4-29   (hex)               Xiaomi Communications Co Ltd\r
+F0B429     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
 \r
-2C-55-D3   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-2C55D3     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
+0C-98-38   (hex)               Xiaomi Communications Co Ltd\r
+0C9838     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-F4-4C-7F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-F44C7F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
+0C-1D-AF   (hex)               Xiaomi Communications Co Ltd\r
+0C1DAF     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-14-30-04   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-143004     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
+28-E3-1F   (hex)               Xiaomi Communications Co Ltd\r
+28E31F     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-7C-46-85   (hex)               Motorola (Wuhan) Mobility Technologies Communication Co., Ltd.\r
-7C4685     (base 16)           Motorola (Wuhan) Mobility Technologies Communication Co., Ltd.\r
-                               No.19, Gaoxin 4th Road, Wuhan East Lake High-tech Zone, Wuhan\r
-                               Wuhan  Hubei  430000\r
+14-F6-5A   (hex)               Xiaomi Communications Co Ltd\r
+14F65A     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-E0-51-63   (hex)               Arcadyan Corporation\r
-E05163     (base 16)           Arcadyan Corporation\r
-                               No.8, Sec.2, Guangfu Rd.\r
-                               Hsinchu City  Hsinchu  30071\r
-                               TW\r
+B4-F9-49   (hex)               optilink networks pvt ltd\r
+B4F949     (base 16)           optilink networks pvt ltd\r
+                               501/502, sanjona complex, hemu kalani marg, chembur\r
+                               mumbai  maharashtra  400071\r
+                               IN\r
 \r
-00-A0-6F   (hex)               Color Sentinel Systems, LLC\r
-00A06F     (base 16)           Color Sentinel Systems, LLC\r
-                               97 Ridgeland Rd, Suite #2\r
-                               ROCHESTER  NY  14623\r
+3C-5C-C4   (hex)               Amazon Technologies Inc.\r
+3C5CC4     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
                                US\r
 \r
-0C-5F-35   (hex)               Niagara Video Corporation\r
-0C5F35     (base 16)           Niagara Video Corporation\r
-                               5627 Stoneridge Drive, Suite 316\r
-                               Pleasanton  CA  94588\r
+88-71-B1   (hex)               ARRIS Group, Inc.\r
+8871B1     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-7C-38-66   (hex)               Texas Instruments\r
-7C3866     (base 16)           Texas Instruments\r
-                               12500 TI Blvd\r
-                               Dallas  TX  75243\r
+F0-AF-85   (hex)               ARRIS Group, Inc.\r
+F0AF85     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-50-F1-4A   (hex)               Texas Instruments\r
-50F14A     (base 16)           Texas Instruments\r
-                               12500 TI Blvd\r
-                               Dallas  TX  75243\r
+B8-9A-9A   (hex)               Xin Shi Jia Technology (Beijing) Co.,Ltd\r
+B89A9A     (base 16)           Xin Shi Jia Technology (Beijing) Co.,Ltd\r
+                               Room 1002, A Tower, Zhongguancun E World Wealth Center, No.11, Zhongguancun Street, Haidian District, Beijing City\r
+                               Beijing  Beijing  100190\r
+                               CN\r
+\r
+D4-C9-4B   (hex)               Motorola Mobility LLC, a Lenovo Company\r
+D4C94B     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
+                               222 West Merchandise Mart Plaza\r
+                               Chicago  IL  60654\r
                                US\r
 \r
-9C-1D-58   (hex)               Texas Instruments\r
-9C1D58     (base 16)           Texas Instruments\r
-                               12500 TI Blvd\r
-                               Dallas  TX  75243\r
+C0-22-50   (hex)               Koss Corporation\r
+C02250     (base 16)           Koss Corporation\r
+                               4129 N. Port Washington Ave.\r
+                               Milwaukee  WI  53212\r
                                US\r
 \r
-50-0F-F5   (hex)               Tenda Technology Co.,Ltd.Dongguan branch\r
-500FF5     (base 16)           Tenda Technology Co.,Ltd.Dongguan branch\r
-                               Room 79,Yuanyi Road,Dalang Town,Dongguan Guangdong 523770\r
-                               Dongguan  Guangdong  523770\r
-                               CN\r
+2C-1C-F6   (hex)               Alien Green LLC\r
+2C1CF6     (base 16)           Alien Green LLC\r
+                               A. Kazbegi Ave., No24g, apt 227\r
+                               Tbilisi  Tbilisi  0160\r
+                               GE\r
 \r
-F0-27-2D   (hex)               Amazon Technologies Inc.\r
-F0272D     (base 16)           Amazon Technologies Inc.\r
-                               P.O Box 8102\r
-                               Reno  NV  89507\r
-                               US\r
+E4-38-8C   (hex)               Digital Products Limited\r
+E4388C     (base 16)           Digital Products Limited\r
+                               53 Clark Road\r
+                               Rothesay  New Brunswick  E2E 2K9\r
+                               CA\r
 \r
-74-C2-46   (hex)               Amazon Technologies Inc.\r
-74C246     (base 16)           Amazon Technologies Inc.\r
-                               P.O Box 8102\r
-                               Reno  NV  89507\r
+18-1E-95   (hex)               AuVerte\r
+181E95     (base 16)           AuVerte\r
+                               14 Riverview Road\r
+                               Niantic  CT  06357\r
                                US\r
 \r
-F4-C4-D6   (hex)               Shenzhen Xinfa Electronic Co.,ltd\r
-F4C4D6     (base 16)           Shenzhen Xinfa Electronic Co.,ltd\r
-                               No 57, Baoli Road, Buji Town\r
-                               Longgang District  Shenzhen, Guangdong   518112\r
-                               CN\r
+18-4B-DF   (hex)               Caavo Inc\r
+184BDF     (base 16)           Caavo Inc\r
+                               1525 McCarthy Blvd., #1182\r
+                               Milpitas    95035\r
+                               US\r
 \r
-08-B2-58   (hex)               Juniper Networks\r
-08B258     (base 16)           Juniper Networks\r
-                               1133 Innovation Way\r
-                               Sunnyvale  CA  94089\r
+1C-54-9E   (hex)               Universal Electronics, Inc.\r
+1C549E     (base 16)           Universal Electronics, Inc.\r
+                               201 E. Sandpointe Ave\r
+                               Santa Ana  CA  92707\r
                                US\r
 \r
-C0-3D-46   (hex)               Shanghai Sango Network Technology Co.,Ltd\r
-C03D46     (base 16)           Shanghai Sango Network Technology Co.,Ltd\r
-                               No 666 Zhangheng Road\r
-                               Pudong  Shanghai  210203\r
+70-3A-51   (hex)               Xiaomi Communications Co Ltd\r
+703A51     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-E8-9F-EC   (hex)               CHENGDU KT ELECTRONIC HI-TECH CO.,LTD\r
-E89FEC     (base 16)           CHENGDU KT ELECTRONIC HI-TECH CO.,LTD\r
-                               No.9, 3rd Wuke Road, Wuhou District\r
-                               Chengdu  Sichuan Province  610045\r
+A0-20-A6   (hex)               Espressif Inc.\r
+A020A6     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
                                CN\r
 \r
-BC-A0-42   (hex)               SHANGHAI FLYCO ELECTRICAL APPLIANCE CO.,LTD\r
-BCA042     (base 16)           SHANGHAI FLYCO ELECTRICAL APPLIANCE CO.,LTD\r
-                               No.555,Guang Fu Lin east Road,Songjiang District\r
-                               Shanghai  Shanghai  201613\r
+84-F3-EB   (hex)               Espressif Inc.\r
+84F3EB     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
                                CN\r
 \r
-D4-7D-FC   (hex)               TECNO MOBILE LIMITED\r
-D47DFC     (base 16)           TECNO MOBILE LIMITED\r
-                               ROOMS 05-15, 13A/F., SOUTH TOWER, WORLD FINANCE CENTRE, HARBOUR CITY, 17 CANTON ROAD, TSIM SHA TSUI, KOWLOON, HONG KONG\r
-                               Hong Kong  Hong Kong  999077\r
-                               HK\r
-\r
-44-37-08   (hex)               MRV Comunications\r
-443708     (base 16)           MRV Comunications\r
-                               Hayetzira\r
-                               Yokneam    614\r
-                               IL\r
+84-0D-8E   (hex)               Espressif Inc.\r
+840D8E     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
 \r
-14-56-8E   (hex)               Samsung Electronics Co.,Ltd\r
-14568E     (base 16)           Samsung Electronics Co.,Ltd\r
-                               #94-1, Imsoo-Dong\r
-                               Gumi  Gyeongbuk  730-350\r
-                               KR\r
+54-9B-72   (hex)               Ericsson AB\r
+549B72     (base 16)           Ericsson AB\r
+                               Torshamnsgatan 36\r
+                               Stockholm    SE-164 80\r
+                               SE\r
 \r
-68-37-E9   (hex)               Amazon Technologies Inc.\r
-6837E9     (base 16)           Amazon Technologies Inc.\r
-                               P.O Box 8102\r
-                               Reno  NV  89507\r
+DC-08-0F   (hex)               Apple, Inc.\r
+DC080F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-80-58-F8   (hex)               Motorola Mobility LLC, a Lenovo Company\r
-8058F8     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
-                               222 West Merchandise Mart Plaza\r
-                               Chicago  IL  60654\r
+F8-2D-7C   (hex)               Apple, Inc.\r
+F82D7C     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-F0-D7-AA   (hex)               Motorola Mobility LLC, a Lenovo Company\r
-F0D7AA     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
-                               222 West Merchandise Mart Plaza\r
-                               Chicago  IL  60654\r
+9C-64-8B   (hex)               Apple, Inc.\r
+9C648B     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-28-FF-3E   (hex)               zte corporation\r
-28FF3E     (base 16)           zte corporation\r
-                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
-                               shenzhen  guangdong  518057\r
-                               CN\r
+C0-3D-D9   (hex)               MitraStar Technology Corp.\r
+C03DD9     (base 16)           MitraStar Technology Corp.\r
+                               No. 6, Innovation Road II,\r
+                               Hsinchu    300\r
+                               TW\r
 \r
-D0-49-8B   (hex)               ZOOM SERVER\r
-D0498B     (base 16)           ZOOM SERVER\r
-                               North keyuan Road\r
-                               Shenzhen    518057\r
+A0-A3-B8   (hex)               WISCLOUD\r
+A0A3B8     (base 16)           WISCLOUD\r
+                               Tech Park Xia Sha\r
+                               Hangzhou  Zhejiang  310000\r
                                CN\r
 \r
-C4-9D-ED   (hex)               Microsoft Corporation\r
-C49DED     (base 16)           Microsoft Corporation\r
-                               One Microsoft Way\r
-                               REDMOND  WA  98052\r
-                               US\r
-\r
-98-A4-0E   (hex)               Snap, Inc.\r
-98A40E     (base 16)           Snap, Inc.\r
-                               64 Market Street\r
-                               Venice  CA  90291\r
-                               US\r
-\r
-2C-5A-0F   (hex)               Cisco Systems, Inc\r
-2C5A0F     (base 16)           Cisco Systems, Inc\r
-                               80 West Tasman Drive\r
-                               San Jose  CA  94568\r
+14-D0-0D   (hex)               Apple, Inc.\r
+14D00D     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-AC-74-09   (hex)               Hangzhou H3C Technologies Co., Limited\r
-AC7409     (base 16)           Hangzhou H3C Technologies Co., Limited\r
+74-85-C4   (hex)               New H3C Technologies Co., Ltd\r
+7485C4     (base 16)           New H3C Technologies Co., Ltd\r
                                466 Changhe Road, Binjiang District\r
-                               Hangzhou  Zhejiang, P.R.China  310052\r
+                               Hangzhou  Zhejiang  310052\r
                                CN\r
 \r
-E0-37-BF   (hex)               Wistron Neweb Corporation\r
-E037BF     (base 16)           Wistron Neweb Corporation\r
-                               No.20,Park Avenue II,Hsinchu Science Park\r
-                               Hsin-Chu  R.O.C.  308\r
-                               TW\r
+34-93-42   (hex)               TTE Corporation\r
+349342     (base 16)           TTE Corporation\r
+                               7/F, Building 22E 22 Science Park East Avenue Hong Kong Science Park Shatin, N.T.\r
+                               Hong Kong    999077\r
+                               HK\r
 \r
-4C-81-20   (hex)               Taicang T&W Electronics\r
-4C8120     (base 16)           Taicang T&W Electronics\r
-                               89# Jiang Nan RD\r
-                               Suzhou  Jiangsu  215412\r
-                               CN\r
+48-E6-95   (hex)               Insigma Inc\r
+48E695     (base 16)           Insigma Inc\r
+                               43490, Yukon Drive, Suite 102\r
+                               Ashburn  VA  20147\r
+                               US\r
 \r
-E8-E7-32   (hex)               Alcatel-Lucent Enterprise\r
-E8E732     (base 16)           Alcatel-Lucent Enterprise\r
-                               26801 West Agoura Road\r
-                               Calabasas  CA  91301\r
+B4-79-C8   (hex)               Ruckus Wireless\r
+B479C8     (base 16)           Ruckus Wireless\r
+                               350 West Java Drive\r
+                               Sunnyvale  CA  94089\r
                                US\r
 \r
-00-11-8B   (hex)               Alcatel-Lucent Enterprise\r
-00118B     (base 16)           Alcatel-Lucent Enterprise\r
-                               26801 West Agoura Road\r
-                               Calabasas  CA  91301\r
+F8-0D-F1   (hex)               Sontex SA\r
+F80DF1     (base 16)           Sontex SA\r
+                               rue de la gare\r
+                               sonceboz  Bern  2605\r
+                               CH\r
+\r
+9C-8C-D8   (hex)               Hewlett Packard Enterprise\r
+9C8CD8     (base 16)           Hewlett Packard Enterprise\r
+                               8000 Foothills Blvd.\r
+                               Roseville  CA  95747\r
                                US\r
 \r
-00-E0-B1   (hex)               Alcatel-Lucent Enterprise\r
-00E0B1     (base 16)           Alcatel-Lucent Enterprise\r
-                               26801 West Agoura Road\r
-                               Calabasas  CA  91301\r
+88-D2-11   (hex)               Eko Devices, Inc.\r
+88D211     (base 16)           Eko Devices, Inc.\r
+                               2600 10th St Ste 260\r
+                               Berkeley  CA  94710-2597\r
                                US\r
 \r
-68-54-ED   (hex)               Alcatel-Lucent\r
-6854ED     (base 16)           Alcatel-Lucent\r
-                               777 E. Middlefield Rd\r
+1C-F2-9A   (hex)               Google, Inc.\r
+1CF29A     (base 16)           Google, Inc.\r
+                               1600 Amphitheatre Parkway\r
                                Mountain View  CA  94043\r
                                US\r
 \r
-E8-DE-8E   (hex)               Integrated Device Technology (Malaysia) Sdn. Bhd.\r
-E8DE8E     (base 16)           Integrated Device Technology (Malaysia) Sdn. Bhd.\r
-                               Phase 3, Bayan Lepas FIZ\r
-                               Bayan Lepas  Penang  11900\r
-                               MY\r
-\r
-40-C8-CB   (hex)               AM Telecom co., Ltd.\r
-40C8CB     (base 16)           AM Telecom co., Ltd.\r
-                               #608,YatapLeaders B/D, Jangmi-ro 42, Bundang-gu\r
-                               Seongnam-si  Gyeonggi-do  463-828\r
+94-54-DF   (hex)               YST CORP.\r
+9454DF     (base 16)           YST CORP.\r
+                               A-1407, 767, Sinsu-ro, Suji-gu,\r
+                               Yongin-si  Gyeonggi-do  16827\r
                                KR\r
 \r
-14-A0-F8   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-14A0F8     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+74-F7-37   (hex)               KCE\r
+74F737     (base 16)           KCE\r
+                               5F KCE B/D,34,Annam-ro 369beon-gil,Bupyoung-gu\r
+                               Incheon    21312\r
+                               KR\r
 \r
-28-B4-48   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-28B448     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+78-0E-D1   (hex)               TRUMPF Werkzeugmaschinen GmbH+Co.KG\r
+780ED1     (base 16)           TRUMPF Werkzeugmaschinen GmbH+Co.KG\r
+                               Johann-Maus-Straße 2\r
+                               Ditzingen    71254\r
+                               DE\r
 \r
-E4-42-A6   (hex)               Intel Corporate\r
-E442A6     (base 16)           Intel Corporate\r
-                               Lot 8, Jalan Hi-Tech 2/3\r
-                               Kulim  Kedah  09000\r
-                               MY\r
+A8-9C-A4   (hex)               Furrion Limited\r
+A89CA4     (base 16)           Furrion Limited\r
+                               Units 503C & 505-508, Level 5, Core D, Cyberport 3, 100 Cyberport Road\r
+                               Hong Kong    00000\r
+                               HK\r
 \r
-60-45-CB   (hex)               ASUSTek COMPUTER INC.\r
-6045CB     (base 16)           ASUSTek COMPUTER INC.\r
-                               15,Li-Te Rd., Peitou, Taipei 112, Taiwan\r
-                               Taipei  Taiwan  112\r
+7C-DB-98   (hex)               ASKEY COMPUTER CORP\r
+7CDB98     (base 16)           ASKEY COMPUTER CORP\r
+                               10F,No.119,JIANKANG RD,ZHONGHE DIST\r
+                               NEW TAIPEI  TAIWAN  23585\r
                                TW\r
 \r
-84-AF-EC   (hex)               BUFFALO.INC\r
-84AFEC     (base 16)           BUFFALO.INC\r
-                               AKAMONDORI Bld.,30-20,Ohsu 3-chome,Naka-ku\r
-                               Nagoya  Aichi Pref.  460-8315\r
-                               JP\r
+6C-DF-FB   (hex)               IEEE Registration Authority\r
+6CDFFB     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
 \r
-AC-20-2E   (hex)               Hitron Technologies. Inc\r
-AC202E     (base 16)           Hitron Technologies. Inc\r
-                               No. 1-8, Lising 1st Rd. Hsinchu Science Park, Hsinchu, 300, Taiwan, R.O.C\r
-                               Hsin-chu  Taiwan  300\r
-                               TW\r
+DC-21-B9   (hex)               Sentec Co.Ltd\r
+DC21B9     (base 16)           Sentec Co.Ltd\r
+                               10, Baekseokgongdan 1-ro, Seobuk-gu\r
+                                Cheonan-si  Chungcheongnam-do  31094\r
+                               KR\r
 \r
-48-A7-4E   (hex)               zte corporation\r
-48A74E     (base 16)           zte corporation\r
-                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
-                               shenzhen  guangdong  518057\r
-                               CN\r
+E4-D3-AA   (hex)               FUJITSU CONNECTED TECHNOLOGIES LIMITED\r
+E4D3AA     (base 16)           FUJITSU CONNECTED TECHNOLOGIES LIMITED\r
+                               4-1-1, Kamikodanaka, Nakahara-ku\r
+                               Kawasaki  Kanagawa  2118588\r
+                               JP\r
 \r
-3C-52-82   (hex)               Hewlett Packard\r
-3C5282     (base 16)           Hewlett Packard\r
-                               11445 Compaq Center Drive\r
-                               Houston  TX  77070\r
-                               US\r
+B0-02-47   (hex)               AMPAK Technology, Inc.\r
+B00247     (base 16)           AMPAK Technology, Inc.\r
+                               3F.,No.15-1 Zhonghua Road,Hsinchu Industrial Park, Hukou,Hsinchu\r
+                               Hsinchu  Taiwan ROC.  30352\r
+                               TW\r
 \r
-B0-AA-36   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-B0AA36     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD\r
-                               DONGGUAN  GUANGDONG  523860\r
-                               CN\r
+BC-E7-96   (hex)               Wireless CCTV Ltd\r
+BCE796     (base 16)           Wireless CCTV Ltd\r
+                               charles Babbage house\r
+                               Rochdale  Greater Manchester  ol164nw\r
+                               GB\r
 \r
-2C-5B-B8   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-2C5BB8     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,WUSHA,CHANG'AN,DONGGUAN,GUANGDONG,CHINA\r
-                               DONGGUAN  GUANGDONG  523860\r
+70-5E-55   (hex)               Realme Chongqing MobileTelecommunications Corp Ltd\r
+705E55     (base 16)           Realme Chongqing MobileTelecommunications Corp Ltd\r
+                               No.24 Nichang Boulevard, Huixing Block, Yubei District, Chongqing.\r
+                               Chongqing  China  401120\r
                                CN\r
 \r
-1C-48-CE   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-1C48CE     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+D4-67-D3   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+D467D3     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
                                NO.18 HAIBIN ROAD,\r
                                DONG GUAN  GUANG DONG  523860\r
                                CN\r
 \r
-00-40-66   (hex)               APRESIA Systems Ltd\r
-004066     (base 16)           APRESIA Systems Ltd\r
-                                Tsukuba Network Technical Center, Tsukuba Network\r
-                               Tsuchiura-shi  Ibaraki-ken  300-0026\r
-                               JP\r
-\r
-9C-AC-6D   (hex)               Universal Electronics, Inc.\r
-9CAC6D     (base 16)           Universal Electronics, Inc.\r
-                               201 E. Sandpointe Ave\r
-                               Santa Ana  CA  92707\r
-                               US\r
-\r
-B0-3D-96   (hex)               Vision Valley FZ LLC\r
-B03D96     (base 16)           Vision Valley FZ LLC\r
-                               Dubai Internet City\r
-                               Dubai  Dubai  500294\r
-                               AE\r
+48-E3-C3   (hex)               JENOPTIK Advanced Systems GmbH\r
+48E3C3     (base 16)           JENOPTIK Advanced Systems GmbH\r
+                               Feldstrasse 155\r
+                               Wedel  Schleswig-Holstein  22880\r
+                               DE\r
 \r
-B0-26-28   (hex)               Broadcom Limited\r
-B02628     (base 16)           Broadcom Limited\r
-                               5300 California Ave.\r
-                               irvine  CA  92617\r
+84-EB-3E   (hex)               Vivint Smart Home\r
+84EB3E     (base 16)           Vivint Smart Home\r
+                               4931 N. 300 W.\r
+                               Provo  UT  84604\r
                                US\r
 \r
-E8-13-63   (hex)               Comstock RD, Inc.\r
-E81363     (base 16)           Comstock RD, Inc.\r
-                               4415 Mason St\r
-                               Ashton  ID  83406\r
+CC-70-ED   (hex)               Cisco Systems, Inc\r
+CC70ED     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
                                US\r
 \r
-44-AA-50   (hex)               Juniper Networks\r
-44AA50     (base 16)           Juniper Networks\r
-                               1133 Innovation Way\r
-                               Sunnyvale  CA  94089\r
-                               US\r
+D4-3D-39   (hex)               FCI. Inc\r
+D43D39     (base 16)           FCI. Inc\r
+                               B-7F, SiliconPark, 35, Pangyo-ro 255beon-gil, Bundang-gu\r
+                               Seongnam-si  Gyeonggi-do  13486\r
+                               KR\r
 \r
-00-80-E7   (hex)               Leonardo Tactical Systems.\r
-0080E7     (base 16)           Leonardo Tactical Systems.\r
+4C-96-2D   (hex)               Fresh AB\r
+4C962D     (base 16)           Fresh AB\r
+                               Gransholmsvägen 136\r
+                               Gemla    35599\r
+                               SE\r
+\r
+AC-7A-4D   (hex)               ALPS ELECTRIC CO., LTD.\r
+AC7A4D     (base 16)           ALPS ELECTRIC CO., LTD.\r
+                               6-1\r
+                               KAKUDA-CITY  MIYAGI-PREF  981-1595\r
+                               JP\r
+\r
+58-C6-F0   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+58C6F0     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+64-9D-99   (hex)               FS COM INC\r
+649D99     (base 16)           FS COM INC\r
+                               380 Centerpoint Blvd New Castle\r
+                               New Castle  DE  19720\r
+                               US\r
+\r
+00-19-3B   (hex)               LigoWave\r
+00193B     (base 16)           LigoWave\r
+                               138 Mountain Brook Drive\r
+                               Canton  GA  30115\r
+                               US\r
+\r
+FC-62-B9   (hex)               ALPS ELECTRIC CO., LTD.\r
+FC62B9     (base 16)           ALPS ELECTRIC CO., LTD.\r
+                               6-1\r
+                               kakuda-city  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+00-19-C1   (hex)               ALPS ELECTRIC CO., LTD.\r
+0019C1     (base 16)           ALPS ELECTRIC CO., LTD.\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+00-1E-3D   (hex)               ALPS ELECTRIC CO., LTD.\r
+001E3D     (base 16)           ALPS ELECTRIC CO., LTD.\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+00-23-06   (hex)               ALPS ELECTRIC CO., LTD.\r
+002306     (base 16)           ALPS ELECTRIC CO., LTD.\r
+                               1-2-1, Okinouchi,\r
+                               Soma-city,  Fukushima-pref.,  976-8501\r
+                               JP\r
+\r
+28-A1-83   (hex)               ALPS ELECTRIC CO., LTD.\r
+28A183     (base 16)           ALPS ELECTRIC CO., LTD.\r
+                               6-1\r
+                               Kakuda  Miyagi-Pref  981-1595\r
+                               JP\r
+\r
+88-4A-18   (hex)               Opulinks\r
+884A18     (base 16)           Opulinks\r
+                               F 28, No.328, Huashan Rd\r
+                               Shanghai    200040\r
+                               CN\r
+\r
+00-0B-5D   (hex)               FUJITSU LIMITED\r
+000B5D     (base 16)           FUJITSU LIMITED\r
+                               403, Kosugi-cho 1-chome, Nakahara-ku\r
+                               Kawasaki  Kanagawa  211-0063\r
+                               JP\r
+\r
+14-4E-2A   (hex)               Ciena Corporation\r
+144E2A     (base 16)           Ciena Corporation\r
+                               7035 Ridge Road\r
+                               Hanover  MD  21076\r
+                               US\r
+\r
+D4-C9-3C   (hex)               Cisco Systems, Inc\r
+D4C93C     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+88-6F-D4   (hex)               Dell Inc.\r
+886FD4     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
+                               US\r
+\r
+50-2B-98   (hex)               Es-tech International\r
+502B98     (base 16)           Es-tech International\r
+                               228-70, Saneop-ro 155beon-gil, Gwonseon-gu, Suwon-si, Gyeonggi-do, Korea\r
+                               Suwon    16648\r
+                               KR\r
+\r
+A0-F9-B7   (hex)               Ademco Smart Homes Technology(Tianjin)Co.,Ltd.\r
+A0F9B7     (base 16)           Ademco Smart Homes Technology(Tianjin)Co.,Ltd.\r
+                               No.156 Nanhai Road,TEDA, Jinbin Development Park , 21st Factory Building\r
+                               Tianjin  Tianjin  300457\r
+                               CN\r
+\r
+48-F1-7F   (hex)               Intel Corporate\r
+48F17F     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+10-9C-70   (hex)               Prusa Research s.r.o.\r
+109C70     (base 16)           Prusa Research s.r.o.\r
+                               Partyzanska 188/7a\r
+                               Prague    17000\r
+                               CZ\r
+\r
+8C-44-4F   (hex)               HUMAX Co., Ltd.\r
+8C444F     (base 16)           HUMAX Co., Ltd.\r
+                               HUMAX Village, 216, Hwangsaeul-ro, Bu\r
+                               Seongnam-si  Gyeonggi-do  463-875\r
+                               KR\r
+\r
+A4-19-08   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+A41908     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
+                               CN\r
+\r
+EC-A9-FA   (hex)               GUANGDONG GENIUS TECHNOLOGY CO., LTD.\r
+ECA9FA     (base 16)           GUANGDONG GENIUS TECHNOLOGY CO., LTD.\r
+                               #126,BBK Road,Wusha,Chang'An\r
+                               Dong Guan  Guang Dong  523860\r
+                               CN\r
+\r
+44-B4-62   (hex)               Flextronics Tech.(Ind) Pvt Ltd\r
+44B462     (base 16)           Flextronics Tech.(Ind) Pvt Ltd\r
+                               SURVEYNO.381, PADUR ROAD, KUTHAMBAKKAM VILLAGE, 602107 POONAMALLEE TALUK, THIRUVALLUR DISTRIC\r
+                               Chennai    602107\r
+                               IN\r
+\r
+DC-67-23   (hex)               barox Kommunikation GmbH\r
+DC6723     (base 16)           barox Kommunikation GmbH\r
+                               Marie-Curie-Strasse 8\r
+                               Lörrach    DE-79539\r
+                               DE\r
+\r
+1C-24-EB   (hex)               Burlywood\r
+1C24EB     (base 16)           Burlywood\r
+                               1501 S Sunset Street\r
+                               Longmont  CO  80501\r
+                               US\r
+\r
+64-6E-EA   (hex)               Iskratel d.o.o.\r
+646EEA     (base 16)           Iskratel d.o.o.\r
+                               Ljubljanska cesta 24a\r
+                               Kranj    4000\r
+                               SI\r
+\r
+00-D0-50   (hex)               Iskratel d.o.o.\r
+00D050     (base 16)           Iskratel d.o.o.\r
+                               Ljubljanska cesta 24a\r
+                               Kranj    4000\r
+                               SI\r
+\r
+7C-60-4A   (hex)               Avelon\r
+7C604A     (base 16)           Avelon\r
+                               Bändliweg 20\r
+                               Zurich    8048\r
+                               CH\r
+\r
+7C-D9-5C   (hex)               Google, Inc.\r
+7CD95C     (base 16)           Google, Inc.\r
+                               1600 Amphitheatre Parkway\r
+                               Mountain View  CA  94043\r
+                               US\r
+\r
+F0-5C-19   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
+F05C19     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
+                               3333 Scott Blvd\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+70-3A-0E   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
+703A0E     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
+                               3333 Scott Blvd\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+B4-5D-50   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
+B45D50     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
+                               3333 Scott Blvd\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+6C-F3-7F   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
+6CF37F     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
+                               3333 Scott Blvd\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+68-FF-7B   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+68FF7B     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+38-21-C7   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
+3821C7     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
+                               3333 Scott Blvd\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+B8-EF-8B   (hex)               SHENZHEN CANNICE TECHNOLOGY CO.,LTD\r
+B8EF8B     (base 16)           SHENZHEN CANNICE TECHNOLOGY CO.,LTD\r
+                               F-20,7A,Baoneng Technology Park\r
+                               Shenzhen  Guangdong  518109\r
+                               CN\r
+\r
+00-13-1E   (hex)               peiker acustic GmbH\r
+00131E     (base 16)           peiker acustic GmbH\r
+                               Max-Planck-Strasse 28-32\r
+                               Friedrichsdorf    61381\r
+                               DE\r
+\r
+D4-9C-DD   (hex)               AMPAK Technology,Inc.\r
+D49CDD     (base 16)           AMPAK Technology,Inc.\r
+                               3F, No.15-1 Zhonghua Road, Hsinchu Industrail Park, Hukou,\r
+                               Hsinchu  Hsinchu,Taiwan R.O.C.  30352\r
+                               TW\r
+\r
+84-69-91   (hex)               Nokia\r
+846991     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+E8-93-63   (hex)               Nokia\r
+E89363     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+CC-66-B2   (hex)               Nokia\r
+CC66B2     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+10-E8-78   (hex)               Nokia\r
+10E878     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+48-F7-F1   (hex)               Nokia\r
+48F7F1     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+4C-C9-4F   (hex)               Nokia\r
+4CC94F     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+04-CF-8C   (hex)               XIAOMI Electronics,CO.,LTD\r
+04CF8C     (base 16)           XIAOMI Electronics,CO.,LTD\r
+                               Xiaomi Building, No.68 Qinghe Middle Street\r
+                               Haidian District  Beijing  100085\r
+                               CN\r
+\r
+40-31-3C   (hex)               XIAOMI Electronics,CO.,LTD\r
+40313C     (base 16)           XIAOMI Electronics,CO.,LTD\r
+                               Xiaomi Building, No.68 Qinghe Middle Street\r
+                               Haidian District  Beijing  100085\r
+                               CN\r
+\r
+7C-49-EB   (hex)               XIAOMI Electronics,CO.,LTD\r
+7C49EB     (base 16)           XIAOMI Electronics,CO.,LTD\r
+                               Xiaomi Building, No.68 Qinghe Middle Street\r
+                               Haidian District  Beijing  100085\r
+                               CN\r
+\r
+1C-EA-1B   (hex)               Nokia\r
+1CEA1B     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+E0-09-BF   (hex)               SHENZHEN TONG BO WEI TECHNOLOGY Co.,LTD\r
+E009BF     (base 16)           SHENZHEN TONG BO WEI TECHNOLOGY Co.,LTD\r
+                               5th floor building 4 pengtengda industrial,langkou community,dalang street longhua newly developed area\r
+                               Shenzhen  GuangDong  518000\r
+                               CN\r
+\r
+00-0C-17   (hex)               AJA Video Systems Inc\r
+000C17     (base 16)           AJA Video Systems Inc\r
+                               180 Litton Drive\r
+                               Grass Valley  CA  95945\r
+                               US\r
+\r
+CC-ED-DC   (hex)               MitraStar Technology Corp.\r
+CCEDDC     (base 16)           MitraStar Technology Corp.\r
+                               No. 6, Innovation Road II,\r
+                               Hsinchu    300\r
+                               TW\r
+\r
+D4-58-00   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+D45800     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
+                               CN\r
+\r
+C4-64-B7   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+C464B7     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
+                               CN\r
+\r
+4C-4D-66   (hex)               Nanjing Jiahao Technology Co., Ltd.\r
+4C4D66     (base 16)           Nanjing Jiahao Technology Co., Ltd.\r
+                               Moling Industrial Park, Development Zone, Jiangning, Nanjing\r
+                               Nanjing  Jiangsu  211111\r
+                               CN\r
+\r
+90-58-51   (hex)               Technicolor CH USA Inc.\r
+905851     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
+                               US\r
+\r
+38-F8-5E   (hex)               HUMAX Co., Ltd.\r
+38F85E     (base 16)           HUMAX Co., Ltd.\r
+                               HUMAX Village, 216, Hwangsaeul-ro, Bu\r
+                               Seongnam-si  Gyeonggi-do  463-875\r
+                               KR\r
+\r
+C0-2E-25   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+C02E25     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+40-A5-EF   (hex)               Shenzhen Four Seas Global Link Network Technology Co., Ltd.\r
+40A5EF     (base 16)           Shenzhen Four Seas Global Link Network Technology Co., Ltd.\r
+                               Room 607-610, Block B, TAOJINDI Electronic Business Incubation Base\r
+                               Tenglong Road, Longhua District,   Shenzhen Guangdong  518000\r
+                               CN\r
+\r
+48-E6-C0   (hex)               SIMCom Wireless Solutions Co.,Ltd.\r
+48E6C0     (base 16)           SIMCom Wireless Solutions Co.,Ltd.\r
+                               Building B,SIM Technology Building,No.633,Jinzhong Road\r
+                               Shanghai    200335\r
+                               CN\r
+\r
+CC-D8-1F   (hex)               Maipu Communication Technology Co.,Ltd.\r
+CCD81F     (base 16)           Maipu Communication Technology Co.,Ltd.\r
+                               Maipu Mansion, No.288 Tianfu 3rd Street, High-tech Zone\r
+                               Chengdu  Sichuan  610094\r
+                               CN\r
+\r
+10-0C-6B   (hex)               NETGEAR\r
+100C6B     (base 16)           NETGEAR\r
+                               350 East Plumeria Drive\r
+                               San Jose  CA  95134\r
+                               US\r
+\r
+2C-F4-32   (hex)               Espressif Inc.\r
+2CF432     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+AC-BB-61   (hex)               YSTen Technology Co.,Ltd\r
+ACBB61     (base 16)           YSTen Technology Co.,Ltd\r
+                               Room 1715,17/F North Star Times Tower,Chaoyang District,Beijing.\r
+                               Beijing    100101\r
+                               CN\r
+\r
+60-6E-D0   (hex)               SEAL AG\r
+606ED0     (base 16)           SEAL AG\r
+                               Landstrasse 176\r
+                               Wettingen    5430\r
+                               CH\r
+\r
+24-79-F8   (hex)               KUPSON spol. s r.o.\r
+2479F8     (base 16)           KUPSON spol. s r.o.\r
+                               Hradecka 787/14\r
+                               Opava  Czech Republic  74601\r
+                               CZ\r
+\r
+00-A0-85   (hex)               Private\r
+00A085     (base 16)           Private\r
+\r
+40-A9-3F   (hex)               Pivotal Commware, Inc.\r
+40A93F     (base 16)           Pivotal Commware, Inc.\r
+                               1555 132nd Ave. NE\r
+                               Bellevue  WA  98005\r
+                               US\r
+\r
+18-D6-CF   (hex)               Kurth Electronic GmbH\r
+18D6CF     (base 16)           Kurth Electronic GmbH\r
+                               Mühleweg 11\r
+                               Eningen    72800\r
+                               DE\r
+\r
+24-3F-30   (hex)               Oxygen Broadband s.a.\r
+243F30     (base 16)           Oxygen Broadband s.a.\r
+                               2 Messogeion ave., Athens Tower\r
+                               Athens  Attiki  11527\r
+                               GR\r
+\r
+48-04-9F   (hex)               ELECOM CO., LTD\r
+48049F     (base 16)           ELECOM CO., LTD\r
+                               9FLand Axis Tower.1-1 fushimi machi,4-chome chuoku\r
+                               osaka    5418765\r
+                               JP\r
+\r
+08-7F-98   (hex)               vivo Mobile Communication Co., Ltd.\r
+087F98     (base 16)           vivo Mobile Communication Co., Ltd.\r
+                               #283,BBK Road\r
+                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
+                               CN\r
+\r
+B4-D0-A9   (hex)               China Mobile Group Device Co.,Ltd.\r
+B4D0A9     (base 16)           China Mobile Group Device Co.,Ltd.\r
+                               32 Xuanwumen West Street,Xicheng District\r
+                               Beijing    100053\r
+                               CN\r
+\r
+48-89-E7   (hex)               Intel Corporate\r
+4889E7     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+04-D4-C4   (hex)               ASUSTek COMPUTER INC.\r
+04D4C4     (base 16)           ASUSTek COMPUTER INC.\r
+                               15,Li-Te Rd., Peitou, Taipei 112, Taiwan\r
+                               Taipei  Taiwan  112\r
+                               TW\r
+\r
+48-46-C1   (hex)               FN-LINK TECHNOLOGY LIMITED\r
+4846C1     (base 16)           FN-LINK TECHNOLOGY LIMITED\r
+                               A Building,HuiXin industial park,No 31, YongHe road, Fuyong town, Bao'an District\r
+                               SHENZHEN  GUANGDONG  518100\r
+                               CN\r
+\r
+24-BF-74   (hex)               Private\r
+24BF74     (base 16)           Private\r
+\r
+00-26-15   (hex)               Teracom Limited\r
+002615     (base 16)           Teracom Limited\r
+                               B-84\r
+                               Noida  Uttar Pradesh  201301\r
+                               IN\r
+\r
+58-CB-52   (hex)               Google, Inc.\r
+58CB52     (base 16)           Google, Inc.\r
+                               1600 Amphitheatre Parkway\r
+                               Mountain View  CA  94043\r
+                               US\r
+\r
+F8-CA-59   (hex)               NetComm Wireless\r
+F8CA59     (base 16)           NetComm Wireless\r
+                               LEVEL 5, 18-20 ORION RD. LANE COVE\r
+                               LANE COVE WEST  NSW  2066\r
+                               AU\r
+\r
+6C-2C-DC   (hex)               Skyworth Digital Technology(Shenzhen) Co.,Ltd\r
+6C2CDC     (base 16)           Skyworth Digital Technology(Shenzhen) Co.,Ltd\r
+                               7F,Block A,Skyworth Building,\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+04-F1-28   (hex)               HMD Global Oy\r
+04F128     (base 16)           HMD Global Oy\r
+                               Bertel Jungin aukio 9\r
+                               Espoo    02600\r
+                               FI\r
+\r
+80-4A-14   (hex)               Apple, Inc.\r
+804A14     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+B8-5D-0A   (hex)               Apple, Inc.\r
+B85D0A     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+94-16-25   (hex)               Apple, Inc.\r
+941625     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+74-40-BE   (hex)               LG Innotek\r
+7440BE     (base 16)           LG Innotek\r
+                               26, Hanamsandan 5beon-ro\r
+                               Gwangju  Gwangsan-gu  506-731\r
+                               KR\r
+\r
+34-A8-EB   (hex)               Apple, Inc.\r
+34A8EB     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
+\r
+AC-57-75   (hex)               HMD Global Oy\r
+AC5775     (base 16)           HMD Global Oy\r
+                               Bertel Jungin aukio 9\r
+                               Espoo    02600\r
+                               FI\r
+\r
+4C-6A-F6   (hex)               HMD Global Oy\r
+4C6AF6     (base 16)           HMD Global Oy\r
+                               Bertel Jungin aukio 9\r
+                               Espoo    02600\r
+                               FI\r
+\r
+AC-8F-F8   (hex)               Nokia\r
+AC8FF8     (base 16)           Nokia\r
+                               600 March Road\r
+                               Kanata  Ontario  K2K 2E6\r
+                               CA\r
+\r
+10-82-86   (hex)               Luxshare Precision Industry Co.,Ltd\r
+108286     (base 16)           Luxshare Precision Industry Co.,Ltd\r
+                               2nd floor, A building, Sanyo New Industrial Area, West of Maoyi, Shajing  Baoan District\r
+                               Shenzhen  Shenzhen  518104\r
+                               CN\r
+\r
+78-32-1B   (hex)               D-Link International\r
+78321B     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
+                               Singapore  Singapore  609917\r
+                               SG\r
+\r
+00-AD-24   (hex)               D-Link International\r
+00AD24     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
+                               Singapore  Singapore  609917\r
+                               SG\r
+\r
+F4-8C-EB   (hex)               D-Link International\r
+F48CEB     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
+                               Singapore  Singapore  609917\r
+                               SG\r
+\r
+A0-AB-1B   (hex)               D-Link International\r
+A0AB1B     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
+                               Singapore  Singapore  609917\r
+                               SG\r
+\r
+10-62-EB   (hex)               D-Link International\r
+1062EB     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
+                               Singapore  Singapore  609917\r
+                               SG\r
+\r
+FC-75-16   (hex)               D-Link International\r
+FC7516     (base 16)           D-Link International\r
+                               1 International Business Park, #03-12, The Synergy \r
+                               SINGAPORE    609917\r
+                               SG\r
+\r
+AC-F1-DF   (hex)               D-Link International\r
+ACF1DF     (base 16)           D-Link International\r
+                               1 International Business Park, #03-12, The Synergy \r
+                               SINGAPORE    609917\r
+                               SG\r
+\r
+9C-D6-43   (hex)               D-Link International\r
+9CD643     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
+                               Singapore  Singapore  609917\r
+                               SG\r
+\r
+AC-EE-70   (hex)               Fontem Ventures BV\r
+ACEE70     (base 16)           Fontem Ventures BV\r
+                               Motion Building 8F, Radarweg 60\r
+                               Amsterdam  Noord-Holland  1043NT\r
+                               NL\r
+\r
+FC-D2-B6   (hex)               IEEE Registration Authority\r
+FCD2B6     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+60-61-DF   (hex)               Z-meta Research LLC\r
+6061DF     (base 16)           Z-meta Research LLC\r
+                               8365 Quay Drive\r
+                               Arvada  CO  80003\r
+                               US\r
+\r
+00-B6-00   (hex)               VOIM Co., Ltd.\r
+00B600     (base 16)           VOIM Co., Ltd.\r
+                               70, Seotan-ro, Jinwi-myeon\r
+                               Pyeongtaek-si  Gyeonggi-do  17706\r
+                               KR\r
+\r
+48-83-B4   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+4883B4     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+20-2A-C5   (hex)               Petite-En\r
+202AC5     (base 16)           Petite-En\r
+                               1, Gwanak-ro, Gwanak-gu\r
+                               Seoul    08826\r
+                               KR\r
+\r
+DC-96-2C   (hex)               NST Audio Ltd\r
+DC962C     (base 16)           NST Audio Ltd\r
+                               32 Whitewall\r
+                               Norton  North Yorkshire  YO17 9EH\r
+                               GB\r
+\r
+50-AD-71   (hex)               Tessolve Semiconductor Private Limited\r
+50AD71     (base 16)           Tessolve Semiconductor Private Limited\r
+                               Plot No: 31, P2, Electronic City Phase II, Electronic City\r
+                               Bengaluru  Karnataka  560100\r
+                               IN\r
+\r
+F4-79-60   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+F47960     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+20-65-8E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+20658E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+08-A6-BC   (hex)               Amazon Technologies Inc.\r
+08A6BC     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+EC-AD-E0   (hex)               D-Link International\r
+ECADE0     (base 16)           D-Link International\r
+                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
+                               Singapore  Singapore  609917\r
+                               SG\r
+\r
+F0-B9-68   (hex)               ITEL MOBILE LIMITED\r
+F0B968     (base 16)           ITEL MOBILE LIMITED\r
+                               RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING  NO.7 KO FAI ROAD, YAU TONG, KLN, H.K\r
+                               Hong Kong  KOWLOON  999077\r
+                               HK\r
+\r
+98-8B-0A   (hex)               Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+988B0A     (base 16)           Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+                               No.555 Qianmo Road, Binjiang District\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
+\r
+1C-BF-CE   (hex)               Shenzhen Century Xinyang Technology Co., Ltd\r
+1CBFCE     (base 16)           Shenzhen Century Xinyang Technology Co., Ltd\r
+                               3F, North Building, Bantian High-tech industrial Zone, No. 2 of Bell Road\r
+                               Shenzhen  Guangdong  518129\r
+                               CN\r
+\r
+F8-30-02   (hex)               Texas Instruments\r
+F83002     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+B0-2A-1F   (hex)                Wingtech Group (HongKong)Limited\r
+B02A1F     (base 16)            Wingtech Group (HongKong)Limited\r
+                                FLAT/RM 1903 19/F PODIUM PLAZA 5HANOI ROAD TSIM SHA TSUI\r
+                               Hong Kong  Hong Kong  999077\r
+                               HK\r
+\r
+1C-B3-E9   (hex)                Shenzhen Zhongke United Communication Technology \r
+1CB3E9     (base 16)            Shenzhen Zhongke United Communication Technology \r
+                               6C jiajiahao commercial building, Shennan avenue\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
+\r
+34-E1-D1   (hex)               IEEE Registration Authority\r
+34E1D1     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+DC-FB-48   (hex)               Intel Corporate\r
+DCFB48     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+6C-40-C6   (hex)               Nimbus Data, Inc.\r
+6C40C6     (base 16)           Nimbus Data, Inc.\r
+                               5151 California Ave, Ste 100\r
+                               Irvine  CA  92617\r
+                               US\r
+\r
+A8-DB-03   (hex)               SAMSUNG ELECTRO-MECHANICS(THAILAND)\r
+A8DB03     (base 16)           SAMSUNG ELECTRO-MECHANICS(THAILAND)\r
+                               93Moo5T. Bangsamak SEMTHAI, WELLGROW INDUSTRIAL ESTATE\r
+                               Bangpakong  Chachoengsao  24180\r
+                               TH\r
+\r
+44-A6-1E   (hex)               INGRAM MICRO SERVICES\r
+44A61E     (base 16)           INGRAM MICRO SERVICES\r
+                               100 CHEMIN DE BAILLOT\r
+                               MONTAUBAN    82000\r
+                               FR\r
+\r
+8C-0F-A0   (hex)               di-soric GmbH & Co. KG\r
+8C0FA0     (base 16)           di-soric GmbH & Co. KG\r
+                               Steinbeisstrasse 6\r
+                               Urbach    73660\r
+                               DE\r
+\r
+90-78-41   (hex)               Intel Corporate\r
+907841     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+10-9E-3A   (hex)               Zhejiang Tmall Technology Co., Ltd.\r
+109E3A     (base 16)           Zhejiang Tmall Technology Co., Ltd.\r
+                               Ali Center,No.3331 Keyuan South RD (Shenzhen bay), Nanshan District, \r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
+\r
+CC-37-AB   (hex)               Edgecore Networks Corporation\r
+CC37AB     (base 16)           Edgecore Networks Corporation\r
+                               1 Creation Road 3.\r
+                               Hsinchu  Hsinchu  30077\r
+                               TW\r
+\r
+24-79-F3   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+2479F3     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+20-58-69   (hex)               Ruckus Wireless\r
+205869     (base 16)           Ruckus Wireless\r
+                               350 West Java Drive\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+60-D2-DD   (hex)               Shenzhen Baitong Putian Technology Co.,Ltd.\r
+60D2DD     (base 16)           Shenzhen Baitong Putian Technology Co.,Ltd.\r
+                               501,5/F,Building 1,No.2,Lianwei Street,Hualian Community,Longhua Street Longhua District\r
+                               Shenzhen  Guangdong  518109\r
+                               CN\r
+\r
+FC-AB-90   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+FCAB90     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+20-DA-22   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+20DA22     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+88-F8-72   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+88F872     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+70-F2-20   (hex)               Actiontec Electronics, Inc\r
+70F220     (base 16)           Actiontec Electronics, Inc\r
+                               3301 Olcott St.\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+00-24-7B   (hex)               Actiontec Electronics, Inc\r
+00247B     (base 16)           Actiontec Electronics, Inc\r
+                               3301 Olcott St.\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+A8-39-44   (hex)               Actiontec Electronics, Inc\r
+A83944     (base 16)           Actiontec Electronics, Inc\r
+                               301 Olcott St\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+88-E6-4B   (hex)               Juniper Networks\r
+88E64B     (base 16)           Juniper Networks\r
+                               1133 Innovation Way\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+48-D8-75   (hex)               China TransInfo Technology Co., Ltd\r
+48D875     (base 16)           China TransInfo Technology Co., Ltd\r
+                               Qianfang Building, Phase I, Zhongguancun Software Park, 8 Wangxi Road, Haidian District\r
+                               Beijing    100085\r
+                               CN\r
+\r
+CC-A1-2B   (hex)               TCL King Electrical Appliances (Huizhou) Co., Ltd\r
+CCA12B     (base 16)           TCL King Electrical Appliances (Huizhou) Co., Ltd\r
+                               10F, TCL Multimedia Building, TCL International E City, No.1001 Zhongshanyuan Rd., Nanshan District\r
+                               Shenzhen  Guangdong  518052\r
+                               CN\r
+\r
+4C-BC-48   (hex)               Cisco Systems, Inc\r
+4CBC48     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+D4-6A-35   (hex)               Cisco Systems, Inc\r
+D46A35     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+E4-F3-E8   (hex)               Shenzhen SuperElectron Technology Co.,Ltd.\r
+E4F3E8     (base 16)           Shenzhen SuperElectron Technology Co.,Ltd.\r
+                               1213-1214, haosheng business center, dongbin road, nanshan street, nanshan district, shenzhen city\r
+                               Shenzhen   Guangdong  518000\r
+                               CN\r
+\r
+B0-30-55   (hex)               China Mobile IOT Company Limited\r
+B03055     (base 16)           China Mobile IOT Company Limited\r
+                               NO.8 Yu Ma Road, NanAn Area\r
+                               Chongqing  Chongqing  401336\r
+                               CN\r
+\r
+E8-D0-FC   (hex)               Liteon Technology Corporation\r
+E8D0FC     (base 16)           Liteon Technology Corporation\r
+                               4F, 90, Chien 1 Road\r
+                               New Taipei City  Taiwan  23585\r
+                               TW\r
+\r
+C0-9F-E1   (hex)               zte corporation\r
+C09FE1     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+AC-00-D0   (hex)               zte corporation\r
+AC00D0     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+10-DC-4A   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+10DC4A     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
+                               CN\r
+\r
+44-4B-7E   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+444B7E     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
+                               CN\r
+\r
+84-C7-8F   (hex)               STORDIS GmbH\r
+84C78F     (base 16)           STORDIS GmbH\r
+                               Rosenwiesstr. 17\r
+                               Stuttgart    70567\r
+                               DE\r
+\r
+78-2C-29   (hex)               New H3C Technologies Co., Ltd\r
+782C29     (base 16)           New H3C Technologies Co., Ltd\r
+                               466 Changhe Road, Binjiang District\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
+\r
+98-B8-BA   (hex)               LG Electronics (Mobile Communications)\r
+98B8BA     (base 16)           LG Electronics (Mobile Communications)\r
+                               60-39, Gasan-dong, Geumcheon-gu\r
+                               Seoul    153-801\r
+                               KR\r
+\r
+D4-9D-C0   (hex)               Samsung Electronics Co.,Ltd\r
+D49DC0     (base 16)           Samsung Electronics Co.,Ltd\r
+                               129, Samsung-ro, Youngtongl-Gu\r
+                               Suwon  Gyeonggi-Do  16677\r
+                               KR\r
+\r
+D4-D2-52   (hex)               Intel Corporate\r
+D4D252     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+08-3A-2F   (hex)               Guangzhou Juan Intelligent Tech Joint Stock Co.,Ltd\r
+083A2F     (base 16)           Guangzhou Juan Intelligent Tech Joint Stock Co.,Ltd\r
+                               NO.9, street 3, HengLing industrial zone, Tangdong, tianhe district\r
+                               Guangzhou  Guangdong  CN 510000\r
+                               CN\r
+\r
+88-EF-16   (hex)               ARRIS Group, Inc.\r
+88EF16     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+FC-EA-50   (hex)               Integrated Device Technology (Malaysia) Sdn. Bhd.\r
+FCEA50     (base 16)           Integrated Device Technology (Malaysia) Sdn. Bhd.\r
+                               Phase 3, Bayan Lepas FIZ\r
+                               Bayan Lepas  Penang  11900\r
+                               MY\r
+\r
+44-65-7F   (hex)               Calix Inc.\r
+44657F     (base 16)           Calix Inc.\r
+                               2777 Orchard Parkway\r
+                               San Jose  CA  95134\r
+                               US\r
+\r
+F0-A9-68   (hex)               Antailiye Technology Co.,Ltd\r
+F0A968     (base 16)           Antailiye Technology Co.,Ltd\r
+                               7/F,Zhengjiyuan Buiding,2 Road,Qianjing, Xixiang, Baoan District,Shenzhen\r
+                               SHEN ZHEN  GUANGDONG  518000\r
+                               CN\r
+\r
+44-13-D0   (hex)               zte corporation\r
+4413D0     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+C0-D9-F7   (hex)               ShanDong Domor Intelligent S&T CO.,Ltd\r
+C0D9F7     (base 16)           ShanDong Domor Intelligent S&T CO.,Ltd\r
+                               Jining high-tech zone base of production,education & research\r
+                               Jining  Shandong  272000\r
+                               CN\r
+\r
+94-FB-29   (hex)               Zebra Technologies Inc.\r
+94FB29     (base 16)           Zebra Technologies Inc.\r
+                               ONE ZEBRA PLAZA\r
+                               HOLTSVILLE  NY  11742\r
+                               US\r
+\r
+64-DB-A0   (hex)               Select Comfort\r
+64DBA0     (base 16)           Select Comfort\r
+                               9800 59th Ave N\r
+                               Minneapolis  MN  55442\r
+                               US\r
+\r
+58-00-E3   (hex)               Liteon Technology Corporation\r
+5800E3     (base 16)           Liteon Technology Corporation\r
+                               4F, 90, Chien 1 Road\r
+                               New Taipei City  Taiwan  23585\r
+                               TW\r
+\r
+64-77-7D   (hex)               Hitron Technologies. Inc\r
+64777D     (base 16)           Hitron Technologies. Inc\r
+                               No. 1-8, Lising 1st Rd. Hsinchu Science Park, Hsinchu, 300, Taiwan, R.O.C\r
+                               Hsin-chu  Taiwan  300\r
+                               TW\r
+\r
+04-95-E6   (hex)               Tenda Technology Co.,Ltd.Dongguan branch\r
+0495E6     (base 16)           Tenda Technology Co.,Ltd.Dongguan branch\r
+                               Room 79,Yuanyi Road,Dalang Town,Dongguan Guangdong 523770\r
+                               Dongguan  Guangdong  523770\r
+                               CN\r
+\r
+00-16-D3   (hex)               Wistron Corporation\r
+0016D3     (base 16)           Wistron Corporation\r
+                               21F, 88, Sec.1, Hsin Tai Wu Rd., Hsichih,\r
+                               Taipei Hsien    221\r
+                               TW\r
+\r
+00-1F-16   (hex)               Wistron Corporation\r
+001F16     (base 16)           Wistron Corporation\r
+                               21F, 88, Sec.1, Hsin Tai Wu Rd., Hsichih,\r
+                               Taipei Hsien    221\r
+                               TW\r
+\r
+4C-4E-03   (hex)               TCT mobile ltd\r
+4C4E03     (base 16)           TCT mobile ltd\r
+                               No.86 hechang 7th road, zhongkai, Hi-Tech District\r
+                               Hui Zhou  Guang Dong  516006\r
+                               CN\r
+\r
+50-E6-66   (hex)               Shenzhen Techtion Electronics Co., Ltd.\r
+50E666     (base 16)           Shenzhen Techtion Electronics Co., Ltd.\r
+                               Floor 2, C2 Building, Huafeng Industrial Park, Hangcheng Avenue, Gushu, Xixiang, Baoan\r
+                               Shenzhen  Guangdong  518102\r
+                               CN\r
+\r
+68-31-FE   (hex)               Teladin Co.,Ltd.\r
+6831FE     (base 16)           Teladin Co.,Ltd.\r
+                               Digital-ro 33 gil, Guro-gu\r
+                               Seoul    08377\r
+                               KR\r
+\r
+D4-B1-69   (hex)               Le Shi Zhi Xin Electronic Technology (Tianjin) Limited\r
+D4B169     (base 16)           Le Shi Zhi Xin Electronic Technology (Tianjin) Limited\r
+                               ,Le Shi Building, No.105 Yaojiayuan Road,Chaoyang District,Beijing,China\r
+                               beijing  beijing  100025\r
+                               CN\r
+\r
+0C-3C-CD   (hex)               Universal Global Scientific Industrial Co., Ltd.\r
+0C3CCD     (base 16)           Universal Global Scientific Industrial Co., Ltd.\r
+                               141, Lane 351, Taiping Road, Sec.1,Tsao Tuen\r
+                               Nan-Tou  Taiwan  54261\r
+                               TW\r
+\r
+B0-40-89   (hex)               Senient Systems LTD\r
+B04089     (base 16)           Senient Systems LTD\r
+                               152 Morrison St\r
+                               Edinburgh  Other (Non US)  EH3 8EB\r
+                               GB\r
+\r
+00-24-45   (hex)               Adtran Inc\r
+002445     (base 16)           Adtran Inc\r
+                               901 Explorer Blvd.\r
+                               Huntsville  AL  35806-2807\r
+                               US\r
+\r
+68-9F-F0   (hex)               zte corporation\r
+689FF0     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+7C-C6-C4   (hex)               Kolff Computer Supplies b.v.\r
+7CC6C4     (base 16)           Kolff Computer Supplies b.v.\r
+                               Kuipershaven 22\r
+                               Dordrecht  Zuid-Holland  3311 AL\r
+                               NL\r
+\r
+F0-6E-32   (hex)               MICROTEL INNOVATION S.R.L.\r
+F06E32     (base 16)           MICROTEL INNOVATION S.R.L.\r
+                               Via Armentera 8\r
+                               BORGO VALSUGANA  TN  38051\r
+                               IT\r
+\r
+00-E0-22   (hex)               Analog Devices, Inc.\r
+00E022     (base 16)           Analog Devices, Inc.\r
+                               Three Technology Way\r
+                               Norwood   MA  02062-2666\r
+                               US\r
+\r
+7C-67-A2   (hex)               Intel Corporate\r
+7C67A2     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+00-03-02   (hex)               Charles Industries, Ltd.\r
+000302     (base 16)           Charles Industries, Ltd.\r
+                               5600 Apollo Drive\r
+                               Rolling Meadows  IL  60008\r
+                               US\r
+\r
+08-96-AD   (hex)               Cisco Systems, Inc\r
+0896AD     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+8C-F5-A3   (hex)               SAMSUNG ELECTRO-MECHANICS(THAILAND)\r
+8CF5A3     (base 16)           SAMSUNG ELECTRO-MECHANICS(THAILAND)\r
+                               93Moo5T. Bangsamak SEMTHAI, WELLGROW INDUSTRIAL ESTATE\r
+                               Bangpakong  Chachoengsao  24180\r
+                               TH\r
+\r
+B8-EA-AA   (hex)               ICG NETWORKS CO.,ltd\r
+B8EAAA     (base 16)           ICG NETWORKS CO.,ltd\r
+                               Room 2030,Block B,Yamei Park,Haidian District\r
+                               BEIJING    100010\r
+                               CN\r
+\r
+B8-F8-83   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+B8F883     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+DC-FE-18   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+DCFE18     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+AC-60-B6   (hex)               Ericsson AB\r
+AC60B6     (base 16)           Ericsson AB\r
+                               Torshamnsgatan 36\r
+                               Stockholm    SE-164 80\r
+                               SE\r
+\r
+3C-19-7D   (hex)               Ericsson AB\r
+3C197D     (base 16)           Ericsson AB\r
+                               Torshamnsgatan 36\r
+                               Stockholm    SE-164 80\r
+                               SE\r
+\r
+74-C9-9A   (hex)               Ericsson AB\r
+74C99A     (base 16)           Ericsson AB\r
+                               Torshamnsgatan 36\r
+                               Stockholm    SE-164 80\r
+                               SE\r
+\r
+00-0F-4F   (hex)               PCS Systemtechnik GmbH\r
+000F4F     (base 16)           PCS Systemtechnik GmbH\r
+                               66 Hillside Rd\r
+                               Auckland    1310\r
+                               NZ\r
+\r
+7C-5A-1C   (hex)               Sophos Ltd\r
+7C5A1C     (base 16)           Sophos Ltd\r
+                               The Pentagon\r
+                               Abingdon  Oxfordshire  OX14 3YP\r
+                               GB\r
+\r
+00-E4-00   (hex)               Sichuan Changhong Electric Ltd.\r
+00E400     (base 16)           Sichuan Changhong Electric Ltd.\r
+                               No.35,East MianXin Road,MianYang,Sichaun,China.\r
+                               MianYang  SiChuan  PRC 621000\r
+                               CN\r
+\r
+00-11-7E   (hex)               Midmark Corp\r
+00117E     (base 16)           Midmark Corp\r
+                               675 Heathrow Drive\r
+                               Lincolnshire  IL  60089\r
+                               US\r
+\r
+10-5A-F7   (hex)               ADB Italia \r
+105AF7     (base 16)           ADB Italia \r
+                               Viale Sarca 222\r
+                               Milan  Italy  20126\r
+                               IT\r
+\r
+70-3A-CB   (hex)               Google, Inc.\r
+703ACB     (base 16)           Google, Inc.\r
+                               1600 Amphitheatre Parkway\r
+                               Mountain View  CA  94043\r
+                               US\r
+\r
+D4-81-D7   (hex)               Dell Inc.\r
+D481D7     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
+                               US\r
+\r
+2C-55-D3   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+2C55D3     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+F4-4C-7F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+F44C7F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+14-30-04   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+143004     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+7C-46-85   (hex)               Motorola (Wuhan) Mobility Technologies Communication Co., Ltd.\r
+7C4685     (base 16)           Motorola (Wuhan) Mobility Technologies Communication Co., Ltd.\r
+                               No.19, Gaoxin 4th Road, Wuhan East Lake High-tech Zone, Wuhan\r
+                               Wuhan  Hubei  430000\r
+                               CN\r
+\r
+E0-51-63   (hex)               Arcadyan Corporation\r
+E05163     (base 16)           Arcadyan Corporation\r
+                               No.8, Sec.2, Guangfu Rd.\r
+                               Hsinchu City  Hsinchu  30071\r
+                               TW\r
+\r
+00-A0-6F   (hex)               Color Sentinel Systems, LLC\r
+00A06F     (base 16)           Color Sentinel Systems, LLC\r
+                               97 Ridgeland Rd, Suite #2\r
+                               ROCHESTER  NY  14623\r
+                               US\r
+\r
+0C-5F-35   (hex)               Niagara Video Corporation\r
+0C5F35     (base 16)           Niagara Video Corporation\r
+                               5627 Stoneridge Drive, Suite 316\r
+                               Pleasanton  CA  94588\r
+                               US\r
+\r
+7C-38-66   (hex)               Texas Instruments\r
+7C3866     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+50-F1-4A   (hex)               Texas Instruments\r
+50F14A     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+9C-1D-58   (hex)               Texas Instruments\r
+9C1D58     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+50-0F-F5   (hex)               Tenda Technology Co.,Ltd.Dongguan branch\r
+500FF5     (base 16)           Tenda Technology Co.,Ltd.Dongguan branch\r
+                               Room 79,Yuanyi Road,Dalang Town,Dongguan Guangdong 523770\r
+                               Dongguan  Guangdong  523770\r
+                               CN\r
+\r
+F0-27-2D   (hex)               Amazon Technologies Inc.\r
+F0272D     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+74-C2-46   (hex)               Amazon Technologies Inc.\r
+74C246     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+F4-C4-D6   (hex)               Shenzhen Xinfa Electronic Co.,ltd\r
+F4C4D6     (base 16)           Shenzhen Xinfa Electronic Co.,ltd\r
+                               No 57, Baoli Road, Buji Town\r
+                               Longgang District  Shenzhen, Guangdong   518112\r
+                               CN\r
+\r
+08-B2-58   (hex)               Juniper Networks\r
+08B258     (base 16)           Juniper Networks\r
+                               1133 Innovation Way\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+C0-3D-46   (hex)               Shanghai Sango Network Technology Co.,Ltd\r
+C03D46     (base 16)           Shanghai Sango Network Technology Co.,Ltd\r
+                               No 666 Zhangheng Road\r
+                               Pudong  Shanghai  210203\r
+                               CN\r
+\r
+E8-9F-EC   (hex)               CHENGDU KT ELECTRONIC HI-TECH CO.,LTD\r
+E89FEC     (base 16)           CHENGDU KT ELECTRONIC HI-TECH CO.,LTD\r
+                               No.9, 3rd Wuke Road, Wuhou District\r
+                               Chengdu  Sichuan Province  610045\r
+                               CN\r
+\r
+BC-A0-42   (hex)               SHANGHAI FLYCO ELECTRICAL APPLIANCE CO.,LTD\r
+BCA042     (base 16)           SHANGHAI FLYCO ELECTRICAL APPLIANCE CO.,LTD\r
+                               No.555,Guang Fu Lin east Road,Songjiang District\r
+                               Shanghai  Shanghai  201613\r
+                               CN\r
+\r
+D4-7D-FC   (hex)               TECNO MOBILE LIMITED\r
+D47DFC     (base 16)           TECNO MOBILE LIMITED\r
+                               ROOMS 05-15, 13A/F., SOUTH TOWER, WORLD FINANCE CENTRE, HARBOUR CITY, 17 CANTON ROAD, TSIM SHA TSUI, KOWLOON, HONG KONG\r
+                               Hong Kong  Hong Kong  999077\r
+                               HK\r
+\r
+44-37-08   (hex)               MRV Comunications\r
+443708     (base 16)           MRV Comunications\r
+                               Hayetzira\r
+                               Yokneam    614\r
+                               IL\r
+\r
+14-56-8E   (hex)               Samsung Electronics Co.,Ltd\r
+14568E     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+68-37-E9   (hex)               Amazon Technologies Inc.\r
+6837E9     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
+\r
+80-58-F8   (hex)               Motorola Mobility LLC, a Lenovo Company\r
+8058F8     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
+                               222 West Merchandise Mart Plaza\r
+                               Chicago  IL  60654\r
+                               US\r
+\r
+F0-D7-AA   (hex)               Motorola Mobility LLC, a Lenovo Company\r
+F0D7AA     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
+                               222 West Merchandise Mart Plaza\r
+                               Chicago  IL  60654\r
+                               US\r
+\r
+28-FF-3E   (hex)               zte corporation\r
+28FF3E     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+D0-49-8B   (hex)               ZOOM SERVER\r
+D0498B     (base 16)           ZOOM SERVER\r
+                               North keyuan Road\r
+                               Shenzhen    518057\r
+                               CN\r
+\r
+C4-9D-ED   (hex)               Microsoft Corporation\r
+C49DED     (base 16)           Microsoft Corporation\r
+                               One Microsoft Way\r
+                               REDMOND  WA  98052\r
+                               US\r
+\r
+98-A4-0E   (hex)               Snap, Inc.\r
+98A40E     (base 16)           Snap, Inc.\r
+                               64 Market Street\r
+                               Venice  CA  90291\r
+                               US\r
+\r
+2C-5A-0F   (hex)               Cisco Systems, Inc\r
+2C5A0F     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+AC-74-09   (hex)               Hangzhou H3C Technologies Co., Limited\r
+AC7409     (base 16)           Hangzhou H3C Technologies Co., Limited\r
+                               466 Changhe Road, Binjiang District\r
+                               Hangzhou  Zhejiang, P.R.China  310052\r
+                               CN\r
+\r
+E0-37-BF   (hex)               Wistron Neweb Corporation\r
+E037BF     (base 16)           Wistron Neweb Corporation\r
+                               No.20,Park Avenue II,Hsinchu Science Park\r
+                               Hsin-Chu  R.O.C.  308\r
+                               TW\r
+\r
+4C-81-20   (hex)               Taicang T&W Electronics\r
+4C8120     (base 16)           Taicang T&W Electronics\r
+                               89# Jiang Nan RD\r
+                               Suzhou  Jiangsu  215412\r
+                               CN\r
+\r
+E8-E7-32   (hex)               Alcatel-Lucent Enterprise\r
+E8E732     (base 16)           Alcatel-Lucent Enterprise\r
+                               26801 West Agoura Road\r
+                               Calabasas  CA  91301\r
+                               US\r
+\r
+00-11-8B   (hex)               Alcatel-Lucent Enterprise\r
+00118B     (base 16)           Alcatel-Lucent Enterprise\r
+                               26801 West Agoura Road\r
+                               Calabasas  CA  91301\r
+                               US\r
+\r
+00-E0-B1   (hex)               Alcatel-Lucent Enterprise\r
+00E0B1     (base 16)           Alcatel-Lucent Enterprise\r
+                               26801 West Agoura Road\r
+                               Calabasas  CA  91301\r
+                               US\r
+\r
+68-54-ED   (hex)               Alcatel-Lucent\r
+6854ED     (base 16)           Alcatel-Lucent\r
+                               777 E. Middlefield Rd\r
+                               Mountain View  CA  94043\r
+                               US\r
+\r
+E8-DE-8E   (hex)               Integrated Device Technology (Malaysia) Sdn. Bhd.\r
+E8DE8E     (base 16)           Integrated Device Technology (Malaysia) Sdn. Bhd.\r
+                               Phase 3, Bayan Lepas FIZ\r
+                               Bayan Lepas  Penang  11900\r
+                               MY\r
+\r
+40-C8-CB   (hex)               AM Telecom co., Ltd.\r
+40C8CB     (base 16)           AM Telecom co., Ltd.\r
+                               #608,YatapLeaders B/D, Jangmi-ro 42, Bundang-gu\r
+                               Seongnam-si  Gyeonggi-do  463-828\r
+                               KR\r
+\r
+14-A0-F8   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+14A0F8     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+28-B4-48   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+28B448     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+E4-42-A6   (hex)               Intel Corporate\r
+E442A6     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
+\r
+60-45-CB   (hex)               ASUSTek COMPUTER INC.\r
+6045CB     (base 16)           ASUSTek COMPUTER INC.\r
+                               15,Li-Te Rd., Peitou, Taipei 112, Taiwan\r
+                               Taipei  Taiwan  112\r
+                               TW\r
+\r
+84-AF-EC   (hex)               BUFFALO.INC\r
+84AFEC     (base 16)           BUFFALO.INC\r
+                               AKAMONDORI Bld.,30-20,Ohsu 3-chome,Naka-ku\r
+                               Nagoya  Aichi Pref.  460-8315\r
+                               JP\r
+\r
+AC-20-2E   (hex)               Hitron Technologies. Inc\r
+AC202E     (base 16)           Hitron Technologies. Inc\r
+                               No. 1-8, Lising 1st Rd. Hsinchu Science Park, Hsinchu, 300, Taiwan, R.O.C\r
+                               Hsin-chu  Taiwan  300\r
+                               TW\r
+\r
+48-A7-4E   (hex)               zte corporation\r
+48A74E     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+3C-52-82   (hex)               Hewlett Packard\r
+3C5282     (base 16)           Hewlett Packard\r
+                               11445 Compaq Center Drive\r
+                               Houston  TX  77070\r
+                               US\r
+\r
+B0-AA-36   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+B0AA36     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD\r
+                               DONGGUAN  GUANGDONG  523860\r
+                               CN\r
+\r
+2C-5B-B8   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+2C5BB8     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,WUSHA,CHANG'AN,DONGGUAN,GUANGDONG,CHINA\r
+                               DONGGUAN  GUANGDONG  523860\r
+                               CN\r
+\r
+1C-48-CE   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+1C48CE     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+00-40-66   (hex)               APRESIA Systems Ltd\r
+004066     (base 16)           APRESIA Systems Ltd\r
+                                Tsukuba Network Technical Center, Tsukuba Network\r
+                               Tsuchiura-shi  Ibaraki-ken  300-0026\r
+                               JP\r
+\r
+9C-AC-6D   (hex)               Universal Electronics, Inc.\r
+9CAC6D     (base 16)           Universal Electronics, Inc.\r
+                               201 E. Sandpointe Ave\r
+                               Santa Ana  CA  92707\r
+                               US\r
+\r
+B0-3D-96   (hex)               Vision Valley FZ LLC\r
+B03D96     (base 16)           Vision Valley FZ LLC\r
+                               Dubai Internet City\r
+                               Dubai  Dubai  500294\r
+                               AE\r
+\r
+B0-26-28   (hex)               Broadcom Limited\r
+B02628     (base 16)           Broadcom Limited\r
+                               5300 California Ave.\r
+                               irvine  CA  92617\r
+                               US\r
+\r
+E8-13-63   (hex)               Comstock RD, Inc.\r
+E81363     (base 16)           Comstock RD, Inc.\r
+                               4415 Mason St\r
+                               Ashton  ID  83406\r
+                               US\r
+\r
+44-AA-50   (hex)               Juniper Networks\r
+44AA50     (base 16)           Juniper Networks\r
+                               1133 Innovation Way\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+00-80-E7   (hex)               Leonardo Tactical Systems.\r
+0080E7     (base 16)           Leonardo Tactical Systems.\r
                                Silvertree, Coxbridge Business Park\r
                                Alton Road,   Farnham  GU10 5EH\r
                                GB\r
@@ -58910,3668 +60524,2624 @@ B817C2     (base 16)              Apple, Inc.
 60-FA-CD   (hex)               Apple, Inc.\r
 60FACD     (base 16)           Apple, Inc.\r
                                1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-1C-AB-A7   (hex)               Apple, Inc.\r
-1CABA7     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-78-4F-43   (hex)               Apple, Inc.\r
-784F43     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-40-4D-7F   (hex)               Apple, Inc.\r
-404D7F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-7C-04-D0   (hex)               Apple, Inc.\r
-7C04D0     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-BC-9F-EF   (hex)               Apple, Inc.\r
-BC9FEF     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-88-66-A5   (hex)               Apple, Inc.\r
-8866A5     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-88-E8-7F   (hex)               Apple, Inc.\r
-88E87F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-B8-53-AC   (hex)               Apple, Inc.\r
-B853AC     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-2C-33-61   (hex)               Apple, Inc.\r
-2C3361     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-A8-60-B6   (hex)               Apple, Inc.\r
-A860B6     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-24-F0-94   (hex)               Apple, Inc.\r
-24F094     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-90-B0-ED   (hex)               Apple, Inc.\r
-90B0ED     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-C4-B3-01   (hex)               Apple, Inc.\r
-C4B301     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-E0-5F-45   (hex)               Apple, Inc.\r
-E05F45     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-48-3B-38   (hex)               Apple, Inc.\r
-483B38     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-E0-C7-67   (hex)               Apple, Inc.\r
-E0C767     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-1C-9E-46   (hex)               Apple, Inc.\r
-1C9E46     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-0C-D7-46   (hex)               Apple, Inc.\r
-0CD746     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-44-00-10   (hex)               Apple, Inc.\r
-440010     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-E4-98-D6   (hex)               Apple, Inc.\r
-E498D6     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-60-69-44   (hex)               Apple, Inc.\r
-606944     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-04-52-F3   (hex)               Apple, Inc.\r
-0452F3     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-24-1E-EB   (hex)               Apple, Inc.\r
-241EEB     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-F4-31-C3   (hex)               Apple, Inc.\r
-F431C3     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-64-A5-C3   (hex)               Apple, Inc.\r
-64A5C3     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-BC-92-6B   (hex)               Apple, Inc.\r
-BC926B     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-50-E4   (hex)               Apple, Inc.\r
-0050E4     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-30-65   (hex)               Apple, Inc.\r
-003065     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-0A-27   (hex)               Apple, Inc.\r
-000A27     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-14-51   (hex)               Apple, Inc.\r
-001451     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-8C-7B-9D   (hex)               Apple, Inc.\r
-8C7B9D     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-88-C6-63   (hex)               Apple, Inc.\r
-88C663     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-C8-2A-14   (hex)               Apple, Inc.\r
-C82A14     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-98-03-D8   (hex)               Apple, Inc.\r
-9803D8     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-8C-58-77   (hex)               Apple, Inc.\r
-8C5877     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-19-E3   (hex)               Apple, Inc.\r
-0019E3     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-23-12   (hex)               Apple, Inc.\r
-002312     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-23-32   (hex)               Apple, Inc.\r
-002332     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-24-36   (hex)               Apple, Inc.\r
-002436     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-25-4B   (hex)               Apple, Inc.\r
-00254B     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-26-BB   (hex)               Apple, Inc.\r
-0026BB     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-70-F0-87   (hex)               Apple, Inc.\r
-70F087     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-88-6B-6E   (hex)               Apple, Inc.\r
-886B6E     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-4C-74-BF   (hex)               Apple, Inc.\r
-4C74BF     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-E8-06-88   (hex)               Apple, Inc.\r
-E80688     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-CC-08-E0   (hex)               Apple, Inc.\r
-CC08E0     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-58-55-CA   (hex)               Apple, Inc.\r
-5855CA     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-5C-09-47   (hex)               Apple, Inc.\r
-5C0947     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-38-89-2C   (hex)               Apple, Inc.\r
-38892C     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-40-83-1D   (hex)               Apple, Inc.\r
-40831D     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-50-BC-96   (hex)               Apple, Inc.\r
-50BC96     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-B4-C0-F5   (hex)               Shenzhen TINNO Mobile Technology Corp.\r
-B4C0F5     (base 16)           Shenzhen TINNO Mobile Technology Corp.\r
-                               4/F, H-3 Building, Qiao Cheng Eastern Industrial Park, Overseas Chinese Town, Shenzhen \r
-                               Shenzhen   guangdong  518053\r
-                               CN\r
-\r
-74-12-BB   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
-7412BB     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
-                               No.5 DongXin Road\r
-                               Wuhan  Hubei  430074\r
-                               CN\r
-\r
-98-5A-EB   (hex)               Apple, Inc.\r
-985AEB     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-20-78-F0   (hex)               Apple, Inc.\r
-2078F0     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-78-D7-5F   (hex)               Apple, Inc.\r
-78D75F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-E0-AC-CB   (hex)               Apple, Inc.\r
-E0ACCB     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-98-E0-D9   (hex)               Apple, Inc.\r
-98E0D9     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-C0-CE-CD   (hex)               Apple, Inc.\r
-C0CECD     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-70-E7-2C   (hex)               Apple, Inc.\r
-70E72C     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-D0-33-11   (hex)               Apple, Inc.\r
-D03311     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-5C-AD-CF   (hex)               Apple, Inc.\r
-5CADCF     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-6D-52   (hex)               Apple, Inc.\r
-006D52     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-48-43-7C   (hex)               Apple, Inc.\r
-48437C     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-34-A3-95   (hex)               Apple, Inc.\r
-34A395     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-9C-F3-87   (hex)               Apple, Inc.\r
-9CF387     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-A8-5B-78   (hex)               Apple, Inc.\r
-A85B78     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-90-8D-6C   (hex)               Apple, Inc.\r
-908D6C     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-0C-15-39   (hex)               Apple, Inc.\r
-0C1539     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-BC-4C-C4   (hex)               Apple, Inc.\r
-BC4CC4     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-0C-BC-9F   (hex)               Apple, Inc.\r
-0CBC9F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-A4-5E-60   (hex)               Apple, Inc.\r
-A45E60     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-54-4E-90   (hex)               Apple, Inc.\r
-544E90     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-9C-E6-5E   (hex)               Apple, Inc.\r
-9CE65E     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-90-DD-5D   (hex)               Apple, Inc.\r
-90DD5D     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-08-F6-9C   (hex)               Apple, Inc.\r
-08F69C     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-D4-61-DA   (hex)               Apple, Inc.\r
-D461DA     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-C8-D0-83   (hex)               Apple, Inc.\r
-C8D083     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-88-E9-FE   (hex)               Apple, Inc.\r
-88E9FE     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-88-AE-07   (hex)               Apple, Inc.\r
-88AE07     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-18-AF-8F   (hex)               Apple, Inc.\r
-18AF8F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-C8-B5-B7   (hex)               Apple, Inc.\r
-C8B5B7     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-A8-BB-CF   (hex)               Apple, Inc.\r
-A8BBCF     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-90-B2-1F   (hex)               Apple, Inc.\r
-90B21F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-B8-E8-56   (hex)               Apple, Inc.\r
-B8E856     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-14-99-E2   (hex)               Apple, Inc.\r
-1499E2     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-B4-18-D1   (hex)               Apple, Inc.\r
-B418D1     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-80-00-6E   (hex)               Apple, Inc.\r
-80006E     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-60-D9-C7   (hex)               Apple, Inc.\r
-60D9C7     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-C8-F6-50   (hex)               Apple, Inc.\r
-C8F650     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-1C-1A-C0   (hex)               Apple, Inc.\r
-1C1AC0     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-E0-66-78   (hex)               Apple, Inc.\r
-E06678     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-5C-8D-4E   (hex)               Apple, Inc.\r
-5C8D4E     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-C0-F2-FB   (hex)               Apple, Inc.\r
-C0F2FB     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-00-F7-6F   (hex)               Apple, Inc.\r
-00F76F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-AC-87-A3   (hex)               Apple, Inc.\r
-AC87A3     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-54-26-96   (hex)               Apple, Inc.\r
-542696     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-D8-D1-CB   (hex)               Apple, Inc.\r
-D8D1CB     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-64-A3-CB   (hex)               Apple, Inc.\r
-64A3CB     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-44-FB-42   (hex)               Apple, Inc.\r
-44FB42     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-F4-1B-A1   (hex)               Apple, Inc.\r
-F41BA1     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-3C-E0-72   (hex)               Apple, Inc.\r
-3CE072     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-E8-8D-28   (hex)               Apple, Inc.\r
-E88D28     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-CC-78-5F   (hex)               Apple, Inc.\r
-CC785F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-AC-3C-0B   (hex)               Apple, Inc.\r
-AC3C0B     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-88-CB-87   (hex)               Apple, Inc.\r
-88CB87     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-EC-35-86   (hex)               Apple, Inc.\r
-EC3586     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-F0-C1-F1   (hex)               Apple, Inc.\r
-F0C1F1     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-F4-F9-51   (hex)               Apple, Inc.\r
-F4F951     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-8C-FA-BA   (hex)               Apple, Inc.\r
-8CFABA     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-5C-95-AE   (hex)               Apple, Inc.\r
-5C95AE     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-E0-C9-7A   (hex)               Apple, Inc.\r
-E0C97A     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-BC-52-B7   (hex)               Apple, Inc.\r
-BC52B7     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-14-10-9F   (hex)               Apple, Inc.\r
-14109F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
-\r
-0C-F8-93   (hex)               ARRIS Group, Inc.\r
-0CF893     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-14-AB-F0   (hex)               ARRIS Group, Inc.\r
-14ABF0     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-AC-B3-13   (hex)               ARRIS Group, Inc.\r
-ACB313     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-30-60-23   (hex)               ARRIS Group, Inc.\r
-306023     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-00-1D-D6   (hex)               ARRIS Group, Inc.\r
-001DD6     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-1C-1B-68   (hex)               ARRIS Group, Inc.\r
-1C1B68     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-44-E1-37   (hex)               ARRIS Group, Inc.\r
-44E137     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-E8-33-81   (hex)               ARRIS Group, Inc.\r
-E83381     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-84-61-A0   (hex)               ARRIS Group, Inc.\r
-8461A0     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-60-19-71   (hex)               ARRIS Group, Inc.\r
-601971     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-00-00-CA   (hex)               ARRIS Group, Inc.\r
-0000CA     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-00-15-96   (hex)               ARRIS Group, Inc.\r
-001596     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-00-15-A2   (hex)               ARRIS Group, Inc.\r
-0015A2     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-00-13-11   (hex)               ARRIS Group, Inc.\r
-001311     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-7C-26-34   (hex)               ARRIS Group, Inc.\r
-7C2634     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-10-05-B1   (hex)               ARRIS Group, Inc.\r
-1005B1     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-10-86-8C   (hex)               ARRIS Group, Inc.\r
-10868C     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-00-1D-D1   (hex)               ARRIS Group, Inc.\r
-001DD1     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-00-26-D9   (hex)               ARRIS Group, Inc.\r
-0026D9     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-28-C8-7A   (hex)               ARRIS Group, Inc.\r
-28C87A     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-54-E2-E0   (hex)               ARRIS Group, Inc.\r
-54E2E0     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-A0-55-DE   (hex)               ARRIS Group, Inc.\r
-A055DE     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-A0-C5-62   (hex)               ARRIS Group, Inc.\r
-A0C562     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-FC-6F-B7   (hex)               ARRIS Group, Inc.\r
-FC6FB7     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
-                               US\r
-\r
-00-D0-37   (hex)               ARRIS Group, Inc.\r
-00D037     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-18-35-D1   (hex)               ARRIS Group, Inc.\r
-1835D1     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+1C-AB-A7   (hex)               Apple, Inc.\r
+1CABA7     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-4C-38-D8   (hex)               ARRIS Group, Inc.\r
-4C38D8     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+78-4F-43   (hex)               Apple, Inc.\r
+784F43     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-A8-9F-EC   (hex)               ARRIS Group, Inc.\r
-A89FEC     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+40-4D-7F   (hex)               Apple, Inc.\r
+404D7F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-0C-EA-C9   (hex)               ARRIS Group, Inc.\r
-0CEAC9     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+7C-04-D0   (hex)               Apple, Inc.\r
+7C04D0     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-F8-8B-37   (hex)               ARRIS Group, Inc.\r
-F88B37     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+BC-9F-EF   (hex)               Apple, Inc.\r
+BC9FEF     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-44-34-A7   (hex)               ARRIS Group, Inc.\r
-4434A7     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+88-66-A5   (hex)               Apple, Inc.\r
+8866A5     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-18-A4   (hex)               ARRIS Group, Inc.\r
-0018A4     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+88-E8-7F   (hex)               Apple, Inc.\r
+88E87F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-1A-1B   (hex)               ARRIS Group, Inc.\r
-001A1B     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+B8-53-AC   (hex)               Apple, Inc.\r
+B853AC     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-14-9A   (hex)               ARRIS Group, Inc.\r
-00149A     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+2C-33-61   (hex)               Apple, Inc.\r
+2C3361     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-13-71   (hex)               ARRIS Group, Inc.\r
-001371     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+A8-60-B6   (hex)               Apple, Inc.\r
+A860B6     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-1D-BE   (hex)               ARRIS Group, Inc.\r
-001DBE     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+24-F0-94   (hex)               Apple, Inc.\r
+24F094     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-1E-5A   (hex)               ARRIS Group, Inc.\r
-001E5A     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+90-B0-ED   (hex)               Apple, Inc.\r
+90B0ED     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-1D-6B   (hex)               ARRIS Group, Inc.\r
-001D6B     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+C4-B3-01   (hex)               Apple, Inc.\r
+C4B301     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-1C-C1   (hex)               ARRIS Group, Inc.\r
-001CC1     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+E0-5F-45   (hex)               Apple, Inc.\r
+E05F45     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-1C-11   (hex)               ARRIS Group, Inc.\r
-001C11     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+48-3B-38   (hex)               Apple, Inc.\r
+483B38     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-1F-7E   (hex)               ARRIS Group, Inc.\r
-001F7E     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+E0-C7-67   (hex)               Apple, Inc.\r
+E0C767     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-24-95   (hex)               ARRIS Group, Inc.\r
-002495     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+1C-9E-46   (hex)               Apple, Inc.\r
+1C9E46     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-2C-9E-5F   (hex)               ARRIS Group, Inc.\r
-2C9E5F     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+0C-D7-46   (hex)               Apple, Inc.\r
+0CD746     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-C8-AA-21   (hex)               ARRIS Group, Inc.\r
-C8AA21     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+44-00-10   (hex)               Apple, Inc.\r
+440010     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-34-1F-E4   (hex)               ARRIS Group, Inc.\r
-341FE4     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+E4-98-D6   (hex)               Apple, Inc.\r
+E498D6     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-40-0D-10   (hex)               ARRIS Group, Inc.\r
-400D10     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+60-69-44   (hex)               Apple, Inc.\r
+606944     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-1A-DB   (hex)               ARRIS Group, Inc.\r
-001ADB     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+04-52-F3   (hex)               Apple, Inc.\r
+0452F3     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-23-75   (hex)               ARRIS Group, Inc.\r
-002375     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+24-1E-EB   (hex)               Apple, Inc.\r
+241EEB     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-24-A1   (hex)               ARRIS Group, Inc.\r
-0024A1     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+F4-31-C3   (hex)               Apple, Inc.\r
+F431C3     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-A4-ED-4E   (hex)               ARRIS Group, Inc.\r
-A4ED4E     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+64-A5-C3   (hex)               Apple, Inc.\r
+64A5C3     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-26-42   (hex)               ARRIS Group, Inc.\r
-002642     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+BC-92-6B   (hex)               Apple, Inc.\r
+BC926B     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-15-CE   (hex)               ARRIS Group, Inc.\r
-0015CE     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+00-50-E4   (hex)               Apple, Inc.\r
+0050E4     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-20-40   (hex)               ARRIS Group, Inc.\r
-002040     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+00-30-65   (hex)               Apple, Inc.\r
+003065     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-11-AE   (hex)               ARRIS Group, Inc.\r
-0011AE     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+00-0A-27   (hex)               Apple, Inc.\r
+000A27     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-0F-9F   (hex)               ARRIS Group, Inc.\r
-000F9F     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+00-14-51   (hex)               Apple, Inc.\r
+001451     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-0B-06   (hex)               ARRIS Group, Inc.\r
-000B06     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+8C-7B-9D   (hex)               Apple, Inc.\r
+8C7B9D     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-15-2F   (hex)               ARRIS Group, Inc.\r
-00152F     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+88-C6-63   (hex)               Apple, Inc.\r
+88C663     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-11-1A   (hex)               ARRIS Group, Inc.\r
-00111A     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+C8-2A-14   (hex)               Apple, Inc.\r
+C82A14     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-16-26   (hex)               ARRIS Group, Inc.\r
-001626     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+98-03-D8   (hex)               Apple, Inc.\r
+9803D8     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-CF-C0   (hex)               China Mobile Group Device Co.,Ltd.\r
-00CFC0     (base 16)           China Mobile Group Device Co.,Ltd.\r
-                               32 Xuanwumen West Street,Xicheng District\r
-                               Beijing    100053\r
-                               CN\r
+8C-58-77   (hex)               Apple, Inc.\r
+8C5877     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-0C-73-EB   (hex)               IEEE Registration Authority\r
-0C73EB     (base 16)           IEEE Registration Authority\r
-                               445 Hoes Lane\r
-                               Piscataway  NJ  08554\r
+00-19-E3   (hex)               Apple, Inc.\r
+0019E3     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-10-65-30   (hex)               Dell Inc.\r
-106530     (base 16)           Dell Inc.\r
-                               One Dell Way\r
-                               Round Rock  TX  78682\r
+00-23-12   (hex)               Apple, Inc.\r
+002312     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-B4-E0-1D   (hex)               CONCEPTION ELECTRONIQUE\r
-B4E01D     (base 16)           CONCEPTION ELECTRONIQUE\r
-                               3 boulevard de l'europe\r
-                               NEUFCHATEL EN BRAY    76270\r
-                               FR\r
+00-23-32   (hex)               Apple, Inc.\r
+002332     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-1C-00-42   (hex)               NARI Technology Co., Ltd.\r
-1C0042     (base 16)           NARI Technology Co., Ltd.\r
-                               NO.19 Chengxin Avenue, Nanjing\r
-                               Nanjing    211106\r
-                               CN\r
+00-24-36   (hex)               Apple, Inc.\r
+002436     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-70-1D-08   (hex)               99IOT Shenzhen co.,ltd\r
-701D08     (base 16)           99IOT Shenzhen co.,ltd\r
-                               609C north block, Cangsong Building, Tairan Seven Road, Futian District\r
-                               Shenzhen  Guangdong  518000\r
-                               CN\r
+00-25-4B   (hex)               Apple, Inc.\r
+00254B     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-00-E0-09   (hex)               Stratus Technologies\r
-00E009     (base 16)           Stratus Technologies\r
-                               5 Mill and Main Place, Suite 500\r
-                               Maynard  MA  01754\r
+00-26-BB   (hex)               Apple, Inc.\r
+0026BB     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-30-0A-C5   (hex)               Ruio telecommunication technologies Co., Limited\r
-300AC5     (base 16)           Ruio telecommunication technologies Co., Limited\r
-                               Room 2501, Broadegate Software Building, No,1003 Keyuan Road,\r
-                               Shenzhen  guangdong  518000\r
-                               CN\r
+70-F0-87   (hex)               Apple, Inc.\r
+70F087     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-3C-24-F0   (hex)               IEEE Registration Authority\r
-3C24F0     (base 16)           IEEE Registration Authority\r
-                               445 Hoes Lane\r
-                               Piscataway  NJ  08554\r
+88-6B-6E   (hex)               Apple, Inc.\r
+886B6E     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-C8-86-29   (hex)               Shenzhen Duubee Intelligent Technologies Co.,LTD.\r
-C88629     (base 16)           Shenzhen Duubee Intelligent Technologies Co.,LTD.\r
-                               9F, Block B, Unicenter, Xin’an Sub district, Bao’an District\r
-                               Shenzhen  GuangDong  518000\r
-                               CN\r
+4C-74-BF   (hex)               Apple, Inc.\r
+4C74BF     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-A0-E6-17   (hex)               MATIS\r
-A0E617     (base 16)           MATIS\r
-                               2/F,Hatchobori MIYATA Bldg.,1-8-2,\r
-                               Shintomi,Chuo-Ku,  Tokyo  104-0041\r
-                               JP\r
+E8-06-88   (hex)               Apple, Inc.\r
+E80688     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-50-5B-C2   (hex)               Liteon Technology Corporation\r
-505BC2     (base 16)           Liteon Technology Corporation\r
-                               4F, 90, Chien 1 Road\r
-                               New Taipei City  Taiwan  23585\r
-                               TW\r
+CC-08-E0   (hex)               Apple, Inc.\r
+CC08E0     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-FC-90-FA   (hex)               Independent Technologies\r
-FC90FA     (base 16)           Independent Technologies\r
-                               1960 Ridgeview Rd\r
-                               Blair  NE  68008\r
+58-55-CA   (hex)               Apple, Inc.\r
+5855CA     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-CC-C9-2C   (hex)               Schindler - PORT Technology\r
-CCC92C     (base 16)           Schindler - PORT Technology\r
-                               via della Pace 22\r
-                               Locarno  Ticino  6600\r
-                               CH\r
+5C-09-47   (hex)               Apple, Inc.\r
+5C0947     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-7C-2E-BD   (hex)               Google, Inc.\r
-7C2EBD     (base 16)           Google, Inc.\r
-                               1600 Amphitheatre Parkway\r
-                               Mountain View  CA  94043\r
+38-89-2C   (hex)               Apple, Inc.\r
+38892C     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-E0-BA-B4   (hex)               Arrcus, Inc\r
-E0BAB4     (base 16)           Arrcus, Inc\r
-                               2077 Gateway Pl, Suite 250,\r
-                               San Jose  CA  95110\r
+40-83-1D   (hex)               Apple, Inc.\r
+40831D     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-0A-DB   (hex)               Trilliant\r
-000ADB     (base 16)           Trilliant\r
-                               401 Harrison Oaks Blvd. Suite 300\r
-                               Cary  NC  27513\r
+50-BC-96   (hex)               Apple, Inc.\r
+50BC96     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-3C-F5-CC   (hex)               New H3C Technologies Co., Ltd\r
-3CF5CC     (base 16)           New H3C Technologies Co., Ltd\r
-                               466 Changhe Road, Binjiang District\r
-                               Hangzhou  Zhejiang  310052\r
+B4-C0-F5   (hex)               Shenzhen TINNO Mobile Technology Corp.\r
+B4C0F5     (base 16)           Shenzhen TINNO Mobile Technology Corp.\r
+                               4/F, H-3 Building, Qiao Cheng Eastern Industrial Park, Overseas Chinese Town, Shenzhen \r
+                               Shenzhen   guangdong  518053\r
                                CN\r
 \r
-74-EC-42   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
-74EC42     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+74-12-BB   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+7412BB     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
                                No.5 DongXin Road\r
                                Wuhan  Hubei  430074\r
                                CN\r
 \r
-2C-58-4F   (hex)               ARRIS Group, Inc.\r
-2C584F     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+98-5A-EB   (hex)               Apple, Inc.\r
+985AEB     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-90-A1-37   (hex)               Beijing Splendidtel Communication Technology Co,. Ltd\r
-90A137     (base 16)           Beijing Splendidtel Communication Technology Co,. Ltd\r
-                               4 Floor,Taixing Tower,No.11 Huayuan East Road. Haidian District\r
-                               Beijing  Beijing  100191\r
-                               CN\r
-\r
-78-AF-E4   (hex)               Comau S.p.A\r
-78AFE4     (base 16)           Comau S.p.A\r
-                               via Rivalta 30\r
-                               Grugliasco  (TO)  10095\r
-                               IT\r
-\r
-AC-3B-77   (hex)               Sagemcom Broadband SAS\r
-AC3B77     (base 16)           Sagemcom Broadband SAS\r
-                               250, route de l'Empereur\r
-                               Rueil Malmaison Cedex  hauts de seine  92848\r
-                               FR\r
-\r
-00-C3-F4   (hex)               Samsung Electronics Co.,Ltd\r
-00C3F4     (base 16)           Samsung Electronics Co.,Ltd\r
-                               129, Samsung-ro, Youngtongl-Gu\r
-                               Suwon  Gyeonggi-Do  16677\r
-                               KR\r
-\r
-B8-8A-EC   (hex)               Nintendo Co.,Ltd\r
-B88AEC     (base 16)           Nintendo Co.,Ltd\r
-                               11-1 HOKOTATE-CHO KAMITOBA,MINAMI-KU\r
-                               KYOTO  KYOTO  601-8501\r
-                               JP\r
-\r
-F4-BF-80   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-F4BF80     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-30-45-96   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-304596     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-F8-C3-9E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-F8C39E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-D0-D7-83   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-D0D783     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-D8-F3-DB   (hex)               Post CH AG\r
-D8F3DB     (base 16)           Post CH AG\r
-                               Wankdorfallee 4\r
-                               Bern    3030\r
-                               CH\r
-\r
-28-11-A5   (hex)               Bose Corporation\r
-2811A5     (base 16)           Bose Corporation\r
-                               The Mountain\r
-                               Framingham  MA  01701-9168\r
+20-78-F0   (hex)               Apple, Inc.\r
+2078F0     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-30-88-41   (hex)               Sichuan AI-Link Technology Co., Ltd.\r
-308841     (base 16)           Sichuan AI-Link Technology Co., Ltd.\r
-                               Anzhou,Industrial Park\r
-                               Anzhou,Industrial Park  Sichuan  621000\r
-                               CN\r
-\r
-80-50-F6   (hex)               ITEL MOBILE LIMITED\r
-8050F6     (base 16)           ITEL MOBILE LIMITED\r
-                               RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING  NO.7 KO FAI ROAD, YAU TONG, KLN, H.K\r
-                               Hong Kong  KOWLOON  999077\r
-                               HK\r
-\r
-0C-01-DB   (hex)               Infinix mobility limited\r
-0C01DB     (base 16)           Infinix mobility limited\r
-                               RMS 05-15, 13A/F SOUTH TOWER WORLD FINANCE CTR HARBOUR CITY 17 CANTON RD TST KLN HONG KONG\r
-                               HongKong  HongKong  999077\r
-                               HK\r
-\r
-3C-F4-F9   (hex)               Moda-InnoChips\r
-3CF4F9     (base 16)           Moda-InnoChips\r
-                               42-7(Wonsi-Dong),Dongsan-ro 27beon-gil,Danwon-gu\r
-                               Ansan-si   Gyeonggi-Do  15433\r
-                               KR\r
-\r
-40-1B-5F   (hex)               WEIFANG GOERTEK ELECTRONICS CO.,LTD\r
-401B5F     (base 16)           WEIFANG GOERTEK ELECTRONICS CO.,LTD\r
-                               Gaoxin 2 Road,Free Trade Zone,Weifang,Shandong,261205,P.R.China\r
-                               Weifang  Shandong  261205\r
-                               CN\r
-\r
-F0-4B-3A   (hex)               Juniper Networks\r
-F04B3A     (base 16)           Juniper Networks\r
-                               1133 Innovation Way\r
-                               Sunnyvale  CA  94089\r
+78-D7-5F   (hex)               Apple, Inc.\r
+78D75F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-D0-58-FC   (hex)               BSkyB Ltd\r
-D058FC     (base 16)           BSkyB Ltd\r
-                               130 Kings Road\r
-                               Brentwood  Essex  08854\r
-                               GB\r
-\r
-74-EB-80   (hex)               Samsung Electronics Co.,Ltd\r
-74EB80     (base 16)           Samsung Electronics Co.,Ltd\r
-                               #94-1, Imsoo-Dong\r
-                               Gumi  Gyeongbuk  730-350\r
-                               KR\r
-\r
-A8-2B-B9   (hex)               Samsung Electronics Co.,Ltd\r
-A82BB9     (base 16)           Samsung Electronics Co.,Ltd\r
-                               #94-1, Imsoo-Dong\r
-                               Gumi  Gyeongbuk  730-350\r
-                               KR\r
-\r
-00-10-17   (hex)               Bosch Access Systems GmbH\r
-001017     (base 16)           Bosch Access Systems GmbH\r
-                               Charlottenburger Allee 50            \r
-                               AACHEN      D-52068 \r
-                               DE\r
-\r
-74-B9-1E   (hex)               Nanjing Bestway Automation System Co., Ltd\r
-74B91E     (base 16)           Nanjing Bestway Automation System Co., Ltd\r
-                               #50 Baoxiang Road, Jiangning Bin Jiang Economic Development Zone\r
-                               nanjing  jiangsu  211161\r
-                               CN\r
-\r
-60-05-8A   (hex)               Hitachi Metals, Ltd.\r
-60058A     (base 16)           Hitachi Metals, Ltd.\r
-                               Shinagawa Season Terrace, 2-70, Konan 1-chome\r
-                               Minato-ku  Tokyo  108-8224\r
-                               JP\r
-\r
-00-21-06   (hex)               RIM Testing Services\r
-002106     (base 16)           RIM Testing Services\r
-                               440 Phillip Street\r
-                               Waterloo  ON  N2L 5R9\r
-                               CA\r
-\r
-14-57-9F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-14579F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-14-4F-8A   (hex)               Intel Corporate\r
-144F8A     (base 16)           Intel Corporate\r
-                               Lot 8, Jalan Hi-Tech 2/3\r
-                               Kulim  Kedah  09000\r
-                               MY\r
-\r
-88-2D-53   (hex)               Baidu Online Network Technology (Beijing) Co., Ltd.\r
-882D53     (base 16)           Baidu Online Network Technology (Beijing) Co., Ltd.\r
-                               Baidu Campus, No.10 Shangdi 10th Street, Haidian District Beijing 100085 CN\r
-                               Beijing    100085\r
-                               CN\r
-\r
-A4-DA-32   (hex)               Texas Instruments\r
-A4DA32     (base 16)           Texas Instruments\r
-                               12500 TI Blvd\r
-                               Dallas  TX  75243\r
+E0-AC-CB   (hex)               Apple, Inc.\r
+E0ACCB     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-8C-14-B4   (hex)               zte corporation\r
-8C14B4     (base 16)           zte corporation\r
-                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
-                               shenzhen  guangdong  518057\r
-                               CN\r
-\r
-3C-98-72   (hex)               Sercomm Corporation.\r
-3C9872     (base 16)           Sercomm Corporation.\r
-                               3F,No.81,Yu-Yih Rd.,Chu-Nan Chen\r
-                               Miao-Lih Hsuan    115\r
-                               TW\r
-\r
-8C-04-FF   (hex)               Technicolor CH USA Inc.\r
-8C04FF     (base 16)           Technicolor CH USA Inc.\r
-                               5030 Sugarloaf Parkway Bldg 6\r
-                               Lawrenceville  GA  30044\r
+98-E0-D9   (hex)               Apple, Inc.\r
+98E0D9     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-FC-91-14   (hex)               Technicolor CH USA Inc.\r
-FC9114     (base 16)           Technicolor CH USA Inc.\r
-                               5030 Sugarloaf Parkway Bldg 6\r
-                               Lawrenceville  GA  30044\r
+C0-CE-CD   (hex)               Apple, Inc.\r
+C0CECD     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-50-09-59   (hex)               Technicolor CH USA Inc.\r
-500959     (base 16)           Technicolor CH USA Inc.\r
-                               5030 Sugarloaf Parkway Bldg 6\r
-                               Lawrenceville  GA  30044\r
+70-E7-2C   (hex)               Apple, Inc.\r
+70E72C     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-14-B7-F8   (hex)               Technicolor CH USA Inc.\r
-14B7F8     (base 16)           Technicolor CH USA Inc.\r
-                               5030 Sugarloaf Parkway Bldg 6\r
-                               Lawrenceville  GA  30044\r
+D0-33-11   (hex)               Apple, Inc.\r
+D03311     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-B4-2A-0E   (hex)               Technicolor CH USA Inc.\r
-B42A0E     (base 16)           Technicolor CH USA Inc.\r
-                               5030 Sugarloaf Parkway Bldg 6\r
-                               Lawrenceville  GA  30044\r
+5C-AD-CF   (hex)               Apple, Inc.\r
+5CADCF     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-B0-18-86   (hex)               SmarDTV\r
-B01886     (base 16)           SmarDTV\r
-                               Route de Genève 22\r
-                               Cheseaux    CH-1033 \r
-                               CH\r
-\r
-08-95-2A   (hex)               Technicolor CH USA Inc.\r
-08952A     (base 16)           Technicolor CH USA Inc.\r
-                               5030 Sugarloaf Parkway Bldg 6\r
-                               Lawrenceville  GA  30044\r
+00-6D-52   (hex)               Apple, Inc.\r
+006D52     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-88-F7-C7   (hex)               Technicolor CH USA Inc.\r
-88F7C7     (base 16)           Technicolor CH USA Inc.\r
-                               5030 Sugarloaf Parkway Bldg 6\r
-                               Lawrenceville  GA  30044\r
+48-43-7C   (hex)               Apple, Inc.\r
+48437C     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-30-24-32   (hex)               Intel Corporate\r
-302432     (base 16)           Intel Corporate\r
-                               Lot 8, Jalan Hi-Tech 2/3\r
-                               Kulim  Kedah  09000\r
-                               MY\r
-\r
-A8-99-69   (hex)               Dell Inc.\r
-A89969     (base 16)           Dell Inc.\r
-                               One Dell Way\r
-                               Round Rock  TX  78682\r
+34-A3-95   (hex)               Apple, Inc.\r
+34A395     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-88-01-18   (hex)               BLT Co\r
-880118     (base 16)           BLT Co\r
-                               Dongan-gu Burim-ro 170beon-gil 44\r
-                               Anyangsi  Kyunggido  14055\r
-                               KR\r
-\r
-4C-21-D0   (hex)               Sony Mobile Communications Inc\r
-4C21D0     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-30-75-12   (hex)               Sony Mobile Communications Inc\r
-307512     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-C4-3A-BE   (hex)               Sony Mobile Communications Inc\r
-C43ABE     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-40-B8-37   (hex)               Sony Mobile Communications Inc\r
-40B837     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-40-40-A7   (hex)               Sony Mobile Communications Inc\r
-4040A7     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-84-C7-EA   (hex)               Sony Mobile Communications Inc\r
-84C7EA     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-84-17-EF   (hex)               Technicolor CH USA Inc.\r
-8417EF     (base 16)           Technicolor CH USA Inc.\r
-                               5030 Sugarloaf Parkway Bldg 6\r
-                               Lawrenceville  GA  30044\r
+9C-F3-87   (hex)               Apple, Inc.\r
+9CF387     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-10-59-17   (hex)               Tonal\r
-105917     (base 16)           Tonal\r
-                               1074 Folsom St\r
-                               San Francisco    94103\r
+A8-5B-78   (hex)               Apple, Inc.\r
+A85B78     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-38-8B-59   (hex)               Google, Inc.\r
-388B59     (base 16)           Google, Inc.\r
-                               1600 Amphitheatre Parkway\r
-                               Mountain View  CA  94043\r
+90-8D-6C   (hex)               Apple, Inc.\r
+908D6C     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-94-CE-2C   (hex)               Sony Mobile Communications Inc\r
-94CE2C     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-D0-51-62   (hex)               Sony Mobile Communications Inc\r
-D05162     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-00-25-E7   (hex)               Sony Mobile Communications Inc\r
-0025E7     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-40-2B-A1   (hex)               Sony Mobile Communications Inc\r
-402BA1     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-34-0A-98   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-340A98     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-60-F1-8A   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-60F18A     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-00-12-EE   (hex)               Sony Mobile Communications Inc\r
-0012EE     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-00-16-20   (hex)               Sony Mobile Communications Inc\r
-001620     (base 16)           Sony Mobile Communications Inc\r
-                               4-12-3 Higashi – Shinagawa\r
-                               Shinagawa-ku  Tokyo  140-0002\r
-                               JP\r
-\r
-28-9E-97   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-289E97     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-24-FA-F3   (hex)               Shanghai Flexem Technology Co.,Ltd.\r
-24FAF3     (base 16)           Shanghai Flexem Technology Co.,Ltd.\r
-                               Room 804, C6 Building,No.52 Bay Valley Technology Park, Lane 1688 North Guoquan Road, Yangpu District.\r
-                               Shanghai    200438\r
-                               CN\r
-\r
-AC-DE-48   (hex)               Private\r
-ACDE48     (base 16)           Private\r
-\r
-0C-8C-24   (hex)               SHENZHEN BILIAN ELECTRONIC CO.,LTD\r
-0C8C24     (base 16)           SHENZHEN BILIAN ELECTRONIC CO.,LTD\r
-                               NO.268, Fuqian Rd, Jutang community, Guanlan Town, Longhua New district\r
-                               shenzhen  guangdong  518000\r
-                               CN\r
-\r
-7C-6B-9C   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-7C6B9C     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,\r
-                               DONG GUAN  GUANG DONG  523860\r
-                               CN\r
-\r
-1C-C3-EB   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-1CC3EB     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,\r
-                               DONG GUAN  GUANG DONG  523860\r
-                               CN\r
-\r
-30-D6-59   (hex)               Merging Technologies SA\r
-30D659     (base 16)           Merging Technologies SA\r
-                               Le Verney 4\r
-                               Puidoux  Outside the U.S or Canada  1070\r
-                               CH\r
+0C-15-39   (hex)               Apple, Inc.\r
+0C1539     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-C4-95-00   (hex)               Amazon Technologies Inc.\r
-C49500     (base 16)           Amazon Technologies Inc.\r
-                               P.O Box 8102\r
-                               Reno  NV  89507\r
+BC-4C-C4   (hex)               Apple, Inc.\r
+BC4CC4     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-F0-F0-8F   (hex)               Nextek Solutions Pte Ltd\r
-F0F08F     (base 16)           Nextek Solutions Pte Ltd\r
-                               105 Cecil Street, #06-01 The Octagon\r
-                               Singapore  Singapore  069534\r
-                               SG\r
+0C-BC-9F   (hex)               Apple, Inc.\r
+0CBC9F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-E4-D1-24   (hex)                Mojo Networks, Inc.\r
-E4D124     (base 16)            Mojo Networks, Inc.\r
-                               339 N.Bernardo Ave\r
-                               Mountain View  CA  94043\r
+A4-5E-60   (hex)               Apple, Inc.\r
+A45E60     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-28-3A-4D   (hex)               Cloud Network Technology (Samoa) Limited\r
-283A4D     (base 16)           Cloud Network Technology (Samoa) Limited\r
-                               Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District\r
-                               Chongqing  Chongqing  401332\r
-                               CN\r
+54-4E-90   (hex)               Apple, Inc.\r
+544E90     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-CC-3A-DF   (hex)               Private\r
-CC3ADF     (base 16)           Private\r
+9C-E6-5E   (hex)               Apple, Inc.\r
+9CE65E     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-B4-CE-FE   (hex)               James Czekaj\r
-B4CEFE     (base 16)           James Czekaj\r
-                               41716 Waterfall Rd\r
-                               Northville  MI  48168\r
+90-DD-5D   (hex)               Apple, Inc.\r
+90DD5D     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-20-1A-06   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-201A06     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-                               NO. 15, THE 3RD Street KUNSHAN EXPORT PROCESSING ZONE\r
-                               KUNSHAN  SUZHOU  215300\r
-                               CN\r
+08-F6-9C   (hex)               Apple, Inc.\r
+08F69C     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-B8-88-E3   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-B888E3     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-                               No.25, Third Avenue, A Zone, Kunshan Comprehensive Free Trade Zone,, Jiangsu, \r
-                               KUNSHAN   SUZHOU  215300\r
-                               CN\r
+D4-61-DA   (hex)               Apple, Inc.\r
+D461DA     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-00-26-22   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-002622     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-                               NO. 25, THE 3RD Street KUNSHAN EXPORT PROCESSING ZONE\r
-                               KUNSHAN  SUZHOU  215300\r
-                               CN\r
+C8-D0-83   (hex)               Apple, Inc.\r
+C8D083     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-00-1E-EC   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-001EEC     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-                               NO. 25, THE 3RD Street\r
-                               KUNSHAN CITY  SUZHOU PROVINCE  215300\r
-                               CN\r
+88-E9-FE   (hex)               Apple, Inc.\r
+88E9FE     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-DC-0E-A1   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-DC0EA1     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-                               No.25, Third Avenue, A Zone, Kunshan Comprehensive Free Trade Zone,, Jiangsu, \r
-                               KUNSHAN   SUZHOU  215300\r
-                               CN\r
+88-AE-07   (hex)               Apple, Inc.\r
+88AE07     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-FC-45-96   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-FC4596     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-                                NO. 25, THE 3RD Street KUNSHAN EXPORT PROCESSING ZON\r
-                               KUNSHAN  SUZHOU  215300\r
-                               CN\r
+18-AF-8F   (hex)               Apple, Inc.\r
+18AF8F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-20-89-84   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-208984     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
-                               No.25, Third Avenue, A Zone, Kunshan Comprehensive Free Trade Zone\r
-                               KUNSHAN   SUZHOU   215300 \r
-                               CN\r
+C8-B5-B7   (hex)               Apple, Inc.\r
+C8B5B7     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-58-03-FB   (hex)               Hangzhou Hikvision Digital Technology Co.,Ltd.\r
-5803FB     (base 16)           Hangzhou Hikvision Digital Technology Co.,Ltd.\r
-                               No.555 Qianmo Road\r
-                               Hangzhou  Zhejiang  310052\r
-                               CN\r
+A8-BB-CF   (hex)               Apple, Inc.\r
+A8BBCF     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-58-FD-BE   (hex)               Shenzhen Taikaida Technology Co., Ltd\r
-58FDBE     (base 16)           Shenzhen Taikaida Technology Co., Ltd\r
-                               Shenzhen Baoan District Fuyong town Fengtang road Xintian building 613\r
-                               shenzhen    518102\r
-                               CN\r
+90-B2-1F   (hex)               Apple, Inc.\r
+90B21F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-F8-CC-6E   (hex)               DEPO Electronics Ltd\r
-F8CC6E     (base 16)           DEPO Electronics Ltd\r
-                               12, kommunalnaya zona Krasnogorsk-Mitino\r
-                               Krasnogorsk  Moscow region  143404\r
-                               RU\r
+B8-E8-56   (hex)               Apple, Inc.\r
+B8E856     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-80-6F-B0   (hex)               Texas Instruments\r
-806FB0     (base 16)           Texas Instruments\r
-                               12500 TI Blvd\r
-                               Dallas  TX  75243\r
+14-99-E2   (hex)               Apple, Inc.\r
+1499E2     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-14-94-2F   (hex)               USYS CO.,LTD.\r
-14942F     (base 16)           USYS CO.,LTD.\r
-                               #911, SeoulTechnoPark, 232, Gongneung-ro, Nowon-gu\r
-                               Seoul    KS013\r
-                               KR\r
-\r
-B8-69-F4   (hex)               Routerboard.com\r
-B869F4     (base 16)           Routerboard.com\r
-                               Mikrotikls SIA\r
-                               Riga  Riga  LV1009\r
-                               LV\r
+B4-18-D1   (hex)               Apple, Inc.\r
+B418D1     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-34-2E-B6   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-342EB6     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+80-00-6E   (hex)               Apple, Inc.\r
+80006E     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-90-2B-D2   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-902BD2     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+60-D9-C7   (hex)               Apple, Inc.\r
+60D9C7     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-9C-7F-57   (hex)               UNIC Memory Technology Co Ltd\r
-9C7F57     (base 16)           UNIC Memory Technology Co Ltd\r
-                               15/F, Building B, Truth Plaza, No.7 Zhichun Road\r
-                               Beijing  Haidian District  102208\r
-                               CN\r
+C8-F6-50   (hex)               Apple, Inc.\r
+C8F650     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-C4-6E-7B   (hex)               SHENZHEN RF-LINK TECHNOLOGY CO.,LTD.\r
-C46E7B     (base 16)           SHENZHEN RF-LINK TECHNOLOGY CO.,LTD.\r
-                               Bldg56A,6/F,Baotian Rd3,Xixiang Town,Baoan District,\r
-                               Shenzhen  Guangdong  518000\r
-                               CN\r
+1C-1A-C0   (hex)               Apple, Inc.\r
+1C1AC0     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-28-D0-CB   (hex)               Cambridge Communication Systems Ltd\r
-28D0CB     (base 16)           Cambridge Communication Systems Ltd\r
-                               Victory House, Vision Park, Chivers Way, Histon\r
-                               Cambridge    CB24 9ZR\r
-                               GB\r
+E0-66-78   (hex)               Apple, Inc.\r
+E06678     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-44-65-7F   (hex)               Calix Inc.\r
-44657F     (base 16)           Calix Inc.\r
-                               1035 North McDowell Boulevard\r
-                               Petaluma  MN  94954\r
+5C-8D-4E   (hex)               Apple, Inc.\r
+5C8D4E     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-00-1A-31   (hex)               SCAN COIN AB\r
-001A31     (base 16)           SCAN COIN AB\r
-                               Jagershillgatan 26\r
-                               Malmö  Skåne  21375\r
-                               SE\r
+C0-F2-FB   (hex)               Apple, Inc.\r
+C0F2FB     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-70-4F-08   (hex)               Shenzhen Huisheng Information Technology Co., Ltd.\r
-704F08     (base 16)           Shenzhen Huisheng Information Technology Co., Ltd.\r
-                                Room 4A-205, Software Industry Base, Yuehai St\r
-                               Nanshan District, Shenzhen  Guangdong  518000\r
-                               CN\r
+00-F7-6F   (hex)               Apple, Inc.\r
+00F76F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-BC-A5-8B   (hex)               Samsung Electronics Co.,Ltd\r
-BCA58B     (base 16)           Samsung Electronics Co.,Ltd\r
-                               #94-1, Imsoo-Dong\r
-                               Gumi  Gyeongbuk  730-350\r
-                               KR\r
+AC-87-A3   (hex)               Apple, Inc.\r
+AC87A3     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-70-FD-46   (hex)               Samsung Electronics Co.,Ltd\r
-70FD46     (base 16)           Samsung Electronics Co.,Ltd\r
-                               #94-1, Imsoo-Dong\r
-                               Gumi  Gyeongbuk  730-350\r
-                               KR\r
+54-26-96   (hex)               Apple, Inc.\r
+542696     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-D0-7F-A0   (hex)               Samsung Electronics Co.,Ltd\r
-D07FA0     (base 16)           Samsung Electronics Co.,Ltd\r
-                               #94-1, Imsoo-Dong\r
-                               Gumi  Gyeongbuk  730-350\r
-                               KR\r
+D8-D1-CB   (hex)               Apple, Inc.\r
+D8D1CB     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-F0-9F-FC   (hex)               SHARP Corporation\r
-F09FFC     (base 16)           SHARP Corporation\r
-                               1 Takumi-cho, Sakai-ku\r
-                               Sakai City  Osaka  590-8522\r
-                               JP\r
+64-A3-CB   (hex)               Apple, Inc.\r
+64A3CB     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-30-42-A1   (hex)               ilumisys Inc. DBA Toggled\r
-3042A1     (base 16)           ilumisys Inc. DBA Toggled\r
-                               1820 E. Big Beaver Road\r
-                               Troy  MI  48083\r
+44-FB-42   (hex)               Apple, Inc.\r
+44FB42     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-20-DE-88   (hex)               IC Realtime LLC\r
-20DE88     (base 16)           IC Realtime LLC\r
-                               3050 N Andrews Ave Ext.\r
-                               Pompano Beach  FL  33064\r
+F4-1B-A1   (hex)               Apple, Inc.\r
+F41BA1     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-14-37-19   (hex)               PT Prakarsa Visi Valutama\r
-143719     (base 16)           PT Prakarsa Visi Valutama\r
-                               Jl. Cideng Timur No.11D\r
-                               Jakarta Pusat  Indonesia  10130\r
-                               ID\r
+3C-E0-72   (hex)               Apple, Inc.\r
+3CE072     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-58-2F-40   (hex)               Nintendo Co.,Ltd\r
-582F40     (base 16)           Nintendo Co.,Ltd\r
-                               11-1 HOKOTATE-CHO KAMITOBA,MINAMI-KU\r
-                               KYOTO  KYOTO  601-8501\r
-                               JP\r
+E8-8D-28   (hex)               Apple, Inc.\r
+E88D28     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-6C-6C-D3   (hex)               Cisco Systems, Inc\r
-6C6CD3     (base 16)           Cisco Systems, Inc\r
-                               80 West Tasman Drive\r
-                               San Jose  CA  94568\r
+CC-78-5F   (hex)               Apple, Inc.\r
+CC785F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-30-16-8D   (hex)               ProLon\r
-30168D     (base 16)           ProLon\r
-                               17510 rue Charles, Suite 100\r
-                               Mirabel  Quebec   J7J 1X9\r
-                               CA\r
+AC-3C-0B   (hex)               Apple, Inc.\r
+AC3C0B     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-80-30-E0   (hex)               Hewlett Packard Enterprise\r
-8030E0     (base 16)           Hewlett Packard Enterprise\r
-                               8000 Foothills Blvd.\r
-                               Roseville  CA  95747\r
+88-CB-87   (hex)               Apple, Inc.\r
+88CB87     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-E8-5D-86   (hex)               CHANG YOW TECHNOLOGIES INTERNATIONAL CO.,LTD.\r
-E85D86     (base 16)           CHANG YOW TECHNOLOGIES INTERNATIONAL CO.,LTD.\r
-                                No 88 Shuren 6th St Wufong District\r
-                               Taichung    413\r
-                               TW\r
+EC-35-86   (hex)               Apple, Inc.\r
+EC3586     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-1C-25-E1   (hex)               China Mobile IOT Company Limited\r
-1C25E1     (base 16)           China Mobile IOT Company Limited\r
-                               NO.8 Yu Ma Road, NanAn Area\r
-                               Chongqing  Chongqing  401336\r
-                               CN\r
+F0-C1-F1   (hex)               Apple, Inc.\r
+F0C1F1     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-AC-54-74   (hex)               China Mobile IOT Company Limited\r
-AC5474     (base 16)           China Mobile IOT Company Limited\r
-                               NO.8 Yu Ma Road, NanAn Area\r
-                               Chongqing  Chongqing  401336\r
-                               CN\r
+F4-F9-51   (hex)               Apple, Inc.\r
+F4F951     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-00-40-84   (hex)               Honeywell International HPS\r
-004084     (base 16)           Honeywell International HPS\r
-                               \r
-                               Fort Washington  PA  19034\r
+8C-FA-BA   (hex)               Apple, Inc.\r
+8CFABA     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
                                US\r
 \r
-64-5D-86   (hex)               Intel Corporate\r
-645D86     (base 16)           Intel Corporate\r
-                               Lot 8, Jalan Hi-Tech 2/3\r
-                               Kulim  Kedah  09000\r
-                               MY\r
+5C-95-AE   (hex)               Apple, Inc.\r
+5C95AE     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-8C-92-46   (hex)               Oerlikon Textile Gmbh&Co.KG\r
-8C9246     (base 16)           Oerlikon Textile Gmbh&Co.KG\r
-                               NO.9 Changyang Street\r
-                               Suzhou  Jiangsu  215000\r
-                               CN\r
+E0-C9-7A   (hex)               Apple, Inc.\r
+E0C97A     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-7C-24-0C   (hex)               Telechips, Inc.\r
-7C240C     (base 16)           Telechips, Inc.\r
-                               19F~23F,Luther Bldg.42, Olympic-ro 35da-gil, Songpa-gu,\r
-                               Seoul  Seoul  05510\r
-                               KR\r
+BC-52-B7   (hex)               Apple, Inc.\r
+BC52B7     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-CC-F0-FD   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-CCF0FD     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District, Hangzhou, Zhejiang\r
-                               Hangzhou  Zhejiang  310000\r
-                               CN\r
+14-10-9F   (hex)               Apple, Inc.\r
+14109F     (base 16)           Apple, Inc.\r
+                               1 Infinite Loop\r
+                               Cupertino  CA  95014\r
+                               US\r
 \r
-4C-01-43   (hex)               eero inc.\r
-4C0143     (base 16)           eero inc.\r
-                               660 3rd Street\r
-                               San Francisco  CA  94107\r
+0C-F8-93   (hex)               ARRIS Group, Inc.\r
+0CF893     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-9C-AA-1B   (hex)               Microsoft Corporation\r
-9CAA1B     (base 16)           Microsoft Corporation\r
-                               One Microsoft Way\r
-                               REDMOND  WA  98052\r
+14-AB-F0   (hex)               ARRIS Group, Inc.\r
+14ABF0     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-18-D7-17   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-18D717     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,\r
-                               DONG GUAN  GUANG DONG  523860\r
-                               CN\r
+AC-B3-13   (hex)               ARRIS Group, Inc.\r
+ACB313     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-0C-9A-42   (hex)               FN-LINK TECHNOLOGY LIMITED\r
-0C9A42     (base 16)           FN-LINK TECHNOLOGY LIMITED\r
-                               A Building,HuiXin industial park,No 31, YongHe road, Fuyong town, Bao'an District\r
-                               SHENZHEN  GUANGDONG  518100\r
-                               CN\r
+30-60-23   (hex)               ARRIS Group, Inc.\r
+306023     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-60-4B-AA   (hex)               Magic Leap, Inc.\r
-604BAA     (base 16)           Magic Leap, Inc.\r
-                               1855 Griffin Rd, Room B454\r
-                               Dania Beach  FL  33004\r
+00-1D-D6   (hex)               ARRIS Group, Inc.\r
+001DD6     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-54-81-2D   (hex)               PAX Computer Technology(Shenzhen) Ltd.\r
-54812D     (base 16)           PAX Computer Technology(Shenzhen) Ltd.\r
-                               4/F, No.3 Building, Software Park, Second Central Science-Tech Road, High-Tech\r
-                               Shenzhen  GuangDong  518057\r
-                               CN\r
+1C-1B-68   (hex)               ARRIS Group, Inc.\r
+1C1B68     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-30-A1-FA   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-30A1FA     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+44-E1-37   (hex)               ARRIS Group, Inc.\r
+44E137     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-88-10-8F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-88108F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+E8-33-81   (hex)               ARRIS Group, Inc.\r
+E83381     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-0C-53-31   (hex)               ETH Zurich\r
-0C5331     (base 16)           ETH Zurich\r
-                               Dept. Computer Science, Universitätstr. 6\r
-                               Zurich  ZH  8092\r
-                               CH\r
+84-61-A0   (hex)               ARRIS Group, Inc.\r
+8461A0     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-F4-63-1F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-F4631F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+60-19-71   (hex)               ARRIS Group, Inc.\r
+601971     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-24-FB-65   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-24FB65     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+00-00-CA   (hex)               ARRIS Group, Inc.\r
+0000CA     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-EC-84-B4   (hex)               CIG SHANGHAI CO LTD\r
-EC84B4     (base 16)           CIG SHANGHAI CO LTD\r
-                               5th Floor, Building 8 No 2388 Chenhang Road\r
-                               SHANGHAI    201114\r
-                               CN\r
+00-15-96   (hex)               ARRIS Group, Inc.\r
+001596     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-EC-B3-13   (hex)               SHENZHEN GONGJIN ELECTRONICS CO.,LT\r
-ECB313     (base 16)           SHENZHEN GONGJIN ELECTRONICS CO.,LT\r
-                               SONGGANG\r
-                               SHENZHEN  GUANGDONG  518105\r
-                               CN\r
+00-15-A2   (hex)               ARRIS Group, Inc.\r
+0015A2     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-8C-FE-74   (hex)               Ruckus Wireless\r
-8CFE74     (base 16)           Ruckus Wireless\r
-                               350 West Java Drive\r
-                               Sunnyvale  CA  94089\r
+00-13-11   (hex)               ARRIS Group, Inc.\r
+001311     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-84-6A-66   (hex)               Sumitomo Kizai  Co.,Ltd.\r
-846A66     (base 16)           Sumitomo Kizai  Co.,Ltd.\r
-                               1-45-1higashiikebukuro\r
-                               tosimaku  tokyo  170-0013\r
-                               JP\r
+7C-26-34   (hex)               ARRIS Group, Inc.\r
+7C2634     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-DC-37-57   (hex)               Integrated Device Technology (Malaysia) Sdn. Bhd.\r
-DC3757     (base 16)           Integrated Device Technology (Malaysia) Sdn. Bhd.\r
-                               Phase 3, Bayan Lepas FIZ\r
-                               Bayan Lepas  Penang  11900\r
-                               MY\r
+10-05-B1   (hex)               ARRIS Group, Inc.\r
+1005B1     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-00-90-04   (hex)               3COM EUROPE LTD\r
-009004     (base 16)           3COM EUROPE LTD\r
-                               3COM CENTRE, BOUNDARY WAY\r
-                               HERTS.  HP2 7YU    \r
-                               GB\r
+10-86-8C   (hex)               ARRIS Group, Inc.\r
+10868C     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-00-50-99   (hex)               3COM EUROPE LTD\r
-005099     (base 16)           3COM EUROPE LTD\r
-                               BOUNDARY WAY\r
-                               HERTS. HP2 7YU    \r
-                               GB\r
+00-1D-D1   (hex)               ARRIS Group, Inc.\r
+001DD1     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-08-00-4E   (hex)               3COM EUROPE LTD\r
-08004E     (base 16)           3COM EUROPE LTD\r
-                               3COM CENTRE\r
-                                 UNITED  KINGDOM\r
-                               GB\r
+00-26-D9   (hex)               ARRIS Group, Inc.\r
+0026D9     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-00-D0-96   (hex)               3COM EUROPE LTD\r
-00D096     (base 16)           3COM EUROPE LTD\r
-                               BOUNDARY WAY\r
-                                 UNITED  KINGDOM\r
-                               GB\r
+28-C8-7A   (hex)               ARRIS Group, Inc.\r
+28C87A     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-00-30-1E   (hex)               3COM EUROPE LTD\r
-00301E     (base 16)           3COM EUROPE LTD\r
-                               BOUNDARY WAY\r
-                                 UNITED  KINGDOM\r
-                               GB\r
+54-E2-E0   (hex)               ARRIS Group, Inc.\r
+54E2E0     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-00-0A-5E   (hex)               3COM\r
-000A5E     (base 16)           3COM\r
-                               5400 Bayfront Plaza\r
-                               Santa Clara  CA  95052-8145\r
+A0-55-DE   (hex)               ARRIS Group, Inc.\r
+A055DE     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-00-06-8C   (hex)               3COM\r
-00068C     (base 16)           3COM\r
-                               5400 BAYFRONT PLAZA\r
-                               SANTA CLARA  CA  95052\r
+A0-C5-62   (hex)               ARRIS Group, Inc.\r
+A0C562     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-00-01-03   (hex)               3COM\r
-000103     (base 16)           3COM\r
-                               5400 BAYFRONT PLAZA\r
-                               SANTA CLARA  CA  95052\r
+FC-6F-B7   (hex)               ARRIS Group, Inc.\r
+FC6FB7     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-02-60-8C   (hex)               3COM\r
-02608C     (base 16)           3COM\r
-                               5400 BAYFRONT PLAZA\r
-                               SANTA CLARA  CA  95052\r
+00-D0-37   (hex)               ARRIS Group, Inc.\r
+00D037     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-00-1B-6E   (hex)               Keysight Technologies, Inc.\r
-001B6E     (base 16)           Keysight Technologies, Inc.\r
-                               1400 Fountaingrove Pkwy.\r
-                               Santa Rosa  CA  95403\r
+18-35-D1   (hex)               ARRIS Group, Inc.\r
+1835D1     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-00-8C-FA   (hex)               INVENTEC CORPORATION\r
-008CFA     (base 16)           INVENTEC CORPORATION\r
-                               No. 255, Jen-Ho Road Sec. 2, 33547,\r
-                               Tachi  Taoyuan  33547\r
-                               TW\r
+4C-38-D8   (hex)               ARRIS Group, Inc.\r
+4C38D8     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-C4-23-A2   (hex)               PT. Emsonic Indonesia\r
-C423A2     (base 16)           PT. Emsonic Indonesia\r
-                               Jl.Timor Blok E5, MM2100 Industrial Town Jatiwangi Cikarang Barat\r
-                               Bekasi  Jawa Barat  17530\r
-                               ID\r
+A8-9F-EC   (hex)               ARRIS Group, Inc.\r
+A89FEC     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-B4-CB-57   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-B4CB57     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,\r
-                               DONG GUAN  GUANG DONG  523860\r
-                               CN\r
+0C-EA-C9   (hex)               ARRIS Group, Inc.\r
+0CEAC9     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-BC-B2-2B   (hex)               EM-Tech\r
-BCB22B     (base 16)           EM-Tech\r
-                               40, Changwon-daero 1144beon-gil\r
-                               Seongsan-gu Changwon  Gyeongsangnam-do  KR 642-120\r
-                               KR\r
+F8-8B-37   (hex)               ARRIS Group, Inc.\r
+F88B37     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-94-91-7F   (hex)               ASKEY COMPUTER CORP\r
-94917F     (base 16)           ASKEY COMPUTER CORP\r
-                               10F,No.119,JIANKANG RD,ZHONGHE DIST\r
-                               NEW TAIPEI  TAIWAN  23585\r
-                               TW\r
+44-34-A7   (hex)               ARRIS Group, Inc.\r
+4434A7     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-C8-BA-E9   (hex)               QDIS\r
-C8BAE9     (base 16)           QDIS\r
-                               #512, Buliding B, 168 GaSanDigital 1st, GeumChun-Gu\r
-                               SEOUL    08507\r
-                               KR\r
+00-18-A4   (hex)               ARRIS Group, Inc.\r
+0018A4     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-B8-6A-97   (hex)               Edgecore Networks Corporation\r
-B86A97     (base 16)           Edgecore Networks Corporation\r
-                               1 Creation RD 3.\r
-                               Hsinchu    30077\r
-                               TW\r
+00-1A-1B   (hex)               ARRIS Group, Inc.\r
+001A1B     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-94-29-8D   (hex)               Shanghai AdaptComm Technology Co., Ltd.\r
-94298D     (base 16)           Shanghai AdaptComm Technology Co., Ltd.\r
-                               3rd Floor, Building 14, No. 518 Xinzhuan Road, Songjiang District,\r
-                               Shanghai    201600\r
-                               CN\r
+00-14-9A   (hex)               ARRIS Group, Inc.\r
+00149A     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-EC-79-F2   (hex)               Startel\r
-EC79F2     (base 16)           Startel\r
-                               Xi Chuang Industrial Park,Second industrial district of Guan Long Village,Xili town ,Nanshan District\r
-                               Shenzhen  Guangdong  518055\r
-                               CN\r
+00-13-71   (hex)               ARRIS Group, Inc.\r
+001371     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-28-31-66   (hex)               vivo Mobile Communication Co., Ltd.\r
-283166     (base 16)           vivo Mobile Communication Co., Ltd.\r
-                               #283,BBK Road\r
-                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
-                               CN\r
+00-1D-BE   (hex)               ARRIS Group, Inc.\r
+001DBE     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-4C-12-65   (hex)               ARRIS Group, Inc.\r
-4C1265     (base 16)           ARRIS Group, Inc.\r
+00-1E-5A   (hex)               ARRIS Group, Inc.\r
+001E5A     (base 16)           ARRIS Group, Inc.\r
                                6450 Sequence Drive\r
                                San Diego  CA  92121\r
                                US\r
 \r
-00-90-7F   (hex)               WatchGuard Technologies, Inc.\r
-00907F     (base 16)           WatchGuard Technologies, Inc.\r
-                               605 Fifth Ave. S\r
-                               Seattle  WA  98104-3892\r
+00-1D-6B   (hex)               ARRIS Group, Inc.\r
+001D6B     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-F0-B0-14   (hex)               AVM Audiovisuelles Marketing und Computersysteme GmbH\r
-F0B014     (base 16)           AVM Audiovisuelles Marketing und Computersysteme GmbH\r
-                               Alt-Moabit 95\r
-                               Berlin  Berlin  10559\r
-                               DE\r
+00-1C-C1   (hex)               ARRIS Group, Inc.\r
+001CC1     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-A8-10-87   (hex)               Texas Instruments\r
-A81087     (base 16)           Texas Instruments\r
-                               12500 TI Blvd\r
-                               Dallas  TX  75243\r
+00-1C-11   (hex)               ARRIS Group, Inc.\r
+001C11     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-AC-86-74   (hex)               Open Mesh, Inc.\r
-AC8674     (base 16)           Open Mesh, Inc.\r
-                               111 SW 5th Ave Ste1150\r
-                               Portland  OR  97204\r
+00-1F-7E   (hex)               ARRIS Group, Inc.\r
+001F7E     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-18-E8-29   (hex)               Ubiquiti Networks Inc.\r
-18E829     (base 16)           Ubiquiti Networks Inc.\r
-                               2580 Orchard Pkwy\r
-                               San Jose  CA  95131\r
+00-24-95   (hex)               ARRIS Group, Inc.\r
+002495     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-18-1D-EA   (hex)               Intel Corporate\r
-181DEA     (base 16)           Intel Corporate\r
-                               Lot 8, Jalan Hi-Tech 2/3\r
-                               Kulim  Kedah  09000\r
-                               MY\r
+2C-9E-5F   (hex)               ARRIS Group, Inc.\r
+2C9E5F     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-F0-D7-DC   (hex)               Wesine (Wuhan) Technology Co., Ltd.\r
-F0D7DC     (base 16)           Wesine (Wuhan) Technology Co., Ltd.\r
-                               10th Floor, Building 2, SBI Venture Street, Hongshan District\r
-                               Wuhan  Hubei  430074\r
-                               CN\r
+C8-AA-21   (hex)               ARRIS Group, Inc.\r
+C8AA21     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-44-E4-EE   (hex)               Wistron Neweb Corporation\r
-44E4EE     (base 16)           Wistron Neweb Corporation\r
-                               No.20,Park Avenue II,Hsinchu Science Park\r
-                               Hsin-Chu  R.O.C.  308\r
-                               TW\r
+34-1F-E4   (hex)               ARRIS Group, Inc.\r
+341FE4     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-30-0A-60   (hex)               IEEE Registration Authority\r
-300A60     (base 16)           IEEE Registration Authority\r
-                               445 Hoes Lane\r
-                               Piscataway  NJ  08554\r
+40-0D-10   (hex)               ARRIS Group, Inc.\r
+400D10     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-2C-79-D7   (hex)               Sagemcom Broadband SAS\r
-2C79D7     (base 16)           Sagemcom Broadband SAS\r
-                               250, route de l'Empereur\r
-                               Rueil Malmaison Cedex  hauts de seine  92848\r
-                               FR\r
+00-1A-DB   (hex)               ARRIS Group, Inc.\r
+001ADB     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-10-C2-2F   (hex)               China Entropy Co., Ltd.\r
-10C22F     (base 16)           China Entropy Co., Ltd.\r
-                               Haidian District\r
-                               Beijing    100085\r
-                               CN\r
+00-23-75   (hex)               ARRIS Group, Inc.\r
+002375     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-C4-FD-E6   (hex)               DRTECH\r
-C4FDE6     (base 16)           DRTECH\r
-                               29, Dunchon-daero 541beon-gil, Jungwon-gu\r
-                               Seongnam  Gyeonggi-do  13216\r
-                               KR\r
+00-24-A1   (hex)               ARRIS Group, Inc.\r
+0024A1     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-44-47-CC   (hex)               Hangzhou Hikvision Digital Technology Co.,Ltd.\r
-4447CC     (base 16)           Hangzhou Hikvision Digital Technology Co.,Ltd.\r
-                               No.555 Qianmo Road\r
-                               Hangzhou  Zhejiang  310052\r
-                               CN\r
+A4-ED-4E   (hex)               ARRIS Group, Inc.\r
+A4ED4E     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-4C-D9-8F   (hex)               Dell Inc.\r
-4CD98F     (base 16)           Dell Inc.\r
-                               One Dell Way\r
-                               Round Rock  TX  78682\r
+00-26-42   (hex)               ARRIS Group, Inc.\r
+002642     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-E4-1D-2D   (hex)               Mellanox Technologies, Inc.\r
-E41D2D     (base 16)           Mellanox Technologies, Inc.\r
-                               350 Oakmead Parkway, Suite 100\r
-                               Sunnyvale  CA  94085\r
+00-15-CE   (hex)               ARRIS Group, Inc.\r
+0015CE     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-B0-AE-25   (hex)               Varikorea\r
-B0AE25     (base 16)           Varikorea\r
-                               #505 kolon digital tower aston, gasan, geumcheon\r
-                               seoul    08502\r
-                               KR\r
+00-20-40   (hex)               ARRIS Group, Inc.\r
+002040     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-44-00-49   (hex)               Amazon Technologies Inc.\r
-440049     (base 16)           Amazon Technologies Inc.\r
-                               P.O Box 8102\r
-                               Reno  NV  89507\r
+00-11-AE   (hex)               ARRIS Group, Inc.\r
+0011AE     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-C0-74-AD   (hex)               Grandstream Networks, Inc.\r
-C074AD     (base 16)           Grandstream Networks, Inc.\r
-                               1297 Beacon Street\r
-                               Brookline  MA  02446\r
+00-0F-9F   (hex)               ARRIS Group, Inc.\r
+000F9F     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-04-91-62   (hex)               Microchip Technology Inc.\r
-049162     (base 16)           Microchip Technology Inc.\r
-                               2355 W. Chandler Blvd.\r
-                               Chandler  AZ  85224\r
+00-0B-06   (hex)               ARRIS Group, Inc.\r
+000B06     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-98-18-88   (hex)               Cisco Meraki\r
-981888     (base 16)           Cisco Meraki\r
-                               500 Terry A. Francois Blvd\r
-                               San Francisco    94158\r
+00-15-2F   (hex)               ARRIS Group, Inc.\r
+00152F     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-74-B5-87   (hex)               Apple, Inc.\r
-74B587     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
+00-11-1A   (hex)               ARRIS Group, Inc.\r
+00111A     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-D8-1C-79   (hex)               Apple, Inc.\r
-D81C79     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
+00-16-26   (hex)               ARRIS Group, Inc.\r
+001626     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-8C-FE-57   (hex)               Apple, Inc.\r
-8CFE57     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
+00-CF-C0   (hex)               China Mobile Group Device Co.,Ltd.\r
+00CFC0     (base 16)           China Mobile Group Device Co.,Ltd.\r
+                               32 Xuanwumen West Street,Xicheng District\r
+                               Beijing    100053\r
+                               CN\r
+\r
+0C-73-EB   (hex)               IEEE Registration Authority\r
+0C73EB     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
                                US\r
 \r
-C0-A6-00   (hex)               Apple, Inc.\r
-C0A600     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
+10-65-30   (hex)               Dell Inc.\r
+106530     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
                                US\r
 \r
-CC-D4-A1   (hex)               MitraStar Technology Corp.\r
-CCD4A1     (base 16)           MitraStar Technology Corp.\r
-                               No. 6, Innovation Road II,\r
-                               Hsinchu    300\r
-                               TW\r
+B4-E0-1D   (hex)               CONCEPTION ELECTRONIQUE\r
+B4E01D     (base 16)           CONCEPTION ELECTRONIQUE\r
+                               3 boulevard de l'europe\r
+                               NEUFCHATEL EN BRAY    76270\r
+                               FR\r
 \r
-08-BA-5F   (hex)               Qingdao Hisense Electronics Co.,Ltd.\r
-08BA5F     (base 16)           Qingdao Hisense Electronics Co.,Ltd.\r
-                               Qianwangang Roard 218\r
-                               Qingdao  Shandong  266510\r
+1C-00-42   (hex)               NARI Technology Co., Ltd.\r
+1C0042     (base 16)           NARI Technology Co., Ltd.\r
+                               NO.19 Chengxin Avenue, Nanjing\r
+                               Nanjing    211106\r
                                CN\r
 \r
-54-06-8B   (hex)               Ningbo Deli Kebei Technology Co.LTD\r
-54068B     (base 16)           Ningbo Deli Kebei Technology Co.LTD\r
-                               zone 2nd , 301#, Road Xuxiake, Ninghai yuelong district\r
-                               ningbo  Zhejiang  315600\r
+70-1D-08   (hex)               99IOT Shenzhen co.,ltd\r
+701D08     (base 16)           99IOT Shenzhen co.,ltd\r
+                               609C north block, Cangsong Building, Tairan Seven Road, Futian District\r
+                               Shenzhen  Guangdong  518000\r
                                CN\r
 \r
-54-9F-AE   (hex)               iBASE Gaming Inc\r
-549FAE     (base 16)           iBASE Gaming Inc\r
-                               2F., No.542-17, Zhongzheng Rd\r
-                               Xinzhuang Dist., New Taipei City    24255\r
-                               TW\r
+00-E0-09   (hex)               Stratus Technologies\r
+00E009     (base 16)           Stratus Technologies\r
+                               5 Mill and Main Place, Suite 500\r
+                               Maynard  MA  01754\r
+                               US\r
 \r
-80-0D-D7   (hex)               Latticework, Inc\r
-800DD7     (base 16)           Latticework, Inc\r
-                               2210 O'Toole Ave, Suite 250\r
-                               San Jose  CA  95131\r
+30-0A-C5   (hex)               Ruio telecommunication technologies Co., Limited\r
+300AC5     (base 16)           Ruio telecommunication technologies Co., Limited\r
+                               Room 2501, Broadegate Software Building, No,1003 Keyuan Road,\r
+                               Shenzhen  guangdong  518000\r
+                               CN\r
+\r
+3C-24-F0   (hex)               IEEE Registration Authority\r
+3C24F0     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
                                US\r
 \r
-68-8F-2E   (hex)               Hitron Technologies. Inc\r
-688F2E     (base 16)           Hitron Technologies. Inc\r
-                               No. 1-8, Lising 1st Rd. Hsinchu Science Park, Hsinchu, 300, Taiwan, R.O.C\r
-                               Hsin-chu  Taiwan  300\r
+C8-86-29   (hex)               Shenzhen Duubee Intelligent Technologies Co.,LTD.\r
+C88629     (base 16)           Shenzhen Duubee Intelligent Technologies Co.,LTD.\r
+                               9F, Block B, Unicenter, Xin’an Sub district, Bao’an District\r
+                               Shenzhen  GuangDong  518000\r
+                               CN\r
+\r
+A0-E6-17   (hex)               MATIS\r
+A0E617     (base 16)           MATIS\r
+                               2/F,Hatchobori MIYATA Bldg.,1-8-2,\r
+                               Shintomi,Chuo-Ku,  Tokyo  104-0041\r
+                               JP\r
+\r
+50-5B-C2   (hex)               Liteon Technology Corporation\r
+505BC2     (base 16)           Liteon Technology Corporation\r
+                               4F, 90, Chien 1 Road\r
+                               New Taipei City  Taiwan  23585\r
                                TW\r
 \r
-80-69-33   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-806933     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+FC-90-FA   (hex)               Independent Technologies\r
+FC90FA     (base 16)           Independent Technologies\r
+                               1960 Ridgeview Rd\r
+                               Blair  NE  68008\r
+                               US\r
 \r
-C8-9C-13   (hex)               Inspiremobile\r
-C89C13     (base 16)           Inspiremobile\r
-                               Rm1412, Daeryung Techno-Town, 15th, 401 , Simin-daero, Dongan-gu\r
-                               Anyang-si  Gyeonggi-do  14057\r
-                               KR\r
+CC-C9-2C   (hex)               Schindler - PORT Technology\r
+CCC92C     (base 16)           Schindler - PORT Technology\r
+                               via della Pace 22\r
+                               Locarno  Ticino  6600\r
+                               CH\r
 \r
-E0-5D-5C   (hex)               Oy Everon Ab\r
-E05D5C     (base 16)           Oy Everon Ab\r
-                               Teräskatu 8\r
-                               Turku    20520\r
-                               FI\r
+7C-2E-BD   (hex)               Google, Inc.\r
+7C2EBD     (base 16)           Google, Inc.\r
+                               1600 Amphitheatre Parkway\r
+                               Mountain View  CA  94043\r
+                               US\r
 \r
-78-47-E3   (hex)               SICHUAN TIANYI COMHEART TELECOM CO.,LTD\r
-7847E3     (base 16)           SICHUAN TIANYI COMHEART TELECOM CO.,LTD\r
-                               NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, \r
-                               CHENGDU  SICHUAN  611330\r
-                               CN\r
+E0-BA-B4   (hex)               Arrcus, Inc\r
+E0BAB4     (base 16)           Arrcus, Inc\r
+                               2077 Gateway Pl, Suite 250,\r
+                               San Jose  CA  95110\r
+                               US\r
 \r
-6C-9B-C0   (hex)               Chemoptics Inc.\r
-6C9BC0     (base 16)           Chemoptics Inc.\r
-                               261, Techno 2-ro, Yuseong-gu\r
-                               Daejeon    34026\r
-                               KR\r
+00-0A-DB   (hex)               Trilliant\r
+000ADB     (base 16)           Trilliant\r
+                               401 Harrison Oaks Blvd. Suite 300\r
+                               Cary  NC  27513\r
+                               US\r
 \r
-A8-23-FE   (hex)               LG Electronics\r
-A823FE     (base 16)           LG Electronics\r
-                               222 LG-ro, JINWI-MYEON\r
-                               Pyeongtaek-si  Gyeonggi-do  451-713\r
-                               KR\r
+3C-F5-CC   (hex)               New H3C Technologies Co., Ltd\r
+3CF5CC     (base 16)           New H3C Technologies Co., Ltd\r
+                               466 Changhe Road, Binjiang District\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
 \r
-C0-78-78   (hex)               FLEXTRONICS MANUFACTURING(ZHUHAI)CO.,LTD.\r
-C07878     (base 16)           FLEXTRONICS MANUFACTURING(ZHUHAI)CO.,LTD.\r
-                               Xin Qing Science & Technology Industrial Park,Jin An Town,Doumen ,Zhuhai,Guangdong,PRC\r
-                               Zhuhai  Guangdong  519180\r
+74-EC-42   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
+74EC42     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
+                               No.5 DongXin Road\r
+                               Wuhan  Hubei  430074\r
                                CN\r
 \r
-E0-46-E5   (hex)               Gosuncn Technology Group Co., Ltd.\r
-E046E5     (base 16)           Gosuncn Technology Group Co., Ltd.\r
-                               6F, 2819 KaiChuang Blvd., Science Town, Huangpu District\r
-                               Guangzhou City   Guangdong  510530\r
+2C-58-4F   (hex)               ARRIS Group, Inc.\r
+2C584F     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+90-A1-37   (hex)               Beijing Splendidtel Communication Technology Co,. Ltd\r
+90A137     (base 16)           Beijing Splendidtel Communication Technology Co,. Ltd\r
+                               4 Floor,Taixing Tower,No.11 Huayuan East Road. Haidian District\r
+                               Beijing  Beijing  100191\r
                                CN\r
 \r
-30-13-89   (hex)               Siemens AG, Automations & Drives,\r
-301389     (base 16)           Siemens AG, Automations & Drives,\r
-                               Systems Engineering\r
-                               Fürth  Deutschlang  90766\r
-                               DE\r
+78-AF-E4   (hex)               Comau S.p.A\r
+78AFE4     (base 16)           Comau S.p.A\r
+                               via Rivalta 30\r
+                               Grugliasco  (TO)  10095\r
+                               IT\r
 \r
-F4-DB-E6   (hex)               Cisco Systems, Inc\r
-F4DBE6     (base 16)           Cisco Systems, Inc\r
-                               80 West Tasman Drive\r
-                               San Jose  CA  94568\r
-                               US\r
+AC-3B-77   (hex)               Sagemcom Broadband SAS\r
+AC3B77     (base 16)           Sagemcom Broadband SAS\r
+                               250, route de l'Empereur\r
+                               Rueil Malmaison Cedex  hauts de seine  92848\r
+                               FR\r
 \r
-DC-F4-01   (hex)               Dell Inc.\r
-DCF401     (base 16)           Dell Inc.\r
-                               One Dell Way\r
-                               Round Rock  TX  78682\r
-                               US\r
+00-C3-F4   (hex)               Samsung Electronics Co.,Ltd\r
+00C3F4     (base 16)           Samsung Electronics Co.,Ltd\r
+                               129, Samsung-ro, Youngtongl-Gu\r
+                               Suwon  Gyeonggi-Do  16677\r
+                               KR\r
 \r
-F4-95-1B   (hex)               Hefei Radio Communication Technology Co., Ltd \r
-F4951B     (base 16)           Hefei Radio Communication Technology Co., Ltd \r
-                                No.108, YinXing Road, High-tech Development Zone \r
-                               Hefei  Anhui  230088\r
-                               CN\r
+B8-8A-EC   (hex)               Nintendo Co.,Ltd\r
+B88AEC     (base 16)           Nintendo Co.,Ltd\r
+                               11-1 HOKOTATE-CHO KAMITOBA,MINAMI-KU\r
+                               KYOTO  KYOTO  601-8501\r
+                               JP\r
 \r
-D0-92-FA   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
-D092FA     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
-                               No.5 DongXin Road\r
-                               Wuhan  Hubei  430074\r
+F4-BF-80   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+F4BF80     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-E8-5A-D1   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
-E85AD1     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
-                               No.5 DongXin Road\r
-                               Wuhan  Hubei  430074\r
+30-45-96   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+304596     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-BC-75-96   (hex)               Beijing Broadwit Technology Co., Ltd.\r
-BC7596     (base 16)           Beijing Broadwit Technology Co., Ltd.\r
-                               Beijing Changping District Beijing International Information Industry Base Jizhida Building 3rd Floor Southeast\r
-                               Beijing  Beijing  10000\r
+F8-C3-9E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+F8C39E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-CC-72-86   (hex)               Xi'an Fengyu Information Technology Co., Ltd.\r
-CC7286     (base 16)           Xi'an Fengyu Information Technology Co., Ltd.\r
-                               5F, Block A, STRC, No.10, Zhangba 5th Road, Yanta\r
-                               Xi'an  Shaanxi  710077\r
+D0-D7-83   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+D0D783     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-04-92-26   (hex)               ASUSTek COMPUTER INC.\r
-049226     (base 16)           ASUSTek COMPUTER INC.\r
-                               15,Li-Te Rd., Peitou, Taipei 112, Taiwan\r
-                               Taipei  Taiwan  112\r
-                               TW\r
+D8-F3-DB   (hex)               Post CH AG\r
+D8F3DB     (base 16)           Post CH AG\r
+                               Wankdorfallee 4\r
+                               Bern    3030\r
+                               CH\r
 \r
-84-32-6F   (hex)               GUANGZHOU AVA ELECTRONICS TECHNOLOGY CO.,LTD \r
-84326F     (base 16)           GUANGZHOU AVA ELECTRONICS TECHNOLOGY CO.,LTD \r
-                               Science town luogang district guangzhou city branch bead road 232 profit people park 301, building 2\r
-                               guangzhou   guangdong  510000\r
+28-11-A5   (hex)               Bose Corporation\r
+2811A5     (base 16)           Bose Corporation\r
+                               The Mountain\r
+                               Framingham  MA  01701-9168\r
+                               US\r
+\r
+30-88-41   (hex)               Sichuan AI-Link Technology Co., Ltd.\r
+308841     (base 16)           Sichuan AI-Link Technology Co., Ltd.\r
+                               Anzhou,Industrial Park\r
+                               Anzhou,Industrial Park  Sichuan  621000\r
                                CN\r
 \r
-00-B8-B3   (hex)               Cisco Systems, Inc\r
-00B8B3     (base 16)           Cisco Systems, Inc\r
-                               80 West Tasman Drive\r
-                               San Jose  CA  94568\r
-                               US\r
+80-50-F6   (hex)               ITEL MOBILE LIMITED\r
+8050F6     (base 16)           ITEL MOBILE LIMITED\r
+                               RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING  NO.7 KO FAI ROAD, YAU TONG, KLN, H.K\r
+                               Hong Kong  KOWLOON  999077\r
+                               HK\r
 \r
-A8-BC-9C   (hex)               Cloud Light Technology Limited\r
-A8BC9C     (base 16)           Cloud Light Technology Limited\r
-                               3/F, 6 Science Park East Avenue Hong Kong Science Park Shatin, N.T., Hong Kong\r
-                               Hong Kong    00000\r
+0C-01-DB   (hex)               Infinix mobility limited\r
+0C01DB     (base 16)           Infinix mobility limited\r
+                               RMS 05-15, 13A/F SOUTH TOWER WORLD FINANCE CTR HARBOUR CITY 17 CANTON RD TST KLN HONG KONG\r
+                               HongKong  HongKong  999077\r
                                HK\r
 \r
-0C-B4-A4   (hex)               Xintai Automobile Intelligent Network Technology\r
-0CB4A4     (base 16)           Xintai Automobile Intelligent Network Technology\r
-                               Room3703E Changfu Jinmao Building,Shihua Road\r
-                               Futian Duty Free Zone,Fubao Street,Futian District  Shenzhen City  518000\r
+3C-F4-F9   (hex)               Moda-InnoChips\r
+3CF4F9     (base 16)           Moda-InnoChips\r
+                               42-7(Wonsi-Dong),Dongsan-ro 27beon-gil,Danwon-gu\r
+                               Ansan-si   Gyeonggi-Do  15433\r
+                               KR\r
+\r
+40-1B-5F   (hex)               WEIFANG GOERTEK ELECTRONICS CO.,LTD\r
+401B5F     (base 16)           WEIFANG GOERTEK ELECTRONICS CO.,LTD\r
+                               Gaoxin 2 Road,Free Trade Zone,Weifang,Shandong,261205,P.R.China\r
+                               Weifang  Shandong  261205\r
                                CN\r
 \r
-2C-CC-44   (hex)               Sony Interactive Entertainment Inc.\r
-2CCC44     (base 16)           Sony Interactive Entertainment Inc.\r
-                               1-7-1 Konan\r
-                               Minato-ku  Tokyo  108-0075\r
-                               JP\r
+F0-4B-3A   (hex)               Juniper Networks\r
+F04B3A     (base 16)           Juniper Networks\r
+                               1133 Innovation Way\r
+                               Sunnyvale  CA  94089\r
+                               US\r
 \r
-FC-AA-B6   (hex)               Samsung Electronics Co.,Ltd\r
-FCAAB6     (base 16)           Samsung Electronics Co.,Ltd\r
-                               #94-1, Imsoo-Dong\r
-                               Gumi  Gyeongbuk  730-350\r
-                               KR\r
+D0-58-FC   (hex)               BSkyB Ltd\r
+D058FC     (base 16)           BSkyB Ltd\r
+                               130 Kings Road\r
+                               Brentwood  Essex  08854\r
+                               GB\r
 \r
-C0-BD-C8   (hex)               Samsung Electronics Co.,Ltd\r
-C0BDC8     (base 16)           Samsung Electronics Co.,Ltd\r
+74-EB-80   (hex)               Samsung Electronics Co.,Ltd\r
+74EB80     (base 16)           Samsung Electronics Co.,Ltd\r
                                #94-1, Imsoo-Dong\r
                                Gumi  Gyeongbuk  730-350\r
                                KR\r
 \r
-A8-87-B3   (hex)               Samsung Electronics Co.,Ltd\r
-A887B3     (base 16)           Samsung Electronics Co.,Ltd\r
+A8-2B-B9   (hex)               Samsung Electronics Co.,Ltd\r
+A82BB9     (base 16)           Samsung Electronics Co.,Ltd\r
                                #94-1, Imsoo-Dong\r
                                Gumi  Gyeongbuk  730-350\r
                                KR\r
 \r
-00-D0-2D   (hex)               Resideo\r
-00D02D     (base 16)           Resideo\r
-                               2 Corporate Center Dr.\r
-                               Melville  NY  11747\r
-                               US\r
-\r
-10-12-B4   (hex)               SICHUAN TIANYI COMHEART TELECOM CO.,LTD\r
-1012B4     (base 16)           SICHUAN TIANYI COMHEART TELECOM CO.,LTD\r
-                               NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, \r
-                               CHENGDU  SICHUAN  611330\r
-                               CN\r
-\r
-3C-9B-D6   (hex)               Vizio, Inc\r
-3C9BD6     (base 16)           Vizio, Inc\r
-                               39 Tesla\r
-                               Irvine  CA  92618\r
-                               US\r
-\r
-74-23-44   (hex)               Xiaomi Communications Co Ltd\r
-742344     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
-                               CN\r
+00-10-17   (hex)               Bosch Access Systems GmbH\r
+001017     (base 16)           Bosch Access Systems GmbH\r
+                               Charlottenburger Allee 50            \r
+                               AACHEN      D-52068 \r
+                               DE\r
 \r
-D8-32-E3   (hex)               Xiaomi Communications Co Ltd\r
-D832E3     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+74-B9-1E   (hex)               Nanjing Bestway Automation System Co., Ltd\r
+74B91E     (base 16)           Nanjing Bestway Automation System Co., Ltd\r
+                               #50 Baoxiang Road, Jiangning Bin Jiang Economic Development Zone\r
+                               nanjing  jiangsu  211161\r
                                CN\r
 \r
-E0-62-67   (hex)               Xiaomi Communications Co Ltd\r
-E06267     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
-                               CN\r
+60-05-8A   (hex)               Hitachi Metals, Ltd.\r
+60058A     (base 16)           Hitachi Metals, Ltd.\r
+                               Shinagawa Season Terrace, 2-70, Konan 1-chome\r
+                               Minato-ku  Tokyo  108-8224\r
+                               JP\r
 \r
-48-2C-A0   (hex)               Xiaomi Communications Co Ltd\r
-482CA0     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
-                               CN\r
+00-21-06   (hex)               RIM Testing Services\r
+002106     (base 16)           RIM Testing Services\r
+                               440 Phillip Street\r
+                               Waterloo  ON  N2L 5R9\r
+                               CA\r
 \r
-18-01-F1   (hex)               Xiaomi Communications Co Ltd\r
-1801F1     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+14-57-9F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+14579F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-70-BB-E9   (hex)               Xiaomi Communications Co Ltd\r
-70BBE9     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
-                               CN\r
+14-4F-8A   (hex)               Intel Corporate\r
+144F8A     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
 \r
-F0-B4-29   (hex)               Xiaomi Communications Co Ltd\r
-F0B429     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+88-2D-53   (hex)               Baidu Online Network Technology (Beijing) Co., Ltd.\r
+882D53     (base 16)           Baidu Online Network Technology (Beijing) Co., Ltd.\r
+                               Baidu Campus, No.10 Shangdi 10th Street, Haidian District Beijing 100085 CN\r
+                               Beijing    100085\r
                                CN\r
 \r
-0C-98-38   (hex)               Xiaomi Communications Co Ltd\r
-0C9838     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
-                               CN\r
+A4-DA-32   (hex)               Texas Instruments\r
+A4DA32     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
 \r
-0C-1D-AF   (hex)               Xiaomi Communications Co Ltd\r
-0C1DAF     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+8C-14-B4   (hex)               zte corporation\r
+8C14B4     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
                                CN\r
 \r
-28-E3-1F   (hex)               Xiaomi Communications Co Ltd\r
-28E31F     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
-                               CN\r
+3C-98-72   (hex)               Sercomm Corporation.\r
+3C9872     (base 16)           Sercomm Corporation.\r
+                               3F,No.81,Yu-Yih Rd.,Chu-Nan Chen\r
+                               Miao-Lih Hsuan    115\r
+                               TW\r
 \r
-14-F6-5A   (hex)               Xiaomi Communications Co Ltd\r
-14F65A     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
-                               CN\r
+8C-04-FF   (hex)               Technicolor CH USA Inc.\r
+8C04FF     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
+                               US\r
 \r
-B4-F9-49   (hex)               optilink networks pvt ltd\r
-B4F949     (base 16)           optilink networks pvt ltd\r
-                               501/502, sanjona complex, hemu kalani marg, chembur\r
-                               mumbai  maharashtra  400071\r
-                               IN\r
+FC-91-14   (hex)               Technicolor CH USA Inc.\r
+FC9114     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
+                               US\r
 \r
-3C-5C-C4   (hex)               Amazon Technologies Inc.\r
-3C5CC4     (base 16)           Amazon Technologies Inc.\r
-                               P.O Box 8102\r
-                               Reno  NV  89507\r
+50-09-59   (hex)               Technicolor CH USA Inc.\r
+500959     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
                                US\r
 \r
-88-71-B1   (hex)               ARRIS Group, Inc.\r
-8871B1     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+14-B7-F8   (hex)               Technicolor CH USA Inc.\r
+14B7F8     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
                                US\r
 \r
-F0-AF-85   (hex)               ARRIS Group, Inc.\r
-F0AF85     (base 16)           ARRIS Group, Inc.\r
-                               6450 Sequence Drive\r
-                               San Diego  CA  92121\r
+B4-2A-0E   (hex)               Technicolor CH USA Inc.\r
+B42A0E     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
                                US\r
 \r
-B8-9A-9A   (hex)               Xin Shi Jia Technology (Beijing) Co.,Ltd\r
-B89A9A     (base 16)           Xin Shi Jia Technology (Beijing) Co.,Ltd\r
-                               Room 1002, A Tower, Zhongguancun E World Wealth Center, No.11, Zhongguancun Street, Haidian District, Beijing City\r
-                               Beijing  Beijing  100190\r
-                               CN\r
+B0-18-86   (hex)               SmarDTV\r
+B01886     (base 16)           SmarDTV\r
+                               Route de Genève 22\r
+                               Cheseaux    CH-1033 \r
+                               CH\r
 \r
-D4-C9-4B   (hex)               Motorola Mobility LLC, a Lenovo Company\r
-D4C94B     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
-                               222 West Merchandise Mart Plaza\r
-                               Chicago  IL  60654\r
+08-95-2A   (hex)               Technicolor CH USA Inc.\r
+08952A     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
                                US\r
 \r
-C0-22-50   (hex)               Koss Corporation\r
-C02250     (base 16)           Koss Corporation\r
-                               4129 N. Port Washington Ave.\r
-                               Milwaukee  WI  53212\r
+88-F7-C7   (hex)               Technicolor CH USA Inc.\r
+88F7C7     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
                                US\r
 \r
-2C-1C-F6   (hex)               Alien Green LLC\r
-2C1CF6     (base 16)           Alien Green LLC\r
-                               A. Kazbegi Ave., No24g, apt 227\r
-                               Tbilisi  Tbilisi  0160\r
-                               GE\r
-\r
-E4-38-8C   (hex)               Digital Products Limited\r
-E4388C     (base 16)           Digital Products Limited\r
-                               53 Clark Road\r
-                               Rothesay  New Brunswick  E2E 2K9\r
-                               CA\r
+30-24-32   (hex)               Intel Corporate\r
+302432     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
 \r
-18-1E-95   (hex)               AuVerte\r
-181E95     (base 16)           AuVerte\r
-                               14 Riverview Road\r
-                               Niantic  CT  06357\r
+A8-99-69   (hex)               Dell Inc.\r
+A89969     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
                                US\r
 \r
-18-4B-DF   (hex)               Caavo Inc\r
-184BDF     (base 16)           Caavo Inc\r
-                               1525 McCarthy Blvd., #1182\r
-                               Milpitas    95035\r
-                               US\r
+88-01-18   (hex)               BLT Co\r
+880118     (base 16)           BLT Co\r
+                               Dongan-gu Burim-ro 170beon-gil 44\r
+                               Anyangsi  Kyunggido  14055\r
+                               KR\r
 \r
-1C-54-9E   (hex)               Universal Electronics, Inc.\r
-1C549E     (base 16)           Universal Electronics, Inc.\r
-                               201 E. Sandpointe Ave\r
-                               Santa Ana  CA  92707\r
-                               US\r
+4C-21-D0   (hex)               Sony Mobile Communications Inc\r
+4C21D0     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
 \r
-70-3A-51   (hex)               Xiaomi Communications Co Ltd\r
-703A51     (base 16)           Xiaomi Communications Co Ltd\r
-                               The Rainbow City of China Resources\r
-                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
-                               CN\r
+30-75-12   (hex)               Sony Mobile Communications Inc\r
+307512     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
 \r
-A0-20-A6   (hex)               Espressif Inc.\r
-A020A6     (base 16)           Espressif Inc.\r
-                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
-                               Shanghai  Shanghai  201203\r
-                               CN\r
+C4-3A-BE   (hex)               Sony Mobile Communications Inc\r
+C43ABE     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
 \r
-84-F3-EB   (hex)               Espressif Inc.\r
-84F3EB     (base 16)           Espressif Inc.\r
-                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
-                               Shanghai  Shanghai  201203\r
-                               CN\r
+40-B8-37   (hex)               Sony Mobile Communications Inc\r
+40B837     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
 \r
-84-0D-8E   (hex)               Espressif Inc.\r
-840D8E     (base 16)           Espressif Inc.\r
-                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
-                               Shanghai  Shanghai  201203\r
-                               CN\r
+40-40-A7   (hex)               Sony Mobile Communications Inc\r
+4040A7     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
 \r
-54-9B-72   (hex)               Ericsson AB\r
-549B72     (base 16)           Ericsson AB\r
-                               Torshamnsgatan 36\r
-                               Stockholm    SE-164 80\r
-                               SE\r
+84-C7-EA   (hex)               Sony Mobile Communications Inc\r
+84C7EA     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
 \r
-DC-08-0F   (hex)               Apple, Inc.\r
-DC080F     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
+84-17-EF   (hex)               Technicolor CH USA Inc.\r
+8417EF     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
                                US\r
 \r
-F8-2D-7C   (hex)               Apple, Inc.\r
-F82D7C     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
+10-59-17   (hex)               Tonal\r
+105917     (base 16)           Tonal\r
+                               1074 Folsom St\r
+                               San Francisco    94103\r
                                US\r
 \r
-9C-64-8B   (hex)               Apple, Inc.\r
-9C648B     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
+38-8B-59   (hex)               Google, Inc.\r
+388B59     (base 16)           Google, Inc.\r
+                               1600 Amphitheatre Parkway\r
+                               Mountain View  CA  94043\r
                                US\r
 \r
-C0-3D-D9   (hex)               MitraStar Technology Corp.\r
-C03DD9     (base 16)           MitraStar Technology Corp.\r
-                               No. 6, Innovation Road II,\r
-                               Hsinchu    300\r
-                               TW\r
+94-CE-2C   (hex)               Sony Mobile Communications Inc\r
+94CE2C     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
 \r
-A0-A3-B8   (hex)               WISCLOUD\r
-A0A3B8     (base 16)           WISCLOUD\r
-                               Tech Park Xia Sha\r
-                               Hangzhou  Zhejiang  310000\r
+D0-51-62   (hex)               Sony Mobile Communications Inc\r
+D05162     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
+\r
+00-25-E7   (hex)               Sony Mobile Communications Inc\r
+0025E7     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
+\r
+40-2B-A1   (hex)               Sony Mobile Communications Inc\r
+402BA1     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
+\r
+34-0A-98   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+340A98     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-14-D0-0D   (hex)               Apple, Inc.\r
-14D00D     (base 16)           Apple, Inc.\r
-                               1 Infinite Loop\r
-                               Cupertino  CA  95014\r
-                               US\r
+60-F1-8A   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+60F18A     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
 \r
-74-85-C4   (hex)               New H3C Technologies Co., Ltd\r
-7485C4     (base 16)           New H3C Technologies Co., Ltd\r
-                               466 Changhe Road, Binjiang District\r
-                               Hangzhou  Zhejiang  310052\r
+00-12-EE   (hex)               Sony Mobile Communications Inc\r
+0012EE     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
+\r
+00-16-20   (hex)               Sony Mobile Communications Inc\r
+001620     (base 16)           Sony Mobile Communications Inc\r
+                               4-12-3 Higashi – Shinagawa\r
+                               Shinagawa-ku  Tokyo  140-0002\r
+                               JP\r
+\r
+28-9E-97   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+289E97     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-34-93-42   (hex)               TTE Corporation\r
-349342     (base 16)           TTE Corporation\r
-                               7/F, Building 22E 22 Science Park East Avenue Hong Kong Science Park Shatin, N.T.\r
-                               Hong Kong    999077\r
-                               HK\r
+24-FA-F3   (hex)               Shanghai Flexem Technology Co.,Ltd.\r
+24FAF3     (base 16)           Shanghai Flexem Technology Co.,Ltd.\r
+                               Room 804, C6 Building,No.52 Bay Valley Technology Park, Lane 1688 North Guoquan Road, Yangpu District.\r
+                               Shanghai    200438\r
+                               CN\r
 \r
-48-E6-95   (hex)               Insigma Inc\r
-48E695     (base 16)           Insigma Inc\r
-                               43490, Yukon Drive, Suite 102\r
-                               Ashburn  VA  20147\r
-                               US\r
+AC-DE-48   (hex)               Private\r
+ACDE48     (base 16)           Private\r
 \r
-B4-79-C8   (hex)               Ruckus Wireless\r
-B479C8     (base 16)           Ruckus Wireless\r
-                               350 West Java Drive\r
-                               Sunnyvale  CA  94089\r
-                               US\r
+0C-8C-24   (hex)               SHENZHEN BILIAN ELECTRONIC CO.,LTD\r
+0C8C24     (base 16)           SHENZHEN BILIAN ELECTRONIC CO.,LTD\r
+                               NO.268, Fuqian Rd, Jutang community, Guanlan Town, Longhua New district\r
+                               shenzhen  guangdong  518000\r
+                               CN\r
 \r
-F8-0D-F1   (hex)               Sontex SA\r
-F80DF1     (base 16)           Sontex SA\r
-                               rue de la gare\r
-                               sonceboz  Bern  2605\r
+7C-6B-9C   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+7C6B9C     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+1C-C3-EB   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+1CC3EB     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
+\r
+30-D6-59   (hex)               Merging Technologies SA\r
+30D659     (base 16)           Merging Technologies SA\r
+                               Le Verney 4\r
+                               Puidoux  Outside the U.S or Canada  1070\r
                                CH\r
 \r
-9C-8C-D8   (hex)               Hewlett Packard Enterprise\r
-9C8CD8     (base 16)           Hewlett Packard Enterprise\r
-                               8000 Foothills Blvd.\r
-                               Roseville  CA  95747\r
+C4-95-00   (hex)               Amazon Technologies Inc.\r
+C49500     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
                                US\r
 \r
-88-D2-11   (hex)               Eko Devices, Inc.\r
-88D211     (base 16)           Eko Devices, Inc.\r
-                               2600 10th St Ste 260\r
-                               Berkeley  CA  94710-2597\r
-                               US\r
+F0-F0-8F   (hex)               Nextek Solutions Pte Ltd\r
+F0F08F     (base 16)           Nextek Solutions Pte Ltd\r
+                               105 Cecil Street, #06-01 The Octagon\r
+                               Singapore  Singapore  069534\r
+                               SG\r
 \r
-1C-F2-9A   (hex)               Google, Inc.\r
-1CF29A     (base 16)           Google, Inc.\r
-                               1600 Amphitheatre Parkway\r
+E4-D1-24   (hex)                Mojo Networks, Inc.\r
+E4D124     (base 16)            Mojo Networks, Inc.\r
+                               339 N.Bernardo Ave\r
                                Mountain View  CA  94043\r
                                US\r
 \r
-94-54-DF   (hex)               YST CORP.\r
-9454DF     (base 16)           YST CORP.\r
-                               A-1407, 767, Sinsu-ro, Suji-gu,\r
-                               Yongin-si  Gyeonggi-do  16827\r
-                               KR\r
-\r
-74-F7-37   (hex)               KCE\r
-74F737     (base 16)           KCE\r
-                               5F KCE B/D,34,Annam-ro 369beon-gil,Bupyoung-gu\r
-                               Incheon    21312\r
-                               KR\r
-\r
-8C-18-50   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-8C1850     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
-                               Hangzhou  Hangzhou  310000\r
+28-3A-4D   (hex)               Cloud Network Technology (Samoa) Limited\r
+283A4D     (base 16)           Cloud Network Technology (Samoa) Limited\r
+                               Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District\r
+                               Chongqing  Chongqing  401332\r
                                CN\r
 \r
-78-0E-D1   (hex)               TRUMPF Werkzeugmaschinen GmbH+Co.KG\r
-780ED1     (base 16)           TRUMPF Werkzeugmaschinen GmbH+Co.KG\r
-                               Johann-Maus-Straße 2\r
-                               Ditzingen    71254\r
-                               DE\r
-\r
-A8-9C-A4   (hex)               Furrion Limited\r
-A89CA4     (base 16)           Furrion Limited\r
-                               Units 503C & 505-508, Level 5, Core D, Cyberport 3, 100 Cyberport Road\r
-                               Hong Kong    00000\r
-                               HK\r
+B4-CE-FE   (hex)               James Czekaj\r
+B4CEFE     (base 16)           James Czekaj\r
+                               41716 Waterfall Rd\r
+                               Northville  MI  48168\r
+                               US\r
 \r
-7C-DB-98   (hex)               ASKEY COMPUTER CORP\r
-7CDB98     (base 16)           ASKEY COMPUTER CORP\r
-                               10F,No.119,JIANKANG RD,ZHONGHE DIST\r
-                               NEW TAIPEI  TAIWAN  23585\r
-                               TW\r
+20-1A-06   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+201A06     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+                               NO. 15, THE 3RD Street KUNSHAN EXPORT PROCESSING ZONE\r
+                               KUNSHAN  SUZHOU  215300\r
+                               CN\r
 \r
-6C-DF-FB   (hex)               IEEE Registration Authority\r
-6CDFFB     (base 16)           IEEE Registration Authority\r
-                               445 Hoes Lane\r
-                               Piscataway  NJ  08554\r
-                               US\r
+B8-88-E3   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+B888E3     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+                               No.25, Third Avenue, A Zone, Kunshan Comprehensive Free Trade Zone,, Jiangsu, \r
+                               KUNSHAN   SUZHOU  215300\r
+                               CN\r
 \r
-DC-21-B9   (hex)               Sentec Co.Ltd\r
-DC21B9     (base 16)           Sentec Co.Ltd\r
-                               10, Baekseokgongdan 1-ro, Seobuk-gu\r
-                                Cheonan-si  Chungcheongnam-do  31094\r
-                               KR\r
+00-26-22   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+002622     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+                               NO. 25, THE 3RD Street KUNSHAN EXPORT PROCESSING ZONE\r
+                               KUNSHAN  SUZHOU  215300\r
+                               CN\r
 \r
-E4-D3-AA   (hex)               FUJITSU CONNECTED TECHNOLOGIES LIMITED\r
-E4D3AA     (base 16)           FUJITSU CONNECTED TECHNOLOGIES LIMITED\r
-                               4-1-1, Kamikodanaka, Nakahara-ku\r
-                               Kawasaki  Kanagawa  2118588\r
-                               JP\r
+00-1E-EC   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+001EEC     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+                               NO. 25, THE 3RD Street\r
+                               KUNSHAN CITY  SUZHOU PROVINCE  215300\r
+                               CN\r
 \r
-B0-02-47   (hex)               AMPAK Technology, Inc.\r
-B00247     (base 16)           AMPAK Technology, Inc.\r
-                               3F.,No.15-1 Zhonghua Road,Hsinchu Industrial Park, Hukou,Hsinchu\r
-                               Hsinchu  Taiwan ROC.  30352\r
-                               TW\r
+DC-0E-A1   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+DC0EA1     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+                               No.25, Third Avenue, A Zone, Kunshan Comprehensive Free Trade Zone,, Jiangsu, \r
+                               KUNSHAN   SUZHOU  215300\r
+                               CN\r
 \r
-BC-E7-96   (hex)               Wireless CCTV Ltd\r
-BCE796     (base 16)           Wireless CCTV Ltd\r
-                               charles Babbage house\r
-                               Rochdale  Greater Manchester  ol164nw\r
-                               GB\r
+FC-45-96   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+FC4596     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+                                NO. 25, THE 3RD Street KUNSHAN EXPORT PROCESSING ZON\r
+                               KUNSHAN  SUZHOU  215300\r
+                               CN\r
 \r
-70-5E-55   (hex)               Realme Chongqing MobileTelecommunications Corp Ltd\r
-705E55     (base 16)           Realme Chongqing MobileTelecommunications Corp Ltd\r
-                               No.24 Nichang Boulevard, Huixing Block, Yubei District, Chongqing.\r
-                               Chongqing  China  401120\r
+20-89-84   (hex)               COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+208984     (base 16)           COMPAL INFORMATION (KUNSHAN) CO., LTD. \r
+                               No.25, Third Avenue, A Zone, Kunshan Comprehensive Free Trade Zone\r
+                               KUNSHAN   SUZHOU   215300 \r
                                CN\r
 \r
-D4-67-D3   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-D467D3     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,\r
-                               DONG GUAN  GUANG DONG  523860\r
+58-03-FB   (hex)               Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+5803FB     (base 16)           Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+                               No.555 Qianmo Road\r
+                               Hangzhou  Zhejiang  310052\r
                                CN\r
 \r
-48-E3-C3   (hex)               JENOPTIK Advanced Systems GmbH\r
-48E3C3     (base 16)           JENOPTIK Advanced Systems GmbH\r
-                               Feldstrasse 155\r
-                               Wedel  Schleswig-Holstein  22880\r
-                               DE\r
+58-FD-BE   (hex)               Shenzhen Taikaida Technology Co., Ltd\r
+58FDBE     (base 16)           Shenzhen Taikaida Technology Co., Ltd\r
+                               Shenzhen Baoan District Fuyong town Fengtang road Xintian building 613\r
+                               shenzhen    518102\r
+                               CN\r
 \r
-84-EB-3E   (hex)               Vivint Smart Home\r
-84EB3E     (base 16)           Vivint Smart Home\r
-                               4931 N. 300 W.\r
-                               Provo  UT  84604\r
-                               US\r
+F8-CC-6E   (hex)               DEPO Electronics Ltd\r
+F8CC6E     (base 16)           DEPO Electronics Ltd\r
+                               12, kommunalnaya zona Krasnogorsk-Mitino\r
+                               Krasnogorsk  Moscow region  143404\r
+                               RU\r
 \r
-CC-70-ED   (hex)               Cisco Systems, Inc\r
-CC70ED     (base 16)           Cisco Systems, Inc\r
-                               80 West Tasman Drive\r
-                               San Jose  CA  94568\r
+80-6F-B0   (hex)               Texas Instruments\r
+806FB0     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
                                US\r
 \r
-D4-3D-39   (hex)               FCI. Inc\r
-D43D39     (base 16)           FCI. Inc\r
-                               B-7F, SiliconPark, 35, Pangyo-ro 255beon-gil, Bundang-gu\r
-                               Seongnam-si  Gyeonggi-do  13486\r
+14-94-2F   (hex)               USYS CO.,LTD.\r
+14942F     (base 16)           USYS CO.,LTD.\r
+                               #911, SeoulTechnoPark, 232, Gongneung-ro, Nowon-gu\r
+                               Seoul    KS013\r
                                KR\r
 \r
-4C-96-2D   (hex)               Fresh AB\r
-4C962D     (base 16)           Fresh AB\r
-                               Gransholmsvägen 136\r
-                               Gemla    35599\r
-                               SE\r
+B8-69-F4   (hex)               Routerboard.com\r
+B869F4     (base 16)           Routerboard.com\r
+                               Mikrotikls SIA\r
+                               Riga  Riga  LV1009\r
+                               LV\r
 \r
-AC-7A-4D   (hex)               ALPS ELECTRIC CO., LTD.\r
-AC7A4D     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               KAKUDA-CITY  MIYAGI-PREF  981-1595\r
-                               JP\r
+34-2E-B6   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+342EB6     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
 \r
-58-C6-F0   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-58C6F0     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,\r
-                               DONG GUAN  GUANG DONG  523860\r
+90-2B-D2   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+902BD2     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-64-9D-99   (hex)               FS COM INC\r
-649D99     (base 16)           FS COM INC\r
-                               380 Centerpoint Blvd New Castle\r
-                               New Castle  DE  19720\r
-                               US\r
+9C-7F-57   (hex)               UNIC Memory Technology Co Ltd\r
+9C7F57     (base 16)           UNIC Memory Technology Co Ltd\r
+                               15/F, Building B, Truth Plaza, No.7 Zhichun Road\r
+                               Beijing  Haidian District  102208\r
+                               CN\r
 \r
-00-19-3B   (hex)               LigoWave\r
-00193B     (base 16)           LigoWave\r
-                               138 Mountain Brook Drive\r
-                               Canton  GA  30115\r
-                               US\r
+C4-6E-7B   (hex)               SHENZHEN RF-LINK TECHNOLOGY CO.,LTD.\r
+C46E7B     (base 16)           SHENZHEN RF-LINK TECHNOLOGY CO.,LTD.\r
+                               Bldg56A,6/F,Baotian Rd3,Xixiang Town,Baoan District,\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
 \r
-FC-62-B9   (hex)               ALPS ELECTRIC CO., LTD.\r
-FC62B9     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               kakuda-city  Miyagi-Pref  981-1595\r
-                               JP\r
+28-D0-CB   (hex)               Cambridge Communication Systems Ltd\r
+28D0CB     (base 16)           Cambridge Communication Systems Ltd\r
+                               Victory House, Vision Park, Chivers Way, Histon\r
+                               Cambridge    CB24 9ZR\r
+                               GB\r
 \r
-00-19-C1   (hex)               ALPS ELECTRIC CO., LTD.\r
-0019C1     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
+00-1A-31   (hex)               SCAN COIN AB\r
+001A31     (base 16)           SCAN COIN AB\r
+                               Jagershillgatan 26\r
+                               Malmö  Skåne  21375\r
+                               SE\r
 \r
-00-1E-3D   (hex)               ALPS ELECTRIC CO., LTD.\r
-001E3D     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
+70-4F-08   (hex)               Shenzhen Huisheng Information Technology Co., Ltd.\r
+704F08     (base 16)           Shenzhen Huisheng Information Technology Co., Ltd.\r
+                                Room 4A-205, Software Industry Base, Yuehai St\r
+                               Nanshan District, Shenzhen  Guangdong  518000\r
+                               CN\r
 \r
-00-23-06   (hex)               ALPS ELECTRIC CO., LTD.\r
-002306     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               1-2-1, Okinouchi,\r
-                               Soma-city,  Fukushima-pref.,  976-8501\r
-                               JP\r
+BC-A5-8B   (hex)               Samsung Electronics Co.,Ltd\r
+BCA58B     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
 \r
-28-A1-83   (hex)               ALPS ELECTRIC CO., LTD.\r
-28A183     (base 16)           ALPS ELECTRIC CO., LTD.\r
-                               6-1\r
-                               Kakuda  Miyagi-Pref  981-1595\r
-                               JP\r
+70-FD-46   (hex)               Samsung Electronics Co.,Ltd\r
+70FD46     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
 \r
-88-4A-18   (hex)               Opulinks\r
-884A18     (base 16)           Opulinks\r
-                               F 28, No.328, Huashan Rd\r
-                               Shanghai    200040\r
-                               CN\r
+D0-7F-A0   (hex)               Samsung Electronics Co.,Ltd\r
+D07FA0     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
 \r
-00-0B-5D   (hex)               FUJITSU LIMITED\r
-000B5D     (base 16)           FUJITSU LIMITED\r
-                               403, Kosugi-cho 1-chome, Nakahara-ku\r
-                               Kawasaki  Kanagawa  211-0063\r
+F0-9F-FC   (hex)               SHARP Corporation\r
+F09FFC     (base 16)           SHARP Corporation\r
+                               1 Takumi-cho, Sakai-ku\r
+                               Sakai City  Osaka  590-8522\r
                                JP\r
 \r
-14-4E-2A   (hex)               Ciena Corporation\r
-144E2A     (base 16)           Ciena Corporation\r
-                               7035 Ridge Road\r
-                               Hanover  MD  21076\r
+30-42-A1   (hex)               ilumisys Inc. DBA Toggled\r
+3042A1     (base 16)           ilumisys Inc. DBA Toggled\r
+                               1820 E. Big Beaver Road\r
+                               Troy  MI  48083\r
                                US\r
 \r
-D4-C9-3C   (hex)               Cisco Systems, Inc\r
-D4C93C     (base 16)           Cisco Systems, Inc\r
+20-DE-88   (hex)               IC Realtime LLC\r
+20DE88     (base 16)           IC Realtime LLC\r
+                               3050 N Andrews Ave Ext.\r
+                               Pompano Beach  FL  33064\r
+                               US\r
+\r
+14-37-19   (hex)               PT Prakarsa Visi Valutama\r
+143719     (base 16)           PT Prakarsa Visi Valutama\r
+                               Jl. Cideng Timur No.11D\r
+                               Jakarta Pusat  Indonesia  10130\r
+                               ID\r
+\r
+58-2F-40   (hex)               Nintendo Co.,Ltd\r
+582F40     (base 16)           Nintendo Co.,Ltd\r
+                               11-1 HOKOTATE-CHO KAMITOBA,MINAMI-KU\r
+                               KYOTO  KYOTO  601-8501\r
+                               JP\r
+\r
+6C-6C-D3   (hex)               Cisco Systems, Inc\r
+6C6CD3     (base 16)           Cisco Systems, Inc\r
                                80 West Tasman Drive\r
                                San Jose  CA  94568\r
                                US\r
 \r
-88-6F-D4   (hex)               Dell Inc.\r
-886FD4     (base 16)           Dell Inc.\r
-                               One Dell Way\r
-                               Round Rock  TX  78682\r
+30-16-8D   (hex)               ProLon\r
+30168D     (base 16)           ProLon\r
+                               17510 rue Charles, Suite 100\r
+                               Mirabel  Quebec   J7J 1X9\r
+                               CA\r
+\r
+80-30-E0   (hex)               Hewlett Packard Enterprise\r
+8030E0     (base 16)           Hewlett Packard Enterprise\r
+                               8000 Foothills Blvd.\r
+                               Roseville  CA  95747\r
                                US\r
 \r
-C4-06-83   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-C40683     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
+E8-5D-86   (hex)               CHANG YOW TECHNOLOGIES INTERNATIONAL CO.,LTD.\r
+E85D86     (base 16)           CHANG YOW TECHNOLOGIES INTERNATIONAL CO.,LTD.\r
+                                No 88 Shuren 6th St Wufong District\r
+                               Taichung    413\r
+                               TW\r
 \r
-FC-87-43   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-FC8743     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
+1C-25-E1   (hex)               China Mobile IOT Company Limited\r
+1C25E1     (base 16)           China Mobile IOT Company Limited\r
+                               NO.8 Yu Ma Road, NanAn Area\r
+                               Chongqing  Chongqing  401336\r
                                CN\r
 \r
-50-2B-98   (hex)               Es-tech International\r
-502B98     (base 16)           Es-tech International\r
-                               228-70, Saneop-ro 155beon-gil, Gwonseon-gu, Suwon-si, Gyeonggi-do, Korea\r
-                               Suwon    16648\r
-                               KR\r
-\r
-A0-F9-B7   (hex)               Ademco Smart Homes Technology(Tianjin)Co.,Ltd.\r
-A0F9B7     (base 16)           Ademco Smart Homes Technology(Tianjin)Co.,Ltd.\r
-                               No.156 Nanhai Road,TEDA, Jinbin Development Park , 21st Factory Building\r
-                               Tianjin  Tianjin  300457\r
+AC-54-74   (hex)               China Mobile IOT Company Limited\r
+AC5474     (base 16)           China Mobile IOT Company Limited\r
+                               NO.8 Yu Ma Road, NanAn Area\r
+                               Chongqing  Chongqing  401336\r
                                CN\r
 \r
-48-F1-7F   (hex)               Intel Corporate\r
-48F17F     (base 16)           Intel Corporate\r
+00-40-84   (hex)               Honeywell International HPS\r
+004084     (base 16)           Honeywell International HPS\r
+                               \r
+                               Fort Washington  PA  19034\r
+                               US\r
+\r
+64-5D-86   (hex)               Intel Corporate\r
+645D86     (base 16)           Intel Corporate\r
                                Lot 8, Jalan Hi-Tech 2/3\r
                                Kulim  Kedah  09000\r
                                MY\r
 \r
-10-9C-70   (hex)               Prusa Research s.r.o.\r
-109C70     (base 16)           Prusa Research s.r.o.\r
-                               Partyzanska 188/7a\r
-                               Prague    17000\r
-                               CZ\r
+8C-92-46   (hex)               Oerlikon Textile Gmbh&Co.KG\r
+8C9246     (base 16)           Oerlikon Textile Gmbh&Co.KG\r
+                               NO.9 Changyang Street\r
+                               Suzhou  Jiangsu  215000\r
+                               CN\r
 \r
-8C-44-4F   (hex)               HUMAX Co., Ltd.\r
-8C444F     (base 16)           HUMAX Co., Ltd.\r
-                               HUMAX Village, 216, Hwangsaeul-ro, Bu\r
-                               Seongnam-si  Gyeonggi-do  463-875\r
+7C-24-0C   (hex)               Telechips, Inc.\r
+7C240C     (base 16)           Telechips, Inc.\r
+                               19F~23F,Luther Bldg.42, Olympic-ro 35da-gil, Songpa-gu,\r
+                               Seoul  Seoul  05510\r
                                KR\r
 \r
-A4-19-08   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
-A41908     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
-                               No.5 DongXin Road\r
-                               Wuhan  Hubei  430074\r
-                               CN\r
-\r
-EC-A9-FA   (hex)               GUANGDONG GENIUS TECHNOLOGY CO., LTD.\r
-ECA9FA     (base 16)           GUANGDONG GENIUS TECHNOLOGY CO., LTD.\r
-                               #126,BBK Road,Wusha,Chang'An\r
-                               Dong Guan  Guang Dong  523860\r
+CC-F0-FD   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+CCF0FD     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District, Hangzhou, Zhejiang\r
+                               Hangzhou  Zhejiang  310000\r
                                CN\r
 \r
-44-B4-62   (hex)               Flextronics Tech.(Ind) Pvt Ltd\r
-44B462     (base 16)           Flextronics Tech.(Ind) Pvt Ltd\r
-                               SURVEYNO.381, PADUR ROAD, KUTHAMBAKKAM VILLAGE, 602107 POONAMALLEE TALUK, THIRUVALLUR DISTRIC\r
-                               Chennai    602107\r
-                               IN\r
-\r
-DC-67-23   (hex)               barox Kommunikation GmbH\r
-DC6723     (base 16)           barox Kommunikation GmbH\r
-                               Marie-Curie-Strasse 8\r
-                               Lörrach    DE-79539\r
-                               DE\r
-\r
-1C-24-EB   (hex)               Burlywood\r
-1C24EB     (base 16)           Burlywood\r
-                               1501 S Sunset Street\r
-                               Longmont  CO  80501\r
+4C-01-43   (hex)               eero inc.\r
+4C0143     (base 16)           eero inc.\r
+                               660 3rd Street\r
+                               San Francisco  CA  94107\r
                                US\r
 \r
-64-6E-EA   (hex)               Iskratel d.o.o.\r
-646EEA     (base 16)           Iskratel d.o.o.\r
-                               Ljubljanska cesta 24a\r
-                               Kranj    4000\r
-                               SI\r
+9C-AA-1B   (hex)               Microsoft Corporation\r
+9CAA1B     (base 16)           Microsoft Corporation\r
+                               One Microsoft Way\r
+                               REDMOND  WA  98052\r
+                               US\r
 \r
-00-D0-50   (hex)               Iskratel d.o.o.\r
-00D050     (base 16)           Iskratel d.o.o.\r
-                               Ljubljanska cesta 24a\r
-                               Kranj    4000\r
-                               SI\r
+18-D7-17   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+18D717     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
+                               CN\r
 \r
-7C-60-4A   (hex)               Avelon\r
-7C604A     (base 16)           Avelon\r
-                               Bändliweg 20\r
-                               Zurich    8048\r
-                               CH\r
+0C-9A-42   (hex)               FN-LINK TECHNOLOGY LIMITED\r
+0C9A42     (base 16)           FN-LINK TECHNOLOGY LIMITED\r
+                               A Building,HuiXin industial park,No 31, YongHe road, Fuyong town, Bao'an District\r
+                               SHENZHEN  GUANGDONG  518100\r
+                               CN\r
 \r
-7C-D9-5C   (hex)               Google, Inc.\r
-7CD95C     (base 16)           Google, Inc.\r
-                               1600 Amphitheatre Parkway\r
-                               Mountain View  CA  94043\r
+60-4B-AA   (hex)               Magic Leap, Inc.\r
+604BAA     (base 16)           Magic Leap, Inc.\r
+                               1855 Griffin Rd, Room B454\r
+                               Dania Beach  FL  33004\r
                                US\r
 \r
-F0-5C-19   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
-F05C19     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
-                               3333 Scott Blvd\r
-                               Santa Clara  CA  95054\r
-                               US\r
+54-81-2D   (hex)               PAX Computer Technology(Shenzhen) Ltd.\r
+54812D     (base 16)           PAX Computer Technology(Shenzhen) Ltd.\r
+                               4/F, No.3 Building, Software Park, Second Central Science-Tech Road, High-Tech\r
+                               Shenzhen  GuangDong  518057\r
+                               CN\r
 \r
-70-3A-0E   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
-703A0E     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
-                               3333 Scott Blvd\r
-                               Santa Clara  CA  95054\r
-                               US\r
+30-A1-FA   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+30A1FA     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
 \r
-B4-5D-50   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
-B45D50     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
-                               3333 Scott Blvd\r
-                               Santa Clara  CA  95054\r
-                               US\r
+88-10-8F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+88108F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
 \r
-6C-F3-7F   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
-6CF37F     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
-                               3333 Scott Blvd\r
-                               Santa Clara  CA  95054\r
-                               US\r
+0C-53-31   (hex)               ETH Zurich\r
+0C5331     (base 16)           ETH Zurich\r
+                               Dept. Computer Science, Universitätstr. 6\r
+                               Zurich  ZH  8092\r
+                               CH\r
 \r
-68-FF-7B   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
-68FF7B     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
-                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
-                               Shenzhen  Guangdong  518057\r
+F4-63-1F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+F4631F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-38-21-C7   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
-3821C7     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
-                               3333 Scott Blvd\r
-                               Santa Clara  CA  95054\r
-                               US\r
+24-FB-65   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+24FB65     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
 \r
-B8-EF-8B   (hex)               SHENZHEN CANNICE TECHNOLOGY CO.,LTD\r
-B8EF8B     (base 16)           SHENZHEN CANNICE TECHNOLOGY CO.,LTD\r
-                               F-20,7A,Baoneng Technology Park\r
-                               Shenzhen  Guangdong  518109\r
+EC-84-B4   (hex)               CIG SHANGHAI CO LTD\r
+EC84B4     (base 16)           CIG SHANGHAI CO LTD\r
+                               5th Floor, Building 8 No 2388 Chenhang Road\r
+                               SHANGHAI    201114\r
                                CN\r
 \r
-00-13-1E   (hex)               peiker acustic GmbH\r
-00131E     (base 16)           peiker acustic GmbH\r
-                               Max-Planck-Strasse 28-32\r
-                               Friedrichsdorf    61381\r
-                               DE\r
+EC-B3-13   (hex)               SHENZHEN GONGJIN ELECTRONICS CO.,LT\r
+ECB313     (base 16)           SHENZHEN GONGJIN ELECTRONICS CO.,LT\r
+                               SONGGANG\r
+                               SHENZHEN  GUANGDONG  518105\r
+                               CN\r
 \r
-D4-9C-DD   (hex)               AMPAK Technology,Inc.\r
-D49CDD     (base 16)           AMPAK Technology,Inc.\r
-                               3F, No.15-1 Zhonghua Road, Hsinchu Industrail Park, Hukou,\r
-                               Hsinchu  Hsinchu,Taiwan R.O.C.  30352\r
-                               TW\r
+8C-FE-74   (hex)               Ruckus Wireless\r
+8CFE74     (base 16)           Ruckus Wireless\r
+                               350 West Java Drive\r
+                               Sunnyvale  CA  94089\r
+                               US\r
 \r
-84-69-91   (hex)               Nokia\r
-846991     (base 16)           Nokia\r
-                               600 March Road\r
-                               Kanata  Ontario  K2K 2E6\r
-                               CA\r
+84-6A-66   (hex)               Sumitomo Kizai  Co.,Ltd.\r
+846A66     (base 16)           Sumitomo Kizai  Co.,Ltd.\r
+                               1-45-1higashiikebukuro\r
+                               tosimaku  tokyo  170-0013\r
+                               JP\r
 \r
-E8-93-63   (hex)               Nokia\r
-E89363     (base 16)           Nokia\r
-                               600 March Road\r
-                               Kanata  Ontario  K2K 2E6\r
-                               CA\r
+DC-37-57   (hex)               Integrated Device Technology (Malaysia) Sdn. Bhd.\r
+DC3757     (base 16)           Integrated Device Technology (Malaysia) Sdn. Bhd.\r
+                               Phase 3, Bayan Lepas FIZ\r
+                               Bayan Lepas  Penang  11900\r
+                               MY\r
 \r
-CC-66-B2   (hex)               Nokia\r
-CC66B2     (base 16)           Nokia\r
-                               600 March Road\r
-                               Kanata  Ontario  K2K 2E6\r
-                               CA\r
+00-90-04   (hex)               3COM EUROPE LTD\r
+009004     (base 16)           3COM EUROPE LTD\r
+                               3COM CENTRE, BOUNDARY WAY\r
+                               HERTS.  HP2 7YU    \r
+                               GB\r
 \r
-10-E8-78   (hex)               Nokia\r
-10E878     (base 16)           Nokia\r
-                               600 March Road\r
-                               Kanata  Ontario  K2K 2E6\r
-                               CA\r
+00-50-99   (hex)               3COM EUROPE LTD\r
+005099     (base 16)           3COM EUROPE LTD\r
+                               BOUNDARY WAY\r
+                               HERTS. HP2 7YU    \r
+                               GB\r
 \r
-48-F7-F1   (hex)               Nokia\r
-48F7F1     (base 16)           Nokia\r
-                               600 March Road\r
-                               Kanata  Ontario  K2K 2E6\r
-                               CA\r
+08-00-4E   (hex)               3COM EUROPE LTD\r
+08004E     (base 16)           3COM EUROPE LTD\r
+                               3COM CENTRE\r
+                                 UNITED  KINGDOM\r
+                               GB\r
 \r
-4C-C9-4F   (hex)               Nokia\r
-4CC94F     (base 16)           Nokia\r
-                               600 March Road\r
-                               Kanata  Ontario  K2K 2E6\r
-                               CA\r
+00-D0-96   (hex)               3COM EUROPE LTD\r
+00D096     (base 16)           3COM EUROPE LTD\r
+                               BOUNDARY WAY\r
+                                 UNITED  KINGDOM\r
+                               GB\r
 \r
-04-CF-8C   (hex)               XIAOMI Electronics,CO.,LTD\r
-04CF8C     (base 16)           XIAOMI Electronics,CO.,LTD\r
-                               Xiaomi Building, No.68 Qinghe Middle Street\r
-                               Haidian District  Beijing  100085\r
-                               CN\r
+00-30-1E   (hex)               3COM EUROPE LTD\r
+00301E     (base 16)           3COM EUROPE LTD\r
+                               BOUNDARY WAY\r
+                                 UNITED  KINGDOM\r
+                               GB\r
 \r
-40-31-3C   (hex)               XIAOMI Electronics,CO.,LTD\r
-40313C     (base 16)           XIAOMI Electronics,CO.,LTD\r
-                               Xiaomi Building, No.68 Qinghe Middle Street\r
-                               Haidian District  Beijing  100085\r
-                               CN\r
+00-0A-5E   (hex)               3COM\r
+000A5E     (base 16)           3COM\r
+                               5400 Bayfront Plaza\r
+                               Santa Clara  CA  95052-8145\r
+                               US\r
 \r
-7C-49-EB   (hex)               XIAOMI Electronics,CO.,LTD\r
-7C49EB     (base 16)           XIAOMI Electronics,CO.,LTD\r
-                               Xiaomi Building, No.68 Qinghe Middle Street\r
-                               Haidian District  Beijing  100085\r
-                               CN\r
+00-06-8C   (hex)               3COM\r
+00068C     (base 16)           3COM\r
+                               5400 BAYFRONT PLAZA\r
+                               SANTA CLARA  CA  95052\r
+                               US\r
 \r
-1C-EA-1B   (hex)               Nokia\r
-1CEA1B     (base 16)           Nokia\r
-                               600 March Road\r
-                               Kanata  Ontario  K2K 2E6\r
-                               CA\r
+00-01-03   (hex)               3COM\r
+000103     (base 16)           3COM\r
+                               5400 BAYFRONT PLAZA\r
+                               SANTA CLARA  CA  95052\r
+                               US\r
 \r
-E0-09-BF   (hex)               SHENZHEN TONG BO WEI TECHNOLOGY Co.,LTD\r
-E009BF     (base 16)           SHENZHEN TONG BO WEI TECHNOLOGY Co.,LTD\r
-                               5th floor building 4 pengtengda industrial,langkou community,dalang street longhua newly developed area\r
-                               Shenzhen  GuangDong  518000\r
-                               CN\r
+02-60-8C   (hex)               3COM\r
+02608C     (base 16)           3COM\r
+                               5400 BAYFRONT PLAZA\r
+                               SANTA CLARA  CA  95052\r
+                               US\r
 \r
-00-0C-17   (hex)               AJA Video Systems Inc\r
-000C17     (base 16)           AJA Video Systems Inc\r
-                               180 Litton Drive\r
-                               Grass Valley  CA  95945\r
+00-1B-6E   (hex)               Keysight Technologies, Inc.\r
+001B6E     (base 16)           Keysight Technologies, Inc.\r
+                               1400 Fountaingrove Pkwy.\r
+                               Santa Rosa  CA  95403\r
                                US\r
 \r
-CC-ED-DC   (hex)               MitraStar Technology Corp.\r
-CCEDDC     (base 16)           MitraStar Technology Corp.\r
-                               No. 6, Innovation Road II,\r
-                               Hsinchu    300\r
+00-8C-FA   (hex)               INVENTEC CORPORATION\r
+008CFA     (base 16)           INVENTEC CORPORATION\r
+                               No. 255, Jen-Ho Road Sec. 2, 33547,\r
+                               Tachi  Taoyuan  33547\r
                                TW\r
 \r
-D4-58-00   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
-D45800     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
-                               No.5 DongXin Road\r
-                               Wuhan  Hubei  430074\r
-                               CN\r
+C4-23-A2   (hex)               PT. Emsonic Indonesia\r
+C423A2     (base 16)           PT. Emsonic Indonesia\r
+                               Jl.Timor Blok E5, MM2100 Industrial Town Jatiwangi Cikarang Barat\r
+                               Bekasi  Jawa Barat  17530\r
+                               ID\r
 \r
-C4-64-B7   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
-C464B7     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
-                               No.5 DongXin Road\r
-                               Wuhan  Hubei  430074\r
+B4-CB-57   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+B4CB57     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
+                               NO.18 HAIBIN ROAD,\r
+                               DONG GUAN  GUANG DONG  523860\r
                                CN\r
 \r
-4C-4D-66   (hex)               Nanjing Jiahao Technology Co., Ltd.\r
-4C4D66     (base 16)           Nanjing Jiahao Technology Co., Ltd.\r
-                               Moling Industrial Park, Development Zone, Jiangning, Nanjing\r
-                               Nanjing  Jiangsu  211111\r
-                               CN\r
+BC-B2-2B   (hex)               EM-Tech\r
+BCB22B     (base 16)           EM-Tech\r
+                               40, Changwon-daero 1144beon-gil\r
+                               Seongsan-gu Changwon  Gyeongsangnam-do  KR 642-120\r
+                               KR\r
 \r
-90-58-51   (hex)               Technicolor CH USA Inc.\r
-905851     (base 16)           Technicolor CH USA Inc.\r
-                               5030 Sugarloaf Parkway Bldg 6\r
-                               Lawrenceville  GA  30044\r
-                               US\r
+94-91-7F   (hex)               ASKEY COMPUTER CORP\r
+94917F     (base 16)           ASKEY COMPUTER CORP\r
+                               10F,No.119,JIANKANG RD,ZHONGHE DIST\r
+                               NEW TAIPEI  TAIWAN  23585\r
+                               TW\r
 \r
-38-F8-5E   (hex)               HUMAX Co., Ltd.\r
-38F85E     (base 16)           HUMAX Co., Ltd.\r
-                               HUMAX Village, 216, Hwangsaeul-ro, Bu\r
-                               Seongnam-si  Gyeonggi-do  463-875\r
+C8-BA-E9   (hex)               QDIS\r
+C8BAE9     (base 16)           QDIS\r
+                               #512, Buliding B, 168 GaSanDigital 1st, GeumChun-Gu\r
+                               SEOUL    08507\r
                                KR\r
 \r
-C0-2E-25   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-C02E25     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,\r
-                               DONG GUAN  GUANG DONG  523860\r
-                               CN\r
+B8-6A-97   (hex)               Edgecore Networks Corporation\r
+B86A97     (base 16)           Edgecore Networks Corporation\r
+                               1 Creation RD 3.\r
+                               Hsinchu    30077\r
+                               TW\r
 \r
-40-A5-EF   (hex)               Shenzhen Four Seas Global Link Network Technology Co., Ltd.\r
-40A5EF     (base 16)           Shenzhen Four Seas Global Link Network Technology Co., Ltd.\r
-                               Room 607-610, Block B, TAOJINDI Electronic Business Incubation Base\r
-                               Tenglong Road, Longhua District,   Shenzhen Guangdong  518000\r
+94-29-8D   (hex)               Shanghai AdaptComm Technology Co., Ltd.\r
+94298D     (base 16)           Shanghai AdaptComm Technology Co., Ltd.\r
+                               3rd Floor, Building 14, No. 518 Xinzhuan Road, Songjiang District,\r
+                               Shanghai    201600\r
                                CN\r
 \r
-48-E6-C0   (hex)               SIMCom Wireless Solutions Co.,Ltd.\r
-48E6C0     (base 16)           SIMCom Wireless Solutions Co.,Ltd.\r
-                               Building B,SIM Technology Building,No.633,Jinzhong Road\r
-                               Shanghai    200335\r
+EC-79-F2   (hex)               Startel\r
+EC79F2     (base 16)           Startel\r
+                               Xi Chuang Industrial Park,Second industrial district of Guan Long Village,Xili town ,Nanshan District\r
+                               Shenzhen  Guangdong  518055\r
                                CN\r
 \r
-CC-D8-1F   (hex)               Maipu Communication Technology Co.,Ltd.\r
-CCD81F     (base 16)           Maipu Communication Technology Co.,Ltd.\r
-                               Maipu Mansion, No.288 Tianfu 3rd Street, High-tech Zone\r
-                               Chengdu  Sichuan  610094\r
+28-31-66   (hex)               vivo Mobile Communication Co., Ltd.\r
+283166     (base 16)           vivo Mobile Communication Co., Ltd.\r
+                               #283,BBK Road\r
+                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
                                CN\r
 \r
-10-0C-6B   (hex)               NETGEAR\r
-100C6B     (base 16)           NETGEAR\r
-                               350 East Plumeria Drive\r
-                               San Jose  CA  95134\r
+4C-12-65   (hex)               ARRIS Group, Inc.\r
+4C1265     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-2C-F4-32   (hex)               Espressif Inc.\r
-2CF432     (base 16)           Espressif Inc.\r
-                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
-                               Shanghai  Shanghai  201203\r
-                               CN\r
-\r
-AC-BB-61   (hex)               YSTen Technology Co.,Ltd\r
-ACBB61     (base 16)           YSTen Technology Co.,Ltd\r
-                               Room 1715,17/F North Star Times Tower,Chaoyang District,Beijing.\r
-                               Beijing    100101\r
-                               CN\r
-\r
-60-6E-D0   (hex)               SEAL AG\r
-606ED0     (base 16)           SEAL AG\r
-                               Landstrasse 176\r
-                               Wettingen    5430\r
-                               CH\r
-\r
-24-79-F8   (hex)               KUPSON spol. s r.o.\r
-2479F8     (base 16)           KUPSON spol. s r.o.\r
-                               Hradecka 787/14\r
-                               Opava  Czech Republic  74601\r
-                               CZ\r
-\r
-00-A0-85   (hex)               Private\r
-00A085     (base 16)           Private\r
-\r
-40-A9-3F   (hex)               Pivotal Commware, Inc.\r
-40A93F     (base 16)           Pivotal Commware, Inc.\r
-                               1555 132nd Ave. NE\r
-                               Bellevue  WA  98005\r
+00-90-7F   (hex)               WatchGuard Technologies, Inc.\r
+00907F     (base 16)           WatchGuard Technologies, Inc.\r
+                               605 Fifth Ave. S\r
+                               Seattle  WA  98104-3892\r
                                US\r
 \r
-18-D6-CF   (hex)               Kurth Electronic GmbH\r
-18D6CF     (base 16)           Kurth Electronic GmbH\r
-                               Mühleweg 11\r
-                               Eningen    72800\r
+F0-B0-14   (hex)               AVM Audiovisuelles Marketing und Computersysteme GmbH\r
+F0B014     (base 16)           AVM Audiovisuelles Marketing und Computersysteme GmbH\r
+                               Alt-Moabit 95\r
+                               Berlin  Berlin  10559\r
                                DE\r
 \r
-24-3F-30   (hex)               Oxygen Broadband s.a.\r
-243F30     (base 16)           Oxygen Broadband s.a.\r
-                               2 Messogeion ave., Athens Tower\r
-                               Athens  Attiki  11527\r
-                               GR\r
-\r
-48-04-9F   (hex)               ELECOM CO., LTD\r
-48049F     (base 16)           ELECOM CO., LTD\r
-                               9FLand Axis Tower.1-1 fushimi machi,4-chome chuoku\r
-                               osaka    5418765\r
-                               JP\r
+A8-10-87   (hex)               Texas Instruments\r
+A81087     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
 \r
-08-7F-98   (hex)               vivo Mobile Communication Co., Ltd.\r
-087F98     (base 16)           vivo Mobile Communication Co., Ltd.\r
-                               #283,BBK Road\r
-                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
-                               CN\r
+AC-86-74   (hex)               Open Mesh, Inc.\r
+AC8674     (base 16)           Open Mesh, Inc.\r
+                               111 SW 5th Ave Ste1150\r
+                               Portland  OR  97204\r
+                               US\r
 \r
-B4-D0-A9   (hex)               China Mobile Group Device Co.,Ltd.\r
-B4D0A9     (base 16)           China Mobile Group Device Co.,Ltd.\r
-                               32 Xuanwumen West Street,Xicheng District\r
-                               Beijing    100053\r
-                               CN\r
+18-E8-29   (hex)               Ubiquiti Networks Inc.\r
+18E829     (base 16)           Ubiquiti Networks Inc.\r
+                               2580 Orchard Pkwy\r
+                               San Jose  CA  95131\r
+                               US\r
 \r
-48-89-E7   (hex)               Intel Corporate\r
-4889E7     (base 16)           Intel Corporate\r
+18-1D-EA   (hex)               Intel Corporate\r
+181DEA     (base 16)           Intel Corporate\r
                                Lot 8, Jalan Hi-Tech 2/3\r
                                Kulim  Kedah  09000\r
                                MY\r
 \r
-04-D4-C4   (hex)               ASUSTek COMPUTER INC.\r
-04D4C4     (base 16)           ASUSTek COMPUTER INC.\r
-                               15,Li-Te Rd., Peitou, Taipei 112, Taiwan\r
-                               Taipei  Taiwan  112\r
+F0-D7-DC   (hex)               Wesine (Wuhan) Technology Co., Ltd.\r
+F0D7DC     (base 16)           Wesine (Wuhan) Technology Co., Ltd.\r
+                               10th Floor, Building 2, SBI Venture Street, Hongshan District\r
+                               Wuhan  Hubei  430074\r
+                               CN\r
+\r
+44-E4-EE   (hex)               Wistron Neweb Corporation\r
+44E4EE     (base 16)           Wistron Neweb Corporation\r
+                               No.20,Park Avenue II,Hsinchu Science Park\r
+                               Hsin-Chu  R.O.C.  308\r
                                TW\r
 \r
-48-46-C1   (hex)               FN-LINK TECHNOLOGY LIMITED\r
-4846C1     (base 16)           FN-LINK TECHNOLOGY LIMITED\r
-                               A Building,HuiXin industial park,No 31, YongHe road, Fuyong town, Bao'an District\r
-                               SHENZHEN  GUANGDONG  518100\r
+30-0A-60   (hex)               IEEE Registration Authority\r
+300A60     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+2C-79-D7   (hex)               Sagemcom Broadband SAS\r
+2C79D7     (base 16)           Sagemcom Broadband SAS\r
+                               250, route de l'Empereur\r
+                               Rueil Malmaison Cedex  hauts de seine  92848\r
+                               FR\r
+\r
+10-C2-2F   (hex)               China Entropy Co., Ltd.\r
+10C22F     (base 16)           China Entropy Co., Ltd.\r
+                               Haidian District\r
+                               Beijing    100085\r
                                CN\r
 \r
-24-BF-74   (hex)               Private\r
-24BF74     (base 16)           Private\r
+C4-FD-E6   (hex)               DRTECH\r
+C4FDE6     (base 16)           DRTECH\r
+                               29, Dunchon-daero 541beon-gil, Jungwon-gu\r
+                               Seongnam  Gyeonggi-do  13216\r
+                               KR\r
 \r
-00-26-15   (hex)               Teracom Limited\r
-002615     (base 16)           Teracom Limited\r
-                               B-84\r
-                               Noida  Uttar Pradesh  201301\r
-                               IN\r
+44-47-CC   (hex)               Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+4447CC     (base 16)           Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+                               No.555 Qianmo Road\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
 \r
-58-CB-52   (hex)               Google, Inc.\r
-58CB52     (base 16)           Google, Inc.\r
-                               1600 Amphitheatre Parkway\r
-                               Mountain View  CA  94043\r
+4C-D9-8F   (hex)               Dell Inc.\r
+4CD98F     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
                                US\r
 \r
-F8-CA-59   (hex)               NetComm Wireless\r
-F8CA59     (base 16)           NetComm Wireless\r
-                               LEVEL 5, 18-20 ORION RD. LANE COVE\r
-                               LANE COVE WEST  NSW  2066\r
-                               AU\r
+E4-1D-2D   (hex)               Mellanox Technologies, Inc.\r
+E41D2D     (base 16)           Mellanox Technologies, Inc.\r
+                               350 Oakmead Parkway, Suite 100\r
+                               Sunnyvale  CA  94085\r
+                               US\r
 \r
-6C-2C-DC   (hex)               Skyworth Digital Technology(Shenzhen) Co.,Ltd\r
-6C2CDC     (base 16)           Skyworth Digital Technology(Shenzhen) Co.,Ltd\r
-                               7F,Block A,Skyworth Building,\r
-                               Shenzhen  Guangdong  518057\r
-                               CN\r
+B0-AE-25   (hex)               Varikorea\r
+B0AE25     (base 16)           Varikorea\r
+                               #505 kolon digital tower aston, gasan, geumcheon\r
+                               seoul    08502\r
+                               KR\r
 \r
-04-F1-28   (hex)               HMD Global Oy\r
-04F128     (base 16)           HMD Global Oy\r
-                               Bertel Jungin aukio 9\r
-                               Espoo    02600\r
-                               FI\r
+44-00-49   (hex)               Amazon Technologies Inc.\r
+440049     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
 \r
-80-4A-14   (hex)               Apple, Inc.\r
-804A14     (base 16)           Apple, Inc.\r
+C0-74-AD   (hex)               Grandstream Networks, Inc.\r
+C074AD     (base 16)           Grandstream Networks, Inc.\r
+                               1297 Beacon Street\r
+                               Brookline  MA  02446\r
+                               US\r
+\r
+04-91-62   (hex)               Microchip Technology Inc.\r
+049162     (base 16)           Microchip Technology Inc.\r
+                               2355 W. Chandler Blvd.\r
+                               Chandler  AZ  85224\r
+                               US\r
+\r
+98-18-88   (hex)               Cisco Meraki\r
+981888     (base 16)           Cisco Meraki\r
+                               500 Terry A. Francois Blvd\r
+                               San Francisco    94158\r
+                               US\r
+\r
+74-B5-87   (hex)               Apple, Inc.\r
+74B587     (base 16)           Apple, Inc.\r
                                1 Infinite Loop\r
                                Cupertino  CA  95014\r
                                US\r
 \r
-B8-5D-0A   (hex)               Apple, Inc.\r
-B85D0A     (base 16)           Apple, Inc.\r
+D8-1C-79   (hex)               Apple, Inc.\r
+D81C79     (base 16)           Apple, Inc.\r
                                1 Infinite Loop\r
                                Cupertino  CA  95014\r
                                US\r
 \r
-94-16-25   (hex)               Apple, Inc.\r
-941625     (base 16)           Apple, Inc.\r
+8C-FE-57   (hex)               Apple, Inc.\r
+8CFE57     (base 16)           Apple, Inc.\r
                                1 Infinite Loop\r
                                Cupertino  CA  95014\r
                                US\r
 \r
-74-40-BE   (hex)               LG Innotek\r
-7440BE     (base 16)           LG Innotek\r
-                               26, Hanamsandan 5beon-ro\r
-                               Gwangju  Gwangsan-gu  506-731\r
-                               KR\r
-\r
-34-A8-EB   (hex)               Apple, Inc.\r
-34A8EB     (base 16)           Apple, Inc.\r
+C0-A6-00   (hex)               Apple, Inc.\r
+C0A600     (base 16)           Apple, Inc.\r
                                1 Infinite Loop\r
                                Cupertino  CA  95014\r
                                US\r
 \r
-AC-57-75   (hex)               HMD Global Oy\r
-AC5775     (base 16)           HMD Global Oy\r
-                               Bertel Jungin aukio 9\r
-                               Espoo    02600\r
-                               FI\r
+CC-D4-A1   (hex)               MitraStar Technology Corp.\r
+CCD4A1     (base 16)           MitraStar Technology Corp.\r
+                               No. 6, Innovation Road II,\r
+                               Hsinchu    300\r
+                               TW\r
 \r
-4C-6A-F6   (hex)               HMD Global Oy\r
-4C6AF6     (base 16)           HMD Global Oy\r
-                               Bertel Jungin aukio 9\r
-                               Espoo    02600\r
-                               FI\r
+08-BA-5F   (hex)               Qingdao Hisense Electronics Co.,Ltd.\r
+08BA5F     (base 16)           Qingdao Hisense Electronics Co.,Ltd.\r
+                               Qianwangang Roard 218\r
+                               Qingdao  Shandong  266510\r
+                               CN\r
 \r
-AC-8F-F8   (hex)               Nokia\r
-AC8FF8     (base 16)           Nokia\r
-                               600 March Road\r
-                               Kanata  Ontario  K2K 2E6\r
-                               CA\r
+54-06-8B   (hex)               Ningbo Deli Kebei Technology Co.LTD\r
+54068B     (base 16)           Ningbo Deli Kebei Technology Co.LTD\r
+                               zone 2nd , 301#, Road Xuxiake, Ninghai yuelong district\r
+                               ningbo  Zhejiang  315600\r
+                               CN\r
 \r
-10-82-86   (hex)               Luxshare Precision Industry Co.,Ltd\r
-108286     (base 16)           Luxshare Precision Industry Co.,Ltd\r
-                               2nd floor, A building, Sanyo New Industrial Area, West of Maoyi, Shajing  Baoan District\r
-                               Shenzhen  Shenzhen  518104\r
+54-9F-AE   (hex)               iBASE Gaming Inc\r
+549FAE     (base 16)           iBASE Gaming Inc\r
+                               2F., No.542-17, Zhongzheng Rd\r
+                               Xinzhuang Dist., New Taipei City    24255\r
+                               TW\r
+\r
+80-0D-D7   (hex)               Latticework, Inc\r
+800DD7     (base 16)           Latticework, Inc\r
+                               2210 O'Toole Ave, Suite 250\r
+                               San Jose  CA  95131\r
+                               US\r
+\r
+68-8F-2E   (hex)               Hitron Technologies. Inc\r
+688F2E     (base 16)           Hitron Technologies. Inc\r
+                               No. 1-8, Lising 1st Rd. Hsinchu Science Park, Hsinchu, 300, Taiwan, R.O.C\r
+                               Hsin-chu  Taiwan  300\r
+                               TW\r
+\r
+80-69-33   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+806933     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-78-32-1B   (hex)               D-Link International\r
-78321B     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
+C8-9C-13   (hex)               Inspiremobile\r
+C89C13     (base 16)           Inspiremobile\r
+                               Rm1412, Daeryung Techno-Town, 15th, 401 , Simin-daero, Dongan-gu\r
+                               Anyang-si  Gyeonggi-do  14057\r
+                               KR\r
 \r
-00-AD-24   (hex)               D-Link International\r
-00AD24     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
+E0-5D-5C   (hex)               Oy Everon Ab\r
+E05D5C     (base 16)           Oy Everon Ab\r
+                               Teräskatu 8\r
+                               Turku    20520\r
+                               FI\r
 \r
-F4-8C-EB   (hex)               D-Link International\r
-F48CEB     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
+78-47-E3   (hex)               SICHUAN TIANYI COMHEART TELECOM CO.,LTD\r
+7847E3     (base 16)           SICHUAN TIANYI COMHEART TELECOM CO.,LTD\r
+                               NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, \r
+                               CHENGDU  SICHUAN  611330\r
+                               CN\r
 \r
-A0-AB-1B   (hex)               D-Link International\r
-A0AB1B     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
+6C-9B-C0   (hex)               Chemoptics Inc.\r
+6C9BC0     (base 16)           Chemoptics Inc.\r
+                               261, Techno 2-ro, Yuseong-gu\r
+                               Daejeon    34026\r
+                               KR\r
 \r
-10-62-EB   (hex)               D-Link International\r
-1062EB     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
+A8-23-FE   (hex)               LG Electronics\r
+A823FE     (base 16)           LG Electronics\r
+                               222 LG-ro, JINWI-MYEON\r
+                               Pyeongtaek-si  Gyeonggi-do  451-713\r
+                               KR\r
 \r
-FC-75-16   (hex)               D-Link International\r
-FC7516     (base 16)           D-Link International\r
-                               1 International Business Park, #03-12, The Synergy \r
-                               SINGAPORE    609917\r
-                               SG\r
+C0-78-78   (hex)               FLEXTRONICS MANUFACTURING(ZHUHAI)CO.,LTD.\r
+C07878     (base 16)           FLEXTRONICS MANUFACTURING(ZHUHAI)CO.,LTD.\r
+                               Xin Qing Science & Technology Industrial Park,Jin An Town,Doumen ,Zhuhai,Guangdong,PRC\r
+                               Zhuhai  Guangdong  519180\r
+                               CN\r
 \r
-AC-F1-DF   (hex)               D-Link International\r
-ACF1DF     (base 16)           D-Link International\r
-                               1 International Business Park, #03-12, The Synergy \r
-                               SINGAPORE    609917\r
-                               SG\r
+98-0D-67   (hex)               Zyxel Communications Corporation\r
+980D67     (base 16)           Zyxel Communications Corporation\r
+                               No. 6 Innovation Road II, Science Park\r
+                               Hsichu  Taiwan  300\r
+                               TW\r
 \r
-9C-D6-43   (hex)               D-Link International\r
-9CD643     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
+00-40-51   (hex)               Garbee and Garbee\r
+004051     (base 16)           Garbee and Garbee\r
+                               4390 Darr Circle\r
+                               Colorado Springs  CO  80908\r
+                               US\r
 \r
-AC-EE-70   (hex)               Fontem Ventures BV\r
-ACEE70     (base 16)           Fontem Ventures BV\r
-                               Motion Building 8F, Radarweg 60\r
-                               Amsterdam  Noord-Holland  1043NT\r
-                               NL\r
+FC-49-2D   (hex)               Amazon Technologies Inc.\r
+FC492D     (base 16)           Amazon Technologies Inc.\r
+                               P.O Box 8102\r
+                               Reno  NV  89507\r
+                               US\r
 \r
-FC-D2-B6   (hex)               IEEE Registration Authority\r
-FCD2B6     (base 16)           IEEE Registration Authority\r
+5C-FA-FB   (hex)               Acubit\r
+5CFAFB     (base 16)           Acubit\r
+                               Afred Nobels Vej 21A\r
+                               Aalborg Ø    9220\r
+                               DK\r
+\r
+1C-82-59   (hex)               IEEE Registration Authority\r
+1C8259     (base 16)           IEEE Registration Authority\r
                                445 Hoes Lane\r
                                Piscataway  NJ  08554\r
                                US\r
 \r
-60-61-DF   (hex)               Z-meta Research LLC\r
-6061DF     (base 16)           Z-meta Research LLC\r
-                               8365 Quay Drive\r
-                               Arvada  CO  80003\r
-                               US\r
+74-38-B7   (hex)               CANON INC.\r
+7438B7     (base 16)           CANON INC.\r
+                               30-2 Shimomaruko 3-chome\r
+                               Ohta-ku  Tokyo  146-8501\r
+                               JP\r
 \r
-00-B6-00   (hex)               VOIM Co., Ltd.\r
-00B600     (base 16)           VOIM Co., Ltd.\r
-                               70, Seotan-ro, Jinwi-myeon\r
-                               Pyeongtaek-si  Gyeonggi-do  17706\r
+B8-A4-4F   (hex)               Axis Communications AB\r
+B8A44F     (base 16)           Axis Communications AB\r
+                               Emdalavägen 14\r
+                               LUND    22369\r
+                               SE\r
+\r
+D0-57-94   (hex)               Sagemcom Broadband SAS\r
+D05794     (base 16)           Sagemcom Broadband SAS\r
+                               250, route de l'Empereur\r
+                               Rueil Malmaison Cedex  hauts de seine  92848\r
+                               FR\r
+\r
+8C-E5-C0   (hex)               Samsung Electronics Co.,Ltd\r
+8CE5C0     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
                                KR\r
 \r
-48-83-B4   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-4883B4     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,\r
-                               DONG GUAN  GUANG DONG  523860\r
-                               CN\r
+F0-8A-76   (hex)               Samsung Electronics Co.,Ltd\r
+F08A76     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
 \r
-28-23-F5   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-2823F5     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
-                               Hangzhou  Zhejiang  310000\r
+00-FA-21   (hex)               Samsung Electronics Co.,Ltd\r
+00FA21     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+14-49-BC   (hex)               DrayTek Corp.\r
+1449BC     (base 16)           DrayTek Corp.\r
+                               No. 26, Fushing Rd., Hukou, Hsinchu Industrial Park,\r
+                               Hsinchu county    30352\r
+                               TW\r
+\r
+28-99-C7   (hex)               LINDSAY BROADBAND INC\r
+2899C7     (base 16)           LINDSAY BROADBAND INC\r
+                               2035 2 FISHER DRIVE\r
+                               PETERBOROUGH  Ontario  K9J 6X6\r
+                               CA\r
+\r
+BC-7F-A4   (hex)               Xiaomi Communications Co Ltd\r
+BC7FA4     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
                                CN\r
 \r
-20-2A-C5   (hex)               Petite-En\r
-202AC5     (base 16)           Petite-En\r
-                               1, Gwanak-ro, Gwanak-gu\r
-                               Seoul    08826\r
-                               KR\r
+AC-42-28   (hex)               Parta Networks\r
+AC4228     (base 16)           Parta Networks\r
+                               Teknopark Izmir No:38\r
+                               URLA  IZMIR  35433\r
+                               TR\r
 \r
-DC-96-2C   (hex)               NST Audio Ltd\r
-DC962C     (base 16)           NST Audio Ltd\r
-                               32 Whitewall\r
-                               Norton  North Yorkshire  YO17 9EH\r
-                               GB\r
+8C-04-BA   (hex)               Dell Inc.\r
+8C04BA     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
+                               US\r
 \r
-50-AD-71   (hex)               Tessolve Semiconductor Private Limited\r
-50AD71     (base 16)           Tessolve Semiconductor Private Limited\r
-                               Plot No: 31, P2, Electronic City Phase II, Electronic City\r
-                               Bengaluru  Karnataka  560100\r
-                               IN\r
+CC-64-A6   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+CC64A6     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
 \r
-F4-79-60   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-F47960     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+18-CF-24   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+18CF24     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
                                No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
                                Dongguan    523808\r
                                CN\r
 \r
-20-65-8E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-20658E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+08-4F-0A   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+084F0A     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
                                No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
                                Dongguan    523808\r
                                CN\r
 \r
-08-A6-BC   (hex)               Amazon Technologies Inc.\r
-08A6BC     (base 16)           Amazon Technologies Inc.\r
-                               P.O Box 8102\r
-                               Reno  NV  89507\r
-                               US\r
+50-F8-A5   (hex)               eWBM Co., Ltd.\r
+50F8A5     (base 16)           eWBM Co., Ltd.\r
+                               14F, 9, Teheran-ro 20-gil\r
+                               Gangnam-gu, Seoul    06236\r
+                               KR\r
 \r
-EC-AD-E0   (hex)               D-Link International\r
-ECADE0     (base 16)           D-Link International\r
-                               1 Internal Business Park, #03-12,The Synergy, Singapore\r
-                               Singapore  Singapore  609917\r
-                               SG\r
+C8-D6-9D   (hex)               Arab International Optronics\r
+C8D69D     (base 16)           Arab International Optronics\r
+                               El Salam St. \r
+                               El Salam City   Cairo  11371\r
+                               EG\r
 \r
-F0-B9-68   (hex)               ITEL MOBILE LIMITED\r
-F0B968     (base 16)           ITEL MOBILE LIMITED\r
-                               RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING  NO.7 KO FAI ROAD, YAU TONG, KLN, H.K\r
-                               Hong Kong  KOWLOON  999077\r
-                               HK\r
+BC-97-40   (hex)               IEEE Registration Authority\r
+BC9740     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
 \r
-98-8B-0A   (hex)               Hangzhou Hikvision Digital Technology Co.,Ltd.\r
-988B0A     (base 16)           Hangzhou Hikvision Digital Technology Co.,Ltd.\r
-                               No.555 Qianmo Road, Binjiang District\r
-                               Hangzhou  Zhejiang  310052\r
+C4-06-83   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+C40683     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
                                CN\r
 \r
-1C-BF-CE   (hex)               Shenzhen Century Xinyang Technology Co., Ltd\r
-1CBFCE     (base 16)           Shenzhen Century Xinyang Technology Co., Ltd\r
-                               3F, North Building, Bantian High-tech industrial Zone, No. 2 of Bell Road\r
-                               Shenzhen  Guangdong  518129\r
+FC-87-43   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+FC8743     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
                                CN\r
 \r
-F8-30-02   (hex)               Texas Instruments\r
-F83002     (base 16)           Texas Instruments\r
-                               12500 TI Blvd\r
-                               Dallas  TX  75243\r
+40-2B-50   (hex)               ARRIS Group, Inc.\r
+402B50     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
                                US\r
 \r
-B0-2A-1F   (hex)                Wingtech Group (HongKong)Limited\r
-B02A1F     (base 16)            Wingtech Group (HongKong)Limited\r
-                                FLAT/RM 1903 19/F PODIUM PLAZA 5HANOI ROAD TSIM SHA TSUI\r
-                               Hong Kong  Hong Kong  999077\r
+AC-DB-48   (hex)               ARRIS Group, Inc.\r
+ACDB48     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+0C-B7-71   (hex)               ARRIS Group, Inc.\r
+0CB771     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+6C-29-90   (hex)               WiZ Connected Lighting Company Limited\r
+6C2990     (base 16)           WiZ Connected Lighting Company Limited\r
+                               Room 3805, 148 Electric Road\r
+                               Hong Kong  0000  0000\r
                                HK\r
 \r
-1C-B3-E9   (hex)                Shenzhen Zhongke United Communication Technology \r
-1CB3E9     (base 16)            Shenzhen Zhongke United Communication Technology \r
-                               6C jiajiahao commercial building, Shennan avenue\r
-                               Shenzhen  Guangdong  518000\r
+24-16-6D   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+24166D     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
                                CN\r
 \r
-34-E1-D1   (hex)               IEEE Registration Authority\r
-34E1D1     (base 16)           IEEE Registration Authority\r
+98-35-ED   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+9835ED     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+70-C7-F2   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+70C7F2     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+8C-FD-18   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+8CFD18     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+C8-5D-38   (hex)               HUMAX Co., Ltd.\r
+C85D38     (base 16)           HUMAX Co., Ltd.\r
+                               HUMAX Village, 216, Hwangsaeul-ro, Bu\r
+                               Seongnam-si  Gyeonggi-do  463-875\r
+                               KR\r
+\r
+D0-C8-57   (hex)               IEEE Registration Authority\r
+D0C857     (base 16)           IEEE Registration Authority\r
                                445 Hoes Lane\r
                                Piscataway  NJ  08554\r
                                US\r
 \r
-DC-FB-48   (hex)               Intel Corporate\r
-DCFB48     (base 16)           Intel Corporate\r
-                               Lot 8, Jalan Hi-Tech 2/3\r
-                               Kulim  Kedah  09000\r
-                               MY\r
-\r
-6C-40-C6   (hex)               Nimbus Data, Inc.\r
-6C40C6     (base 16)           Nimbus Data, Inc.\r
-                               5151 California Ave, Ste 100\r
-                               Irvine  CA  92617\r
+B8-07-56   (hex)               Cisco Meraki\r
+B80756     (base 16)           Cisco Meraki\r
+                               500 Terry A. Francois Blvd\r
+                               San Francisco    94158\r
                                US\r
 \r
-A8-DB-03   (hex)               SAMSUNG ELECTRO-MECHANICS(THAILAND)\r
-A8DB03     (base 16)           SAMSUNG ELECTRO-MECHANICS(THAILAND)\r
-                               93Moo5T. Bangsamak SEMTHAI, WELLGROW INDUSTRIAL ESTATE\r
-                               Bangpakong  Chachoengsao  24180\r
-                               TH\r
-\r
-44-A6-1E   (hex)               INGRAM MICRO SERVICES\r
-44A61E     (base 16)           INGRAM MICRO SERVICES\r
-                               100 CHEMIN DE BAILLOT\r
-                               MONTAUBAN    82000\r
-                               FR\r
-\r
-8C-0F-A0   (hex)               di-soric GmbH & Co. KG\r
-8C0FA0     (base 16)           di-soric GmbH & Co. KG\r
-                               Steinbeisstrasse 6\r
-                               Urbach    73660\r
-                               DE\r
+98-86-5D   (hex)               Nokia Shanghai Bell Co., Ltd.\r
+98865D     (base 16)           Nokia Shanghai Bell Co., Ltd.\r
+                               No.388 Ning Qiao Road,Jin Qiao Pudong Shanghai\r
+                               Shanghai     201206\r
+                               CN\r
 \r
-90-78-41   (hex)               Intel Corporate\r
-907841     (base 16)           Intel Corporate\r
-                               Lot 8, Jalan Hi-Tech 2/3\r
-                               Kulim  Kedah  09000\r
-                               MY\r
+D8-D4-E6   (hex)               Hytec Inter Co., Ltd.\r
+D8D4E6     (base 16)           Hytec Inter Co., Ltd.\r
+                               3-28-6 Yoyogi\r
+                               Shibuya-ku  Tokyo  1510053\r
+                               JP\r
 \r
-10-9E-3A   (hex)               Zhejiang Tmall Technology Co., Ltd.\r
-109E3A     (base 16)           Zhejiang Tmall Technology Co., Ltd.\r
-                               Ali Center,No.3331 Keyuan South RD (Shenzhen bay), Nanshan District, \r
-                               Shenzhen  Guangdong  518000\r
+28-23-F5   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+2823F5     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
+                               Hangzhou  Zhejiang  310000\r
                                CN\r
 \r
-CC-37-AB   (hex)               Edgecore Networks Corporation\r
-CC37AB     (base 16)           Edgecore Networks Corporation\r
-                               1 Creation Road 3.\r
-                               Hsinchu  Hsinchu  30077\r
-                               TW\r
-\r
-24-79-F3   (hex)               GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-2479F3     (base 16)           GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD\r
-                               NO.18 HAIBIN ROAD,\r
-                               DONG GUAN  GUANG DONG  523860\r
+8C-18-50   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+8C1850     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
+                               Hangzhou  Hangzhou  310000\r
                                CN\r
 \r
-20-58-69   (hex)               Ruckus Wireless\r
-205869     (base 16)           Ruckus Wireless\r
-                               350 West Java Drive\r
-                               Sunnyvale  CA  94089\r
+2C-4F-52   (hex)               Cisco Systems, Inc\r
+2C4F52     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
                                US\r
 \r
-60-D2-DD   (hex)               Shenzhen Baitong Putian Technology Co.,Ltd.\r
-60D2DD     (base 16)           Shenzhen Baitong Putian Technology Co.,Ltd.\r
-                               501,5/F,Building 1,No.2,Lianwei Street,Hualian Community,Longhua Street Longhua District\r
-                               Shenzhen  Guangdong  518109\r
+60-3A-7C   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+603A7C     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
                                CN\r
 \r
-FC-AB-90   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-FCAB90     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
+7C-B5-9B   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+7CB59B     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
                                CN\r
 \r
-20-DA-22   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-20DA22     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
+F8-E7-A0   (hex)               vivo Mobile Communication Co., Ltd.\r
+F8E7A0     (base 16)           vivo Mobile Communication Co., Ltd.\r
+                               #283,BBK Road\r
+                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
                                CN\r
 \r
-88-F8-72   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-88F872     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
+2C-FF-EE   (hex)               vivo Mobile Communication Co., Ltd.\r
+2CFFEE     (base 16)           vivo Mobile Communication Co., Ltd.\r
+                               #283,BBK Road\r
+                               Wusha,Chang'An  DongGuan City,Guangdong,  523860\r
                                CN\r
 \r
-70-F2-20   (hex)               Actiontec Electronics, Inc\r
-70F220     (base 16)           Actiontec Electronics, Inc\r
-                               3301 Olcott St.\r
-                               Santa Clara  CA  95054\r
-                               US\r
+CC-3A-DF   (hex)               Private\r
+CC3ADF     (base 16)           Private\r
 \r
-00-24-7B   (hex)               Actiontec Electronics, Inc\r
-00247B     (base 16)           Actiontec Electronics, Inc\r
-                               3301 Olcott St.\r
-                               Santa Clara  CA  95054\r
-                               US\r
+24-EE-9A   (hex)               Intel Corporate\r
+24EE9A     (base 16)           Intel Corporate\r
+                               Lot 8, Jalan Hi-Tech 2/3\r
+                               Kulim  Kedah  09000\r
+                               MY\r
 \r
-A8-39-44   (hex)               Actiontec Electronics, Inc\r
-A83944     (base 16)           Actiontec Electronics, Inc\r
-                               301 Olcott St\r
-                               Santa Clara  CA  95054\r
-                               US\r
+50-97-44   (hex)               Integrated Device Technology (Malaysia) Sdn. Bhd.\r
+509744     (base 16)           Integrated Device Technology (Malaysia) Sdn. Bhd.\r
+                               Phase 3, Bayan Lepas FIZ\r
+                               Bayan Lepas  Penang  11900\r
+                               MY\r
 \r
-88-E6-4B   (hex)               Juniper Networks\r
-88E64B     (base 16)           Juniper Networks\r
-                               1133 Innovation Way\r
-                               Sunnyvale  CA  94089\r
-                               US\r
+38-1A-52   (hex)               Seiko Epson Corporation\r
+381A52     (base 16)           Seiko Epson Corporation\r
+                               2070 Kotobuki Koaka\r
+                               Matsumoto-shi  Nagano-ken  399-8702\r
+                               JP\r
 \r
-48-D8-75   (hex)               China TransInfo Technology Co., Ltd\r
-48D875     (base 16)           China TransInfo Technology Co., Ltd\r
-                               Qianfang Building, Phase I, Zhongguancun Software Park, 8 Wangxi Road, Haidian District\r
-                               Beijing    100085\r
-                               CN\r
+88-9F-AA   (hex)               Hella Gutmann Solutions GmbH \r
+889FAA     (base 16)           Hella Gutmann Solutions GmbH \r
+                               Am Krebsbach 2\r
+                               Ihringen   Baden Württemberg  79241\r
+                               DE\r
 \r
-CC-A1-2B   (hex)               TCL King Electrical Appliances (Huizhou) Co., Ltd\r
-CCA12B     (base 16)           TCL King Electrical Appliances (Huizhou) Co., Ltd\r
-                               10F, TCL Multimedia Building, TCL International E City, No.1001 Zhongshanyuan Rd., Nanshan District\r
-                               Shenzhen  Guangdong  518052\r
-                               CN\r
+F8-8E-85   (hex)               Comtrend Corporation\r
+F88E85     (base 16)           Comtrend Corporation\r
+                               3F-1, 10 Lane 609, Chongxin Road, Section 5, \r
+                               New Taipei City,  Taiwan  24159\r
+                               TW\r
 \r
-4C-BC-48   (hex)               Cisco Systems, Inc\r
-4CBC48     (base 16)           Cisco Systems, Inc\r
-                               80 West Tasman Drive\r
-                               San Jose  CA  94568\r
+00-C0-17   (hex)               NetAlly\r
+00C017     (base 16)           NetAlly\r
+                               310 Littleton Road\r
+                               Westford  MA  01886\r
                                US\r
 \r
-D4-6A-35   (hex)               Cisco Systems, Inc\r
-D46A35     (base 16)           Cisco Systems, Inc\r
-                               80 West Tasman Drive\r
-                               San Jose  CA  94568\r
+3C-B7-4B   (hex)               Technicolor CH USA Inc.\r
+3CB74B     (base 16)           Technicolor CH USA Inc.\r
+                               5030 Sugarloaf Parkway Bldg 6\r
+                               Lawrenceville  GA  30044\r
                                US\r
 \r
-E4-F3-E8   (hex)               Shenzhen SuperElectron Technology Co.,Ltd.\r
-E4F3E8     (base 16)           Shenzhen SuperElectron Technology Co.,Ltd.\r
-                               1213-1214, haosheng business center, dongbin road, nanshan street, nanshan district, shenzhen city\r
-                               Shenzhen   Guangdong  518000\r
-                               CN\r
+14-42-FC   (hex)               Texas Instruments\r
+1442FC     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
 \r
-B0-30-55   (hex)               China Mobile IOT Company Limited\r
-B03055     (base 16)           China Mobile IOT Company Limited\r
-                               NO.8 Yu Ma Road, NanAn Area\r
-                               Chongqing  Chongqing  401336\r
-                               CN\r
+F4-33-28   (hex)               CIMCON Lighting Inc.\r
+F43328     (base 16)           CIMCON Lighting Inc.\r
+                               35 Crosby Drive\r
+                               Bedford  MA  01730\r
+                               US\r
 \r
-E8-D0-FC   (hex)               Liteon Technology Corporation\r
-E8D0FC     (base 16)           Liteon Technology Corporation\r
-                               4F, 90, Chien 1 Road\r
-                               New Taipei City  Taiwan  23585\r
-                               TW\r
+B0-B5-E8   (hex)               Ruroc LTD\r
+B0B5E8     (base 16)           Ruroc LTD\r
+                               Unit 2, Barnett Way, Barnwood Estate\r
+                               Gloucester    GL4 3RT\r
+                               GB\r
 \r
-C0-9F-E1   (hex)               zte corporation\r
-C09FE1     (base 16)           zte corporation\r
-                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
-                               shenzhen  guangdong  518057\r
-                               CN\r
+04-D5-90   (hex)               Fortinet, Inc.\r
+04D590     (base 16)           Fortinet, Inc.\r
+                               899 Kifer Road\r
+                               Sunnyvale    94086\r
+                               US\r
 \r
-AC-00-D0   (hex)               zte corporation\r
-AC00D0     (base 16)           zte corporation\r
-                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
-                               shenzhen  guangdong  518057\r
-                               CN\r
+5C-5A-C7   (hex)               Cisco Systems, Inc\r
+5C5AC7     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
 \r
-10-DC-4A   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
-10DC4A     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
-                               No.5 DongXin Road\r
-                               Wuhan  Hubei  430074\r
+1C-B7-96   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+1CB796     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-44-4B-7E   (hex)               Fiberhome Telecommunication Technologies Co.,LTD\r
-444B7E     (base 16)           Fiberhome Telecommunication Technologies Co.,LTD\r
-                               No.5 DongXin Road\r
-                               Wuhan  Hubei  430074\r
+D4-62-EA   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+D462EA     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-84-C7-8F   (hex)               STORDIS GmbH\r
-84C78F     (base 16)           STORDIS GmbH\r
-                               Rosenwiesstr. 17\r
-                               Stuttgart    70567\r
-                               DE\r
-\r
-78-2C-29   (hex)               New H3C Technologies Co., Ltd\r
-782C29     (base 16)           New H3C Technologies Co., Ltd\r
-                               466 Changhe Road, Binjiang District\r
-                               Hangzhou  Zhejiang  310052\r
+38-47-BC   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+3847BC     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
                                CN\r
 \r
-98-B8-BA   (hex)               LG Electronics (Mobile Communications)\r
-98B8BA     (base 16)           LG Electronics (Mobile Communications)\r
-                               60-39, Gasan-dong, Geumcheon-gu\r
-                               Seoul    153-801\r
-                               KR\r
-\r
-D4-9D-C0   (hex)               Samsung Electronics Co.,Ltd\r
-D49DC0     (base 16)           Samsung Electronics Co.,Ltd\r
-                               129, Samsung-ro, Youngtongl-Gu\r
-                               Suwon  Gyeonggi-Do  16677\r
-                               KR\r
-\r
-D4-D2-52   (hex)               Intel Corporate\r
-D4D252     (base 16)           Intel Corporate\r
-                               Lot 8, Jalan Hi-Tech 2/3\r
-                               Kulim  Kedah  09000\r
-                               MY\r
+F8-AD-CB   (hex)               HMD Global Oy\r
+F8ADCB     (base 16)           HMD Global Oy\r
+                               Bertel Jungin aukio 9\r
+                               Espoo    02600\r
+                               FI\r
 \r
 58-46-E1   (hex)               Baxter International Inc\r
 5846E1     (base 16)           Baxter International Inc\r
@@ -65978,12 +66548,6 @@ D862DB     (base 16)           Eno Inc.
                                Tokyo    1700013\r
                                JP\r
 \r
-68-DB-67   (hex)               Nantong Coship Electronics Co., Ltd\r
-68DB67     (base 16)           Nantong Coship Electronics Co., Ltd\r
-                               No.188 Xinsheng Road\r
-                               Nantong  Jiangsu  226000\r
-                               US\r
-\r
 BC-26-1D   (hex)               HONG KONG TECON TECHNOLOGY\r
 BC261D     (base 16)           HONG KONG TECON TECHNOLOGY\r
                                ROOM 2802,BLOCK A,SHEN FANG OLAZA\r
@@ -66152,12 +66716,6 @@ C47DCC     (base 16)           Zebra Technologies Inc
                                Freiburg  BW  79111\r
                                US\r
 \r
-84-C2-E4   (hex)               Jiangsu Qinheng Co., Ltd.\r
-84C2E4     (base 16)           Jiangsu Qinheng Co., Ltd.\r
-                               No. 18, Ningshuang Road\r
-                               Nanjing  Jiangsu  210012\r
-                               CN\r
-\r
 C0-B8-B1   (hex)               BitBox Ltd\r
 C0B8B1     (base 16)           BitBox Ltd\r
                                Whitney Road\r
@@ -75959,12 +76517,6 @@ A893E6     (base 16)           JIANGXI JINGGANGSHAN CKING COMMUNICATION TECHNOLOGY CO.,LT
                                Walkersville  Maryland  21793\r
                                US\r
 \r
-00-0C-FF   (hex)               MRO-TEK LIMITED\r
-000CFF     (base 16)           MRO-TEK LIMITED\r
-                               14, 1ST D MAIN ROAD,\r
-                               BANGALORE  KARNATAKA  560032\r
-                               IN\r
-\r
 00-0C-ED   (hex)               Real Digital Media\r
 000CED     (base 16)           Real Digital Media\r
                                485 North Keller Road\r
@@ -77294,12 +77846,6 @@ A893E6     (base 16)           JIANGXI JINGGANGSHAN CKING COMMUNICATION TECHNOLOGY CO.,LT
                                Cupertino  CA  95014\r
                                US\r
 \r
-00-08-5D   (hex)               Aastra\r
-00085D     (base 16)           Aastra\r
-                               1160 Route 22 East\r
-                               Bridgewater  NJ  08807\r
-                               US\r
-\r
 00-08-62   (hex)               NEC Eluminant Technologies, Inc.\r
 000862     (base 16)           NEC Eluminant Technologies, Inc.\r
                                14700 Avion Parkway\r
@@ -85826,12 +86372,6 @@ BC282C     (base 16)           e-Smart Systems Pvt. Ltd
                                Dallas  TX  75243\r
                                US\r
 \r
-D8-E7-2B   (hex)               NetScout Systems, Inc.\r
-D8E72B     (base 16)           NetScout Systems, Inc.\r
-                               310 Littleton Road\r
-                               Westford  MA  01886\r
-                               US\r
-\r
 04-FE-A1   (hex)               Fihonest communication co.,Ltd\r
 04FEA1     (base 16)           Fihonest communication co.,Ltd\r
                                Room902,Park road,Zhixing business-building\r
@@ -86630,12 +87170,6 @@ B83A9D     (base 16)           Alarm.com
                                INCHEON    22830\r
                                KR\r
 \r
-E0-D9-E3   (hex)               Eltex Enterprise Ltd.\r
-E0D9E3     (base 16)           Eltex Enterprise Ltd.\r
-                               Okruzhnaya 29v\r
-                               Novosibirsk    630020\r
-                               RU\r
-\r
 50-98-F3   (hex)               Rheem Australia Pty Ltd\r
 5098F3     (base 16)           Rheem Australia Pty Ltd\r
                                1 Alan Street\r
@@ -90176,12 +90710,6 @@ B8F74A     (base 16)           RCNTEC
                                Moscow    127018\r
                                RU\r
 \r
-C8-D1-2A   (hex)               Comtrend Corporation\r
-C8D12A     (base 16)           Comtrend Corporation\r
-                               3F-1, No. 10, Lane 609, Chung Hsin Road, Sec 5, San Chung Dist.\r
-                               New Taipei City  Taiwan  24159\r
-                               TW\r
-\r
 B4-F1-DA   (hex)               LG Electronics (Mobile Communications)\r
 B4F1DA     (base 16)           LG Electronics (Mobile Communications)\r
                                60-39, Gasan-dong, Geumcheon-gu\r
@@ -90854,12 +91382,6 @@ D0B214     (base 16)           PoeWit Inc
                                Fort Lauderdale  FL  33301\r
                                US\r
 \r
-08-47-D0   (hex)               Nokia Shanghai Bell Co. Ltd.)\r
-0847D0     (base 16)           Nokia Shanghai Bell Co. Ltd.)\r
-                               No.388 Ning Qiao Road,Jin Qiao Pudong Shanghai 201206,P.R.China\r
-                               Shanghai   Pudong  201206\r
-                               CN\r
-\r
 18-69-DA   (hex)               China Mobile Group Device Co.,Ltd.\r
 1869DA     (base 16)           China Mobile Group Device Co.,Ltd.\r
                                32 Xuanwumen West Street,Xicheng District\r
@@ -92330,30 +92852,6 @@ C8F742     (base 16)           HangZhou Gubei Electronics Technology Co.,Ltd
                                Lawrenceville  GA  30044\r
                                US\r
 \r
-74-60-FA   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-7460FA     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-88-40-3B   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-88403B     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-68-A0-3E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-68A03E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
-B8-C3-85   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-B8C385     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
 30-DF-8D   (hex)               SHENZHEN GONGJIN ELECTRONICS CO.,LT\r
 30DF8D     (base 16)           SHENZHEN GONGJIN ELECTRONICS CO.,LT\r
                                SONGGANG\r
@@ -92750,12 +93248,6 @@ A4CF12     (base 16)           Espressif Inc.
                                Shanghai  Shanghai  201203\r
                                CN\r
 \r
-08-9C-86   (hex)               Nokia Shanghai Bell Co. Ltd.)\r
-089C86     (base 16)           Nokia Shanghai Bell Co. Ltd.)\r
-                               No.388 Ning Qiao Road,Jin Qiao Pudong Shanghai 201206,P.R.China\r
-                               Shanghai   Pudong  201206\r
-                               CN\r
-\r
 94-BF-C4   (hex)               Ruckus Wireless\r
 94BFC4     (base 16)           Ruckus Wireless\r
                                350 West Java Drive\r
@@ -92972,12 +93464,6 @@ E8ECA3     (base 16)           Dongguan Liesheng Electronic Co.Ltd
                                shenzhen  guangdong  518057\r
                                CN\r
 \r
-20-96-8A   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-20968A     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
-                               Hangzhou  Zhejiang  310000\r
-                               CN\r
-\r
 F0-D4-F7   (hex)               varram system\r
 F0D4F7     (base 16)           varram system\r
                                57, TECHNO 11-RO,YUSEONG-GU, DAEJEON, KOREA \r
@@ -93230,6 +93716,300 @@ D420B0     (base 16)          Mist Systems, Inc.
                                Cologne  NW  50676\r
                                DE\r
 \r
+EC-5B-73   (hex)               Advanced & Wise Technology Corp.\r
+EC5B73     (base 16)           Advanced & Wise Technology Corp.\r
+                               5F, No. 3-2, Industry East 9th Road, Hsinchu Science Park,\r
+                               Hsinchu City  Hsinchu  30075\r
+                               TW\r
+\r
+60-D2-48   (hex)               ARRIS Group, Inc.\r
+60D248     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+C0-89-AB   (hex)               ARRIS Group, Inc.\r
+C089AB     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+68-6D-BC   (hex)               Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+686DBC     (base 16)           Hangzhou Hikvision Digital Technology Co.,Ltd.\r
+                               No.555 Qianmo Road, Binjiang District\r
+                               Hangzhou  Zhejiang  310052\r
+                               CN\r
+\r
+18-AA-CA   (hex)               Sichuan tianyi kanghe communications co., LTD\r
+18AACA     (base 16)           Sichuan tianyi kanghe communications co., LTD\r
+                               No.198, section 1, xueshan avenue, jinyuan town, dayi county, sichuan province\r
+                               chengdu  sichuan  611330\r
+                               CN\r
+\r
+D4-F0-57   (hex)               Nintendo Co.,Ltd\r
+D4F057     (base 16)           Nintendo Co.,Ltd\r
+                               11-1 HOKOTATE-CHO KAMITOBA,MINAMI-KU\r
+                               KYOTO  KYOTO  601-8501\r
+                               JP\r
+\r
+68-DB-67   (hex)               Nantong Coship Electronics Co., Ltd.\r
+68DB67     (base 16)           Nantong Coship Electronics Co., Ltd.\r
+                               No.188 Xinsheng Road\r
+                               Nantong  Jiangsu  226000\r
+                               US\r
+\r
+84-C2-E4   (hex)               Jiangsu Qinheng Co., Ltd.\r
+84C2E4     (base 16)           Jiangsu Qinheng Co., Ltd.\r
+                               No. 18, Ningshuang Road\r
+                               Nanjing  Jiangsu  210012\r
+                               CN\r
+\r
+74-45-CE   (hex)               CRESYN\r
+7445CE     (base 16)           CRESYN\r
+                               8-22,Jamwon-dong\r
+                               Seoul  Seocho-Gu  #137-902\r
+                               KR\r
+\r
+C8-EA-F8   (hex)               zte corporation\r
+C8EAF8     (base 16)           zte corporation\r
+                               12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China\r
+                               shenzhen  guangdong  518057\r
+                               CN\r
+\r
+30-31-7D   (hex)               Hosiden Corporation\r
+30317D     (base 16)           Hosiden Corporation\r
+                               4-33, Kitakyuhoji 1-chome\r
+                               Yao  Osaka  5810071\r
+                               JP\r
+\r
+38-3B-26   (hex)               Jiangsu Qinheng Co., Ltd.\r
+383B26     (base 16)           Jiangsu Qinheng Co., Ltd.\r
+                               No. 18, Ningshuang Road\r
+                               Nanjing  Jiangsu  210012\r
+                               CN\r
+\r
+BC-98-DF   (hex)               Motorola Mobility LLC, a Lenovo Company\r
+BC98DF     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
+                               222 West Merchandise Mart Plaza\r
+                               Chicago  IL  60654\r
+                               US\r
+\r
+74-EE-2A   (hex)               SHENZHEN BILIAN ELECTRONIC CO.,LTD\r
+74EE2A     (base 16)           SHENZHEN BILIAN ELECTRONIC CO.,LTD\r
+                               NO.268, Fuqian Rd, Jutang community, Guanlan Town, Longhua New district\r
+                               shenzhen  guangdong  518000\r
+                               CN\r
+\r
+C4-F7-D5   (hex)               Cisco Systems, Inc\r
+C4F7D5     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+54-E0-19   (hex)               Ring LLC\r
+54E019     (base 16)           Ring LLC\r
+                               1523 26th St\r
+                               Santa Monica  CA  90404\r
+                               US\r
+\r
+E0-D9-E3   (hex)               Eltex Enterprise Ltd.\r
+E0D9E3     (base 16)           Eltex Enterprise Ltd.\r
+                               Okruzhnaya st. 29v\r
+                               Novosibirsk    630020\r
+                               RU\r
+\r
+D8-13-99   (hex)               Hui Zhou Gaoshengda Technology Co.,LTD\r
+D81399     (base 16)           Hui Zhou Gaoshengda Technology Co.,LTD\r
+                               No.75,Zhongkai High-Tech Development District,Huizhou\r
+                               Hui Zhou  Guangdong  516006\r
+                               CN\r
+\r
+E8-28-C1   (hex)               Eltex Enterprise Ltd.\r
+E828C1     (base 16)           Eltex Enterprise Ltd.\r
+                               Okruzhnaya st. 29v\r
+                               Novosibirsk    630020\r
+                               RU\r
+\r
+6C-F1-7E   (hex)               Zhejiang Uniview Technologies Co.,Ltd.\r
+6CF17E     (base 16)           Zhejiang Uniview Technologies Co.,Ltd.\r
+                               No.88,Jiangling Road\r
+                               Hangzhou  Zhejiang,P.R.China  310051\r
+                               CN\r
+\r
+00-08-5D   (hex)               Mitel Corporation\r
+00085D     (base 16)           Mitel Corporation\r
+                               350 Legget Drive\r
+                               -    K2K 2W7\r
+                               CA\r
+\r
+18-B6-F7   (hex)               NEW POS TECHNOLOGY LIMITED\r
+18B6F7     (base 16)           NEW POS TECHNOLOGY LIMITED\r
+                               AB Unit, 14th Floor,Block A, Financial Technology Building.No. 11 Keyuan Rd\r
+                               Shenzhen    518057\r
+                               CN\r
+\r
+BC-97-E1   (hex)               Broadcom Limited\r
+BC97E1     (base 16)           Broadcom Limited\r
+                               15191 Alton Parkway\r
+                               Irvine  CA  92618\r
+                               US\r
+\r
+EC-AA-25   (hex)               Samsung Electronics Co.,Ltd\r
+ECAA25     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+18-19-D6   (hex)               Samsung Electronics Co.,Ltd\r
+1819D6     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+54-EC-2F   (hex)               Ruckus Wireless\r
+54EC2F     (base 16)           Ruckus Wireless\r
+                               350 West Java Drive\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+20-F4-78   (hex)               Xiaomi Communications Co Ltd\r
+20F478     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+1C-20-DB   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+1C20DB     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+74-60-FA   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+7460FA     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+88-40-3B   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+88403B     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+68-A0-3E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+68A03E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+B8-C3-85   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+B8C385     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+08-47-D0   (hex)               Nokia Shanghai Bell Co., Ltd.\r
+0847D0     (base 16)           Nokia Shanghai Bell Co., Ltd.\r
+                               No.388 Ning Qiao Road,Jin Qiao Pudong Shanghai 201206,P.R.China\r
+                               Shanghai   Pudong  201206\r
+                               CN\r
+\r
+08-9C-86   (hex)               Nokia Shanghai Bell Co., Ltd.\r
+089C86     (base 16)           Nokia Shanghai Bell Co., Ltd.\r
+                               No.388 Ning Qiao Road,Jin Qiao Pudong Shanghai 201206,P.R.China\r
+                               Shanghai   Pudong  201206\r
+                               CN\r
+\r
+C8-50-CE   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+C850CE     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+CC-90-70   (hex)               Cisco Systems, Inc\r
+CC9070     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+54-EF-44   (hex)               Lumi United Technology Co., Ltd\r
+54EF44     (base 16)           Lumi United Technology Co., Ltd\r
+                               8th Floor, JinQi Wisdom Valley, No.1 TangLing Road, LinXian Ave, Taoyuan Residential District,Nanshan District\r
+                               ShenZhen  GuangDong  518055\r
+                               CN\r
+\r
+48-A7-3C   (hex)               Sichuan tianyi kanghe communications co., LTD\r
+48A73C     (base 16)           Sichuan tianyi kanghe communications co., LTD\r
+                               No.198, section 1, xueshan avenue, jinyuan town, dayi county\r
+                               chengdu  sichuan  611330\r
+                               CN\r
+\r
+20-96-8A   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+20968A     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
+                               Hangzhou  Zhejiang  310000\r
+                               CN\r
+\r
+9C-99-CD   (hex)               Voippartners\r
+9C99CD     (base 16)           Voippartners\r
+                               Via di Passolombardo 35\r
+                               Rome     00133\r
+                               IT\r
+\r
+C8-D1-2A   (hex)               Comtrend Corporation\r
+C8D12A     (base 16)           Comtrend Corporation\r
+                               3F-1, 10 Lane 609, Chongxin Road, Section 5, \r
+                               New Taipei City,  Taiwan  24159\r
+                               TW\r
+\r
+00-0C-FF   (hex)               MRO-TEK Realty Limited\r
+000CFF     (base 16)           MRO-TEK Realty Limited\r
+                               #6, New BEL Road\r
+                               Chikkamaranahalli  Bangalore  560 054\r
+                               IN\r
+\r
+D8-E7-2B   (hex)               NetAlly\r
+D8E72B     (base 16)           NetAlly\r
+                               310 Littleton Road\r
+                               Westford  MA  01886\r
+                               US\r
+\r
+00-35-FF   (hex)               Texas Instruments\r
+0035FF     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+44-59-E3   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+4459E3     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+54-BA-D6   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+54BAD6     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+74-59-09   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+745909     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+E4-FD-A1   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+E4FDA1     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+68-3F-1E   (hex)               EFFECT Photonics B.V.\r
+683F1E     (base 16)           EFFECT Photonics B.V.\r
+                               Kastanjelaan 400\r
+                               Eindhoven  Noord-Brabant  5616 LZ\r
+                               NL\r
+\r
 D8-6C-E9   (hex)               Sagemcom Broadband SAS\r
 D86CE9     (base 16)           Sagemcom Broadband SAS\r
                                250 route de l'Empereur\r
@@ -96524,12 +97304,6 @@ C034B4     (base 16)           Gigastone Corporation
                                Taipei    11492\r
                                TW\r
 \r
-74-AD-B7   (hex)               China Mobile Group Device Co.,Ltd.\r
-74ADB7     (base 16)           China Mobile Group Device Co.,Ltd.\r
-                               32 Xuanwumen West Street\r
-                               Beijing    100053\r
-                               CN\r
-\r
 DC-6F-00   (hex)               Livescribe, Inc.\r
 DC6F00     (base 16)           Livescribe, Inc.\r
                                7677 Oakport Street\r
@@ -101285,12 +102059,6 @@ EC3091     (base 16)         Cisco Systems, Inc
                                Mamaroneck  NY  10543\r
                                US\r
 \r
-00-25-7E   (hex)               NEW POS Technology Limited\r
-00257E     (base 16)           NEW POS Technology Limited\r
-                               6FRM, 6F, China Economic Trade Building\r
-                               Shenzhen  Guangdong  518000\r
-                               CN\r
-\r
 00-25-72   (hex)               Nemo-Q International AB\r
 002572     (base 16)           Nemo-Q International AB\r
                                Box 210\r
@@ -109646,12 +110414,6 @@ EC3091     (base 16)         Cisco Systems, Inc
                                94537 Orly  Cedex  \r
                                FR\r
 \r
-00-04-C4   (hex)               Allen & Heath Limited\r
-0004C4     (base 16)           Allen & Heath Limited\r
-                               Kernick Industrial Estate, Penryn\r
-                               Cornwall  England  TR10 9LU\r
-                               GB\r
-\r
 00-04-B7   (hex)               AMB i.t. Holding\r
 0004B7     (base 16)           AMB i.t. Holding\r
                                Zuiderhoutlaan 4\r
@@ -115223,12 +115985,6 @@ A80600     (base 16)         Samsung Electronics Co.,Ltd
                                Gumi  Gyeongbuk  730-350\r
                                KR\r
 \r
-38-72-C0   (hex)               Comtrend Corporation\r
-3872C0     (base 16)           Comtrend Corporation\r
-                               3F-1,10 Lane 609, Chung Hsin Road, Section 5\r
-                               Taipei Hsien    241\r
-                               TW\r
-\r
 00-0B-CA   (hex)               DATAVAN TC\r
 000BCA     (base 16)           DATAVAN TC\r
                                4FL,#120-12,Chung Shan Rd, Sec.3\r
@@ -116609,12 +117365,6 @@ EC8EAE     (base 16)         Nagravision SA
                                Enschede    NL-7500\r
                                NL\r
 \r
-00-A0-0E   (hex)               NetScout Systems, Inc.\r
-00A00E     (base 16)           NetScout Systems, Inc.\r
-                               310 Littleton Road\r
-                               Westford  MA  01886\r
-                               US\r
-\r
 1C-33-0E   (hex)               PernixData\r
 1C330E     (base 16)           PernixData\r
                                1745 Technology Drive, Suite 800\r
@@ -118331,24 +119081,6 @@ C4D197     (base 16)         Ventia Utility Services
                                Köln    51147\r
                                DE\r
 \r
-CC-BE-59   (hex)               Calix Inc.\r
-CCBE59     (base 16)           Calix Inc.\r
-                               1035 North McDowell Boulevard\r
-                               Petaluma  MN  94954\r
-                               US\r
-\r
-EC-4F-82   (hex)               Calix Inc.\r
-EC4F82     (base 16)           Calix Inc.\r
-                               1035 North McDowell Boulevard\r
-                               Petaluma  MN  94954\r
-                               US\r
-\r
-00-06-31   (hex)               Calix Inc.\r
-000631     (base 16)           Calix Inc.\r
-                               1035 North McDowell Boulevard\r
-                               Petaluma  MN  94954\r
-                               US\r
-\r
 B8-D7-AF   (hex)               Murata Manufacturing Co., Ltd.\r
 B8D7AF     (base 16)           Murata Manufacturing Co., Ltd.\r
                                1-10-1, Higashikotari\r
@@ -123626,12 +124358,6 @@ D4AD71     (base 16)         Cisco Systems, Inc
                                Palo Alto  CA  94304\r
                                US\r
 \r
-94-D0-0D   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-94D00D     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
 E8-4C-56   (hex)               INTERCEPT SERVICES LIMITED\r
 E84C56     (base 16)           INTERCEPT SERVICES LIMITED\r
                                Bates Mill, Colne Road\r
@@ -124370,6 +125096,267 @@ D44DA4     (base 16)                Murata Manufacturing Co., Ltd.
                                Nagaokakyo-shi  Kyoto  617-8555\r
                                JP\r
 \r
+8C-A9-6F   (hex)               D&M Holdings Inc.\r
+8CA96F     (base 16)           D&M Holdings Inc.\r
+                               D&M Building, 2-1 Nisshin-cho\r
+                               Kawasaki-shi  Kanagawa    210-8569\r
+                               JP\r
+\r
+14-C0-3E   (hex)               ARRIS Group, Inc.\r
+14C03E     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+08-ED-ED   (hex)               Zhejiang Dahua Technology Co., Ltd.\r
+08EDED     (base 16)           Zhejiang Dahua Technology Co., Ltd.\r
+                               No.1199,Waterfront Road \r
+                               Hangzhou  Zhejiang  310053\r
+                               CN\r
+\r
+AC-F5-E6   (hex)               Cisco Systems, Inc\r
+ACF5E6     (base 16)           Cisco Systems, Inc\r
+                               80 West Tasman Drive\r
+                               San Jose  CA  94568\r
+                               US\r
+\r
+20-17-42   (hex)               LG Electronics\r
+201742     (base 16)           LG Electronics\r
+                               222 LG-ro, JINWI-MYEON\r
+                               Pyeongtaek-si  Gyeonggi-do  451-713\r
+                               KR\r
+\r
+00-06-31   (hex)               Calix Inc.\r
+000631     (base 16)           Calix Inc.\r
+                               2777 Orchard Parkway\r
+                               San Jose  CA  95134\r
+                               US\r
+\r
+EC-4F-82   (hex)               Calix Inc.\r
+EC4F82     (base 16)           Calix Inc.\r
+                               2777 Orchard Parkway\r
+                               San Jose  CA  95134\r
+                               US\r
+\r
+CC-BE-59   (hex)               Calix Inc.\r
+CCBE59     (base 16)           Calix Inc.\r
+                               2777 Orchard Parkway\r
+                               San Jose  CA  95134\r
+                               US\r
+\r
+24-62-AB   (hex)               Espressif Inc.\r
+2462AB     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+88-B4-36   (hex)               Private\r
+88B436     (base 16)           Private\r
+\r
+48-E1-E9   (hex)               Chengdu Meross Technology Co., Ltd.\r
+48E1E9     (base 16)           Chengdu Meross Technology Co., Ltd.\r
+                               No. 25, Yizhou Avenue, Gaoxin\r
+                               Chengdu  Sichuan  610000\r
+                               CN\r
+\r
+6C-8A-EC   (hex)               Nantong Coship Electronics Co., Ltd.\r
+6C8AEC     (base 16)           Nantong Coship Electronics Co., Ltd.\r
+                               No.188 Xinsheng Road\r
+                               Nantong  Jiangsu  226001\r
+                               CN\r
+\r
+88-9E-33   (hex)               TCT mobile ltd\r
+889E33     (base 16)           TCT mobile ltd\r
+                               No.86 hechang 7th road, zhongkai, Hi-Tech District\r
+                               Hui Zhou  Guang Dong  516006\r
+                               CN\r
+\r
+04-5C-6C   (hex)               Juniper Networks\r
+045C6C     (base 16)           Juniper Networks\r
+                               1133 Innovation Way\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
+04-D9-F5   (hex)               ASUSTek COMPUTER INC.\r
+04D9F5     (base 16)           ASUSTek COMPUTER INC.\r
+                               15,Li-Te Rd., Peitou, Taipei 112, Taiwan\r
+                               Taipei  Taiwan  112\r
+                               TW\r
+\r
+50-1B-32   (hex)               Taicang T&W Electronics\r
+501B32     (base 16)           Taicang T&W Electronics\r
+                               89# Jiang Nan RD\r
+                               Suzhou  Jiangsu  215412\r
+                               CN\r
+\r
+B4-CF-E0   (hex)               Sichuan tianyi kanghe communications co., LTD\r
+B4CFE0     (base 16)           Sichuan tianyi kanghe communications co., LTD\r
+                               No.198, section 1, xueshan avenue, jinyuan town, dayi county\r
+                               chengdu  sichuan  611330\r
+                               CN\r
+\r
+88-29-9C   (hex)               Samsung Electronics Co.,Ltd\r
+88299C     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+48-51-69   (hex)               Samsung Electronics Co.,Ltd\r
+485169     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+70-FC-8F   (hex)               FREEBOX SAS\r
+70FC8F     (base 16)           FREEBOX SAS\r
+                               16 rue de la Ville l'Eveque\r
+                               PARIS  IdF  75008\r
+                               FR\r
+\r
+00-25-7E   (hex)               NEW POS TECHNOLOGY LIMITED\r
+00257E     (base 16)           NEW POS TECHNOLOGY LIMITED\r
+                               6FRM, 6F, China Economic Trade Building\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
+\r
+74-AD-B7   (hex)               China Mobile Group Device Co.,Ltd.\r
+74ADB7     (base 16)           China Mobile Group Device Co.,Ltd.\r
+                               32 Xuanwumen West Street\r
+                               Beijing    100053\r
+                               CN\r
+\r
+74-34-AE   (hex)               this is engineering Inc.\r
+7434AE     (base 16)           this is engineering Inc.\r
+                               352, 815 Daewangpangyo-ro, Sujeong-gu\r
+                               Seongnam-si  Gyeonggi-do  13449\r
+                               KR\r
+\r
+C4-8F-C1   (hex)               DEEPTRACK S.L.U.\r
+C48FC1     (base 16)           DEEPTRACK S.L.U.\r
+                               Avenida de Barajas 32, Parque E. Omega, Edificio A\r
+                               Alcobendas    28100\r
+                               ES\r
+\r
+94-D0-0D   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+94D00D     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+28-41-C6   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+2841C6     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+F8-A7-63   (hex)               Zhejiang Tmall Technology Co., Ltd.\r
+F8A763     (base 16)           Zhejiang Tmall Technology Co., Ltd.\r
+                               Ali Center,No.3331 Keyuan South RD (Shenzhen bay), Nanshan District, Shenzhen Guangdong province\r
+                               Shenzhen  GuangDong  518000\r
+                               CN\r
+\r
+14-AD-CA   (hex)               China Mobile Iot Limited company\r
+14ADCA     (base 16)           China Mobile Iot Limited company\r
+                               No. 8 Yangliu North Road, Yubei District, Chongqing, China\r
+                               Chong Qing  Chong Qing  401120\r
+                               CN\r
+\r
+38-01-18   (hex)               ULVAC,Inc.\r
+380118     (base 16)           ULVAC,Inc.\r
+                               2500 Hagizono\r
+                               Chigasaki  Kanagawa  253-8543\r
+                               JP\r
+\r
+C4-41-1E   (hex)               Belkin International Inc.\r
+C4411E     (base 16)           Belkin International Inc.\r
+                               12045 East Waterfront Drive\r
+                               Playa Vista    90094\r
+                               US\r
+\r
+00-77-E4   (hex)               Nokia\r
+0077E4     (base 16)           Nokia\r
+                               Karaportti 3\r
+                               Espoo  Finland  02610\r
+                               FI\r
+\r
+84-0B-7C   (hex)               Hitron Technologies. Inc\r
+840B7C     (base 16)           Hitron Technologies. Inc\r
+                               No. 1-8, Lising 1st Rd. Hsinchu Science Park, Hsinchu, 300, Taiwan, R.O.C\r
+                               Hsin-chu  Taiwan  300\r
+                               TW\r
+\r
+B4-54-59   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+B45459     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
+                               Hangzhou  Zhejiang  310000\r
+                               CN\r
+\r
+00-04-C4   (hex)               Audiotonix Group Limited\r
+0004C4     (base 16)           Audiotonix Group Limited\r
+                               Unit 10, Silverglade Business Park\r
+                               Chessington  Surrey  KT9 2QL\r
+                               GB\r
+\r
+00-AD-63   (hex)               Dedicated Micros Malta LTD\r
+00AD63     (base 16)           Dedicated Micros Malta LTD\r
+                               Blb017, Qasam Industrijali Bulebel\r
+                               ZEJTUN    ZTN 3000\r
+                               MT\r
+\r
+B4-DC-09   (hex)               Guangzhou Dawei Communication Co.,Ltd\r
+B4DC09     (base 16)           Guangzhou Dawei Communication Co.,Ltd\r
+                               Zone A 906#, International Business Incubator, No.3 Juquan Road, Huangpu District\r
+                               Guangzhou  Guangdong  510660\r
+                               CN\r
+\r
+BC-A1-3A   (hex)               SES-imagotag\r
+BCA13A     (base 16)           SES-imagotag\r
+                               St.-Peter-Gürtel 10b\r
+                               Graz    8010\r
+                               AT\r
+\r
+2C-1E-4F   (hex)               Chengdu Qianli Network Technology Co., Ltd.\r
+2C1E4F     (base 16)           Chengdu Qianli Network Technology Co., Ltd.\r
+                               Room 1208, 4 Building, Ideal Center, NO.38 Tianyi Street, Chengdu High-tech Zone\r
+                               Chengdu  Sichuan  610000\r
+                               CN\r
+\r
+AC-5D-5C   (hex)               FN-LINK TECHNOLOGY LIMITED\r
+AC5D5C     (base 16)           FN-LINK TECHNOLOGY LIMITED\r
+                               A Building,HuiXin industial park,No 31, YongHe road, Fuyong town, Bao'an District\r
+                               SHENZHEN  GUANGDONG  518100\r
+                               CN\r
+\r
+38-72-C0   (hex)               Comtrend Corporation\r
+3872C0     (base 16)           Comtrend Corporation\r
+                               3F-1, 10 Lane 609, Chongxin Road, Section 5, \r
+                               New Taipei City,  Taiwan  24159\r
+                               TW\r
+\r
+00-A0-0E   (hex)               NetAlly\r
+00A00E     (base 16)           NetAlly\r
+                               310 Littleton Road\r
+                               Westford  MA  01886\r
+                               US\r
+\r
+A4-AE-11   (hex)               Hon Hai Precision Ind. Co., Ltd.\r
+A4AE11     (base 16)           Hon Hai Precision Ind. Co., Ltd.\r
+                               GuangDongShenZhen\r
+                               ShenZhen  GuangDong  518109\r
+                               CN\r
+\r
+B4-52-A9   (hex)               Texas Instruments\r
+B452A9     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+E4-54-E8   (hex)               Dell Inc.\r
+E454E8     (base 16)           Dell Inc.\r
+                               One Dell Way\r
+                               Round Rock  TX  78682\r
+                               US\r
+\r
 2C-39-96   (hex)               Sagemcom Broadband SAS\r
 2C3996     (base 16)           Sagemcom Broadband SAS\r
                                250 route de l'Empereur\r
@@ -126467,12 +127454,6 @@ D855A3     (base 16)         zte corporation
                                Shenzhen  Guangdong  518054\r
                                CN\r
 \r
-D8-B6-B7   (hex)               Comtrend Corporation\r
-D8B6B7     (base 16)           Comtrend Corporation\r
-                               3F-1, 10 Lane 609,\r
-                               New Taipei City ,  Taiwan  24159\r
-                               TW\r
-\r
 04-99-E6   (hex)               Shenzhen Yoostar Technology Co., Ltd\r
 0499E6     (base 16)           Shenzhen Yoostar Technology Co., Ltd\r
                                #503,Tower D, HUA HAN Innovation Park,\r
@@ -132050,12 +133031,6 @@ A0593A     (base 16)         V.D.S. Video Display Systems srl
                                SCANDICCI  FI  50018\r
                                IT\r
 \r
-A8-F9-4B   (hex)               Eltex Enterprise Ltd.\r
-A8F94B     (base 16)           Eltex Enterprise Ltd.\r
-                               Obyedineniya st., 9\r
-                               Novosibirsk    630020\r
-                               RU\r
-\r
 90-6D-C8   (hex)               DLG Automação Industrial Ltda\r
 906DC8     (base 16)           DLG Automação Industrial Ltda\r
                                Rua José Batista Soares, 53\r
@@ -138752,12 +139727,6 @@ DC3350     (base 16)         TechSAT GmbH
                                Moss Landing  CA  95039\r
                                US\r
 \r
-00-0C-6C   (hex)               Elgato Systems LLC\r
-000C6C     (base 16)           Elgato Systems LLC\r
-                               900 Kearny St #750\r
-                               San Francisco  CA  94133\r
-                               US\r
-\r
 00-0B-88   (hex)               Vidisco ltd.\r
 000B88     (base 16)           Vidisco ltd.\r
                                17 Yechiel Dresner\r
@@ -138944,12 +139913,6 @@ DC3350     (base 16)         TechSAT GmbH
                                Shibata  Miyagi pref.  989-1695\r
                                JP\r
 \r
-00-0B-E4   (hex)               Hosiden Corporation\r
-000BE4     (base 16)           Hosiden Corporation\r
-                               4-33\r
-                               Yao-city  Osaka  581-0071\r
-                               JP\r
-\r
 00-0B-D8   (hex)               Industrial Scientific Corp.\r
 000BD8     (base 16)           Industrial Scientific Corp.\r
                                1001 Oakdale Road\r
@@ -142772,12 +143735,6 @@ DC3350     (base 16)         TechSAT GmbH
                                GOLDEN  CO  80401\r
                                US\r
 \r
-00-50-C6   (hex)               LOOP TELECOMMUNICATION INTERNATIONAL, INC.\r
-0050C6     (base 16)           LOOP TELECOMMUNICATION INTERNATIONAL, INC.\r
-                               2F, NO. 22, PROSPERITY RD. 2\r
-                               HSINCHU    \r
-                               TW\r
-\r
 00-50-49   (hex)               Arbor Networks Inc\r
 005049     (base 16)           Arbor Networks Inc\r
                                6 Omni Way\r
@@ -146690,18 +147647,6 @@ D8C4E9     (base 16)         Samsung Electronics Co.,Ltd
                                Hsinchu    \r
                                TW\r
 \r
-00-30-DA   (hex)               Comtrend Corporation\r
-0030DA     (base 16)           Comtrend Corporation\r
-                               3F-1 10 LANE 609 CHUNG\r
-                                 TAIWAN  241\r
-                               TW\r
-\r
-64-68-0C   (hex)               Comtrend Corporation\r
-64680C     (base 16)           Comtrend Corporation\r
-                               3F-1,10 Lane 609, Chung Hsin Road, Section 5\r
-                               Taipei Hsien    241\r
-                               TW\r
-\r
 00-CF-1C   (hex)               Communication Machinery Corporation\r
 00CF1C     (base 16)           Communication Machinery Corporation\r
                                1226 ANACAPA\r
@@ -153185,9 +154130,6 @@ B0FC0D     (base 16)          Amazon Technologies Inc.
                                Reno  NV  89507\r
                                US\r
 \r
-E0-CB-1D   (hex)               Private\r
-E0CB1D     (base 16)           Private\r
-\r
 10-7B-A4   (hex)               Olive & Dove Co.,Ltd.\r
 107BA4     (base 16)           Olive & Dove Co.,Ltd.\r
                                803 Polaris bldg., 381, Seongnam-daero, Bundang-gu \r
@@ -153218,9 +154160,6 @@ D49E05     (base 16)          zte corporation
                                Nes Ziona     7404996\r
                                IL\r
 \r
-9C-93-E4   (hex)               Private\r
-9C93E4     (base 16)           Private\r
-\r
 74-C1-4F   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
 74C14F     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
                                No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
@@ -153845,12 +154784,6 @@ A49B4F     (base 16)         HUAWEI TECHNOLOGIES CO.,LTD
                                SANTA CLARA  CA  95052\r
                                US\r
 \r
-58-C8-76   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-58C876     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
-                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
-                               Hangzhou  Zhejiang  310000\r
-                               CN\r
-\r
 8C-8F-8B   (hex)               China Mobile Chongqing branch\r
 8C8F8B     (base 16)           China Mobile Chongqing branch\r
                                6 building, No. 2, Xingguang three road\r
@@ -154625,12 +155558,6 @@ A83CCB     (base 16)         ROSSMA
                                PERM    614087\r
                                RU\r
 \r
-C8-C2-FA   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
-C8C2FA     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
-                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
-                               Dongguan    523808\r
-                               CN\r
-\r
 38-C2-BA   (hex)               CCTV NEOTECH\r
 38C2BA     (base 16)           CCTV NEOTECH\r
                                68, Digital-ro 9-gil, Geumcheon-gu\r
@@ -155468,5 +156395,275 @@ DC8C37     (base 16)                Cisco Systems, Inc
                                Nürnberg  Bayern  90478\r
                                DE\r
 \r
+1C-3A-60   (hex)               Ruckus Wireless\r
+1C3A60     (base 16)           Ruckus Wireless\r
+                               350 West Java Drive\r
+                               Sunnyvale  CA  94089\r
+                               US\r
+\r
 7C-50-DA   (hex)               Private\r
 7C50DA     (base 16)           Private\r
+\r
+BC-9F-E4   (hex)               Aruba, a Hewlett Packard Enterprise Company\r
+BC9FE4     (base 16)           Aruba, a Hewlett Packard Enterprise Company\r
+                               3333 Scott Blvd\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
+00-50-C6   (hex)               LOOP TELECOMMUNICATION INTERNATIONAL, INC.\r
+0050C6     (base 16)           LOOP TELECOMMUNICATION INTERNATIONAL, INC.\r
+                               7F, No. 8, Hsin Ann Road\r
+                               Hsinchu    -   \r
+                               TW\r
+\r
+B0-A6-F5   (hex)               Xaptum, Inc.\r
+B0A6F5     (base 16)           Xaptum, Inc.\r
+                               350 W Ontario ST FL 4\r
+                               Chicago  IL  60654\r
+                               US\r
+\r
+E0-CB-1D   (hex)               Private\r
+E0CB1D     (base 16)           Private\r
+\r
+48-77-46   (hex)               Calix Inc.\r
+487746     (base 16)           Calix Inc.\r
+                               2777 Orchard Parkway\r
+                               San Jose  CA  95134\r
+                               US\r
+\r
+00-0B-E4   (hex)               Hosiden Corporation\r
+000BE4     (base 16)           Hosiden Corporation\r
+                               4-33\r
+                               Yao-city  Osaka  581-0071\r
+                               JP\r
+\r
+9C-7B-EF   (hex)               Hewlett Packard\r
+9C7BEF     (base 16)           Hewlett Packard\r
+                               11445 Compaq Center Drive\r
+                               Houston  TX  77070\r
+                               US\r
+\r
+90-73-5A   (hex)               Motorola Mobility LLC, a Lenovo Company\r
+90735A     (base 16)           Motorola Mobility LLC, a Lenovo Company\r
+                               222 West Merchandise Mart Plaza\r
+                               Chicago  IL  60654\r
+                               US\r
+\r
+A8-F9-4B   (hex)               Eltex Enterprise Ltd.\r
+A8F94B     (base 16)           Eltex Enterprise Ltd.\r
+                               Okruzhnaya st. 29v\r
+                               Novosibirsk    630020\r
+                               RU\r
+\r
+F8-23-87   (hex)               Shenzhen Horn Audio Co.,Ltd.\r
+F82387     (base 16)           Shenzhen Horn Audio Co.,Ltd.\r
+                               NO.6 4th GuiHua road,PingShan,\r
+                               Shenzhen  Guangdong  518118\r
+                               CN\r
+\r
+D8-F1-5B   (hex)               Espressif Inc.\r
+D8F15B     (base 16)           Espressif Inc.\r
+                               Room 204, Building 2, 690 Bibo Rd, Pudong New Area\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+78-D3-47   (hex)               Ericsson AB\r
+78D347     (base 16)           Ericsson AB\r
+                               Torshamnsgatan 36\r
+                               Stockholm    SE-164 80\r
+                               SE\r
+\r
+9C-93-E4   (hex)               Private\r
+9C93E4     (base 16)           Private\r
+\r
+7C-23-02   (hex)               Samsung Electronics Co.,Ltd\r
+7C2302     (base 16)           Samsung Electronics Co.,Ltd\r
+                               #94-1, Imsoo-Dong\r
+                               Gumi  Gyeongbuk  730-350\r
+                               KR\r
+\r
+28-D1-B7   (hex)               Shenzhen YOUHUA Technology Co., Ltd\r
+28D1B7     (base 16)           Shenzhen YOUHUA Technology Co., Ltd\r
+                               Room 407 Shenzhen University-town Business Park,Lishan Road,Taoyuan Street,Nanshan District\r
+                               Shenzhen  Guangdong  518055\r
+                               CN\r
+\r
+80-91-33   (hex)               AzureWave Technology Inc.\r
+809133     (base 16)           AzureWave Technology Inc.\r
+                               8F., No. 94, Baozhong Rd.\r
+                               New Taipei City  Taiwan  231\r
+                               TW\r
+\r
+AC-83-E9   (hex)               Beijing Zile Technology Co., Ltd\r
+AC83E9     (base 16)           Beijing Zile Technology Co., Ltd\r
+                               Tecent WeWork, Huilongguan East Avenue, Changping District\r
+                               Beijing  Beijing  100096\r
+                               CN\r
+\r
+A4-00-E2   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+A400E2     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+D0-C6-5B   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+D0C65B     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+B4-C4-FC   (hex)               Xiaomi Communications Co Ltd\r
+B4C4FC     (base 16)           Xiaomi Communications Co Ltd\r
+                               The Rainbow City of China Resources\r
+                               NO.68, Qinghe Middle Street  Haidian District, Beijing  100085\r
+                               CN\r
+\r
+40-5B-D8   (hex)               CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
+405BD8     (base 16)           CHONGQING FUGUI ELECTRONICS CO.,LTD.\r
+                               Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District\r
+                               Chongqing  Chongqing  401332\r
+                               CN\r
+\r
+E4-AB-89   (hex)               MitraStar Technology Corp.\r
+E4AB89     (base 16)           MitraStar Technology Corp.\r
+                               No. 6, Innovation Road II,\r
+                               Hsinchu    300\r
+                               TW\r
+\r
+44-00-4D   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+44004D     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+B4-F5-8E   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+B4F58E     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+B4-9A-95   (hex)               Shenzhen Boomtech Industrial Corporation\r
+B49A95     (base 16)           Shenzhen Boomtech Industrial Corporation\r
+                               2F, Block E, Bao'an Intelligent Valley, Yingtian Road No.4 Xixiang Sub-District Office, Bao'an District\r
+                               Shenzhen  Guangdong  518102\r
+                               CN\r
+\r
+00-0C-6C   (hex)               Eve Systems GmbH\r
+000C6C     (base 16)           Eve Systems GmbH\r
+                               Rotkreuzplatz 1\r
+                               Munich    80634\r
+                               DE\r
+\r
+C8-C2-FA   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+C8C2FA     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+A4-98-13   (hex)               ARRIS Group, Inc.\r
+A49813     (base 16)           ARRIS Group, Inc.\r
+                               6450 Sequence Drive\r
+                               San Diego  CA  92121\r
+                               US\r
+\r
+F4-1D-6B   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+F41D6B     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan     523808\r
+                               CN\r
+\r
+B4-A3-05   (hex)               XIAMEN YAXON NETWORK CO., LTD.\r
+B4A305     (base 16)           XIAMEN YAXON NETWORK CO., LTD.\r
+                               46#,Guanri Road, Software Park II\r
+                               Xiamen  Fujian  361008\r
+                               CN\r
+\r
+58-C8-76   (hex)               China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+58C876     (base 16)           China Mobile (Hangzhou) Information Technology Co., Ltd.\r
+                               No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District\r
+                               Hangzhou  Zhejiang  310000\r
+                               CN\r
+\r
+38-EF-E3   (hex)                INGENICO TERMINALS SAS\r
+38EFE3     (base 16)            INGENICO TERMINALS SAS\r
+                               28-32 BOULEVARD DE GRENELLE\r
+                               PARIS    75015\r
+                               FR\r
+\r
+D0-37-45   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+D03745     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+50-D4-F7   (hex)               TP-LINK TECHNOLOGIES CO.,LTD.\r
+50D4F7     (base 16)           TP-LINK TECHNOLOGIES CO.,LTD.\r
+                               Building 24(floors 1,3,4,5)and 28(floors 1-4)Central Science and Technology Park,Shennan Road,Nanshan\r
+                               Shenzhen  Guangdong  518057\r
+                               CN\r
+\r
+8C-59-3C   (hex)               IEEE Registration Authority\r
+8C593C     (base 16)           IEEE Registration Authority\r
+                               445 Hoes Lane\r
+                               Piscataway  NJ  08554\r
+                               US\r
+\r
+00-30-DA   (hex)               Comtrend Corporation\r
+0030DA     (base 16)           Comtrend Corporation\r
+                               3F-1, 10 Lane 609, Chongxin Road, Section 5, \r
+                               New Taipei City,  Taiwan  24159\r
+                               TW\r
+\r
+64-68-0C   (hex)               Comtrend Corporation\r
+64680C     (base 16)           Comtrend Corporation\r
+                               3F-1, 10 Lane 609, Chongxin Road, Section 5, \r
+                               New Taipei City,  Taiwan  24159\r
+                               TW\r
+\r
+D8-B6-B7   (hex)               Comtrend Corporation\r
+D8B6B7     (base 16)           Comtrend Corporation\r
+                               3F-1, 10 Lane 609, Chongxin Road, Section 5, \r
+                               New Taipei City,  Taiwan  24159\r
+                               TW\r
+\r
+00-ED-B8   (hex)               KYOCERA Corporation \r
+00EDB8     (base 16)           KYOCERA Corporation \r
+                               30 Hoji\r
+                               Kitami,  Hokkaido  099-1595\r
+                               JP\r
+\r
+00-F6-20   (hex)               Google, Inc.\r
+00F620     (base 16)           Google, Inc.\r
+                               1600 Amphitheatre Parkway\r
+                               Mountain View  CA  94043\r
+                               US\r
+\r
+E4-15-F6   (hex)               Texas Instruments\r
+E415F6     (base 16)           Texas Instruments\r
+                               12500 TI Blvd\r
+                               Dallas  TX  75243\r
+                               US\r
+\r
+B4-60-77   (hex)               Sichuan Changhong Electric Ltd.\r
+B46077     (base 16)           Sichuan Changhong Electric Ltd.\r
+                               No.35,East MianXin Road,MianYang,Sichaun,China.\r
+                               MianYang  SiChuan  PRC 621000\r
+                               CN\r
+\r
+54-92-09   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+549209     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+E4-19-C1   (hex)               HUAWEI TECHNOLOGIES CO.,LTD\r
+E419C1     (base 16)           HUAWEI TECHNOLOGIES CO.,LTD\r
+                               No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park\r
+                               Dongguan    523808\r
+                               CN\r
+\r
+B8-66-85   (hex)               Sagemcom Broadband SAS\r
+B86685     (base 16)           Sagemcom Broadband SAS\r
+                               250, route de l'Empereur\r
+                               Rueil Malmaison Cedex  hauts de seine  92848\r
+                               FR\r
index 3090a95..4abc550 100644 (file)
@@ -2426,9 +2426,6 @@ A0-19-B2   (hex)          ARIMA Communications Corp.
 D0-D9-4F   (hex)               Private\r
 700000-7FFFFF     (base 16)            Private\r
 \r
-F4-0E-11   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
-\r
 B4-4B-D6   (hex)               ShenZhen Comstar Technology Company\r
 500000-5FFFFF     (base 16)            ShenZhen Comstar Technology Company\r
                                Pengnian Science Park Building A 314\r
@@ -2843,12 +2840,6 @@ E4-1E-0A   (hex)         Avast Software s.r.o.
                                Prague 4    14000\r
                                CZ\r
 \r
-C8-2C-2B   (hex)               Fungible, Inc.\r
-000000-0FFFFF     (base 16)            Fungible, Inc.\r
-                               3201 Scott Blvd., 2nd floor\r
-                               Santa Clara  CA  95054\r
-                               US\r
-\r
 E4-1E-0A   (hex)               Shanghai LeXiang Technology Co., Ltd\r
 E00000-EFFFFF     (base 16)            Shanghai LeXiang Technology Co., Ltd\r
                                Floor 6,Building 8,Yanjiaqiao Road,Pudong Area ,Shanghai ,China\r
@@ -2867,6 +2858,12 @@ C8-2C-2B   (hex)         RF Engineering and Energy Resource
                                Portage  MI  49002\r
                                US\r
 \r
+C8-2C-2B   (hex)               Fungible, Inc.\r
+000000-0FFFFF     (base 16)            Fungible, Inc.\r
+                               3201 Scott Blvd., 2nd floor\r
+                               Santa Clara  CA  95054\r
+                               US\r
+\r
 C8-2C-2B   (hex)               Repp Health\r
 200000-2FFFFF     (base 16)            Repp Health\r
                                1919 14th Street , Suite 700\r
@@ -2894,6 +2891,123 @@ B0-FD-0B   (hex)                eSenseLab Ltd.
 1C-CA-E3   (hex)               Private\r
 F00000-FFFFFF     (base 16)            Private\r
 \r
+B0-FD-0B   (hex)               TAE HYUNG Industrial Electronics Co., Ltd.\r
+000000-0FFFFF     (base 16)            TAE HYUNG Industrial Electronics Co., Ltd.\r
+                               301-404, Bucheon Technopark, 345, Seokcheon-ro\r
+                               Bucheon-si  Gyeonggi-do  14501\r
+                               KR\r
+\r
+84-8B-CD   (hex)               TWTG R&D B.V. \r
+600000-6FFFFF     (base 16)            TWTG R&D B.V. \r
+                               Schaardijk 386\r
+                               Capelle aan den IJssel    2909LA\r
+                               NL\r
+\r
+B0-FD-0B   (hex)               Everynet Oy\r
+700000-7FFFFF     (base 16)            Everynet Oy\r
+                               At Azets Insight Oy, Hatanpään valtatie 26 (5.krs)\r
+                               Tampere    33100\r
+                               FI\r
+\r
+84-8B-CD   (hex)               SouXin Corporate\r
+000000-0FFFFF     (base 16)            SouXin Corporate\r
+                               33 Jingyou Road\r
+                               Nanjing  Jiangsu  211100\r
+                               CN\r
+\r
+1C-82-59   (hex)               3xLOGIC Inc.\r
+100000-1FFFFF     (base 16)            3xLOGIC Inc.\r
+                               10385 Westmoor Dr, Suite 210\r
+                               Westminster  CO  80021\r
+                               US\r
+\r
+1C-82-59   (hex)               Applied Concepts, Inc.\r
+D00000-DFFFFF     (base 16)            Applied Concepts, Inc.\r
+                               855 E Collins Blvd\r
+                               Richardson  TX  75081\r
+                               US\r
+\r
+60-95-CE   (hex)               Untangle, Inc.\r
+400000-4FFFFF     (base 16)            Untangle, Inc.\r
+                               100 W. San Fernando St., Ste. 565\r
+                               San Jose  CA  95113\r
+                               US\r
+\r
+BC-97-40   (hex)               Amap Information Technology Co., Ltd\r
+A00000-AFFFFF     (base 16)            Amap Information Technology Co., Ltd\r
+                               A051, No.01, 3/F, No.55 Suzhou Street, Haidian District\r
+                               Beijing  Beijing  100080\r
+                               CN\r
+\r
+BC-97-40   (hex)               LISTEC GmbH\r
+C00000-CFFFFF     (base 16)            LISTEC GmbH\r
+                               Am Sandberg 34\r
+                               Isen  Bavaria  84424\r
+                               DE\r
+\r
+F4-0E-11   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
+\r
+BC-97-40   (hex)               Shanghai Laisi Information Technology Co.,Ltd\r
+500000-5FFFFF     (base 16)            Shanghai Laisi Information Technology Co.,Ltd\r
+                               1001,21#,No.1158 Zhongxin RD,Songjiang district Shanghai\r
+                               shanghai    201614\r
+                               CN\r
+\r
+BC-97-40   (hex)               Shenzhen Colorwin Optical Technology Co.,Ltd\r
+600000-6FFFFF     (base 16)            Shenzhen Colorwin Optical Technology Co.,Ltd\r
+                               201-2,2nd Floor,G3 Building, TCL International E City,1001 Zhongshanyuan Road,Nanshan District\r
+                               Shenzhen  Guangdong  518055\r
+                               CN\r
+\r
+D0-C8-57   (hex)               Dante Security Inc.\r
+C00000-CFFFFF     (base 16)            Dante Security Inc.\r
+                               303 MERRICK RD., Unit 208\r
+                               LYNBROOK  NY  11563\r
+                               US\r
+\r
+BC-97-40   (hex)               Lattec I/S\r
+200000-2FFFFF     (base 16)            Lattec I/S\r
+                               Blytækkervej 10\r
+                               Hillerød    3400\r
+                               DK\r
+\r
+D0-C8-57   (hex)               Eco Mobile \r
+700000-7FFFFF     (base 16)            Eco Mobile \r
+                               Samoborska cesta 330\r
+                               Zagreb  Zagreb  10090\r
+                               HR\r
+\r
+D0-C8-57   (hex)               CHUNGHSIN INTERNATIONAL ELECTRONICS CO.,LTD.\r
+B00000-BFFFFF     (base 16)            CHUNGHSIN INTERNATIONAL ELECTRONICS CO.,LTD.\r
+                               618-2# Gongren West Road,Jiaojiang,\r
+                               Taizhou  Zhejiang  317700\r
+                               CN\r
+\r
+D0-C8-57   (hex)               E-T-A Elektrotechnische Apparate GmbH\r
+E00000-EFFFFF     (base 16)            E-T-A Elektrotechnische Apparate GmbH\r
+                               Industriestr. 2-8\r
+                               Altdorf    90518\r
+                               DE\r
+\r
+8C-59-3C   (hex)               GENIS\r
+900000-9FFFFF     (base 16)            GENIS\r
+                               1111, 11F RACREUM, 26 Wiryeseoil-ro\r
+                               Seongnam-si  Gyeonggi-do  13647\r
+                               KR\r
+\r
+8C-59-3C   (hex)               Future Robot Technology Co., Limited\r
+100000-1FFFFF     (base 16)            Future Robot Technology Co., Limited\r
+                               Room 406 Block A South Wind Tower, Nanshan Cloud Valley Innovation Industry Park, No 4093 Lau Sin Avenue Taoyuan Street Nanshan District\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
+\r
+8C-59-3C   (hex)               OBO Pro.2 Inc.\r
+700000-7FFFFF     (base 16)            OBO Pro.2 Inc.\r
+                               2148 Bering Dr.\r
+                               San Jose  CA  95131\r
+                               US\r
+\r
 1C-87-76   (hex)               Strone Technology\r
 C00000-CFFFFF     (base 16)            Strone Technology\r
                                13 Ellis Street\r
@@ -4601,1071 +4715,1161 @@ C00000-CFFFFF     (base 16)          Shanghai Think-Force Electronic Technology Co. Ltd
                                Norderstedt    22844\r
                                DE\r
 \r
-34-04-9E   (hex)               uikismart\r
-D00000-DFFFFF     (base 16)            uikismart\r
-                               Nanshan\r
-                               Shenzhen  Guangdong  518061\r
+A8-3F-A1   (hex)               Guangzhou Navigateworx Technologies Co., Limited\r
+E00000-EFFFFF     (base 16)            Guangzhou Navigateworx Technologies Co., Limited\r
+                               Room 2320, Qianjin Commercial Building, Dongpu Town\r
+                               Guangzhou  Guangdong  510660\r
                                CN\r
 \r
-50-A4-D0   (hex)               Guangzhou Hysoon Electronic Co., Ltd.\r
-300000-3FFFFF     (base 16)            Guangzhou Hysoon Electronic Co., Ltd.\r
-                               No.1, Fenghuang South Road, Xinhua, Huadu District\r
-                               Guangzhou  Guangdong  510800\r
+A8-3F-A1   (hex)               Shanghai East China Computer Co., Ltd\r
+A00000-AFFFFF     (base 16)            Shanghai East China Computer Co., Ltd\r
+                               27/F Tower B, No.391 Guiping Rd\r
+                               Shanghai  Shanghai  200233\r
                                CN\r
 \r
-50-A4-D0   (hex)               Shanghai Pujiang Smart Card Systems Co., Ltd.\r
-700000-7FFFFF     (base 16)            Shanghai Pujiang Smart Card Systems Co., Ltd.\r
-                               No.100, Lane 7488, Hutai Road\r
-                               Shanghai    86-201809\r
+A8-3F-A1   (hex)               BEGLEC\r
+600000-6FFFFF     (base 16)            BEGLEC\r
+                               hofveld 2c\r
+                               Groot-Bijgaarden    1702\r
+                               BE\r
+\r
+1C-FD-08   (hex)               SABIK Offshore GmbH\r
+400000-4FFFFF     (base 16)            SABIK Offshore GmbH\r
+                               Wilhelm-Maybach-Straße 3\r
+                               Schwerin  Mecklenburg-Vorpommern  D-19061\r
+                               DE\r
+\r
+1C-FD-08   (hex)               Shanghai YottaTech Co Ltd (上海尧它科技有限公司)\r
+C00000-CFFFFF     (base 16)            Shanghai YottaTech Co Ltd (上海尧它科技有限公司)\r
+                               399 keyuan Rd, Pudong New District\r
+                               Shanghai    201203\r
                                CN\r
 \r
-8C-C8-F4   (hex)               Swift Navigation Inc\r
-900000-9FFFFF     (base 16)            Swift Navigation Inc\r
-                               1543 Mission Street\r
-                               San Francisco  CA  94103\r
-                               US\r
+10-07-23   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
 \r
-8C-C8-F4   (hex)               Lanhomex Technology(Shen Zhen)Co.,Ltd. \r
-100000-1FFFFF     (base 16)            Lanhomex Technology(Shen Zhen)Co.,Ltd. \r
-                               Room 409, Building 29,Zhi Heng Industrial Part, Guankou 2nd  Road, Nanshan District\r
-                               SHENZHEN    518000\r
+0C-FE-5D   (hex)               Chengdu Ledong Information & Technology Co., Ltd. \r
+000000-0FFFFF     (base 16)            Chengdu Ledong Information & Technology Co., Ltd. \r
+                               D7-13F, Chengdu Tianfu Software Park, No. 599 Shijicheng South street, Gaoxin District, Chengdu, China\r
+                               Chengdu  sichaun  610041\r
                                CN\r
 \r
-8C-C8-F4   (hex)               Trilux Group Management GmbH\r
-A00000-AFFFFF     (base 16)            Trilux Group Management GmbH\r
-                               Heidestrasse\r
-                               Arnsberg    59759\r
-                               DE\r
+C0-D3-91   (hex)               Private\r
+B00000-BFFFFF     (base 16)            Private\r
 \r
-40-F3-85   (hex)               Lennox International Incorporated\r
-600000-6FFFFF     (base 16)            Lennox International Incorporated\r
-                               1600 Metrocrest Drive\r
-                               Carrollton  TX  75006\r
+1C-CA-E3   (hex)               Insigma Inc\r
+200000-2FFFFF     (base 16)            Insigma Inc\r
+                               43490, Yukon Drive, Suite 102\r
+                               Ashburn  VA  20147\r
                                US\r
 \r
-40-F3-85   (hex)               KATO ENGINEERING INC.\r
-500000-5FFFFF     (base 16)            KATO ENGINEERING INC.\r
-                               2075 HOWARD DRIVE WEST\r
-                               NORTH MANKATO   MN  56003\r
-                               US\r
+0C-FE-5D   (hex)               Celerway Communication AS\r
+900000-9FFFFF     (base 16)            Celerway Communication AS\r
+                               Martin Lingesvei 25\r
+                               Fornebu    1364\r
+                               NO\r
 \r
-1C-A0-D3   (hex)               Dynamic Connect (Suzhou) Hi-Tech Electronic Co.,Ltd.\r
-500000-5FFFFF     (base 16)            Dynamic Connect (Suzhou) Hi-Tech Electronic Co.,Ltd.\r
-                               Unit C&D, No.201 WuXiang, Export Processing Zone A No.200Suhong Road SIP\r
-                               Suzhou  JiangSu  215021\r
+0C-FE-5D   (hex)               Beijing WayClouds Technology Co., Ltd.\r
+300000-3FFFFF     (base 16)            Beijing WayClouds Technology Co., Ltd.\r
+                               RM501, 5F, DASCOM BD,NO.9 SHANGDI EAST RD, HAIDIAN DISTRICT,BEIJING,CHINA\r
+                               Beijing    100085\r
                                CN\r
 \r
-A4-11-63   (hex)               AlterG, Inc.\r
-400000-4FFFFF     (base 16)            AlterG, Inc.\r
-                               48438 Milmont Drive\r
-                               Fremont  CA  94538\r
-                               US\r
+98-F9-C7   (hex)               Beijing Horizon Information Technology Co., Ltd\r
+300000-3FFFFF     (base 16)            Beijing Horizon Information Technology Co., Ltd\r
+                               3F,Unit H, West Gate, Hailong Mansion, No.1 Zhongguancun Street, Haidian District\r
+                               Beijing    100080\r
+                               CN\r
 \r
-1C-A0-D3   (hex)               SAVELEC\r
-300000-3FFFFF     (base 16)            SAVELEC\r
-                               rue de la houille blanche\r
-                               HERMILLON  SAVOIE  73300\r
-                               FR\r
+98-F9-C7   (hex)               GoodBox\r
+600000-6FFFFF     (base 16)            GoodBox\r
+                               Ground Floor, Optimum House\r
+                               Clippers Quay  Salford Quays  M50 3XP\r
+                               GB\r
 \r
-A4-11-63   (hex)               INTER CONTROL Hermann Köhler Elektrik GmbH & Co.KG\r
-100000-1FFFFF     (base 16)            INTER CONTROL Hermann Köhler Elektrik GmbH & Co.KG\r
-                               Schafhofstrasse 30\r
-                               Nuernberg    90411\r
+98-F9-C7   (hex)               Promess GmbH\r
+400000-4FFFFF     (base 16)            Promess GmbH\r
+                               Schaffhausener Str. 44\r
+                               Berlin    12099\r
                                DE\r
 \r
-14-4F-D7   (hex)               Shenzhen V-Streaming Technology Co., Ltd.\r
-700000-7FFFFF     (base 16)            Shenzhen V-Streaming Technology Co., Ltd.\r
-                               Room610, LangShanGe Building, Yugu Hi-Tech Park, Liuxin Road 1183, Nanshan District\r
-                               Shenzhen  Guangdong  518000\r
-                               CN\r
-\r
-14-4F-D7   (hex)               Unirobot Corporation\r
-A00000-AFFFFF     (base 16)            Unirobot Corporation\r
-                               MK Hatagaya Sasazuka building 6F, Hatagaya, Shibuya-ku\r
-                               Tokyo  Japan  1510072\r
-                               JP\r
-\r
-98-AA-FC   (hex)               SURTEC\r
-100000-1FFFFF     (base 16)            SURTEC\r
-                               616 avenue de l'Europe\r
-                               Le Creusot  burgundy  71206\r
+7C-BC-84   (hex)               CONTINENTAL\r
+400000-4FFFFF     (base 16)            CONTINENTAL\r
+                               1 AVENUE PAUL OURLIAC\r
+                               TOULOUSE    31100\r
                                FR\r
 \r
-08-ED-02   (hex)               HANTAS CO., LTD.\r
-800000-8FFFFF     (base 16)            HANTAS CO., LTD.\r
-                               474 Dunchondaero, Jungwon-gu\r
-                               Seongnam-si  Kyonggi-do  13229\r
-                               KR\r
+7C-BC-84   (hex)               OPNT BV\r
+A00000-AFFFFF     (base 16)            OPNT BV\r
+                               De Boelelaan 1081\r
+                               Amsterdam    1081 HV\r
+                               NL\r
 \r
-08-ED-02   (hex)               Eleven Engineering Incorporated\r
-700000-7FFFFF     (base 16)            Eleven Engineering Incorporated\r
-                               10150 - 100 Street, Suite 800\r
-                               Edmonton  Canada, Alberta  T5J 0P6\r
-                               CA\r
+7C-BC-84   (hex)               Tibit Communications\r
+C00000-CFFFFF     (base 16)            Tibit Communications\r
+                               1 Willowbrook Court, Suite 150\r
+                               Petaluma  CA  94954\r
+                               US\r
 \r
-08-ED-02   (hex)               TES Touch Embedded Solutions Inc.\r
-200000-2FFFFF     (base 16)            TES Touch Embedded Solutions Inc.\r
-                               3F, No. 141, Sec. 3, Ren'ai Rd.,\r
-                               Taipei    106\r
-                               TW\r
+6C-DF-FB   (hex)               Toucan Systems Ltd\r
+C00000-CFFFFF     (base 16)            Toucan Systems Ltd\r
+                               3 Roseheyworth Business Park\r
+                               Abertillery  Bleanau Gwent  NP13 1SP\r
+                               GB\r
 \r
-08-ED-02   (hex)               Telstra Corporation Limited\r
-E00000-EFFFFF     (base 16)            Telstra Corporation Limited\r
-                               Level 2 / 150 Lonsdale St\r
-                               Melbourne  Victoria  3000\r
-                               AU\r
+6C-DF-FB   (hex)               YongTechs Electric Co. Ltd\r
+900000-9FFFFF     (base 16)            YongTechs Electric Co. Ltd\r
+                               18F-8, No.118, Ci-Yun Rd., Hsin Chu 30072, Taiwan(R.O.C.)\r
+                               Hsin Chu    30072\r
+                               TW\r
 \r
-60-D7-E3   (hex)               Zhejiang Send Intelligent Technology,Ltd\r
-C00000-CFFFFF     (base 16)            Zhejiang Send Intelligent Technology,Ltd\r
-                               6-7F,E Building,Tiantang Software Park,Xidoumen Road,Xihu District\r
-                               Hangzhou  Zhejiang  310012\r
+6C-DF-FB   (hex)               Guilin Zhishen Information TechonlogyCO.,Ltd\r
+A00000-AFFFFF     (base 16)            Guilin Zhishen Information TechonlogyCO.,Ltd\r
+                               Creative Industrial Park,GuiMo Rd.,Qi Xing\r
+                               Guilin  Guangxi  541004\r
                                CN\r
 \r
-60-D7-E3   (hex)               HindlePower, Inc\r
-800000-8FFFFF     (base 16)            HindlePower, Inc\r
-                               1075 Saint John St\r
-                               Easton  PA  18042\r
+74-1A-E0   (hex)               Private\r
+900000-9FFFFF     (base 16)            Private\r
+\r
+4C-91-7A   (hex)               Openeye\r
+600000-6FFFFF     (base 16)            Openeye\r
+                               23221 East Knox Avenue\r
+                               Liberty Lake  WA  99019\r
                                US\r
 \r
-60-D7-E3   (hex)               Wilderness Labs Inc.\r
-A00000-AFFFFF     (base 16)            Wilderness Labs Inc.\r
-                               700 Edgewater Blvd., #108\r
-                               Foster City  CA  94404\r
+4C-91-7A   (hex)               AvertX\r
+B00000-BFFFFF     (base 16)            AvertX\r
+                               23221 E. Knox Ave\r
+                               Liberty Lake  WA  99019\r
                                US\r
 \r
-60-D7-E3   (hex)               Elap s.r.l.\r
-100000-1FFFFF     (base 16)            Elap s.r.l.\r
-                               Via V. Veneto 4\r
-                               Corsico  Milano  20094\r
-                               IT\r
-\r
-04-71-4B   (hex)               uAvionix Corporation\r
-100000-1FFFFF     (base 16)            uAvionix Corporation\r
-                               380 Portage Ave.\r
-                               Palo Alto  CA  94306\r
+4C-91-7A   (hex)               LumiGrow Inc.\r
+400000-4FFFFF     (base 16)            LumiGrow Inc.\r
+                               1480 64th Street, Suite #150\r
+                               Emeryville  CA  94608\r
                                US\r
 \r
-04-71-4B   (hex)               Energport Inc\r
-800000-8FFFFF     (base 16)            Energport Inc\r
-                               48660 Kato Road\r
-                               Fremont  CA  94538\r
+9C-69-B4   (hex)               Toughdog Security Systems\r
+B00000-BFFFFF     (base 16)            Toughdog Security Systems\r
+                               1317 E Hackberry Ave\r
+                               McAllen  TX  78501\r
                                US\r
 \r
-F0-23-B9   (hex)               EZVIS LIMITED\r
-400000-4FFFFF     (base 16)            EZVIS LIMITED\r
-                               FLAT/RM 1605A Ho KING COMMERCIAL CENTRE 2-16 FA YUEN STREET\r
-                               HONGKONG    999077\r
-                               HK\r
+9C-69-B4   (hex)               Guangdong Hanwei intergration Co.,Ltd\r
+C00000-CFFFFF     (base 16)            Guangdong Hanwei intergration Co.,Ltd\r
+                               Room 404,7# Hongtai Zhihui Gu, No.23 Sicheng Road\r
+                               Guangzhou  Guangdong  510663\r
+                               CN\r
 \r
-8C-14-7D   (hex)               Unwired Networks\r
-500000-5FFFFF     (base 16)            Unwired Networks\r
-                               Gonzagagasse 11/25\r
-                               Vienna    1010\r
-                               AT\r
+9C-69-B4   (hex)               Skydock do Brasil Ltda\r
+800000-8FFFFF     (base 16)            Skydock do Brasil Ltda\r
+                               Rua Gralha Azul, 147\r
+                               Quatro Barras  PR  83420-000\r
+                               BR\r
 \r
-8C-14-7D   (hex)               Agilent S.p.A\r
-200000-2FFFFF     (base 16)            Agilent S.p.A\r
-                               Via.flli Varian 54\r
-                               Leini  Torino  10040\r
+9C-69-B4   (hex)               Globalcom Engineering SPA\r
+400000-4FFFFF     (base 16)            Globalcom Engineering SPA\r
+                               Via Volta 9\r
+                               MORNAGO  VA  21020\r
                                IT\r
 \r
-8C-14-7D   (hex)               Electrical & Automation Larsen & Toubro Limited\r
-E00000-EFFFFF     (base 16)            Electrical & Automation Larsen & Toubro Limited\r
-                               Mysore Campus, KIADB Industrial Area, Hebbal, Hootagalli\r
-                               Mysore  Karnataka  570020\r
-                               IN\r
+F0-23-B9   (hex)               Annapurna labs\r
+A00000-AFFFFF     (base 16)            Annapurna labs\r
+                               Matam Scientific Industries Center,   Building 8.2\r
+                               Mail box 15123  Haifa  3508409\r
+                               IL\r
 \r
-A0-C5-F2   (hex)               Impulse Networks Pte Ltd\r
-900000-9FFFFF     (base 16)            Impulse Networks Pte Ltd\r
-                               1 Raffles Place, #44-08 Raffles Place\r
-                               Singapore    048616\r
-                               SG\r
+D4-25-CC   (hex)               NORDI TELEKOMMUNIKATSIOONI OÜ\r
+000000-0FFFFF     (base 16)            NORDI TELEKOMMUNIKATSIOONI OÜ\r
+                               Valukoja 8\r
+                               Tallinn city  Estonian Republic  11415\r
+                               EE\r
 \r
-A0-C5-F2   (hex)               Oray.com co., LTD.\r
-B00000-BFFFFF     (base 16)            Oray.com co., LTD.\r
-                               8008Rm, building No.1 GuoDing d. Yangpu District\r
-                               Shanghai  Shanghai  200433\r
-                               CN\r
+38-B1-9E   (hex)               Gesellschaft industrieller Technologien \r
+C00000-CFFFFF     (base 16)            Gesellschaft industrieller Technologien \r
+                               Hauptstraße 10\r
+                               Großbeeren    14979 \r
+                               DE\r
 \r
-4C-65-A8   (hex)               SHENZHEN LISAIER TRONICS CO.,LTD\r
-900000-9FFFFF     (base 16)            SHENZHEN LISAIER TRONICS CO.,LTD\r
-                               No.22 xihu industrial park ,xikeng henggang Town Longgang District      \r
-                                shenzhen   Guang Dong      518115\r
+38-B1-9E   (hex)               HDANYWHERE\r
+200000-2FFFFF     (base 16)            HDANYWHERE\r
+                               Unit 23 Link Business Centre\r
+                               Malvern  Worcs  WR14 1UQ\r
+                               GB\r
+\r
+38-B1-9E   (hex)               Triple Jump Medical\r
+000000-0FFFFF     (base 16)            Triple Jump Medical\r
+                               5 HaCarmel St.\r
+                               Yokneam    2069203\r
+                               IL\r
+\r
+38-B1-9E   (hex)               Thrust Networks\r
+600000-6FFFFF     (base 16)            Thrust Networks\r
+                               Pangeran Jayakarta 129 No B 7\r
+                               Jakarta  Jakarta  10730\r
+                               ID\r
+\r
+D8-86-0B   (hex)               Teplovodokhran Ltd.\r
+400000-4FFFFF     (base 16)            Teplovodokhran Ltd.\r
+                               Novaya , 51v\r
+                               Ryazan    390027\r
+                               RU\r
+\r
+D8-86-0B   (hex)               ComNav Technology Ltd.\r
+D00000-DFFFFF     (base 16)            ComNav Technology Ltd.\r
+                               Buliding 2,No. 618  Chengliu Middle  Road\r
+                               JiaDing District  Shanghai  201801\r
                                CN\r
 \r
-4C-65-A8   (hex)               Nuviz Oy\r
-600000-6FFFFF     (base 16)            Nuviz Oy\r
-                               Joensuunkatu 7\r
-                               Salo    24100\r
-                               FI\r
+D8-86-0B   (hex)               VRINDA NANO TECHNOLOGIES PVT LTD\r
+800000-8FFFFF     (base 16)            VRINDA NANO TECHNOLOGIES PVT LTD\r
+                               PLOT NO.283, SECTOR 7, IMT MANESAR, GURGAON \r
+                               INDIA  HARYANA  122050\r
+                               IN\r
 \r
-A0-C5-F2   (hex)               Shenzhen Feima Robotics Technology Co.,Ltd\r
-300000-3FFFFF     (base 16)            Shenzhen Feima Robotics Technology Co.,Ltd\r
-                               1/f,16 ,Zhiheng Industrial Park, Nantou Second Road, Nantou Street, Nanshan District\r
+D8-86-0B   (hex)               Shenzhen Yidong Technology Co.,Ltd\r
+E00000-EFFFFF     (base 16)            Shenzhen Yidong Technology Co.,Ltd\r
+                               13th Floor,Jia'anda Building, No.110 Huafan Road,Tongsheng Community, Dalang Street,Longhua District\r
                                Shenzhen  Guangdong  518000\r
                                CN\r
 \r
-7C-BA-CC   (hex)               Fortem Technologies, Inc.\r
-500000-5FFFFF     (base 16)            Fortem Technologies, Inc.\r
-                               1712 S East Bay Boulevard Suite 325\r
-                               Provo  UT  84606\r
+E0-5A-9F   (hex)               Hale Products\r
+400000-4FFFFF     (base 16)            Hale Products\r
+                               607 NW 27th Ave\r
+                               Ocala  FL  34475\r
                                US\r
 \r
-78-D8-00   (hex)               Alango Technologies Ltd\r
-600000-6FFFFF     (base 16)            Alango Technologies Ltd\r
-                               Etgar 2, Carmel Biulding 1rd floor\r
-                               Tirat Carmel  Haifa  39100\r
-                               IL\r
-\r
-78-D8-00   (hex)               Shenzhen Chenzhuo Technology Co., Ltd.\r
-C00000-CFFFFF     (base 16)            Shenzhen Chenzhuo Technology Co., Ltd.\r
-                               301,3/F,Longtangge,1183 Liuxian Avenue,Nanshan\r
-                               Shenzhen  Guangdong  518055\r
+E0-5A-9F   (hex)               Chengdu Song Yuan Electronic Technology Co.,Ltd\r
+200000-2FFFFF     (base 16)            Chengdu Song Yuan Electronic Technology Co.,Ltd\r
+                               Building 63 Cui Feng International, No.366 Bai Cao Road, High-tech West Zone\r
+                               Chengdu  Sichuan  610000\r
                                CN\r
 \r
-28-F5-37   (hex)               Phyn LLC\r
-400000-4FFFFF     (base 16)            Phyn LLC\r
-                               1855 Del Amo Blvd\r
-                               Torrance  CA  90501\r
-                               US\r
+4C-BC-98   (hex)               Heliotis AG\r
+C00000-CFFFFF     (base 16)            Heliotis AG\r
+                               Längenbold 5\r
+                               Root    6037\r
+                               CH\r
 \r
-28-F5-37   (hex)               MyOmega Systems GmbH\r
-600000-6FFFFF     (base 16)            MyOmega Systems GmbH\r
-                               Neumeyerstr. 28-34\r
-                               Nürnberg  Bavaria  90411\r
-                               DE\r
+1C-A0-D3   (hex)               Private\r
+700000-7FFFFF     (base 16)            Private\r
 \r
-28-F5-37   (hex)               Shenzhen Modern Cowboy Technology Co.,Ltd.     \r
-700000-7FFFFF     (base 16)            Shenzhen Modern Cowboy Technology Co.,Ltd.     \r
-                               Room 1006,Beike building,Keyuan road,Yuehai streets,Nanshan District\r
-                               Shenzhen  Guangdong Province  518200\r
+E4-4C-C7   (hex)               HANGZHOU OLE-SYSTEMS CO., LTD\r
+600000-6FFFFF     (base 16)            HANGZHOU OLE-SYSTEMS CO., LTD\r
+                                No.35 Jiuhuan Road, Jianggan District , Hangzhou , Zhejiang , China\r
+                               Hangzhou  Zhejiang  310019\r
                                CN\r
 \r
-28-F5-37   (hex)               Honeywell Safety Products USA, Inc\r
-A00000-AFFFFF     (base 16)            Honeywell Safety Products USA, Inc\r
-                               7828 Waterville Road\r
-                               San Diego  CA  92154\r
+E4-4C-C7   (hex)               Muzik Inc\r
+A00000-AFFFFF     (base 16)            Muzik Inc\r
+                               9220 Sunset Blvd #112\r
+                               West Hollywood    CA 90069\r
                                US\r
 \r
-34-00-8A   (hex)               Fotonic i Norden AB\r
-400000-4FFFFF     (base 16)            Fotonic i Norden AB\r
-                               Box 733\r
-                               Skelleftea  SE  93127\r
-                               SE\r
-\r
-34-00-8A   (hex)               uberGARD Pte. Ltd.\r
-700000-7FFFFF     (base 16)            uberGARD Pte. Ltd.\r
-                               39 Sungei Kadut Avenue\r
-                               Singapore    729663\r
-                               SG\r
-\r
-34-00-8A   (hex)               Shenzhen Andakai Technologies Co., Ltd.\r
-800000-8FFFFF     (base 16)            Shenzhen Andakai Technologies Co., Ltd.\r
-                               Unit B, 10/F, Building 2, NO.10 Industial Park, Tianliao Community, Gongming Street, GuangMing District, Shenzhen,China\r
-                               Shenzhen  Guangdong  518107\r
+74-5B-C5   (hex)               SHENZHEN ATX TECHNOLOGY CO.,LTD \r
+700000-7FFFFF     (base 16)            SHENZHEN ATX TECHNOLOGY CO.,LTD \r
+                               7/F,Zhengjiyuan Buiding,2 Road,Qianjing, Xixiang, Baoan District\r
+                               Shenzhen  GUANGDONG  518000\r
                                CN\r
 \r
-34-00-8A   (hex)               Angee Technologies Ltd.\r
-000000-0FFFFF     (base 16)            Angee Technologies Ltd.\r
-                               City House, 3 Cranwood Street\r
-                               London     EC1V 9PE\r
-                               GB\r
-\r
-34-00-8A   (hex)               Shenzhen Eternal Idea Tech Co.,Ltd\r
-C00000-CFFFFF     (base 16)            Shenzhen Eternal Idea Tech Co.,Ltd\r
-                               5/F, Building C, Chuangwei Technology Park,1st Rd,Shiyan tangtou,Baoan District, Shenzhen, Guang Dong Province,PRC \r
-                               Shenzhen  Guang Dong  518000\r
+74-5B-C5   (hex)               SIGLENT TECHNOLOGIES CO., LTD.\r
+200000-2FFFFF     (base 16)            SIGLENT TECHNOLOGIES CO., LTD.\r
+                               Blog No.4 & No.5, Antongda Industrial Zone, 3rd Liuxian Road, Bao’an District, Shenzhen, 518101, China.\r
+                               Shenzhen  Guangdong  518101\r
                                CN\r
 \r
-34-29-8F   (hex)               BlackEdge Capital\r
-000000-0FFFFF     (base 16)            BlackEdge Capital\r
-                               801 West Adams Street, Suite 500\r
-                               Chicago    60607\r
+74-5B-C5   (hex)               Smartiply Inc.\r
+B00000-BFFFFF     (base 16)            Smartiply Inc.\r
+                               233 Mt. Airy Road\r
+                               Basking Ridge  NJ  07920\r
                                US\r
 \r
-34-29-8F   (hex)               Chengdu Meross Technology Co., Ltd.\r
-100000-1FFFFF     (base 16)            Chengdu Meross Technology Co., Ltd.\r
-                               No. 25, Yizhou Avenue, Gaoxin\r
-                               Chengdu  Sichuan  610000\r
+FC-D2-B6   (hex)               T CHIP DIGITAL TECHNOLOGY CO.LTD\r
+B00000-BFFFFF     (base 16)            T CHIP DIGITAL TECHNOLOGY CO.LTD\r
+                               Room 320, C Tower, Jingji Building, HuaFeng Headquarter, Xixiang, Baoan\r
+                               SHENZHEN  Guangdong  518000\r
                                CN\r
 \r
-CC-1B-E0   (hex)               Microtech System,Inc  \r
-000000-0FFFFF     (base 16)            Microtech System,Inc  \r
-                               A-1102, Digital Empire Building\r
-                               Suwon  Gyeonggi-do  16690\r
-                               KR\r
-\r
-18-9B-A5   (hex)               Mantra Softech India Pvt Ltd\r
-600000-6FFFFF     (base 16)            Mantra Softech India Pvt Ltd\r
-                               B203, Shapath Hexa, S.G. Highway, Sola,\r
-                               Ahmedabad  Gujarat  380060\r
-                               IN\r
+FC-D2-B6   (hex)               SHEN ZHEN XIN HAO YUAN PRECISION TECHNOLOGY CO.,L TD\r
+400000-4FFFFF     (base 16)            SHEN ZHEN XIN HAO YUAN PRECISION TECHNOLOGY CO.,L TD\r
+                               1,2,3 Building,XinHaoYuan Industrial Area,HeYi Community,Shajing Street,BaoAn District.Shenzhen\r
+                               shenzhen  guangdongsheng  518000\r
+                               CN\r
 \r
-18-9B-A5   (hex)               Airprotec\r
-200000-2FFFFF     (base 16)            Airprotec\r
-                               Avenue de l'Industrie 22\r
-                               Braine-l'Alleud    1420\r
-                               BE\r
+FC-D2-B6   (hex)               Winglet Systems Inc.\r
+900000-9FFFFF     (base 16)            Winglet Systems Inc.\r
+                               4-6, Shinyokohama 2-chome, Kohoku-ku\r
+                                Yokohama  Kanagawa  222-0033\r
+                               JP\r
 \r
-18-9B-A5   (hex)               Dectris Ltd.\r
-000000-0FFFFF     (base 16)            Dectris Ltd.\r
-                               Taefernweg 1\r
-                               Baden-Daettwil    5405\r
-                               CH\r
+34-E1-D1   (hex)               Doki Technologies Limited\r
+500000-5FFFFF     (base 16)            Doki Technologies Limited\r
+                               Unit 601,Tower One, Silvercord, 30 Canton Road, Tsim Sha Tsui\r
+                               Kowloon    00000\r
+                               HK\r
 \r
-18-9B-A5   (hex)               Eutron SPA\r
-B00000-BFFFFF     (base 16)            Eutron SPA\r
-                               Via Crespi 29/31\r
-                               Pradalunga  Bergamo  24020\r
-                               IT\r
+34-E1-D1   (hex)               HI-TECH.ORG\r
+D00000-DFFFFF     (base 16)            HI-TECH.ORG\r
+                               Volgogradskiy prospekt, 43, k.3, room XXVI\r
+                               Moscow     109316\r
+                               RU\r
 \r
-18-9B-A5   (hex)               Shenzhen Tong Tai Yi information Technology Co.,Ltd\r
-800000-8FFFFF     (base 16)            Shenzhen Tong Tai Yi information Technology Co.,Ltd\r
-                               District C,3rd Floor,Bldg B1,Digital Tech Park,7th GaoXin South Blvd,Tech Park,NanShan,ShenZhen,China\r
-                               shenzhen  guangdong  518102\r
+34-E1-D1   (hex)               Tianjin Sublue Ocean Science & Technology Co., Ltd\r
+000000-0FFFFF     (base 16)            Tianjin Sublue Ocean Science & Technology Co., Ltd\r
+                               No.29 Factory No.156 Nanhai Road,TEDA\r
+                               Tianjin    300050\r
                                CN\r
 \r
-90-4E-91   (hex)               CommandScape, Inc.\r
-800000-8FFFFF     (base 16)            CommandScape, Inc.\r
-                               505 South Flagler Dr, Suite 900\r
-                               West Palm Beach  FL  33401\r
+34-E1-D1   (hex)               CREW by True Rowing, Inc.\r
+C00000-CFFFFF     (base 16)            CREW by True Rowing, Inc.\r
+                               14 Arrow St, Floor 4\r
+                               Cambridge  MA  02138\r
                                US\r
 \r
-2C-27-9E   (hex)               Rutledge Omni Services Pte Ltd\r
-600000-6FFFFF     (base 16)            Rutledge Omni Services Pte Ltd\r
-                               34 Toh Guan Road East, #01-12/13 Enterprise Hub\r
-                               Singapore  Singapore  608579\r
-                               SG\r
+34-E1-D1   (hex)               Annapurna labs\r
+E00000-EFFFFF     (base 16)            Annapurna labs\r
+                               Matam Scientific Industries Center,   Building 8.2\r
+                               Mail box 15123  Haifa  3508409\r
+                               IL\r
 \r
-88-5F-E8   (hex)               Apoidea Technology Co., Ltd.\r
-100000-1FFFFF     (base 16)            Apoidea Technology Co., Ltd.\r
-                               No. 111, Boyun Road\r
-                               Shanghai    201203\r
-                               CN\r
+C8-63-14   (hex)               Autonics Co., Ltd.\r
+100000-1FFFFF     (base 16)            Autonics Co., Ltd.\r
+                               4-14-26, Shimo-Muneoka\r
+                               Shiki  Saitama  3530003\r
+                               JP\r
 \r
-88-5F-E8   (hex)               zhejiang yuanwang communication technolgy co.,ltd\r
-D00000-DFFFFF     (base 16)            zhejiang yuanwang communication technolgy co.,ltd\r
-                               No. 6 of shen shi lei lu Road\r
-                               ZhuJi  Zhejiang  311800\r
-                               CN\r
+C8-63-14   (hex)               GRINBI PARTNERS\r
+600000-6FFFFF     (base 16)            GRINBI PARTNERS\r
+                               222, Dogok-ro, Gangnam-gu\r
+                               Seoul    06272\r
+                               KR\r
 \r
-48-0B-B2   (hex)               Thales CETCA Avionics CO., Ltd\r
-200000-2FFFFF     (base 16)            Thales CETCA Avionics CO., Ltd\r
-                               NO.9 Baichuan road,Hi-tech industry west zone park, Chengdu, Sichuan\r
-                               Chengdu  Sichuan  611731\r
-                               CN\r
+E4-1E-0A   (hex)               Safety Vision, LLC\r
+B00000-BFFFFF     (base 16)            Safety Vision, LLC\r
+                               6100 West Sam Houston Parkway North\r
+                               Houston  TX  77041-5113\r
+                               US\r
 \r
-48-0B-B2   (hex)               M2Lab Ltd.\r
-D00000-DFFFFF     (base 16)            M2Lab Ltd.\r
-                               148 Des Voeux Rd Central\r
-                               Hong Kong    HK\r
-                               HK\r
+E4-1E-0A   (hex)               Zavod № 423\r
+000000-0FFFFF     (base 16)            Zavod № 423\r
+                               2B, Zavodskoy proezd\r
+                               Bogoroditsk  Tula  301830\r
+                               RU\r
 \r
-48-0B-B2   (hex)               Beijing MFOX technology Co., Ltd.\r
-E00000-EFFFFF     (base 16)            Beijing MFOX technology Co., Ltd.\r
-                               B zone,floor 2,NO.A5 east Rongchang street .BDA (yizhuang) BeiJing\r
-                               BeiJing  BeiJing  100176\r
+C8-2C-2B   (hex)               Verifone Systems (China),lnc.\r
+800000-8FFFFF     (base 16)            Verifone Systems (China),lnc.\r
+                               2nd Floor,No.39,Region C, Tongpan Road,Gulou District\r
+                               fuzhou  fujian  350004\r
                                CN\r
 \r
-0C-73-EB   (hex)               EVERSEC TECHNOLOGY CORPORATION\r
-100000-1FFFFF     (base 16)            EVERSEC TECHNOLOGY CORPORATION\r
-                               F5,Tower D,JingYi Technology Building NO.9 Dazhongsi East Road.,Beijing,P.R.China\r
-                               BEIJING  BEIJING  100086\r
+B0-FD-0B   (hex)               Taian Yuqi Communication Technology Co., Ltd\r
+500000-5FFFFF     (base 16)            Taian Yuqi Communication Technology Co., Ltd\r
+                               Building 4, Fengxiang Road, Tai'an Development Zone\r
+                               Tai’an  Shandong  271000\r
                                CN\r
 \r
-0C-73-EB   (hex)               Pi Innovo LLC\r
-A00000-AFFFFF     (base 16)            Pi Innovo LLC\r
-                               47023 Five Mile Rd\r
-                               Plymouth  MI  48170\r
-                               US\r
-\r
-0C-73-EB   (hex)               Gemini Data Loggers (UK) Limited\r
-000000-0FFFFF     (base 16)            Gemini Data Loggers (UK) Limited\r
-                               Scientific House, Terminus Road\r
-                               Chichester  West Sussex  PO19 8UJ\r
-                               GB\r
+B0-FD-0B   (hex)               Shenzhen FEIBIT Electronic Technology Co.,LTD\r
+E00000-EFFFFF     (base 16)            Shenzhen FEIBIT Electronic Technology Co.,LTD\r
+                               5th floor,Bld. A1, Lilang Software Park\r
+                               Shenzhen    518112\r
+                               CN\r
 \r
-3C-24-F0   (hex)               Abrites Ltd.\r
-100000-1FFFFF     (base 16)            Abrites Ltd.\r
-                               147 Cherni Vrah Blvd.\r
-                               Sofia  Sofia  1407\r
-                               BG\r
+B0-FD-0B   (hex)               IDspire Corporation Ltd.\r
+100000-1FFFFF     (base 16)            IDspire Corporation Ltd.\r
+                               9F, No. 266, Sec. 1, Wenhua Rd., Banqiao Dist.\r
+                               New Taipei City    22041\r
+                               TW\r
 \r
-3C-24-F0   (hex)               Wisycom\r
-300000-3FFFFF     (base 16)            Wisycom\r
-                               Via Spin 156\r
-                               Romano D'Ezzelino  Vicenza  36060\r
-                               IT\r
+84-8B-CD   (hex)               Shenzhen LTIME In-Vehicle Entertainment System Company Limited\r
+100000-1FFFFF     (base 16)            Shenzhen LTIME In-Vehicle Entertainment System Company Limited\r
+                               4/F, Building 1, Nangang 1st Industrial Park No. 1029, Songbai Road, Xili, Nanshan District\r
+                               SHENZHEN  GUANGDONG  518055\r
+                               CN\r
 \r
-3C-24-F0   (hex)               GETMOBIT LLC\r
-E00000-EFFFFF     (base 16)            GETMOBIT LLC\r
-                               d. 4 str. 2 pom. 137, ul. Programmistov\r
-                               Dubna  Moscow  141983\r
-                               RU\r
+34-04-9E   (hex)               uikismart\r
+D00000-DFFFFF     (base 16)            uikismart\r
+                               Nanshan\r
+                               Shenzhen  Guangdong  518061\r
+                               CN\r
 \r
-3C-24-F0   (hex)               Sivat Technology Co.,Ltd.\r
-800000-8FFFFF     (base 16)            Sivat Technology Co.,Ltd.\r
-                               Room 1602, Starbuilding 2, west Complex of ChangYing TianJie ChaoYang District\r
-                               BeiJing  Beijing  100024\r
+50-A4-D0   (hex)               Guangzhou Hysoon Electronic Co., Ltd.\r
+300000-3FFFFF     (base 16)            Guangzhou Hysoon Electronic Co., Ltd.\r
+                               No.1, Fenghuang South Road, Xinhua, Huadu District\r
+                               Guangzhou  Guangdong  510800\r
                                CN\r
 \r
-A4-3B-FA   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
+50-A4-D0   (hex)               Shanghai Pujiang Smart Card Systems Co., Ltd.\r
+700000-7FFFFF     (base 16)            Shanghai Pujiang Smart Card Systems Co., Ltd.\r
+                               No.100, Lane 7488, Hutai Road\r
+                               Shanghai    86-201809\r
+                               CN\r
 \r
-8C-1C-DA   (hex)               Structura Technology & Innovation\r
-300000-3FFFFF     (base 16)            Structura Technology & Innovation\r
-                               via Roveredo 20/B\r
-                               Pordenone  PN  33170\r
-                               IT\r
+8C-C8-F4   (hex)               Swift Navigation Inc\r
+900000-9FFFFF     (base 16)            Swift Navigation Inc\r
+                               1543 Mission Street\r
+                               San Francisco  CA  94103\r
+                               US\r
 \r
-2C-48-35   (hex)               Exertus Oy\r
-600000-6FFFFF     (base 16)            Exertus Oy\r
-                               Kampusranta 9 C\r
-                               Seinäjoki    60320\r
-                               FI\r
+8C-C8-F4   (hex)               Lanhomex Technology(Shen Zhen)Co.,Ltd. \r
+100000-1FFFFF     (base 16)            Lanhomex Technology(Shen Zhen)Co.,Ltd. \r
+                               Room 409, Building 29,Zhi Heng Industrial Part, Guankou 2nd  Road, Nanshan District\r
+                               SHENZHEN    518000\r
+                               CN\r
 \r
-2C-48-35   (hex)               Collatz+Trojan GmbH\r
-A00000-AFFFFF     (base 16)            Collatz+Trojan GmbH\r
-                               Borsteler Chaussee85-99a\r
-                               Hamburg  Hamburg  22453\r
+8C-C8-F4   (hex)               Trilux Group Management GmbH\r
+A00000-AFFFFF     (base 16)            Trilux Group Management GmbH\r
+                               Heidestrasse\r
+                               Arnsberg    59759\r
                                DE\r
 \r
-2C-48-35   (hex)               GEARTECH LTD\r
-400000-4FFFFF     (base 16)            GEARTECH LTD\r
-                               R310/312,3/F,Beike Venture Building,No.1077,Nanhai Avenue,Nanshan District\r
-                               Shenzhen  Guangdong  518067\r
+40-F3-85   (hex)               Lennox International Incorporated\r
+600000-6FFFFF     (base 16)            Lennox International Incorporated\r
+                               1600 Metrocrest Drive\r
+                               Carrollton  TX  75006\r
+                               US\r
+\r
+40-F3-85   (hex)               KATO ENGINEERING INC.\r
+500000-5FFFFF     (base 16)            KATO ENGINEERING INC.\r
+                               2075 HOWARD DRIVE WEST\r
+                               NORTH MANKATO   MN  56003\r
+                               US\r
+\r
+1C-A0-D3   (hex)               Dynamic Connect (Suzhou) Hi-Tech Electronic Co.,Ltd.\r
+500000-5FFFFF     (base 16)            Dynamic Connect (Suzhou) Hi-Tech Electronic Co.,Ltd.\r
+                               Unit C&D, No.201 WuXiang, Export Processing Zone A No.200Suhong Road SIP\r
+                               Suzhou  JiangSu  215021\r
                                CN\r
 \r
-2C-48-35   (hex)               Progress Rail Services, Inspection and Information Systems\r
-000000-0FFFFF     (base 16)            Progress Rail Services, Inspection and Information Systems\r
-                               3801-1 South Selsa Road\r
-                               Independence    64057\r
+A4-11-63   (hex)               AlterG, Inc.\r
+400000-4FFFFF     (base 16)            AlterG, Inc.\r
+                               48438 Milmont Drive\r
+                               Fremont  CA  94538\r
                                US\r
 \r
-2C-48-35   (hex)               Rheonik Messtechnik GmbH\r
-200000-2FFFFF     (base 16)            Rheonik Messtechnik GmbH\r
-                               Rudolf-Diesel-Str., 5\r
-                               Odelzhausen  Deutschland  85235\r
-                               DE\r
+1C-A0-D3   (hex)               SAVELEC\r
+300000-3FFFFF     (base 16)            SAVELEC\r
+                               rue de la houille blanche\r
+                               HERMILLON  SAVOIE  73300\r
+                               FR\r
 \r
-7C-70-BC   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
+A4-11-63   (hex)               INTER CONTROL Hermann Köhler Elektrik GmbH & Co.KG\r
+100000-1FFFFF     (base 16)            INTER CONTROL Hermann Köhler Elektrik GmbH & Co.KG\r
+                               Schafhofstrasse 30\r
+                               Nuernberg    90411\r
+                               DE\r
 \r
-A0-19-B2   (hex)               Lon Microsystems Inc.\r
-900000-9FFFFF     (base 16)            Lon Microsystems Inc.\r
-                               11F Ali center Tianfu four street \r
-                               chengdu  sichuan  610041\r
+14-4F-D7   (hex)               Shenzhen V-Streaming Technology Co., Ltd.\r
+700000-7FFFFF     (base 16)            Shenzhen V-Streaming Technology Co., Ltd.\r
+                               Room610, LangShanGe Building, Yugu Hi-Tech Park, Liuxin Road 1183, Nanshan District\r
+                               Shenzhen  Guangdong  518000\r
                                CN\r
 \r
-A0-19-B2   (hex)               LDA Technologies\r
-C00000-CFFFFF     (base 16)            LDA Technologies\r
-                               2680 Matheson Blvd E., Suite 102\r
-                               Mississauga  Ontario  L4W2C6\r
-                               CA\r
+14-4F-D7   (hex)               Unirobot Corporation\r
+A00000-AFFFFF     (base 16)            Unirobot Corporation\r
+                               MK Hatagaya Sasazuka building 6F, Hatagaya, Shibuya-ku\r
+                               Tokyo  Japan  1510072\r
+                               JP\r
 \r
-D4-7C-44   (hex)               Innoviz Technologies LTD\r
-100000-1FFFFF     (base 16)            Innoviz Technologies LTD\r
-                               Atir Yeda 15\r
-                               Kfar Saba  Ha Sharon  4464312\r
-                               IL\r
+98-AA-FC   (hex)               SURTEC\r
+100000-1FFFFF     (base 16)            SURTEC\r
+                               616 avenue de l'Europe\r
+                               Le Creusot  burgundy  71206\r
+                               FR\r
 \r
-D4-7C-44   (hex)               YunDing Network Technology (Beijing) Co., Ltd\r
-200000-2FFFFF     (base 16)            YunDing Network Technology (Beijing) Co., Ltd\r
-                               A521,Floor 5, Tencent Space Building No.388, Hui long guan East St. \r
-                               Beijing    100000\r
-                               CN\r
-\r
-D4-7C-44   (hex)               ASDA ICT Co., Ltd.\r
-600000-6FFFFF     (base 16)            ASDA ICT Co., Ltd.\r
-                               4F-2,No.2,Sec.4,Zhongyang Rd,Tucheng Dist,\r
-                               New Taipei City    999079\r
-                               TW\r
-\r
-D4-7C-44   (hex)               Exafore Oy\r
-000000-0FFFFF     (base 16)            Exafore Oy\r
-                               Hermiankatu 6-8D\r
-                               Tampere    33720\r
-                               FI\r
+08-ED-02   (hex)               HANTAS CO., LTD.\r
+800000-8FFFFF     (base 16)            HANTAS CO., LTD.\r
+                               474 Dunchondaero, Jungwon-gu\r
+                               Seongnam-si  Kyonggi-do  13229\r
+                               KR\r
 \r
-B4-4B-D6   (hex)               G4S Monitoring Technologies Ltd\r
-000000-0FFFFF     (base 16)            G4S Monitoring Technologies Ltd\r
-                               3 Centurion Court, Meridian East\r
-                               Leicester  Leicestershire  LE19 1TP\r
-                               GB\r
+08-ED-02   (hex)               Eleven Engineering Incorporated\r
+700000-7FFFFF     (base 16)            Eleven Engineering Incorporated\r
+                               10150 - 100 Street, Suite 800\r
+                               Edmonton  Canada, Alberta  T5J 0P6\r
+                               CA\r
 \r
-B4-4B-D6   (hex)               SHENZHEN TITA INTERACTIVE TECHNOLOGY CO.,LTD\r
-100000-1FFFFF     (base 16)            SHENZHEN TITA INTERACTIVE TECHNOLOGY CO.,LTD\r
-                               Floor 23, Haowei Technology Mansion,Keji south eighth Road, Gaoxin Sci-Tech. Park(South Zone), \r
-                               Shenzhen  Guangdong  518000\r
-                               CN\r
+08-ED-02   (hex)               TES Touch Embedded Solutions Inc.\r
+200000-2FFFFF     (base 16)            TES Touch Embedded Solutions Inc.\r
+                               3F, No. 141, Sec. 3, Ren'ai Rd.,\r
+                               Taipei    106\r
+                               TW\r
 \r
-B4-4B-D6   (hex)                Shenzhen Huabai Intelligent Technology Co., Ltd.\r
-A00000-AFFFFF     (base 16)             Shenzhen Huabai Intelligent Technology Co., Ltd.\r
-                               Science Park South District Shenzhen Digital\r
-                               Technology Park Building B2 4th Floor Area A  Shenzhen, Guangdong  518000\r
-                               CN\r
+08-ED-02   (hex)               Telstra Corporation Limited\r
+E00000-EFFFFF     (base 16)            Telstra Corporation Limited\r
+                               Level 2 / 150 Lonsdale St\r
+                               Melbourne  Victoria  3000\r
+                               AU\r
 \r
-3C-42-7E   (hex)               ROBOX SMART MOTION (WUHU) CO.,LTD\r
-D00000-DFFFFF     (base 16)            ROBOX SMART MOTION (WUHU) CO.,LTD\r
-                               No.96,Wanchun East Road,Jiujiang Economic Development District,Wuhu,Anhui,China\r
-                               Wuhu  Anhui  241000\r
+60-D7-E3   (hex)               Zhejiang Send Intelligent Technology,Ltd\r
+C00000-CFFFFF     (base 16)            Zhejiang Send Intelligent Technology,Ltd\r
+                               6-7F,E Building,Tiantang Software Park,Xidoumen Road,Xihu District\r
+                               Hangzhou  Zhejiang  310012\r
                                CN\r
 \r
-B4-4B-D6   (hex)               Perspicace Intellegince Technology\r
-600000-6FFFFF     (base 16)            Perspicace Intellegince Technology\r
-                               4F, 1326#, West YanAn road, Shanghai, P.R.China\r
-                               ShangHai  ShangHai  200052\r
-                               CN\r
+60-D7-E3   (hex)               HindlePower, Inc\r
+800000-8FFFFF     (base 16)            HindlePower, Inc\r
+                               1075 Saint John St\r
+                               Easton  PA  18042\r
+                               US\r
 \r
-B0-1F-81   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
+60-D7-E3   (hex)               Wilderness Labs Inc.\r
+A00000-AFFFFF     (base 16)            Wilderness Labs Inc.\r
+                               700 Edgewater Blvd., #108\r
+                               Foster City  CA  94404\r
+                               US\r
 \r
-3C-42-7E   (hex)               Dongguan Taide Industrial Co.,Ltd.\r
-100000-1FFFFF     (base 16)            Dongguan Taide Industrial Co.,Ltd.\r
-                               Taide Industrial Park,Phase 2 Jinfenghuang Industrial District Huangdong,Fenggang Town\r
-                               Dongguan City  GuangDong  523696\r
-                               CN\r
+60-D7-E3   (hex)               Elap s.r.l.\r
+100000-1FFFFF     (base 16)            Elap s.r.l.\r
+                               Via V. Veneto 4\r
+                               Corsico  Milano  20094\r
+                               IT\r
 \r
-CC-D3-1E   (hex)               NantEnergy\r
-C00000-CFFFFF     (base 16)            NantEnergy\r
-                               8455 North 90th Street Suite 4\r
-                               Scottsdale  AZ  85258\r
+04-71-4B   (hex)               uAvionix Corporation\r
+100000-1FFFFF     (base 16)            uAvionix Corporation\r
+                               380 Portage Ave.\r
+                               Palo Alto  CA  94306\r
                                US\r
 \r
-A0-19-B2   (hex)               Adomi\r
-A00000-AFFFFF     (base 16)            Adomi\r
-                               777 Mariners Island Blvd. Suite 150\r
-                               San Mateo  CA  94404\r
+04-71-4B   (hex)               Energport Inc\r
+800000-8FFFFF     (base 16)            Energport Inc\r
+                               48660 Kato Road\r
+                               Fremont  CA  94538\r
                                US\r
 \r
-04-C3-E6   (hex)               DREAMKAS LLC\r
-000000-0FFFFF     (base 16)            DREAMKAS LLC\r
-                               Bolshoy  Sampsoniyevskiy pr., 62A, office 2H\r
-                               Saint-Petersburg    194044\r
-                               RU\r
+F0-23-B9   (hex)               EZVIS LIMITED\r
+400000-4FFFFF     (base 16)            EZVIS LIMITED\r
+                               FLAT/RM 1605A Ho KING COMMERCIAL CENTRE 2-16 FA YUEN STREET\r
+                               HONGKONG    999077\r
+                               HK\r
 \r
-C0-83-59   (hex)               Suzhou Siheng Science and Technology Ltd.\r
-B00000-BFFFFF     (base 16)            Suzhou Siheng Science and Technology Ltd.\r
-                               8 floor of Jincheng star, Yunhe road NO.150, gaoxin Zone, Suzhou\r
-                               Suzhou    215000\r
-                               CN\r
+8C-14-7D   (hex)               Unwired Networks\r
+500000-5FFFFF     (base 16)            Unwired Networks\r
+                               Gonzagagasse 11/25\r
+                               Vienna    1010\r
+                               AT\r
 \r
-04-C3-E6   (hex)               Teleepoch Ltd\r
-E00000-EFFFFF     (base 16)            Teleepoch Ltd\r
-                               No.13 Langshan Rd,HiTech Park,Nanshan District\r
-                               Shenzhen  Guangdong  518000\r
-                               CN\r
+8C-14-7D   (hex)               Agilent S.p.A\r
+200000-2FFFFF     (base 16)            Agilent S.p.A\r
+                               Via.flli Varian 54\r
+                               Leini  Torino  10040\r
+                               IT\r
 \r
-C0-83-59   (hex)               SHANGHAI CHARMHOPE INFORMATION TECHNOLOGY CO.,LTD.\r
-A00000-AFFFFF     (base 16)            SHANGHAI CHARMHOPE INFORMATION TECHNOLOGY CO.,LTD.\r
-                               Building 11,No.230,Chuanhong Rd,Pudong Distrist\r
-                               Shanghai  Shanghai  201202\r
-                               CN\r
+8C-14-7D   (hex)               Electrical & Automation Larsen & Toubro Limited\r
+E00000-EFFFFF     (base 16)            Electrical & Automation Larsen & Toubro Limited\r
+                               Mysore Campus, KIADB Industrial Area, Hebbal, Hootagalli\r
+                               Mysore  Karnataka  570020\r
+                               IN\r
 \r
-B0-C5-CA   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
+A0-C5-F2   (hex)               Impulse Networks Pte Ltd\r
+900000-9FFFFF     (base 16)            Impulse Networks Pte Ltd\r
+                               1 Raffles Place, #44-08 Raffles Place\r
+                               Singapore    048616\r
+                               SG\r
 \r
-C0-83-59   (hex)               ANTS\r
-400000-4FFFFF     (base 16)            ANTS\r
-                               88, Simindae-ro, Dongan-Gu\r
-                               Anyang    14079\r
-                               KR\r
+A0-C5-F2   (hex)               Oray.com co., LTD.\r
+B00000-BFFFFF     (base 16)            Oray.com co., LTD.\r
+                               8008Rm, building No.1 GuoDing d. Yangpu District\r
+                               Shanghai  Shanghai  200433\r
+                               CN\r
 \r
-9C-F6-DD   (hex)               Lighting New Energy Technology Co., Ltd.\r
-C00000-CFFFFF     (base 16)            Lighting New Energy Technology Co., Ltd.\r
-                               Room 402, Building 22, Chentian Industrial Zone, Xixiang Street, Bao'an District,\r
-                               Shenzhen  Guangdong  518100\r
+4C-65-A8   (hex)               SHENZHEN LISAIER TRONICS CO.,LTD\r
+900000-9FFFFF     (base 16)            SHENZHEN LISAIER TRONICS CO.,LTD\r
+                               No.22 xihu industrial park ,xikeng henggang Town Longgang District      \r
+                                shenzhen   Guang Dong      518115\r
                                CN\r
 \r
-9C-F6-DD   (hex)               Ithor IT Co.,Ltd.\r
-100000-1FFFFF     (base 16)            Ithor IT Co.,Ltd.\r
-                               No. 501, Building I, ZTE Park, Hi-Tech Industrial Zone\r
-                               XI'AN  ShanXi  710065\r
+4C-65-A8   (hex)               Nuviz Oy\r
+600000-6FFFFF     (base 16)            Nuviz Oy\r
+                               Joensuunkatu 7\r
+                               Salo    24100\r
+                               FI\r
+\r
+A0-C5-F2   (hex)               Shenzhen Feima Robotics Technology Co.,Ltd\r
+300000-3FFFFF     (base 16)            Shenzhen Feima Robotics Technology Co.,Ltd\r
+                               1/f,16 ,Zhiheng Industrial Park, Nantou Second Road, Nantou Street, Nanshan District\r
+                               Shenzhen  Guangdong  518000\r
                                CN\r
 \r
-9C-F6-DD   (hex)               Savari Inc\r
-800000-8FFFFF     (base 16)            Savari Inc\r
-                               2005 De la cruz blvd, st 111,\r
-                               santa clara  CA  95050\r
+7C-BA-CC   (hex)               Fortem Technologies, Inc.\r
+500000-5FFFFF     (base 16)            Fortem Technologies, Inc.\r
+                               1712 S East Bay Boulevard Suite 325\r
+                               Provo  UT  84606\r
                                US\r
 \r
-30-09-F9   (hex)               Honeywell\r
-C00000-CFFFFF     (base 16)            Honeywell\r
-                               13350 US Hwy 19 N \r
-                               Clearwater    33764\r
-                               US\r
+78-D8-00   (hex)               Alango Technologies Ltd\r
+600000-6FFFFF     (base 16)            Alango Technologies Ltd\r
+                               Etgar 2, Carmel Biulding 1rd floor\r
+                               Tirat Carmel  Haifa  39100\r
+                               IL\r
 \r
-30-09-F9   (hex)               Beijing Mydreamplus Information Technology Co., Ltd.\r
-600000-6FFFFF     (base 16)            Beijing Mydreamplus Information Technology Co., Ltd.\r
-                               Room 301-2, North Building, No. 11, CangJingGuan Lane, DongCheng District,\r
-                               Beijing  Beijing  100005\r
+78-D8-00   (hex)               Shenzhen Chenzhuo Technology Co., Ltd.\r
+C00000-CFFFFF     (base 16)            Shenzhen Chenzhuo Technology Co., Ltd.\r
+                               301,3/F,Longtangge,1183 Liuxian Avenue,Nanshan\r
+                               Shenzhen  Guangdong  518055\r
                                CN\r
 \r
-30-09-F9   (hex)               Beijing Netswift Technology Co.,Ltd.\r
-200000-2FFFFF     (base 16)            Beijing Netswift Technology Co.,Ltd.\r
-                               No. 7, 7th floor, No.49 Zhichun Road, Haidian District\r
-                               Beijing  Beijing  100190 \r
-                               CN\r
+28-F5-37   (hex)               Phyn LLC\r
+400000-4FFFFF     (base 16)            Phyn LLC\r
+                               1855 Del Amo Blvd\r
+                               Torrance  CA  90501\r
+                               US\r
 \r
-84-89-EC   (hex)               Price Industries Limited\r
-D00000-DFFFFF     (base 16)            Price Industries Limited\r
-                               638 Raleigh Street\r
-                               Winnipeg  Manitoba  R2K3Z9\r
-                               CA\r
+28-F5-37   (hex)               MyOmega Systems GmbH\r
+600000-6FFFFF     (base 16)            MyOmega Systems GmbH\r
+                               Neumeyerstr. 28-34\r
+                               Nürnberg  Bavaria  90411\r
+                               DE\r
 \r
-84-89-EC   (hex)               thousand star tech LTD.\r
-200000-2FFFFF     (base 16)            thousand star tech LTD.\r
-                               guan nan yuan 1 road dangdai optical valley dream workshop\r
-                               wuhan  hubei  430070\r
+28-F5-37   (hex)               Shenzhen Modern Cowboy Technology Co.,Ltd.     \r
+700000-7FFFFF     (base 16)            Shenzhen Modern Cowboy Technology Co.,Ltd.     \r
+                               Room 1006,Beike building,Keyuan road,Yuehai streets,Nanshan District\r
+                               Shenzhen  Guangdong Province  518200\r
                                CN\r
 \r
-84-89-EC   (hex)               Newell Brands\r
-A00000-AFFFFF     (base 16)            Newell Brands\r
-                               221 River Street\r
-                               Hoboken  NJ  07030\r
+28-F5-37   (hex)               Honeywell Safety Products USA, Inc\r
+A00000-AFFFFF     (base 16)            Honeywell Safety Products USA, Inc\r
+                               7828 Waterville Road\r
+                               San Diego  CA  92154\r
                                US\r
 \r
-84-89-EC   (hex)               SHINKAWA LTD.\r
-C00000-CFFFFF     (base 16)            SHINKAWA LTD.\r
-                               Shinjuku Front Tower 32F, 2-21-1 Kitashinjyuku\r
-                               Shinjuku-ku  Tokyo  169-0074\r
-                               JP\r
+34-00-8A   (hex)               Fotonic i Norden AB\r
+400000-4FFFFF     (base 16)            Fotonic i Norden AB\r
+                               Box 733\r
+                               Skelleftea  SE  93127\r
+                               SE\r
 \r
-84-89-EC   (hex)               Shenzhen Intellifusion Technologies Co., Ltd.\r
-E00000-EFFFFF     (base 16)            Shenzhen Intellifusion Technologies Co., Ltd.\r
-                               Suite701, Science Museum, Shenzhen City\r
-                               Shenzhen  Guangdong  518000\r
+34-00-8A   (hex)               uberGARD Pte. Ltd.\r
+700000-7FFFFF     (base 16)            uberGARD Pte. Ltd.\r
+                               39 Sungei Kadut Avenue\r
+                               Singapore    729663\r
+                               SG\r
+\r
+34-00-8A   (hex)               Shenzhen Andakai Technologies Co., Ltd.\r
+800000-8FFFFF     (base 16)            Shenzhen Andakai Technologies Co., Ltd.\r
+                               Unit B, 10/F, Building 2, NO.10 Industial Park, Tianliao Community, Gongming Street, GuangMing District, Shenzhen,China\r
+                               Shenzhen  Guangdong  518107\r
                                CN\r
 \r
-A0-28-33   (hex)               IMESHX CORPORATION LIMITED\r
-900000-9FFFFF     (base 16)            IMESHX CORPORATION LIMITED\r
-                               10A7F, ShenZhen Bay Technology Ecological Park, NanShan District,\r
-                               Shenzhen  Guangdong  518000\r
+34-00-8A   (hex)               Angee Technologies Ltd.\r
+000000-0FFFFF     (base 16)            Angee Technologies Ltd.\r
+                               City House, 3 Cranwood Street\r
+                               London     EC1V 9PE\r
+                               GB\r
+\r
+34-00-8A   (hex)               Shenzhen Eternal Idea Tech Co.,Ltd\r
+C00000-CFFFFF     (base 16)            Shenzhen Eternal Idea Tech Co.,Ltd\r
+                               5/F, Building C, Chuangwei Technology Park,1st Rd,Shiyan tangtou,Baoan District, Shenzhen, Guang Dong Province,PRC \r
+                               Shenzhen  Guang Dong  518000\r
                                CN\r
 \r
-A0-28-33   (hex)               Precision Planting, LLC.\r
-E00000-EFFFFF     (base 16)            Precision Planting, LLC.\r
-                               23207 Townline Rd.\r
-                               Tremont  IL  61568\r
+34-29-8F   (hex)               BlackEdge Capital\r
+000000-0FFFFF     (base 16)            BlackEdge Capital\r
+                               801 West Adams Street, Suite 500\r
+                               Chicago    60607\r
                                US\r
 \r
-A4-ED-43   (hex)               Heyuan intelligence technology CO.,Ltd\r
-900000-9FFFFF     (base 16)            Heyuan intelligence technology CO.,Ltd\r
-                               No.1166 Xinluo Street\r
-                               Jinan City  Shandong Province  250101\r
+34-29-8F   (hex)               Chengdu Meross Technology Co., Ltd.\r
+100000-1FFFFF     (base 16)            Chengdu Meross Technology Co., Ltd.\r
+                               No. 25, Yizhou Avenue, Gaoxin\r
+                               Chengdu  Sichuan  610000\r
                                CN\r
 \r
-A4-ED-43   (hex)               Sweam AB\r
-000000-0FFFFF     (base 16)            Sweam AB\r
-                               Kistagången 12\r
-                               Kista  Stockholm  16440\r
-                               SE\r
+CC-1B-E0   (hex)               Microtech System,Inc  \r
+000000-0FFFFF     (base 16)            Microtech System,Inc  \r
+                               A-1102, Digital Empire Building\r
+                               Suwon  Gyeonggi-do  16690\r
+                               KR\r
 \r
-A4-ED-43   (hex)               Linseis Messgeraete GmbH\r
-800000-8FFFFF     (base 16)            Linseis Messgeraete GmbH\r
-                               Vielitzer Str. 43                      \r
-                               Selb    95100\r
-                               DE\r
+18-9B-A5   (hex)               Mantra Softech India Pvt Ltd\r
+600000-6FFFFF     (base 16)            Mantra Softech India Pvt Ltd\r
+                               B203, Shapath Hexa, S.G. Highway, Sola,\r
+                               Ahmedabad  Gujarat  380060\r
+                               IN\r
 \r
-30-0A-60   (hex)               Private\r
-300000-3FFFFF     (base 16)            Private\r
+18-9B-A5   (hex)               Airprotec\r
+200000-2FFFFF     (base 16)            Airprotec\r
+                               Avenue de l'Industrie 22\r
+                               Braine-l'Alleud    1420\r
+                               BE\r
 \r
-30-0A-60   (hex)               Beijing Ruiteng Zhongtian TECH Ltd.,Co\r
-100000-1FFFFF     (base 16)            Beijing Ruiteng Zhongtian TECH Ltd.,Co\r
-                               Blk 6,Rm 602,Noble CenterⅡ,No.1 Automotive Museum East Lane,South Fourth Ring Road, Fengtai District\r
-                               Beijing  Beijing  100070\r
-                               CN\r
+18-9B-A5   (hex)               Dectris Ltd.\r
+000000-0FFFFF     (base 16)            Dectris Ltd.\r
+                               Taefernweg 1\r
+                               Baden-Daettwil    5405\r
+                               CH\r
 \r
-30-0A-60   (hex)               KAZUtechnica Co.,Ltd.\r
-000000-0FFFFF     (base 16)            KAZUtechnica Co.,Ltd.\r
-                               1-9-18,Chuo,Chuo-ku\r
-                               Sagamihara-shi  Kanagawa  2520239\r
-                               JP\r
+18-9B-A5   (hex)               Eutron SPA\r
+B00000-BFFFFF     (base 16)            Eutron SPA\r
+                               Via Crespi 29/31\r
+                               Pradalunga  Bergamo  24020\r
+                               IT\r
 \r
-30-0A-60   (hex)               Bronkhorst High-Tech BV\r
-800000-8FFFFF     (base 16)            Bronkhorst High-Tech BV\r
-                               Nijverheidsstraat 1a\r
-                               Ruurlo  Gelderland  NL-7261AK\r
-                               NL\r
+18-9B-A5   (hex)               Shenzhen Tong Tai Yi information Technology Co.,Ltd\r
+800000-8FFFFF     (base 16)            Shenzhen Tong Tai Yi information Technology Co.,Ltd\r
+                               District C,3rd Floor,Bldg B1,Digital Tech Park,7th GaoXin South Blvd,Tech Park,NanShan,ShenZhen,China\r
+                               shenzhen  guangdong  518102\r
+                               CN\r
 \r
-3C-6A-2C   (hex)               Olibra LLC\r
-100000-1FFFFF     (base 16)            Olibra LLC\r
-                               45 legin dr\r
-                               creskill  NJ  07626\r
+90-4E-91   (hex)               CommandScape, Inc.\r
+800000-8FFFFF     (base 16)            CommandScape, Inc.\r
+                               505 South Flagler Dr, Suite 900\r
+                               West Palm Beach  FL  33401\r
                                US\r
 \r
-3C-6A-2C   (hex)               XI'AN YEP TELECOM TECHNOLOGY CO.,LTD\r
-400000-4FFFFF     (base 16)            XI'AN YEP TELECOM TECHNOLOGY CO.,LTD\r
-                               5F,Building C,CLP Park,No.211, Tiangu 8 Road, High-tech Zone, Xi' an, Shanxi Province, China\r
-                               Xi’an  Shanxi   710001\r
+2C-27-9E   (hex)               Rutledge Omni Services Pte Ltd\r
+600000-6FFFFF     (base 16)            Rutledge Omni Services Pte Ltd\r
+                               34 Toh Guan Road East, #01-12/13 Enterprise Hub\r
+                               Singapore  Singapore  608579\r
+                               SG\r
+\r
+88-5F-E8   (hex)               Apoidea Technology Co., Ltd.\r
+100000-1FFFFF     (base 16)            Apoidea Technology Co., Ltd.\r
+                               No. 111, Boyun Road\r
+                               Shanghai    201203\r
                                CN\r
 \r
-3C-6A-2C   (hex)               Qingdao iGuan Technology Co., Ltd.\r
-500000-5FFFFF     (base 16)            Qingdao iGuan Technology Co., Ltd.\r
-                               Room416, Science and Technology Park, Ocean University of China, No.23 HongKongEast Road\r
-                               Qingdao  Shandong  266100\r
+88-5F-E8   (hex)               zhejiang yuanwang communication technolgy co.,ltd\r
+D00000-DFFFFF     (base 16)            zhejiang yuanwang communication technolgy co.,ltd\r
+                               No. 6 of shen shi lei lu Road\r
+                               ZhuJi  Zhejiang  311800\r
                                CN\r
 \r
-3C-6A-2C   (hex)               Homegear GmbH\r
-700000-7FFFFF     (base 16)            Homegear GmbH\r
-                               Am Schützenplatz 3\r
-                               Preetz  Schleswig-Holstein  24211\r
-                               DE\r
+48-0B-B2   (hex)               Thales CETCA Avionics CO., Ltd\r
+200000-2FFFFF     (base 16)            Thales CETCA Avionics CO., Ltd\r
+                               NO.9 Baichuan road,Hi-tech industry west zone park, Chengdu, Sichuan\r
+                               Chengdu  Sichuan  611731\r
+                               CN\r
 \r
-A8-3F-A1   (hex)               Guangzhou Navigateworx Technologies Co., Limited\r
-E00000-EFFFFF     (base 16)            Guangzhou Navigateworx Technologies Co., Limited\r
-                               Room 2320, Qianjin Commercial Building, Dongpu Town\r
-                               Guangzhou  Guangdong  510660\r
+48-0B-B2   (hex)               M2Lab Ltd.\r
+D00000-DFFFFF     (base 16)            M2Lab Ltd.\r
+                               148 Des Voeux Rd Central\r
+                               Hong Kong    HK\r
+                               HK\r
+\r
+48-0B-B2   (hex)               Beijing MFOX technology Co., Ltd.\r
+E00000-EFFFFF     (base 16)            Beijing MFOX technology Co., Ltd.\r
+                               B zone,floor 2,NO.A5 east Rongchang street .BDA (yizhuang) BeiJing\r
+                               BeiJing  BeiJing  100176\r
                                CN\r
 \r
-A8-3F-A1   (hex)               Shanghai East China Computer Co., Ltd\r
-A00000-AFFFFF     (base 16)            Shanghai East China Computer Co., Ltd\r
-                               27/F Tower B, No.391 Guiping Rd\r
-                               Shanghai  Shanghai  200233\r
+0C-73-EB   (hex)               EVERSEC TECHNOLOGY CORPORATION\r
+100000-1FFFFF     (base 16)            EVERSEC TECHNOLOGY CORPORATION\r
+                               F5,Tower D,JingYi Technology Building NO.9 Dazhongsi East Road.,Beijing,P.R.China\r
+                               BEIJING  BEIJING  100086\r
                                CN\r
 \r
-A8-3F-A1   (hex)               BEGLEC\r
-600000-6FFFFF     (base 16)            BEGLEC\r
-                               hofveld 2c\r
-                               Groot-Bijgaarden    1702\r
-                               BE\r
+0C-73-EB   (hex)               Pi Innovo LLC\r
+A00000-AFFFFF     (base 16)            Pi Innovo LLC\r
+                               47023 Five Mile Rd\r
+                               Plymouth  MI  48170\r
+                               US\r
 \r
-1C-FD-08   (hex)               SABIK Offshore GmbH\r
-400000-4FFFFF     (base 16)            SABIK Offshore GmbH\r
-                               Wilhelm-Maybach-Straße 3\r
-                               Schwerin  Mecklenburg-Vorpommern  D-19061\r
-                               DE\r
+0C-73-EB   (hex)               Gemini Data Loggers (UK) Limited\r
+000000-0FFFFF     (base 16)            Gemini Data Loggers (UK) Limited\r
+                               Scientific House, Terminus Road\r
+                               Chichester  West Sussex  PO19 8UJ\r
+                               GB\r
 \r
-1C-FD-08   (hex)               Shanghai YottaTech Co Ltd (上海尧它科技有限公司)\r
-C00000-CFFFFF     (base 16)            Shanghai YottaTech Co Ltd (上海尧它科技有限公司)\r
-                               399 keyuan Rd, Pudong New District\r
-                               Shanghai    201203\r
-                               CN\r
+3C-24-F0   (hex)               Abrites Ltd.\r
+100000-1FFFFF     (base 16)            Abrites Ltd.\r
+                               147 Cherni Vrah Blvd.\r
+                               Sofia  Sofia  1407\r
+                               BG\r
 \r
-10-07-23   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
+3C-24-F0   (hex)               Wisycom\r
+300000-3FFFFF     (base 16)            Wisycom\r
+                               Via Spin 156\r
+                               Romano D'Ezzelino  Vicenza  36060\r
+                               IT\r
 \r
-0C-FE-5D   (hex)               Chengdu Ledong Information & Technology Co., Ltd. \r
-000000-0FFFFF     (base 16)            Chengdu Ledong Information & Technology Co., Ltd. \r
-                               D7-13F, Chengdu Tianfu Software Park, No. 599 Shijicheng South street, Gaoxin District, Chengdu, China\r
-                               Chengdu  sichaun  610041\r
+3C-24-F0   (hex)               GETMOBIT LLC\r
+E00000-EFFFFF     (base 16)            GETMOBIT LLC\r
+                               d. 4 str. 2 pom. 137, ul. Programmistov\r
+                               Dubna  Moscow  141983\r
+                               RU\r
+\r
+3C-24-F0   (hex)               Sivat Technology Co.,Ltd.\r
+800000-8FFFFF     (base 16)            Sivat Technology Co.,Ltd.\r
+                               Room 1602, Starbuilding 2, west Complex of ChangYing TianJie ChaoYang District\r
+                               BeiJing  Beijing  100024\r
                                CN\r
 \r
-C0-D3-91   (hex)               Private\r
-B00000-BFFFFF     (base 16)            Private\r
+8C-1C-DA   (hex)               Structura Technology & Innovation\r
+300000-3FFFFF     (base 16)            Structura Technology & Innovation\r
+                               via Roveredo 20/B\r
+                               Pordenone  PN  33170\r
+                               IT\r
 \r
-1C-CA-E3   (hex)               Insigma Inc\r
-200000-2FFFFF     (base 16)            Insigma Inc\r
-                               43490, Yukon Drive, Suite 102\r
-                               Ashburn  VA  20147\r
-                               US\r
+2C-48-35   (hex)               Exertus Oy\r
+600000-6FFFFF     (base 16)            Exertus Oy\r
+                               Kampusranta 9 C\r
+                               Seinäjoki    60320\r
+                               FI\r
 \r
-0C-FE-5D   (hex)               Celerway Communication AS\r
-900000-9FFFFF     (base 16)            Celerway Communication AS\r
-                               Martin Lingesvei 25\r
-                               Fornebu    1364\r
-                               NO\r
+2C-48-35   (hex)               Collatz+Trojan GmbH\r
+A00000-AFFFFF     (base 16)            Collatz+Trojan GmbH\r
+                               Borsteler Chaussee85-99a\r
+                               Hamburg  Hamburg  22453\r
+                               DE\r
 \r
-0C-FE-5D   (hex)               Beijing WayClouds Technology Co., Ltd.\r
-300000-3FFFFF     (base 16)            Beijing WayClouds Technology Co., Ltd.\r
-                               RM501, 5F, DASCOM BD,NO.9 SHANGDI EAST RD, HAIDIAN DISTRICT,BEIJING,CHINA\r
-                               Beijing    100085\r
+2C-48-35   (hex)               GEARTECH LTD\r
+400000-4FFFFF     (base 16)            GEARTECH LTD\r
+                               R310/312,3/F,Beike Venture Building,No.1077,Nanhai Avenue,Nanshan District\r
+                               Shenzhen  Guangdong  518067\r
                                CN\r
 \r
-98-F9-C7   (hex)               Beijing Horizon Information Technology Co., Ltd\r
-300000-3FFFFF     (base 16)            Beijing Horizon Information Technology Co., Ltd\r
-                               3F,Unit H, West Gate, Hailong Mansion, No.1 Zhongguancun Street, Haidian District\r
-                               Beijing    100080\r
+2C-48-35   (hex)               Progress Rail Services, Inspection and Information Systems\r
+000000-0FFFFF     (base 16)            Progress Rail Services, Inspection and Information Systems\r
+                               3801-1 South Selsa Road\r
+                               Independence    64057\r
+                               US\r
+\r
+2C-48-35   (hex)               Rheonik Messtechnik GmbH\r
+200000-2FFFFF     (base 16)            Rheonik Messtechnik GmbH\r
+                               Rudolf-Diesel-Str., 5\r
+                               Odelzhausen  Deutschland  85235\r
+                               DE\r
+\r
+7C-70-BC   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
+\r
+A0-19-B2   (hex)               Lon Microsystems Inc.\r
+900000-9FFFFF     (base 16)            Lon Microsystems Inc.\r
+                               11F Ali center Tianfu four street \r
+                               chengdu  sichuan  610041\r
                                CN\r
 \r
-98-F9-C7   (hex)               GoodBox\r
-600000-6FFFFF     (base 16)            GoodBox\r
-                               Ground Floor, Optimum House\r
-                               Clippers Quay  Salford Quays  M50 3XP\r
-                               GB\r
+A0-19-B2   (hex)               LDA Technologies\r
+C00000-CFFFFF     (base 16)            LDA Technologies\r
+                               2680 Matheson Blvd E., Suite 102\r
+                               Mississauga  Ontario  L4W2C6\r
+                               CA\r
 \r
-98-F9-C7   (hex)               Promess GmbH\r
-400000-4FFFFF     (base 16)            Promess GmbH\r
-                               Schaffhausener Str. 44\r
-                               Berlin    12099\r
-                               DE\r
+D4-7C-44   (hex)               Innoviz Technologies LTD\r
+100000-1FFFFF     (base 16)            Innoviz Technologies LTD\r
+                               Atir Yeda 15\r
+                               Kfar Saba  Ha Sharon  4464312\r
+                               IL\r
 \r
-7C-BC-84   (hex)               CONTINENTAL\r
-400000-4FFFFF     (base 16)            CONTINENTAL\r
-                               1 AVENUE PAUL OURLIAC\r
-                               TOULOUSE    31100\r
-                               FR\r
+D4-7C-44   (hex)               YunDing Network Technology (Beijing) Co., Ltd\r
+200000-2FFFFF     (base 16)            YunDing Network Technology (Beijing) Co., Ltd\r
+                               A521,Floor 5, Tencent Space Building No.388, Hui long guan East St. \r
+                               Beijing    100000\r
+                               CN\r
 \r
-7C-BC-84   (hex)               OPNT BV\r
-A00000-AFFFFF     (base 16)            OPNT BV\r
-                               De Boelelaan 1081\r
-                               Amsterdam    1081 HV\r
-                               NL\r
+D4-7C-44   (hex)               ASDA ICT Co., Ltd.\r
+600000-6FFFFF     (base 16)            ASDA ICT Co., Ltd.\r
+                               4F-2,No.2,Sec.4,Zhongyang Rd,Tucheng Dist,\r
+                               New Taipei City    999079\r
+                               TW\r
 \r
-7C-BC-84   (hex)               Tibit Communications\r
-C00000-CFFFFF     (base 16)            Tibit Communications\r
-                               1 Willowbrook Court, Suite 150\r
-                               Petaluma  CA  94954\r
-                               US\r
+D4-7C-44   (hex)               Exafore Oy\r
+000000-0FFFFF     (base 16)            Exafore Oy\r
+                               Hermiankatu 6-8D\r
+                               Tampere    33720\r
+                               FI\r
 \r
-6C-DF-FB   (hex)               Toucan Systems Ltd\r
-C00000-CFFFFF     (base 16)            Toucan Systems Ltd\r
-                               3 Roseheyworth Business Park\r
-                               Abertillery  Bleanau Gwent  NP13 1SP\r
+B4-4B-D6   (hex)               G4S Monitoring Technologies Ltd\r
+000000-0FFFFF     (base 16)            G4S Monitoring Technologies Ltd\r
+                               3 Centurion Court, Meridian East\r
+                               Leicester  Leicestershire  LE19 1TP\r
                                GB\r
 \r
-6C-DF-FB   (hex)               YongTechs Electric Co. Ltd\r
-900000-9FFFFF     (base 16)            YongTechs Electric Co. Ltd\r
-                               18F-8, No.118, Ci-Yun Rd., Hsin Chu 30072, Taiwan(R.O.C.)\r
-                               Hsin Chu    30072\r
-                               TW\r
+B4-4B-D6   (hex)               SHENZHEN TITA INTERACTIVE TECHNOLOGY CO.,LTD\r
+100000-1FFFFF     (base 16)            SHENZHEN TITA INTERACTIVE TECHNOLOGY CO.,LTD\r
+                               Floor 23, Haowei Technology Mansion,Keji south eighth Road, Gaoxin Sci-Tech. Park(South Zone), \r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
 \r
-6C-DF-FB   (hex)               Guilin Zhishen Information TechonlogyCO.,Ltd\r
-A00000-AFFFFF     (base 16)            Guilin Zhishen Information TechonlogyCO.,Ltd\r
-                               Creative Industrial Park,GuiMo Rd.,Qi Xing\r
-                               Guilin  Guangxi  541004\r
+B4-4B-D6   (hex)                Shenzhen Huabai Intelligent Technology Co., Ltd.\r
+A00000-AFFFFF     (base 16)             Shenzhen Huabai Intelligent Technology Co., Ltd.\r
+                               Science Park South District Shenzhen Digital\r
+                               Technology Park Building B2 4th Floor Area A  Shenzhen, Guangdong  518000\r
+                               CN\r
+\r
+3C-42-7E   (hex)               ROBOX SMART MOTION (WUHU) CO.,LTD\r
+D00000-DFFFFF     (base 16)            ROBOX SMART MOTION (WUHU) CO.,LTD\r
+                               No.96,Wanchun East Road,Jiujiang Economic Development District,Wuhu,Anhui,China\r
+                               Wuhu  Anhui  241000\r
+                               CN\r
+\r
+B4-4B-D6   (hex)               Perspicace Intellegince Technology\r
+600000-6FFFFF     (base 16)            Perspicace Intellegince Technology\r
+                               4F, 1326#, West YanAn road, Shanghai, P.R.China\r
+                               ShangHai  ShangHai  200052\r
                                CN\r
 \r
-74-1A-E0   (hex)               Private\r
-900000-9FFFFF     (base 16)            Private\r
+B0-1F-81   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
 \r
-4C-91-7A   (hex)               Openeye\r
-600000-6FFFFF     (base 16)            Openeye\r
-                               23221 East Knox Avenue\r
-                               Liberty Lake  WA  99019\r
-                               US\r
+3C-42-7E   (hex)               Dongguan Taide Industrial Co.,Ltd.\r
+100000-1FFFFF     (base 16)            Dongguan Taide Industrial Co.,Ltd.\r
+                               Taide Industrial Park,Phase 2 Jinfenghuang Industrial District Huangdong,Fenggang Town\r
+                               Dongguan City  GuangDong  523696\r
+                               CN\r
 \r
-4C-91-7A   (hex)               AvertX\r
-B00000-BFFFFF     (base 16)            AvertX\r
-                               23221 E. Knox Ave\r
-                               Liberty Lake  WA  99019\r
+CC-D3-1E   (hex)               NantEnergy\r
+C00000-CFFFFF     (base 16)            NantEnergy\r
+                               8455 North 90th Street Suite 4\r
+                               Scottsdale  AZ  85258\r
                                US\r
 \r
-4C-91-7A   (hex)               LumiGrow Inc.\r
-400000-4FFFFF     (base 16)            LumiGrow Inc.\r
-                               1480 64th Street, Suite #150\r
-                               Emeryville  CA  94608\r
+A0-19-B2   (hex)               Adomi\r
+A00000-AFFFFF     (base 16)            Adomi\r
+                               777 Mariners Island Blvd. Suite 150\r
+                               San Mateo  CA  94404\r
                                US\r
 \r
-9C-69-B4   (hex)               Toughdog Security Systems\r
-B00000-BFFFFF     (base 16)            Toughdog Security Systems\r
-                               1317 E Hackberry Ave\r
-                               McAllen  TX  78501\r
-                               US\r
+04-C3-E6   (hex)               DREAMKAS LLC\r
+000000-0FFFFF     (base 16)            DREAMKAS LLC\r
+                               Bolshoy  Sampsoniyevskiy pr., 62A, office 2H\r
+                               Saint-Petersburg    194044\r
+                               RU\r
 \r
-9C-69-B4   (hex)               Guangdong Hanwei intergration Co.,Ltd\r
-C00000-CFFFFF     (base 16)            Guangdong Hanwei intergration Co.,Ltd\r
-                               Room 404,7# Hongtai Zhihui Gu, No.23 Sicheng Road\r
-                               Guangzhou  Guangdong  510663\r
+C0-83-59   (hex)               Suzhou Siheng Science and Technology Ltd.\r
+B00000-BFFFFF     (base 16)            Suzhou Siheng Science and Technology Ltd.\r
+                               8 floor of Jincheng star, Yunhe road NO.150, gaoxin Zone, Suzhou\r
+                               Suzhou    215000\r
                                CN\r
 \r
-9C-69-B4   (hex)               Skydock do Brasil Ltda\r
-800000-8FFFFF     (base 16)            Skydock do Brasil Ltda\r
-                               Rua Gralha Azul, 147\r
-                               Quatro Barras  PR  83420-000\r
-                               BR\r
+04-C3-E6   (hex)               Teleepoch Ltd\r
+E00000-EFFFFF     (base 16)            Teleepoch Ltd\r
+                               No.13 Langshan Rd,HiTech Park,Nanshan District\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
 \r
-9C-69-B4   (hex)               Globalcom Engineering SPA\r
-400000-4FFFFF     (base 16)            Globalcom Engineering SPA\r
-                               Via Volta 9\r
-                               MORNAGO  VA  21020\r
-                               IT\r
+C0-83-59   (hex)               SHANGHAI CHARMHOPE INFORMATION TECHNOLOGY CO.,LTD.\r
+A00000-AFFFFF     (base 16)            SHANGHAI CHARMHOPE INFORMATION TECHNOLOGY CO.,LTD.\r
+                               Building 11,No.230,Chuanhong Rd,Pudong Distrist\r
+                               Shanghai  Shanghai  201202\r
+                               CN\r
 \r
-F0-23-B9   (hex)               Annapurna labs\r
-A00000-AFFFFF     (base 16)            Annapurna labs\r
-                               Matam Scientific Industries Center,   Building 8.2\r
-                               Mail box 15123  Haifa  3508409\r
-                               IL\r
+B0-C5-CA   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
 \r
-D4-25-CC   (hex)               NORDI TELEKOMMUNIKATSIOONI OÜ\r
-000000-0FFFFF     (base 16)            NORDI TELEKOMMUNIKATSIOONI OÜ\r
-                               Valukoja 8\r
-                               Tallinn city  Estonian Republic  11415\r
-                               EE\r
+C0-83-59   (hex)               ANTS\r
+400000-4FFFFF     (base 16)            ANTS\r
+                               88, Simindae-ro, Dongan-Gu\r
+                               Anyang    14079\r
+                               KR\r
 \r
-38-B1-9E   (hex)               Gesellschaft industrieller Technologien \r
-C00000-CFFFFF     (base 16)            Gesellschaft industrieller Technologien \r
-                               Hauptstraße 10\r
-                               Großbeeren    14979 \r
-                               DE\r
+9C-F6-DD   (hex)               Lighting New Energy Technology Co., Ltd.\r
+C00000-CFFFFF     (base 16)            Lighting New Energy Technology Co., Ltd.\r
+                               Room 402, Building 22, Chentian Industrial Zone, Xixiang Street, Bao'an District,\r
+                               Shenzhen  Guangdong  518100\r
+                               CN\r
 \r
-38-B1-9E   (hex)               HDANYWHERE\r
-200000-2FFFFF     (base 16)            HDANYWHERE\r
-                               Unit 23 Link Business Centre\r
-                               Malvern  Worcs  WR14 1UQ\r
-                               GB\r
+9C-F6-DD   (hex)               Ithor IT Co.,Ltd.\r
+100000-1FFFFF     (base 16)            Ithor IT Co.,Ltd.\r
+                               No. 501, Building I, ZTE Park, Hi-Tech Industrial Zone\r
+                               XI'AN  ShanXi  710065\r
+                               CN\r
 \r
-38-B1-9E   (hex)               Triple Jump Medical\r
-000000-0FFFFF     (base 16)            Triple Jump Medical\r
-                               5 HaCarmel St.\r
-                               Yokneam    2069203\r
-                               IL\r
+9C-F6-DD   (hex)               Savari Inc\r
+800000-8FFFFF     (base 16)            Savari Inc\r
+                               2005 De la cruz blvd, st 111,\r
+                               santa clara  CA  95050\r
+                               US\r
 \r
-38-B1-9E   (hex)               Thrust Networks\r
-600000-6FFFFF     (base 16)            Thrust Networks\r
-                               Pangeran Jayakarta 129 No B 7\r
-                               Jakarta  Jakarta  10730\r
-                               ID\r
+30-09-F9   (hex)               Honeywell\r
+C00000-CFFFFF     (base 16)            Honeywell\r
+                               13350 US Hwy 19 N \r
+                               Clearwater    33764\r
+                               US\r
 \r
-D8-86-0B   (hex)               Teplovodokhran Ltd.\r
-400000-4FFFFF     (base 16)            Teplovodokhran Ltd.\r
-                               Novaya , 51v\r
-                               Ryazan    390027\r
-                               RU\r
+30-09-F9   (hex)               Beijing Mydreamplus Information Technology Co., Ltd.\r
+600000-6FFFFF     (base 16)            Beijing Mydreamplus Information Technology Co., Ltd.\r
+                               Room 301-2, North Building, No. 11, CangJingGuan Lane, DongCheng District,\r
+                               Beijing  Beijing  100005\r
+                               CN\r
 \r
-D8-86-0B   (hex)               ComNav Technology Ltd.\r
-D00000-DFFFFF     (base 16)            ComNav Technology Ltd.\r
-                               Buliding 2,No. 618  Chengliu Middle  Road\r
-                               JiaDing District  Shanghai  201801\r
+30-09-F9   (hex)               Beijing Netswift Technology Co.,Ltd.\r
+200000-2FFFFF     (base 16)            Beijing Netswift Technology Co.,Ltd.\r
+                               No. 7, 7th floor, No.49 Zhichun Road, Haidian District\r
+                               Beijing  Beijing  100190 \r
                                CN\r
 \r
-D8-86-0B   (hex)               VRINDA NANO TECHNOLOGIES PVT LTD\r
-800000-8FFFFF     (base 16)            VRINDA NANO TECHNOLOGIES PVT LTD\r
-                               PLOT NO.283, SECTOR 7, IMT MANESAR, GURGAON \r
-                               INDIA  HARYANA  122050\r
-                               IN\r
+84-89-EC   (hex)               Price Industries Limited\r
+D00000-DFFFFF     (base 16)            Price Industries Limited\r
+                               638 Raleigh Street\r
+                               Winnipeg  Manitoba  R2K3Z9\r
+                               CA\r
 \r
-D8-86-0B   (hex)               Shenzhen Yidong Technology Co.,Ltd\r
-E00000-EFFFFF     (base 16)            Shenzhen Yidong Technology Co.,Ltd\r
-                               13th Floor,Jia'anda Building, No.110 Huafan Road,Tongsheng Community, Dalang Street,Longhua District\r
+84-89-EC   (hex)               thousand star tech LTD.\r
+200000-2FFFFF     (base 16)            thousand star tech LTD.\r
+                               guan nan yuan 1 road dangdai optical valley dream workshop\r
+                               wuhan  hubei  430070\r
+                               CN\r
+\r
+84-89-EC   (hex)               Newell Brands\r
+A00000-AFFFFF     (base 16)            Newell Brands\r
+                               221 River Street\r
+                               Hoboken  NJ  07030\r
+                               US\r
+\r
+84-89-EC   (hex)               SHINKAWA LTD.\r
+C00000-CFFFFF     (base 16)            SHINKAWA LTD.\r
+                               Shinjuku Front Tower 32F, 2-21-1 Kitashinjyuku\r
+                               Shinjuku-ku  Tokyo  169-0074\r
+                               JP\r
+\r
+84-89-EC   (hex)               Shenzhen Intellifusion Technologies Co., Ltd.\r
+E00000-EFFFFF     (base 16)            Shenzhen Intellifusion Technologies Co., Ltd.\r
+                               Suite701, Science Museum, Shenzhen City\r
                                Shenzhen  Guangdong  518000\r
                                CN\r
 \r
-E0-5A-9F   (hex)               Hale Products\r
-400000-4FFFFF     (base 16)            Hale Products\r
-                               607 NW 27th Ave\r
-                               Ocala  FL  34475\r
+A0-28-33   (hex)               IMESHX CORPORATION LIMITED\r
+900000-9FFFFF     (base 16)            IMESHX CORPORATION LIMITED\r
+                               10A7F, ShenZhen Bay Technology Ecological Park, NanShan District,\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
+\r
+A0-28-33   (hex)               Precision Planting, LLC.\r
+E00000-EFFFFF     (base 16)            Precision Planting, LLC.\r
+                               23207 Townline Rd.\r
+                               Tremont  IL  61568\r
                                US\r
 \r
-E0-5A-9F   (hex)               Chengdu Song Yuan Electronic Technology Co.,Ltd\r
-200000-2FFFFF     (base 16)            Chengdu Song Yuan Electronic Technology Co.,Ltd\r
-                               Building 63 Cui Feng International, No.366 Bai Cao Road, High-tech West Zone\r
-                               Chengdu  Sichuan  610000\r
+A4-ED-43   (hex)               Heyuan intelligence technology CO.,Ltd\r
+900000-9FFFFF     (base 16)            Heyuan intelligence technology CO.,Ltd\r
+                               No.1166 Xinluo Street\r
+                               Jinan City  Shandong Province  250101\r
                                CN\r
 \r
-4C-BC-98   (hex)               Heliotis AG\r
-C00000-CFFFFF     (base 16)            Heliotis AG\r
-                               Längenbold 5\r
-                               Root    6037\r
-                               CH\r
+A4-ED-43   (hex)               Sweam AB\r
+000000-0FFFFF     (base 16)            Sweam AB\r
+                               Kistagången 12\r
+                               Kista  Stockholm  16440\r
+                               SE\r
 \r
-1C-A0-D3   (hex)               Private\r
-700000-7FFFFF     (base 16)            Private\r
+A4-ED-43   (hex)               Linseis Messgeraete GmbH\r
+800000-8FFFFF     (base 16)            Linseis Messgeraete GmbH\r
+                               Vielitzer Str. 43                      \r
+                               Selb    95100\r
+                               DE\r
 \r
-E4-4C-C7   (hex)               HANGZHOU OLE-SYSTEMS CO., LTD\r
-600000-6FFFFF     (base 16)            HANGZHOU OLE-SYSTEMS CO., LTD\r
-                                No.35 Jiuhuan Road, Jianggan District , Hangzhou , Zhejiang , China\r
-                               Hangzhou  Zhejiang  310019\r
+30-0A-60   (hex)               Private\r
+300000-3FFFFF     (base 16)            Private\r
+\r
+30-0A-60   (hex)               Beijing Ruiteng Zhongtian TECH Ltd.,Co\r
+100000-1FFFFF     (base 16)            Beijing Ruiteng Zhongtian TECH Ltd.,Co\r
+                               Blk 6,Rm 602,Noble CenterⅡ,No.1 Automotive Museum East Lane,South Fourth Ring Road, Fengtai District\r
+                               Beijing  Beijing  100070\r
                                CN\r
 \r
-E4-4C-C7   (hex)               Muzik Inc\r
-A00000-AFFFFF     (base 16)            Muzik Inc\r
-                               9220 Sunset Blvd #112\r
-                               West Hollywood    CA 90069\r
+30-0A-60   (hex)               KAZUtechnica Co.,Ltd.\r
+000000-0FFFFF     (base 16)            KAZUtechnica Co.,Ltd.\r
+                               1-9-18,Chuo,Chuo-ku\r
+                               Sagamihara-shi  Kanagawa  2520239\r
+                               JP\r
+\r
+30-0A-60   (hex)               Bronkhorst High-Tech BV\r
+800000-8FFFFF     (base 16)            Bronkhorst High-Tech BV\r
+                               Nijverheidsstraat 1a\r
+                               Ruurlo  Gelderland  NL-7261AK\r
+                               NL\r
+\r
+3C-6A-2C   (hex)               Olibra LLC\r
+100000-1FFFFF     (base 16)            Olibra LLC\r
+                               45 legin dr\r
+                               creskill  NJ  07626\r
                                US\r
 \r
-74-5B-C5   (hex)               Beijing Inspiry Technology Co., Ltd.\r
-100000-1FFFFF     (base 16)            Beijing Inspiry Technology Co., Ltd.\r
-                               Building No. 5, East Zone, No. 10, Xibeiwang East Road, Haidian District\r
-                               Beijing  Beijing  100092\r
+3C-6A-2C   (hex)               XI'AN YEP TELECOM TECHNOLOGY CO.,LTD\r
+400000-4FFFFF     (base 16)            XI'AN YEP TELECOM TECHNOLOGY CO.,LTD\r
+                               5F,Building C,CLP Park,No.211, Tiangu 8 Road, High-tech Zone, Xi' an, Shanxi Province, China\r
+                               Xi’an  Shanxi   710001\r
                                CN\r
 \r
-74-5B-C5   (hex)               SHENZHEN ATX TECHNOLOGY CO.,LTD \r
-700000-7FFFFF     (base 16)            SHENZHEN ATX TECHNOLOGY CO.,LTD \r
-                               7/F,Zhengjiyuan Buiding,2 Road,Qianjing, Xixiang, Baoan District\r
-                               Shenzhen  GUANGDONG  518000\r
+3C-6A-2C   (hex)               Qingdao iGuan Technology Co., Ltd.\r
+500000-5FFFFF     (base 16)            Qingdao iGuan Technology Co., Ltd.\r
+                               Room416, Science and Technology Park, Ocean University of China, No.23 HongKongEast Road\r
+                               Qingdao  Shandong  266100\r
                                CN\r
 \r
-74-5B-C5   (hex)               SIGLENT TECHNOLOGIES CO., LTD.\r
-200000-2FFFFF     (base 16)            SIGLENT TECHNOLOGIES CO., LTD.\r
-                               Blog No.4 & No.5, Antongda Industrial Zone, 3rd Liuxian Road, Bao’an District, Shenzhen, 518101, China.\r
-                               Shenzhen  Guangdong  518101\r
-                               CN\r
+3C-6A-2C   (hex)               Homegear GmbH\r
+700000-7FFFFF     (base 16)            Homegear GmbH\r
+                               Am Schützenplatz 3\r
+                               Preetz  Schleswig-Holstein  24211\r
+                               DE\r
 \r
-74-5B-C5   (hex)               Smartiply Inc.\r
-B00000-BFFFFF     (base 16)            Smartiply Inc.\r
-                               233 Mt. Airy Road\r
-                               Basking Ridge  NJ  07920\r
+1C-82-59   (hex)               C&A Marketing, INC.\r
+300000-3FFFFF     (base 16)            C&A Marketing, INC.\r
+                               114 Tived Lane East\r
+                               Edison   NJ  08837\r
                                US\r
 \r
-FC-D2-B6   (hex)               T CHIP DIGITAL TECHNOLOGY CO.LTD\r
-B00000-BFFFFF     (base 16)            T CHIP DIGITAL TECHNOLOGY CO.LTD\r
-                               Room 320, C Tower, Jingji Building, HuaFeng Headquarter, Xixiang, Baoan\r
-                               SHENZHEN  Guangdong  518000\r
-                               CN\r
-\r
-FC-D2-B6   (hex)               SHEN ZHEN XIN HAO YUAN PRECISION TECHNOLOGY CO.,L TD\r
-400000-4FFFFF     (base 16)            SHEN ZHEN XIN HAO YUAN PRECISION TECHNOLOGY CO.,L TD\r
-                               1,2,3 Building,XinHaoYuan Industrial Area,HeYi Community,Shajing Street,BaoAn District.Shenzhen\r
-                               shenzhen  guangdongsheng  518000\r
+1C-82-59   (hex)               SHENZHEN AOA TECHNOLOGY CO.,LTD\r
+800000-8FFFFF     (base 16)            SHENZHEN AOA TECHNOLOGY CO.,LTD\r
+                               B624,C1 Building,Hengchao Industrial Park,Tangtou Road,Shiyan,Bao'an District\r
+                               SHENZHEN  Guangdong  518108\r
                                CN\r
 \r
-FC-D2-B6   (hex)               Winglet Systems Inc.\r
-900000-9FFFFF     (base 16)            Winglet Systems Inc.\r
-                               4-6, Shinyokohama 2-chome, Kohoku-ku\r
-                                Yokohama  Kanagawa  222-0033\r
+60-95-CE   (hex)               Ponoor Experiments Inc.\r
+100000-1FFFFF     (base 16)            Ponoor Experiments Inc.\r
+                               Higashi-shinagawa 1-33-10, Terrada Art Complex 216\r
+                               Shinagawa-ku  Tokyo  1400002\r
                                JP\r
 \r
-34-E1-D1   (hex)               Doki Technologies Limited\r
-500000-5FFFFF     (base 16)            Doki Technologies Limited\r
-                               Unit 601,Tower One, Silvercord, 30 Canton Road, Tsim Sha Tsui\r
-                               Kowloon    00000\r
-                               HK\r
-\r
-34-E1-D1   (hex)               HI-TECH.ORG\r
-D00000-DFFFFF     (base 16)            HI-TECH.ORG\r
-                               Volgogradskiy prospekt, 43, k.3, room XXVI\r
-                               Moscow     109316\r
-                               RU\r
+60-95-CE   (hex)               AdvanWISE Corporation\r
+500000-5FFFFF     (base 16)            AdvanWISE Corporation\r
+                               No.11, Aly. 18, Ln. 85, Fuqun St., Xiangshan Dist.\r
+                               Hsinchu    30067\r
+                               TW\r
 \r
-34-E1-D1   (hex)               Tianjin Sublue Ocean Science & Technology Co., Ltd\r
-000000-0FFFFF     (base 16)            Tianjin Sublue Ocean Science & Technology Co., Ltd\r
-                               No.29 Factory No.156 Nanhai Road,TEDA\r
-                               Tianjin    300050\r
+60-95-CE   (hex)               Beijing Sinomedisite Bio-tech Co.,Ltd\r
+B00000-BFFFFF     (base 16)            Beijing Sinomedisite Bio-tech Co.,Ltd\r
+                               No.9 Kangding Street,Economic-Technological Development Area\r
+                               Beijing  Beijing  100176\r
                                CN\r
 \r
-34-E1-D1   (hex)               CREW by True Rowing, Inc.\r
-C00000-CFFFFF     (base 16)            CREW by True Rowing, Inc.\r
-                               14 Arrow St, Floor 4\r
-                               Cambridge  MA  02138\r
-                               US\r
+60-95-CE   (hex)               Synamedia\r
+C00000-CFFFFF     (base 16)            Synamedia\r
+                               Luipaardstraat 12\r
+                               Kortrijk  West-Vlaanderen  8500\r
+                               BE\r
 \r
-34-E1-D1   (hex)               Annapurna labs\r
-E00000-EFFFFF     (base 16)            Annapurna labs\r
-                               Matam Scientific Industries Center,   Building 8.2\r
-                               Mail box 15123  Haifa  3508409\r
-                               IL\r
+60-95-CE   (hex)               Siema Applications\r
+000000-0FFFFF     (base 16)            Siema Applications\r
+                               35 rue Alfred Brinon\r
+                               Villeurbanne    69100\r
+                               FR\r
 \r
-C8-63-14   (hex)               Autonics Co., Ltd.\r
-100000-1FFFFF     (base 16)            Autonics Co., Ltd.\r
-                               4-14-26, Shimo-Muneoka\r
-                               Shiki  Saitama  3530003\r
-                               JP\r
+BC-97-40   (hex)               Alpha ESS Co., Ltd.\r
+000000-0FFFFF     (base 16)            Alpha ESS Co., Ltd.\r
+                               JiuHua Road 888, Nantong High-Tech Industrial Development Zone,\r
+                               Nantong  Jiangsu  226300\r
+                               CN\r
 \r
-C8-63-14   (hex)               GRINBI PARTNERS\r
-600000-6FFFFF     (base 16)            GRINBI PARTNERS\r
-                               222, Dogok-ro, Gangnam-gu\r
-                               Seoul    06272\r
-                               KR\r
+BC-97-40   (hex)               comtac AG\r
+100000-1FFFFF     (base 16)            comtac AG\r
+                               Allenwindenstrasse 1\r
+                               Flurlingen    8247\r
+                               CH\r
 \r
-E4-1E-0A   (hex)               Safety Vision, LLC\r
-B00000-BFFFFF     (base 16)            Safety Vision, LLC\r
-                               6100 West Sam Houston Parkway North\r
-                               Houston  TX  77041-5113\r
-                               US\r
+D0-C8-57   (hex)               FORGAMERS INC.\r
+200000-2FFFFF     (base 16)            FORGAMERS INC.\r
+                               6F., NO.51, DONGXING RD., XINYI DIST., TAIPEI CITY 110-70, TAIWAN\r
+                               Taipei    110\r
+                               TW\r
 \r
-E4-1E-0A   (hex)               Zavod № 423\r
-000000-0FFFFF     (base 16)            Zavod № 423\r
-                               2B, Zavodskoy proezd\r
-                               Bogoroditsk  Tula  301830\r
-                               RU\r
+D0-C8-57   (hex)               Nanjing Magewell Electronics Co.,Ltd\r
+800000-8FFFFF     (base 16)            Nanjing Magewell Electronics Co.,Ltd\r
+                               14th Floor, Building 3, No. 89 Shengli Road, Jiangning Economic and Technological Development Zone\r
+                               Nanjing  Jiangsu  211100\r
+                               CN\r
 \r
-C8-2C-2B   (hex)               Verifone Systems (China),lnc.\r
-800000-8FFFFF     (base 16)            Verifone Systems (China),lnc.\r
-                               2nd Floor,No.39,Region C, Tongpan Road,Gulou District\r
-                               fuzhou  fujian  350004\r
+74-5B-C5   (hex)               Beijing Inspiry Technology Co., Ltd. \r
+100000-1FFFFF     (base 16)            Beijing Inspiry Technology Co., Ltd. \r
+                               Building No. 5, East Zone, No. 10, Xibeiwang East Road, Haidian District\r
+                               Beijing  Beijing  100092\r
                                CN\r
 \r
+A4-3B-FA   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
+\r
 1C-87-76   (hex)               Zhuhai MYZR Technology Co.,Ltd\r
 500000-5FFFFF     (base 16)            Zhuhai MYZR Technology Co.,Ltd\r
                                Room 302,Area D2,National Hi-tech Zone,NO.1,Software Park Road\r
@@ -7724,9 +7928,6 @@ B00000-BFFFFF     (base 16)               COMATIS
                                Leuven    3001\r
                                BE\r
 \r
-80-E4-DA   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
-\r
 74-19-F8   (hex)               Private\r
 F00000-FFFFFF     (base 16)            Private\r
 \r
@@ -7736,9 +7937,6 @@ F00000-FFFFFF     (base 16)               Private
                                Montreal  Quebec  H2Y 1P5\r
                                CA\r
 \r
-BC-34-00   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
-\r
 74-F8-DB   (hex)               Ballard Technology, Inc,\r
 A00000-AFFFFF     (base 16)            Ballard Technology, Inc,\r
                                11400 Airport Rd\r
@@ -8009,9 +8207,6 @@ D4-7C-44   (hex)          OMRON SENTECH CO., LTD.
                                Ebina-City  Kanagawa  243-0432\r
                                JP\r
 \r
-88-5D-90   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
-\r
 B4-4B-D6   (hex)               Taizhou convergence Information technology Co.,LTD\r
 700000-7FFFFF     (base 16)            Taizhou convergence Information technology Co.,LTD\r
                                Room 1006,general chamber of commerce,159 henghu road\r
@@ -8675,6 +8870,135 @@ B0-FD-0B   (hex)                Vista Manufacturing
                                Elkhart  IN  46514\r
                                US\r
 \r
+84-8B-CD   (hex)               CCX Technologies Inc.\r
+200000-2FFFFF     (base 16)            CCX Technologies Inc.\r
+                               408 - 11 Rosemount Ave.\r
+                               Ottawa  Ontario  K1Y 4R8\r
+                               CA\r
+\r
+84-8B-CD   (hex)               Emotiv Inc\r
+E00000-EFFFFF     (base 16)            Emotiv Inc\r
+                               490 Post Street\r
+                               San Francisco  CA  94102\r
+                               US\r
+\r
+1C-82-59   (hex)               winsun AG\r
+400000-4FFFFF     (base 16)            winsun AG\r
+                               Beeschi Mattenstrasse 2\r
+                               Steg  Wallis  3940\r
+                               CH\r
+\r
+1C-82-59   (hex)               Jump Trading\r
+700000-7FFFFF     (base 16)            Jump Trading\r
+                               1 London Wall\r
+                               London     EC2Y 5EA\r
+                               GB\r
+\r
+1C-82-59   (hex)               Shandong Luneng Intelligence Technology CO., Ltd\r
+000000-0FFFFF     (base 16)            Shandong Luneng Intelligence Technology CO., Ltd\r
+                               Shandong Jinan Hightech zone Yinhe building block B, 2008 Xinluo Street\r
+                               Jinan  Shandong  250100\r
+                               CN\r
+\r
+1C-82-59   (hex)               Diatrend Corporation\r
+200000-2FFFFF     (base 16)            Diatrend Corporation\r
+                               Grand Front Osaka Tower-B 28F, 3-1 ofuka-cho, kita-ku\r
+                               Osaka  Osaka  530-0011\r
+                               JP\r
+\r
+1C-82-59   (hex)               KeyWest Networks, Inc\r
+B00000-BFFFFF     (base 16)            KeyWest Networks, Inc\r
+                               2200 N Glassell St\r
+                               Orange  CA  92865\r
+                               US\r
+\r
+1C-82-59   (hex)               Evondos Oy\r
+C00000-CFFFFF     (base 16)            Evondos Oy\r
+                               Salorankatu 5-7\r
+                               Salo    24240\r
+                               FI\r
+\r
+1C-82-59   (hex)               Fagus-GreCon Greten GmbH & Co. KG\r
+500000-5FFFFF     (base 16)            Fagus-GreCon Greten GmbH & Co. KG\r
+                               Hannoversche Straße 58\r
+                               Alfeld    31061\r
+                               DE\r
+\r
+88-5D-90   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
+\r
+1C-82-59   (hex)               Microtronics Engineering GmbH\r
+E00000-EFFFFF     (base 16)            Microtronics Engineering GmbH\r
+                               Hauptstrasse 7\r
+                               Ruprechtshofen    3244\r
+                               AT\r
+\r
+60-95-CE   (hex)               GovComm\r
+D00000-DFFFFF     (base 16)            GovComm\r
+                               3830 SW 30 Ave\r
+                               Fort Lauderdale  FL  33312\r
+                               US\r
+\r
+BC-34-00   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
+\r
+60-95-CE   (hex)               Robot S.A.\r
+300000-3FFFFF     (base 16)            Robot S.A.\r
+                               Gremi de Cirurgians i Barbers 22\r
+                               Palma de Mallorca  SPAIN / Balearic Islands  07009\r
+                               ES\r
+\r
+BC-97-40   (hex)               Direct Communication Solutions\r
+900000-9FFFFF     (base 16)            Direct Communication Solutions\r
+                               17150 Via del Campo, Ste 200\r
+                               San Diego  CA  92127\r
+                               US\r
+\r
+BC-97-40   (hex)               ForoTel\r
+B00000-BFFFFF     (base 16)            ForoTel\r
+                               77, Shaumyana Str. \r
+                               Rostov-na-Donu  UFO  344079\r
+                               RU\r
+\r
+BC-97-40   (hex)               Airfi Oy AB\r
+700000-7FFFFF     (base 16)            Airfi Oy AB\r
+                               Piilipuunkatu 11\r
+                               RAISIO    21200\r
+                               FI\r
+\r
+D0-C8-57   (hex)               shenzhen cnsun\r
+A00000-AFFFFF     (base 16)            shenzhen cnsun\r
+                               5 Floor, 2 Building,Tongfuyu Industrial City\r
+                               shenzhen  guangdong  518000\r
+                               CN\r
+\r
+D0-C8-57   (hex)               YUAN High-Tech Development Co., Ltd.\r
+000000-0FFFFF     (base 16)            YUAN High-Tech Development Co., Ltd.\r
+                               18F, No.88, Sec. 2, Chung Hsiao E.Rd., \r
+                               Taipei,   Taiwan   10050 \r
+                               TW\r
+\r
+D0-C8-57   (hex)               Beijing Inspiry Technology Co., Ltd. \r
+500000-5FFFFF     (base 16)            Beijing Inspiry Technology Co., Ltd. \r
+                               Building No. 5, East Zone, No. 10, Xibeiwang East Road, Haidian District\r
+                               Beijing   Beijing   100092\r
+                               CN\r
+\r
+80-E4-DA   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
+\r
+8C-59-3C   (hex)               Chongqing beimoting technology co.ltd\r
+300000-3FFFFF     (base 16)            Chongqing beimoting technology co.ltd\r
+                               97-2 keyuan 2nd street, jiulongpo district,\r
+                               Chongqing  Chongqing  400039\r
+                               CN\r
+\r
+8C-59-3C   (hex)               IDRO-ELETTRICA S.P.A.\r
+D00000-DFFFFF     (base 16)            IDRO-ELETTRICA S.P.A.\r
+                               VIA BELLINI 2\r
+                               SAN CESARIO SUL PANARO  ITALY/MODENA  41018\r
+                               IT\r
+\r
 1C-87-76   (hex)               Hekatron Vertriebs GmbH\r
 B00000-BFFFFF     (base 16)            Hekatron Vertriebs GmbH\r
                                Brühlmatten 9\r
@@ -10751,9 +11075,6 @@ D00000-DFFFFF     (base 16)             D-Link (Shanghai)Limited Corp.
                                GYEONGGI-DO  GOYANG-SI,ILSANDONG-GU  410315\r
                                KR\r
 \r
-2C-D1-41   (hex)               Private\r
-F00000-FFFFFF     (base 16)            Private\r
-\r
 8C-1C-DA   (hex)               T+A elektroakustik GmbH & Co.KG\r
 B00000-BFFFFF     (base 16)            T+A elektroakustik GmbH & Co.KG\r
                                Planckstr. 9-11\r
@@ -11510,18 +11831,18 @@ E4-1E-0A   (hex)              XPR Group
                                Waterloo    1410\r
                                BE\r
 \r
-C8-2C-2B   (hex)               Galgus\r
-100000-1FFFFF     (base 16)            Galgus\r
-                               Italica 1, 1st floor\r
-                               Camas  Seville  41900\r
-                               ES\r
-\r
 C8-2C-2B   (hex)               Fränkische Rohrwerke Gebr. Kirchner GmbH & Co. KG\r
 E00000-EFFFFF     (base 16)            Fränkische Rohrwerke Gebr. Kirchner GmbH & Co. KG\r
                                Hellinger Str. 1\r
                                Königsberg/Bayern    97486\r
                                DE\r
 \r
+C8-2C-2B   (hex)               Galgus\r
+100000-1FFFFF     (base 16)            Galgus\r
+                               Italica 1, 1st floor\r
+                               Camas  Seville  41900\r
+                               ES\r
+\r
 B0-FD-0B   (hex)               Haltian Products Oy\r
 C00000-CFFFFF     (base 16)            Haltian Products Oy\r
                                Yrttipellontie 1D\r
@@ -11534,6 +11855,105 @@ D00000-DFFFFF     (base 16)           Private
 8C-14-7D   (hex)               Private\r
 100000-1FFFFF     (base 16)            Private\r
 \r
+B0-FD-0B   (hex)               Fasii Information Technology (Shanghai) Ltd.\r
+400000-4FFFFF     (base 16)            Fasii Information Technology (Shanghai) Ltd.\r
+                               Room 5011, Building 1, No.335 Guoding Road, Yangpu District\r
+                               Shanghai  Shanghai  200433\r
+                               CN\r
+\r
+84-8B-CD   (hex)               Sphera Telecom\r
+A00000-AFFFFF     (base 16)            Sphera Telecom\r
+                               Pos. Moscowskiy, 22-nd km of Kievskoye highway, household 4, building 2, body G, office 802G\r
+                               Moscow    108811\r
+                               RU\r
+\r
+84-8B-CD   (hex)               NORALSY\r
+900000-9FFFFF     (base 16)            NORALSY\r
+                               16 rue Lavoisier\r
+                               Chennevieres sur Marne  Ile de France  94430\r
+                               FR\r
+\r
+84-8B-CD   (hex)               CHONGQING HUAYI KANGDAO TECHNOLOGY CO.,LTD.\r
+B00000-BFFFFF     (base 16)            CHONGQING HUAYI KANGDAO TECHNOLOGY CO.,LTD.\r
+                               14th Floor, Unicom Building, 192 Yuzhou Road, Yuzhong District\r
+                               CHONGQING    410010\r
+                               CN\r
+\r
+1C-82-59   (hex)               ESTec Corporation\r
+A00000-AFFFFF     (base 16)            ESTec Corporation\r
+                               22, Yusangongdan 9-gil\r
+                               Yangsan  Gyeongsangnam-do  50592\r
+                               KR\r
+\r
+1C-82-59   (hex)               Shanghai Xiaoyan Technology Co., Ltd.\r
+900000-9FFFFF     (base 16)            Shanghai Xiaoyan Technology Co., Ltd.\r
+                               Room 503, Building B, NO. 2305, Zuchongzhi Road\r
+                               Shanghai  Shanghai  201203\r
+                               CN\r
+\r
+1C-82-59   (hex)               CGI IT UK LIMITED\r
+600000-6FFFFF     (base 16)            CGI IT UK LIMITED\r
+                               20 Fenchurch Street, 14th Floor\r
+                               London    EC3M 3BY\r
+                               GB\r
+\r
+60-95-CE   (hex)               Trophy SAS\r
+800000-8FFFFF     (base 16)            Trophy SAS\r
+                               4 rue F. Pelloutier\r
+                               Croissy-Beaubourg    77435\r
+                               FR\r
+\r
+60-95-CE   (hex)               Q-SENTECH Co.,Ltd.\r
+200000-2FFFFF     (base 16)            Q-SENTECH Co.,Ltd.\r
+                               #201,170 Seonyu-ro, Yeongdeungpo-gu\r
+                               Seoul  Korea  07255\r
+                               KR\r
+\r
+BC-97-40   (hex)               Wind Mobility Technology (Beijing) Co., Ltd\r
+400000-4FFFFF     (base 16)            Wind Mobility Technology (Beijing) Co., Ltd\r
+                               13603, Building 13, No. 2, Nanzhuzhang Hutong, Dongcheng District\r
+                               Beijing  Beijing  100010\r
+                               CN\r
+\r
+BC-97-40   (hex)               Precision Galaxy Pvt. Ltd\r
+300000-3FFFFF     (base 16)            Precision Galaxy Pvt. Ltd\r
+                               3rd Floor, No.22 Habibullah Road, T Nagar\r
+                               CHENNAI,Tamil Nadu  Tamilnadu  600017\r
+                               IN\r
+\r
+BC-97-40   (hex)               Rollock Oy\r
+D00000-DFFFFF     (base 16)            Rollock Oy\r
+                               Viestitie 2 B\r
+                               Kajaani    87700\r
+                               FI\r
+\r
+BC-97-40   (hex)               B4ComTechnologies LLC\r
+E00000-EFFFFF     (base 16)            B4ComTechnologies LLC\r
+                               Office 2/6, 16a, Ivana Babushkina street\r
+                               Moscow    117292\r
+                               RU\r
+\r
+D0-C8-57   (hex)               Shenzhen xiaosha  Intelligence  Technology Co. Ltd\r
+900000-9FFFFF     (base 16)            Shenzhen xiaosha  Intelligence  Technology Co. Ltd\r
+                                Poly Building, 2702 Nanhai Avenue, Nanshan District\r
+                               Shenzhen  Guangdong  518054\r
+                               CN\r
+\r
+2C-D1-41   (hex)               Private\r
+F00000-FFFFFF     (base 16)            Private\r
+\r
+60-95-CE   (hex)               VNS Inc.\r
+E00000-EFFFFF     (base 16)            VNS Inc.\r
+                               3F, No. 27, Lane 66, Ruiguang Rd.\r
+                               Taipei  Taiwan  11466\r
+                               TW\r
+\r
+8C-59-3C   (hex)               Nanonord A/S\r
+800000-8FFFFF     (base 16)            Nanonord A/S\r
+                               Skjernvej 4A\r
+                               Aalborg    9220\r
+                               DK\r
+\r
 1C-87-74   (hex)               Philips Personal Health Solutions\r
 000000-0FFFFF     (base 16)            Philips Personal Health Solutions\r
                                High Tech Campus, HTC37 floor 0\r
@@ -14449,3 +14869,123 @@ A00000-AFFFFF     (base 16)           TEMCO JAPAN CO., LTD.
 \r
 80-7B-85   (hex)               Private\r
 F00000-FFFFFF     (base 16)            Private\r
+\r
+B0-FD-0B   (hex)               Eagle Acoustics Manufacturing, LLC \r
+900000-9FFFFF     (base 16)            Eagle Acoustics Manufacturing, LLC \r
+                               333 E IL ROUTE 83, Ste. 100\r
+                               MUNDELEIN  IL  60060-4214\r
+                               US\r
+\r
+B0-FD-0B   (hex)               DNESO TEN Ltd.\r
+600000-6FFFFF     (base 16)            DNESO TEN Ltd.\r
+                               1-2-28,gosho-doori,hyougo-ku\r
+                               kobe  hyougo  652-8510\r
+                               JP\r
+\r
+84-8B-CD   (hex)               Logic Supply\r
+400000-4FFFFF     (base 16)            Logic Supply\r
+                               35 Thompson St\r
+                               South Burlington  VT  05403\r
+                               US\r
+\r
+84-8B-CD   (hex)               Smart Code (Shenzhen) Technology Co.,Ltd\r
+700000-7FFFFF     (base 16)            Smart Code (Shenzhen) Technology Co.,Ltd\r
+                               Keji North 3rd Rd\r
+                               Shenzhen  guangdong  518000\r
+                               CN\r
+\r
+84-8B-CD   (hex)               exodraft a/s\r
+500000-5FFFFF     (base 16)            exodraft a/s\r
+                               C. F. Teiegens Boulevard 41\r
+                               Odense SØ    5220\r
+                               DK\r
+\r
+84-8B-CD   (hex)               Annapurna labs\r
+300000-3FFFFF     (base 16)            Annapurna labs\r
+                               Matam Scientific Industries Center,   Building 8.2\r
+                               Mail box 15123  Haifa  3508409\r
+                               IL\r
+\r
+84-8B-CD   (hex)               ENGISAT LDA\r
+D00000-DFFFFF     (base 16)            ENGISAT LDA\r
+                               RUA CENTRAL SAO LOURENÇO Nº 312\r
+                               VILAR DE ANDORINHO  PORTO  4430-358\r
+                               PT\r
+\r
+60-95-CE   (hex)               Cadmo Soluciones SAC\r
+700000-7FFFFF     (base 16)            Cadmo Soluciones SAC\r
+                               Av. Angamos Este 2495 Dpt. 301, San Borja\r
+                               Lima  Lima  15036\r
+                               PE\r
+\r
+60-95-CE   (hex)               Xiamen Sigmastar Technology Ltd.\r
+600000-6FFFFF     (base 16)            Xiamen Sigmastar Technology Ltd.\r
+                               15th Floor ,Unit A,Chuangxin Building, Software Park, Xiamen Torch Hi-Tech Industrial Development Zone, Xiamen,China\r
+                               Xiamen  Fujian  361005\r
+                               CN\r
+\r
+60-95-CE   (hex)               (UN)MANNED\r
+A00000-AFFFFF     (base 16)            (UN)MANNED\r
+                               Baron Ruzettelaan 3\r
+                               Brugge    8310\r
+                               BE\r
+\r
+60-95-CE   (hex)               Jlztlink Industry(ShenZhen)Co.,Ltd.\r
+900000-9FFFFF     (base 16)            Jlztlink Industry(ShenZhen)Co.,Ltd.\r
+                               D-502#,Tongan logistics center,Sanwei hangkong 30#,Xiang street,Baoan,\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
+\r
+BC-97-40   (hex)               Gaodi Rus\r
+800000-8FFFFF     (base 16)            Gaodi Rus\r
+                               Korneeva, 14\r
+                               Elektrostal  Moscow region  144009\r
+                               RU\r
+\r
+D0-C8-57   (hex)               IFLYTEK CO.,LTD.\r
+D00000-DFFFFF     (base 16)            IFLYTEK CO.,LTD.\r
+                               National Intelligent Speech High-tech Industrialization Base, No. 666, Wangjiang Road West,\r
+                               Heifei  An hui  230088\r
+                               CN\r
+\r
+D0-C8-57   (hex)               Mobicon\r
+300000-3FFFFF     (base 16)            Mobicon\r
+                               #406, 97, Jungbu-daero 448beon-gil, Yeongtong-gu\r
+                               Suwon-si  Gyeonggi-do  16521\r
+                               KR\r
+\r
+D0-C8-57   (hex)               DALI A/S\r
+100000-1FFFFF     (base 16)            DALI A/S\r
+                               Dali Alle 1\r
+                               Norager    9610\r
+                               DK\r
+\r
+D0-C8-57   (hex)               Imin Technology Pte Ltd\r
+400000-4FFFFF     (base 16)            Imin Technology Pte Ltd\r
+                               77 Sciene park Drive #03-10 Cintech III \r
+                               Singapore  Singapore  118256\r
+                               SG\r
+\r
+D0-C8-57   (hex)               Innovative Industrial(HK)Co., Limited\r
+600000-6FFFFF     (base 16)            Innovative Industrial(HK)Co., Limited\r
+                               OFFICE 3A,12/F,KAISER CENTRE,NO.18CENTRE STREET\r
+                               SAI YING PUN    999077\r
+                               HK\r
+\r
+8C-59-3C   (hex)               Spectranetix\r
+500000-5FFFFF     (base 16)            Spectranetix\r
+                               845 Stewart Drive, Suite B\r
+                               Sunnyvale  CA  94085\r
+                               US\r
+\r
+8C-59-3C   (hex)               Qbic Technology Co., Ltd\r
+600000-6FFFFF     (base 16)            Qbic Technology Co., Ltd\r
+                               26F.-12, No.99, Sec. 1, Xintai 5th Rd., Xizhi Dist.,\r
+                               New Taipei     22175\r
+                               TW\r
+\r
+8C-59-3C   (hex)               Beida Jade Bird Universal Fire Alarm Device CO.,LTD.\r
+200000-2FFFFF     (base 16)            Beida Jade Bird Universal Fire Alarm Device CO.,LTD.\r
+                               Jade Bird Building C, 207 Chengfu RD, Haidian District\r
+                               Beijing  Beijing  100871\r
+                               CN\r
index abafe21..e9c20f2 100644 (file)
@@ -2186,12 +2186,6 @@ FAF000-FAFFFF     (base 16)              Radig Hard & Software
                                Northfield  IL  60093\r
                                US\r
 \r
-70-B3-D5   (hex)               Alpha ESS Co., Ltd.\r
-7A2000-7A2FFF     (base 16)            Alpha ESS Co., Ltd.\r
-                               JiuHua Road 888, Nantong High-Tech Industrial Development Zone,\r
-                               Nantong  Jiangsu  226300\r
-                               CN\r
-\r
 70-B3-D5   (hex)               Quan International Co., Ltd.\r
 724000-724FFF     (base 16)            Quan International Co., Ltd.\r
                                4F, No. 196, Hsinghu 3rd Rd., Neihu District\r
@@ -3506,6 +3500,108 @@ EAE000-EAEFFF     (base 16)             Orlaco Products B.V.
                                Montrevault sur Evre  Maine et Loire  49110\r
                                FR\r
 \r
+70-B3-D5   (hex)               Acrodea, Inc.\r
+4A8000-4A8FFF     (base 16)            Acrodea, Inc.\r
+                               3F, Daisan Yamada Bldg., 22 Aizumi-cho\r
+                               Shinjuku-ku  Tokyo  1600005\r
+                               JP\r
+\r
+70-B3-D5   (hex)               SamabaNova Systems\r
+F29000-F29FFF     (base 16)            SamabaNova Systems\r
+                               2100 Geng Rd #103\r
+                               Palo Alto  CA  94303\r
+                               US\r
+\r
+70-B3-D5   (hex)               TimeMachines Inc.\r
+5A6000-5A6FFF     (base 16)            TimeMachines Inc.\r
+                               300 S 68th Street Place, Suite 100\r
+                               Lincoln  NE  68510\r
+                               US\r
+\r
+70-B3-D5   (hex)               INTECH\r
+E9D000-E9DFFF     (base 16)            INTECH\r
+                               Vavilova st,13/7\r
+                               Moscow    117312\r
+                               RU\r
+\r
+70-B3-D5   (hex)               KeyW Corporation\r
+7CB000-7CBFFF     (base 16)            KeyW Corporation\r
+                               7763 Old Telegraph Road\r
+                               Severn  MD  21144\r
+                               US\r
+\r
+70-B3-D5   (hex)               Viper Innovations Ltd\r
+A45000-A45FFF     (base 16)            Viper Innovations Ltd\r
+                               45 Martingale Way\r
+                               Bristol    BS20 7AW\r
+                               GB\r
+\r
+70-B3-D5   (hex)               microtec Sicherheitstechnik GmbH\r
+DFE000-DFEFFF     (base 16)            microtec Sicherheitstechnik GmbH\r
+                               Auf der Langwies 20\r
+                               Hünstetten    65510\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Alpha ESS Co., Ltd.\r
+7A2000-7A2FFF     (base 16)            Alpha ESS Co., Ltd.\r
+                               JiuHua Road 888, Nantong High-Tech Industrial Development Zone,\r
+                               Nantong  Jiangsu  226300\r
+                               CN\r
+\r
+70-B3-D5   (hex)               VITEC\r
+0CA000-0CAFFF     (base 16)            VITEC\r
+                               99, rue Pierre Semard\r
+                               CHATILLON    92320\r
+                               FR\r
+\r
+70-B3-D5   (hex)               Onethinx BV\r
+068000-068FFF     (base 16)            Onethinx BV\r
+                               Punterweg 2\r
+                               Zwolle  OV  8042 PB\r
+                               NL\r
+\r
+70-B3-D5   (hex)               Worldsensing\r
+2C7000-2C7FFF     (base 16)            Worldsensing\r
+                               Carrer Viriat 47, Edificio Numancia 1 7th floor\r
+                               Barcelona  - Please Choose -  08014\r
+                               ES\r
+\r
+70-B3-D5   (hex)               Fath Mechatronics\r
+DC3000-DC3FFF     (base 16)            Fath Mechatronics\r
+                               Hügelmühle 31\r
+                               Spalt  bavaria  91174\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Oxford Monitoring Solutions Ltd\r
+102000-102FFF     (base 16)            Oxford Monitoring Solutions Ltd\r
+                               Oakfield Estate\r
+                               Eynsham  Oxford  OX298JG\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Sensative AB\r
+2C0000-2C0FFF     (base 16)            Sensative AB\r
+                               Mobilvägen 10\r
+                               Lund    22362\r
+                               SE\r
+\r
+70-B3-D5   (hex)               Astronomical Research Cameras, Inc.\r
+24C000-24CFFF     (base 16)            Astronomical Research Cameras, Inc.\r
+                               2247 San Diego Ave #135\r
+                               San Diego  CA  92110\r
+                               US\r
+\r
+70-B3-D5   (hex)               Sicon srl\r
+D49000-D49FFF     (base 16)            Sicon srl\r
+                               Via Sila 1/3\r
+                               Isola Vicentina  Vicenza  36033\r
+                               IT\r
+\r
+70-B3-D5   (hex)               ATGS\r
+726000-726FFF     (base 16)            ATGS\r
+                               11 POLBINA ST.\r
+                               MOSCOW    109388\r
+                               RU\r
+\r
 70-B3-D5   (hex)               Flintab AB\r
 D60000-D60FFF     (base 16)            Flintab AB\r
                                Kabelvägen 4\r
@@ -5861,1442 +5957,1544 @@ C1C000-C1CFFF     (base 16)         D.E.M. SPA
                                Longarone (BL)    32013\r
                                IT\r
 \r
-70-B3-D5   (hex)               PTYPE Co., LTD.\r
-6B0000-6B0FFF     (base 16)            PTYPE Co., LTD.\r
-                               B121, B-dong, Keumkang Penterium IT Tower, 810, Gwanyand 2-dong, Dongan-gu\r
-                               Anyang-si  Gyeonggi-do  14056\r
-                               KR\r
+70-B3-D5   (hex)               NIRIT- Xinwei  Telecom Technology Co., Ltd.\r
+F27000-F27FFF     (base 16)            NIRIT- Xinwei  Telecom Technology Co., Ltd.\r
+                               2-й Кожуховский проезд, д.12, стр.2\r
+                               Moscow    115432\r
+                               RU\r
 \r
-70-B3-D5   (hex)               comtime GmbH\r
-1E9000-1E9FFF     (base 16)            comtime GmbH\r
-                               Gutenbergring 22\r
-                               Norderstedt    22848\r
-                               DE\r
+70-B3-D5   (hex)               AML\r
+759000-759FFF     (base 16)            AML\r
+                               2190 Regal Parkway\r
+                               Euless  TX  76040\r
+                               US\r
 \r
-70-B3-D5   (hex)               eeas gmbh\r
-86C000-86CFFF     (base 16)            eeas gmbh\r
-                               Bachstrasse 44\r
-                               Schwertberg    4311\r
-                               AT\r
+70-B3-D5   (hex)               Beijing HuaLian Technology Co, Ltd.\r
+623000-623FFF     (base 16)            Beijing HuaLian Technology Co, Ltd.\r
+                               Floor4 16C, north district of Ufida software park, No. 68 Beiqing road, HaiDian district.\r
+                               Beijing  Beijing  100094\r
+                               CN\r
 \r
-70-B3-D5   (hex)               Vigilate srl\r
-B0C000-B0CFFF     (base 16)            Vigilate srl\r
-                               Via Napoleonica, 6\r
-                               Rezzato  BS  25086\r
-                               IT\r
+70-B3-D5   (hex)               Private\r
+B71000-B71FFF     (base 16)            Private\r
 \r
-70-B3-D5   (hex)               CODEC Co., Ltd.\r
-B37000-B37FFF     (base 16)            CODEC Co., Ltd.\r
-                               1-29-18 Tamagawa\r
-                               Choufu-shi  Tokyo  182-0025\r
+70-B3-D5   (hex)               MicroElectronics System Co.Ltd\r
+8DA000-8DAFFF     (base 16)            MicroElectronics System Co.Ltd\r
+                               29 uchihata-cho Nishinokyo Nakagyoku\r
+                               Kyoto City  Kyoto-fu  604-8411\r
                                JP\r
 \r
-70-B3-D5   (hex)               VAPE RAIL INTERNATIONAL\r
-597000-597FFF     (base 16)            VAPE RAIL INTERNATIONAL\r
-                               9 RUE DES NOISETIERS\r
-                               MONTREAL LA CLUSE    01460\r
-                               FR\r
+70-B3-D5   (hex)               Software Systems Plus\r
+7DC000-7DCFFF     (base 16)            Software Systems Plus\r
+                               9924 N. Ash Avenue\r
+                               Kansas City    64157\r
+                               US\r
 \r
-70-B3-D5   (hex)               REO AG\r
-850000-850FFF     (base 16)            REO AG\r
-                               Brühlerstr. 100\r
-                               Solingen    42657\r
-                               DE\r
+70-B3-D5   (hex)               Telefire\r
+2E8000-2E8FFF     (base 16)            Telefire\r
+                               43 hasivim \r
+                               Petah Tikva  Israel  49000\r
+                               IL\r
 \r
-70-B3-D5   (hex)               APG Cash Drawer, LLC\r
-37A000-37AFFF     (base 16)            APG Cash Drawer, LLC\r
-                               5250 Industrial Blvd NE\r
-                               Minneapolis  MN  55421\r
+70-B3-D5   (hex)               Opti-Sciences, Inc.\r
+338000-338FFF     (base 16)            Opti-Sciences, Inc.\r
+                               8 Winn Ave\r
+                               Hudson  NH  03051\r
                                US\r
 \r
-70-B3-D5   (hex)               CISTECH Solutions\r
-C3D000-C3DFFF     (base 16)            CISTECH Solutions\r
-                               170 JAMES ST\r
-                               TOOWOOMBA  QLD  4350\r
-                               AU\r
-\r
-70-B3-D5   (hex)               IOOOTA Srl\r
-F8B000-F8BFFF     (base 16)            IOOOTA Srl\r
-                               Via Molino Rosso, 8\r
-                               Imola  BO  40026\r
-                               IT\r
+70-B3-D5   (hex)               eze System, Inc.\r
+2F5000-2F5FFF     (base 16)            eze System, Inc.\r
+                               785 Orchard Dr #100\r
+                               Folsom  CA  95630\r
+                               US\r
 \r
-70-B3-D5   (hex)               Grupo Epelsa S.L.\r
-2EC000-2ECFFF     (base 16)            Grupo Epelsa S.L.\r
-                               C/ Punto Net,3\r
-                               Alcala de Henares  Madrid  28805\r
-                               ES\r
+00-1B-C5   (hex)               Corporate Systems Engineering \r
+015000-015FFF     (base 16)            Corporate Systems Engineering \r
+                               1215 Brookville Way\r
+                               Indianapolis   IN  46239\r
+                               US\r
 \r
-70-B3-D5   (hex)               Trinity College Dublin\r
-99E000-99EFFF     (base 16)            Trinity College Dublin\r
-                               Dunlop Oriel House, Fenian Street\r
-                               Dublin 2    2\r
-                               IE\r
+70-B3-D5   (hex)               WICELL TECHNOLOGY\r
+BB0000-BB0FFF     (base 16)            WICELL TECHNOLOGY\r
+                               61 Dien Bien Phu\r
+                               Ho Chi Minh    700000\r
+                               VN\r
 \r
-70-B3-D5   (hex)               EarTex\r
-462000-462FFF     (base 16)            EarTex\r
-                               Flat 11 Princes Park Apartments South,, 52 Prince Of Wales Road\r
-                               London  England  NW5 3LN\r
-                               GB\r
+70-B3-D5   (hex)               Waldo System\r
+CA1000-CA1FFF     (base 16)            Waldo System\r
+                               4th Floor, 658, Yangcheon-ro, Gangseo-gu,\r
+                               Seoul     07554\r
+                               KR\r
 \r
-70-B3-D5   (hex)               Agilack\r
-4CE000-4CEFFF     (base 16)            Agilack\r
-                               12 avenue Jules Verne\r
-                               Saint Sebastien sur loire    44230\r
-                               FR\r
+70-B3-D5   (hex)               DogWatch Inc\r
+302000-302FFF     (base 16)            DogWatch Inc\r
+                               10 Michigan Drive\r
+                               Natick  MA  01760\r
+                               US\r
 \r
-70-B3-D5   (hex)               VITEC\r
-F17000-F17FFF     (base 16)            VITEC\r
-                               99 rue pierre sémard\r
-                               Chatillon  France  92320\r
-                               FR\r
+70-B3-D5   (hex)               Zumbach Electronic AG\r
+B10000-B10FFF     (base 16)            Zumbach Electronic AG\r
+                               Hauptstrasse 93\r
+                               Orpund  Bern  2552\r
+                               CH\r
 \r
-70-B3-D5   (hex)               Dakton Microlabs LLC\r
-11D000-11DFFF     (base 16)            Dakton Microlabs LLC\r
-                               520 Brickell Key Drive, A-1811\r
-                               Miami  FL  33131\r
-                               US\r
+70-B3-D5   (hex)               EvoLogics GmbH\r
+F9B000-F9BFFF     (base 16)            EvoLogics GmbH\r
+                               Ackerstr. 76\r
+                               Berlin    13355\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Meridian Technologies Inc\r
-924000-924FFF     (base 16)            Meridian Technologies Inc\r
-                               700 Elmont Rd\r
-                               Elmont  NY  11003\r
-                               US\r
+70-B3-D5   (hex)               SOREL GmbH Mikroelektronik\r
+A84000-A84FFF     (base 16)            SOREL GmbH Mikroelektronik\r
+                               REME-Str. 12\r
+                               Wetter    58300\r
+                               DE\r
 \r
-70-B3-D5   (hex)               QUERCUS TECHNOLOGIES, S.L.\r
-03D000-03DFFF     (base 16)            QUERCUS TECHNOLOGIES, S.L.\r
-                               Av. Onze de Setembre 19\r
-                               Reus  Tarragona  43203\r
-                               ES\r
+70-B3-D5   (hex)               Qingdao CNR HITACH Railway Signal&communication co.,ltd\r
+802000-802FFF     (base 16)            Qingdao CNR HITACH Railway Signal&communication co.,ltd\r
+                               231-2 Ruichang Road\r
+                               Qingdao    266031\r
+                               CN\r
 \r
-70-B3-D5   (hex)               Canam Technology, Inc.\r
-B97000-B97FFF     (base 16)            Canam Technology, Inc.\r
-                               5318 East 2nd. St, #700\r
-                               Long Beach  CA  90803\r
+70-B3-D5   (hex)               WiSuite USA\r
+19A000-19AFFF     (base 16)            WiSuite USA\r
+                               13201 Stephens Road Suite E\r
+                               Warren  MI  48089\r
                                US\r
 \r
-70-B3-D5   (hex)               Globalcom Engineering SPA\r
-352000-352FFF     (base 16)            Globalcom Engineering SPA\r
-                               Via Volta 39\r
-                               CARDANO AL CAMPO  VA  21010\r
-                               IT\r
+70-B3-D5   (hex)               Lightdrop\r
+072000-072FFF     (base 16)            Lightdrop\r
+                               Matiční 730/3\r
+                               Ostrava    70200\r
+                               CZ\r
 \r
-70-B3-D5   (hex)               KST technology\r
-7F4000-7F4FFF     (base 16)            KST technology\r
-                               164-1, KST b/d., Bangi-dong, songpa-gu\r
-                               SEOUL  N/A  138-050\r
+70-B3-D5   (hex)               dds\r
+F21000-F21FFF     (base 16)            dds\r
+                               606, Woolim Lions Valley 2Cha, 2, Gasan digital 1-ro Geumcheon-gu\r
+                               Seoul    08591\r
                                KR\r
 \r
-70-B3-D5   (hex)               Henri Systems Holland bv\r
-122000-122FFF     (base 16)            Henri Systems Holland bv\r
-                               Scheepmalersstraat 33\r
-                               Zwijndrecht  ZH  3334 KG\r
-                               NL\r
-\r
-70-B3-D5   (hex)               FRANKLIN FRANCE\r
-767000-767FFF     (base 16)            FRANKLIN FRANCE\r
-                               13 RUE LOUIS ARMAND\r
-                               OZOIR LA FERRIERE    77330\r
-                               FR\r
-\r
-70-B3-D5   (hex)               ENERGISME\r
-465000-465FFF     (base 16)            ENERGISME\r
-                               88 avenue du General Leclerc\r
-                               Boulogne Billancourt    92100\r
+70-B3-D5   (hex)               COPPERNIC SAS\r
+25F000-25FFFF     (base 16)            COPPERNIC SAS\r
+                               185 avenue Archimede\r
+                               Aix en Provence    13857\r
                                FR\r
 \r
-70-B3-D5   (hex)               L-3 communications ComCept Division\r
-E09000-E09FFF     (base 16)            L-3 communications ComCept Division\r
-                               1700 Science Place\r
-                               Rockwall   TX  75032\r
+70-B3-D5   (hex)               Rhythm Engineering, LLC.\r
+57A000-57AFFF     (base 16)            Rhythm Engineering, LLC.\r
+                               11228 Thompson Ave.\r
+                               Lenexa  KS  66219\r
                                US\r
 \r
-70-B3-D5   (hex)               IoTrek Technology Private Limited\r
-A07000-A07FFF     (base 16)            IoTrek Technology Private Limited\r
-                               Paharganj, Delhi\r
-                               New Delhi  New Delhi  110055\r
-                               IN\r
+70-B3-D5   (hex)               Taejin InforTech\r
+A75000-A75FFF     (base 16)            Taejin InforTech\r
+                               40, Imi-ro, A-411\r
+                               Uiwang-si  Gyeonggi-do  16006\r
+                               KR\r
 \r
-70-B3-D5   (hex)               iRF - Intelligent RF Solutions, LLC\r
-21D000-21DFFF     (base 16)            iRF - Intelligent RF Solutions, LLC\r
-                               14600 York Road, Suite B\r
-                               Sparks  MD  21152\r
+70-B3-D5   (hex)               MEGGITT\r
+1EE000-1EEFFF     (base 16)            MEGGITT\r
+                               14600 MYFORD RD\r
+                               IRVINE  CA  92606\r
                                US\r
 \r
-70-B3-D5   (hex)               ATG UV Technology\r
-E9C000-E9CFFF     (base 16)            ATG UV Technology\r
-                               Genesis House\r
-                               Wigan    WN5 8AA\r
+70-B3-D5   (hex)               Smashtag Ltd\r
+F6F000-F6FFFF     (base 16)            Smashtag Ltd\r
+                               Unit B6 Beech House, Melbourn Science Park\r
+                               Royston  Hertfordshire  SG8 6HB\r
                                GB\r
 \r
-70-B3-D5   (hex)               Lanmark Controls Inc.\r
-39E000-39EFFF     (base 16)            Lanmark Controls Inc.\r
-                               125 Nagog Park\r
-                               Acton  MA  01720\r
-                               US\r
+70-B3-D5   (hex)               YUYAMA MFG Co.,Ltd\r
+2DE000-2DEFFF     (base 16)            YUYAMA MFG Co.,Ltd\r
+                               3-3-1\r
+                               TOYONAKASHI  OSAKA  561-0841\r
+                               JP\r
 \r
-70-B3-D5   (hex)               Zehntner Testing Instruments\r
-267000-267FFF     (base 16)            Zehntner Testing Instruments\r
-                               Gewerbestrasse 4\r
-                               Sissach    4450\r
-                               CH\r
+70-B3-D5   (hex)               CRDMDEVEOPPEMENTS\r
+B5F000-B5FFFF     (base 16)            CRDMDEVEOPPEMENTS\r
+                               13 Petit chemin de la generale\r
+                               Villenave d'Ornon  Gironde  33140\r
+                               FR\r
 \r
-70-B3-D5   (hex)               Dextera Labs\r
-0EF000-0EFFFF     (base 16)            Dextera Labs\r
-                               3175 Quatre-Bourgeois #104\r
-                               Quebec  Quebec  G1W2K7\r
-                               CA\r
+70-B3-D5   (hex)               Open System Solutions Limited\r
+FAB000-FABFFF     (base 16)            Open System Solutions Limited\r
+                               Unit 33, Mitchell Point, Ensign Way\r
+                               Southampton  Hampshire  SO31 4RF\r
+                               GB\r
 \r
-70-B3-D5   (hex)               hera Laborsysteme GmbH\r
-4C2000-4C2FFF     (base 16)            hera Laborsysteme GmbH\r
-                               Hermann-Rapp-Str. 40\r
-                               Blaufelden    74572\r
+70-B3-D5   (hex)               SOFTLAND INDIA LTD\r
+C29000-C29FFF     (base 16)            SOFTLAND INDIA LTD\r
+                               #14A, KINFRA SMALL INDUSTRIES PARK, MENAMKULAM, KAZHAKOOTTAM\r
+                               TRIVANDRUM  KERALA  695586\r
+                               IN\r
+\r
+70-B3-D5   (hex)               Scame Sistemi srl\r
+F04000-F04FFF     (base 16)            Scame Sistemi srl\r
+                               Via Lombardia 5\r
+                               Arluno  Milan  20010\r
+                               IT\r
+\r
+70-B3-D5   (hex)               SYS TEC electronic GmbH\r
+41B000-41BFFF     (base 16)            SYS TEC electronic GmbH\r
+                               Am Windrad 2\r
+                               Heinsdorfergrund     D-08468\r
                                DE\r
 \r
-70-B3-D5   (hex)               PTN Electronics Limited \r
-0A1000-0A1FFF     (base 16)            PTN Electronics Limited \r
-                               G2, JinXiongDa Technology Park, HuanGuan Road South 105th  GuanLan Block, LongHua New District \r
-                               ShenZhen City  guangdong  518000\r
-                               CN\r
+70-B3-D5   (hex)               Alcohol Countermeasure Systems\r
+FD0000-FD0FFF     (base 16)            Alcohol Countermeasure Systems\r
+                               60 International Blvd\r
+                               Toronto  Ontario  M9W 6J2\r
+                               CA\r
 \r
-70-B3-D5   (hex)               Pullnet Technology,S.L.\r
-AA4000-AA4FFF     (base 16)            Pullnet Technology,S.L.\r
-                               Parc Tecnologic BCNord\r
-                               Barcelona  Catalonia  08042\r
-                               ES\r
+70-B3-D5   (hex)               PEEK TRAFFIC\r
+0C7000-0C7FFF     (base 16)            PEEK TRAFFIC\r
+                               5401 N SAM HOUSTON PKWY W\r
+                               HOUSTON    77086\r
+                               US\r
 \r
-70-B3-D5   (hex)               Mini Solution Co. Ltd.\r
-C68000-C68FFF     (base 16)            Mini Solution Co. Ltd.\r
-                               2-98-85, Yarimizu\r
-                               Hachiouji  Toyko  1920375\r
-                               JP\r
+70-B3-D5   (hex)               Project Service S.r.l.\r
+A2D000-A2DFFF     (base 16)            Project Service S.r.l.\r
+                               Via Paderno 31/C\r
+                               Seriate (BG)    24068\r
+                               IT\r
 \r
-70-B3-D5   (hex)               Joehl & Koeferli AG\r
-81A000-81AFFF     (base 16)            Joehl & Koeferli AG\r
-                               Wittenwilerstrasse 31\r
-                               Aadorf  TG  8355\r
-                               CH\r
+70-B3-D5   (hex)               SwineTech, Inc.\r
+DC2000-DC2FFF     (base 16)            SwineTech, Inc.\r
+                               230 2nd Street SE, Ste 302\r
+                               Cedar Rapids  IA  52401\r
+                               US\r
 \r
-70-B3-D5   (hex)               Profcon AB\r
-86E000-86EFFF     (base 16)            Profcon AB\r
-                               Victor Hasselblads gata 9\r
-                               Västra Frölunda    42131\r
-                               SE\r
+70-B3-D5   (hex)               OSMOZIS\r
+A9B000-A9BFFF     (base 16)            OSMOZIS\r
+                               7 AVENUE DE L'EUROPE\r
+                               CLAPIERS  LANGUEDOC ROUSSSILLON  34830\r
+                               FR\r
 \r
-70-B3-D5   (hex)               Grossenbacher Systeme AG\r
-0E8000-0E8FFF     (base 16)            Grossenbacher Systeme AG\r
-                               Spinnereistrasse 10\r
-                               St. Gallen    9008\r
-                               CH\r
+70-B3-D5   (hex)               Electrónica Falcón S.A.U\r
+36E000-36EFFF     (base 16)            Electrónica Falcón S.A.U\r
+                               Polígono Industrial Escopar, Calle E, Nº 1\r
+                               Peralta  Navarra  31350\r
+                               ES\r
 \r
-70-B3-D5   (hex)               ATX Networks Corp\r
-9D9000-9D9FFF     (base 16)            ATX Networks Corp\r
-                               1-501 Clements Road West\r
-                               Ajax  Ontario  L1s7H4\r
-                               CA\r
+70-B3-D5   (hex)               WAVES SYSTEM\r
+CE4000-CE4FFF     (base 16)            WAVES SYSTEM\r
+                               La Ville en Bois\r
+                               BOUAYE  Loire Atlantique  44830\r
+                               FR\r
 \r
-70-B3-D5   (hex)               BÄR Bahnsicherung AG\r
-348000-348FFF     (base 16)            BÄR Bahnsicherung AG\r
-                               Luppmenstrasse 3\r
-                               Fehraltorf     8320\r
-                               CH\r
+70-B3-D5   (hex)               HeadsafeIP PTY LTD\r
+800000-800FFF     (base 16)            HeadsafeIP PTY LTD\r
+                               231 Birrell st\r
+                               bronte  nsw  2024\r
+                               AU\r
 \r
-70-B3-D5   (hex)               SHEN ZHEN HUAWANG TECHNOLOGY CO; LTD\r
-A30000-A30FFF     (base 16)            SHEN ZHEN HUAWANG TECHNOLOGY CO; LTD\r
-                               Longhua New District Qing Xiang Road, Bao Neng Technology Park\r
-                               SHEN ZHEN  GUANG DONG  518109\r
-                               CN\r
+70-B3-D5   (hex)               Tieline Research Pty Ltd\r
+FCB000-FCBFFF     (base 16)            Tieline Research Pty Ltd\r
+                               PO Box 2092\r
+                               MALAGA  Western Australia  6944\r
+                               AU\r
 \r
-70-B3-D5   (hex)               Contiweb\r
-DFD000-DFDFFF     (base 16)            Contiweb\r
-                               Ir. Wagterstraat 10\r
-                               Boxmeer    5831 AZ\r
-                               NL\r
+70-B3-D5   (hex)               LG Electronics\r
+4F1000-4F1FFF     (base 16)            LG Electronics\r
+                               Science Park W5, 10, Magokjungang 10-ro, Gangseo-gu\r
+                               Seoul    07796\r
+                               KR\r
 \r
-70-B3-D5   (hex)               Systolé Hardware B.V.\r
-B30000-B30FFF     (base 16)            Systolé Hardware B.V.\r
-                               Hogehilweg, 5E\r
-                               Amsterdam    1101 CA\r
-                               NL\r
+70-B3-D5   (hex)                Zhiye Electronics Co., Ltd.\r
+8E2000-8E2FFF     (base 16)             Zhiye Electronics Co., Ltd.\r
+                               No. 1117, Pioneer Road, High-tech Zone\r
+                               Jinan City  Shandong Province  250101\r
+                               CN\r
 \r
-70-B3-D5   (hex)               Star Electronics GmbH & Co. KG \r
-3BF000-3BFFFF     (base 16)            Star Electronics GmbH & Co. KG \r
-                               Jahnstraße 86 \r
-                               Göppingen  BW  73037\r
+70-B3-D5   (hex)               ifak technology + service GmbH\r
+264000-264FFF     (base 16)            ifak technology + service GmbH\r
+                               Ludwig-Erhard-Allee 10\r
+                               Karlsruhe    76131\r
                                DE\r
 \r
-70-B3-D5   (hex)               TMSI LLC\r
-745000-745FFF     (base 16)            TMSI LLC\r
-                               9073 Pleasantwood Ave NW\r
-                               North Canton  OH  44720\r
-                               US\r
+70-B3-D5   (hex)               ABB S.p.A.\r
+5A7000-5A7FFF     (base 16)            ABB S.p.A.\r
+                               Via Pisani 16\r
+                               Milano  MI  20124\r
+                               IT\r
 \r
-70-B3-D5   (hex)               Specialised Imaging Limited\r
-D1C000-D1CFFF     (base 16)            Specialised Imaging Limited\r
-                               6 Harvington Park\r
-                               Pitstone  Bucks  LU7 9GX\r
-                               GB\r
+70-B3-D5   (hex)               OOO Alyans\r
+107000-107FFF     (base 16)            OOO Alyans\r
+                               9 maya, 20\r
+                               Krasnoyarsk  Krasnoyarski Krai  660125\r
+                               RU\r
 \r
-70-B3-D5   (hex)               Macnica Technology\r
-E8E000-E8EFFF     (base 16)            Macnica Technology\r
-                               380 Stevens Avenue\r
-                               Solana Beach  CA  92075\r
-                               US\r
+70-B3-D5   (hex)               Alere Technologies AS\r
+91C000-91CFFF     (base 16)            Alere Technologies AS\r
+                               Kjelsaasveien 161\r
+                               Oslo  Oslo  0382\r
+                               NO\r
 \r
-70-B3-D5   (hex)               Seraphim Optronics Ltd\r
-ADF000-ADFFFF     (base 16)            Seraphim Optronics Ltd\r
-                               2 hacarmel  st  \r
-                               Yokneam   Israel  20692\r
-                               IL\r
+70-B3-D5   (hex)               Transas Marine Limited\r
+ED8000-ED8FFF     (base 16)            Transas Marine Limited\r
+                               10 Eastgate Avenue, Eastgate Business Park\r
+                               Little Island, Cork    0\r
+                               IE\r
 \r
-70-B3-D5   (hex)               Hiquel Elektronik- und Anlagenbau GmbH\r
-22C000-22CFFF     (base 16)            Hiquel Elektronik- und Anlagenbau GmbH\r
-                               Bairisch Koelldorf 266\r
-                               Bad Gleichenberg    8344\r
-                               AT\r
-\r
-70-B3-D5   (hex)               Stahl GmbH\r
-DCE000-DCEFFF     (base 16)            Stahl GmbH\r
-                               Wilhelm-Maybach-Str. 3\r
-                               Crailsheim    74564\r
-                               DE\r
+70-B3-D5   (hex)               Private\r
+A03000-A03FFF     (base 16)            Private\r
 \r
-70-B3-D5   (hex)               Visualware, Inc.\r
-2A2000-2A2FFF     (base 16)            Visualware, Inc.\r
-                               937 SIERRA DRIVE\r
-                               TURLOCK  CA  95380\r
+70-B3-D5   (hex)               SA Photonics\r
+E17000-E17FFF     (base 16)            SA Photonics\r
+                               120 Knowles Drive\r
+                               Los Gatos  CA  95032\r
                                US\r
 \r
-70-B3-D5   (hex)               Veeco Instruments\r
-D08000-D08FFF     (base 16)            Veeco Instruments\r
-                               4875 Constellation Dr\r
-                               St. Paul  MN  55127\r
+70-B3-D5   (hex)               Private\r
+9EE000-9EEFFF     (base 16)            Private\r
+\r
+70-B3-D5   (hex)               Elbit Systems of America\r
+B7E000-B7EFFF     (base 16)            Elbit Systems of America\r
+                               4700 Marine Creek Parkway\r
+                               Fort Worth  TX  76179\r
                                US\r
 \r
-70-B3-D5   (hex)               LGE\r
-630000-630FFF     (base 16)            LGE\r
-                               2621, Nambusunhwan-ro, Gangnam-gu\r
-                               Seoul    06267\r
+70-B3-D5   (hex)               QuestHouse, Inc.\r
+84B000-84BFFF     (base 16)            QuestHouse, Inc.\r
+                               Rm 204, 5 B/D, 20 Techno 1-ro, Yuseong-gu\r
+                               Daejeon    34016\r
                                KR\r
 \r
-70-B3-D5   (hex)               Vishay Nobel AB\r
-873000-873FFF     (base 16)            Vishay Nobel AB\r
-                               Box 423\r
-                               Karlskoga    SE-691 27\r
-                               SE\r
+70-B3-D5   (hex)               Monnit Corporation\r
+D1A000-D1AFFF     (base 16)            Monnit Corporation\r
+                               3400 S West Temple\r
+                               Taylorsville  UT  84115\r
+                               US\r
 \r
-70-B3-D5   (hex)               Luxar Tech, Inc.\r
-653000-653FFF     (base 16)            Luxar Tech, Inc.\r
-                               42840 Christy St, Suite 101\r
-                               Fremont  CA  94538\r
+70-B3-D5   (hex)               Smart Controls LLC\r
+199000-199FFF     (base 16)            Smart Controls LLC\r
+                               10000 St. Clair Ave.\r
+                               Fairview Heights  IL  62208\r
                                US\r
 \r
-70-B3-D5   (hex)               HKC Limited\r
-F1F000-F1FFFF     (base 16)            HKC Limited\r
-                               Parkway Business Centre\r
-                               Ballymount  Dublin  Dublin 24\r
-                               IE\r
+70-B3-D5   (hex)               ENTEC Electric & Electronic Co., LTD.\r
+1DF000-1DFFFF     (base 16)            ENTEC Electric & Electronic Co., LTD.\r
+                               78-2 Buncheon-ri, Bongdam-eup\r
+                               Hwaseong-city  Gyungki-do  445-894\r
+                               KR\r
 \r
-70-B3-D5   (hex)               S.C.E. srl\r
-AF6000-AF6FFF     (base 16)            S.C.E. srl\r
-                               Via Giardini 1271/A\r
-                               Modena  Italy  41126\r
-                               IT\r
+70-B3-D5   (hex)               GMI Ltd\r
+C93000-C93FFF     (base 16)            GMI Ltd\r
+                               Inchinnan Business Park\r
+                               Renfre    PA4 9RG\r
+                               GB\r
 \r
-70-B3-D5   (hex)               Mitsubishi Electric Micro-Computer Application Software Co.,Ltd. \r
-F37000-F37FFF     (base 16)            Mitsubishi Electric Micro-Computer Application Software Co.,Ltd. \r
-                               Inadera, 2-5-1\r
-                               Amagasaki  Hyogo  661-0981\r
+70-B3-D5   (hex)               YUYAMA MFG Co.,Ltd\r
+150000-150FFF     (base 16)            YUYAMA MFG Co.,Ltd\r
+                               3-3-1\r
+                               TOYONAKASHI  OSAKA  561-0841\r
                                JP\r
 \r
-70-B3-D5   (hex)               Wyebot, Inc.\r
-8C3000-8C3FFF     (base 16)            Wyebot, Inc.\r
-                               2 Mount Royal Ave.\r
-                               Marlborough  MA  01752\r
-                               US\r
+70-B3-D5   (hex)               OBSERVER FOUNDATION\r
+633000-633FFF     (base 16)            OBSERVER FOUNDATION\r
+                               Narva mnt 5\r
+                               Tallinn city  Harju county  10117\r
+                               EE\r
 \r
-70-B3-D5   (hex)               RCH Italia SpA\r
-42D000-42DFFF     (base 16)            RCH Italia SpA\r
-                               Via Cendon 39\r
-                               SILEA  Treviso  31057\r
+70-B3-D5   (hex)               MECT SRL\r
+7C4000-7C4FFF     (base 16)            MECT SRL\r
+                               VIA E. FERMI 57/59\r
+                               ALPIGNANO    10091\r
                                IT\r
 \r
-70-B3-D5   (hex)               InnoSenT\r
-332000-332FFF     (base 16)            InnoSenT\r
-                               Am Roedertor 30  \r
-                               Donnersdorf  Bavaria  97499\r
-                               DE\r
+70-B3-D5   (hex)               Benetel\r
+E15000-E15FFF     (base 16)            Benetel\r
+                               Guinness Enterprise Centre, Taylors Lane,\r
+                               Dublin    D08 XV25\r
+                               IE\r
 \r
-70-B3-D5   (hex)               CRDE\r
-DEE000-DEEFFF     (base 16)            CRDE\r
-                               ZI DES GRANDS CAMPS\r
-                               MERCUES  LOT  46090\r
-                               FR\r
+70-B3-D5   (hex)               XANTIA SA\r
+33F000-33FFFF     (base 16)            XANTIA SA\r
+                               Chemin du Longchamps 99\r
+                               Bienne    2504\r
+                               CH\r
 \r
-70-B3-D5   (hex)               KANOA INC\r
-A47000-A47FFF     (base 16)            KANOA INC\r
-                               760 Bryant Street\r
-                               San Francisco  CA  94107\r
+70-B3-D5   (hex)               Divelbiss Corporation\r
+F43000-F43FFF     (base 16)            Divelbiss Corporation\r
+                               9778 Mount Gilead Road\r
+                               Fredericktown  OH  43019\r
                                US\r
 \r
-70-B3-D5   (hex)               Norbit ODM AS\r
-F45000-F45FFF     (base 16)            Norbit ODM AS\r
-                               Stiklestadveien 1\r
-                               Trondheim    7041\r
-                               NO\r
-\r
-70-B3-D5   (hex)               Fracarro srl\r
-E59000-E59FFF     (base 16)            Fracarro srl\r
-                               VIA CAZZARO 3\r
-                               CASTELFRANCO VENETO  TV  31033\r
-                               IT\r
-\r
-70-B3-D5   (hex)               VITEC\r
-127000-127FFF     (base 16)            VITEC\r
-                               99, rue Pierre Semard\r
-                               CHATILLON    92320\r
-                               FR\r
-\r
-00-1B-C5   (hex)               GÉANT\r
-046000-046FFF     (base 16)            GÉANT\r
-                               Singel 468D\r
-                               Amsterdam  Noord-Holland  1017AW\r
-                               NL\r
+70-B3-D5   (hex)               INTERNET PROTOCOLO LOGICA SL\r
+275000-275FFF     (base 16)            INTERNET PROTOCOLO LOGICA SL\r
+                               Sector Foresta 43, local 26\r
+                               Tres Cantos  Madrid  28760\r
+                               ES\r
 \r
-70-B3-D5   (hex)               System 11 Sp. z o.o.\r
-9DE000-9DEFFF     (base 16)            System 11 Sp. z o.o.\r
-                               Wieniawskiego 18\r
-                               Chorzow    41-506\r
+70-B3-D5   (hex)               Integrotech sp. z o.o.\r
+6BA000-6BAFFF     (base 16)            Integrotech sp. z o.o.\r
+                               plac Zwyciestwa 2 bud. D\r
+                               Lodz  lodzkie  90-312\r
                                PL\r
 \r
-70-B3-D5   (hex)               MSB Elektronik und Gerätebau GmbH\r
-96D000-96DFFF     (base 16)            MSB Elektronik und Gerätebau GmbH\r
-                               Hofwiesenstr. 23\r
-                               Crailsheim    74564\r
-                               DE\r
+70-B3-D5   (hex)               Invent Vision - iVision Sistemas de Imagem e Visão S.A.\r
+E29000-E29FFF     (base 16)            Invent Vision - iVision Sistemas de Imagem e Visão S.A.\r
+                               R. Prof. José Vieira de Mendonça, 770, 2° andar - BHTEC, Parque Tecnológico de Belo Horizonte\r
+                               Belo Horizonte  Minas Gerais  31310-260\r
+                               BR\r
 \r
-70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
-C17000-C17FFF     (base 16)            Potter Electric Signal Co. LLC\r
-                               1609 Park 370 Place\r
-                               Hazelwood    63042\r
-                               US\r
+70-B3-D5   (hex)               Altaneos\r
+69A000-69AFFF     (base 16)            Altaneos\r
+                               Chaussée Verte, 93B\r
+                               Saint-Georges    4470\r
+                               BE\r
 \r
-70-B3-D5   (hex)               TEX COMPUTER SRL \r
-108000-108FFF     (base 16)            TEX COMPUTER SRL \r
-                               VIA MERCADANTE 35\r
-                               CATTOLICA   RIMINI   47841\r
+70-B3-D5   (hex)               Sicon srl\r
+BEE000-BEEFFF     (base 16)            Sicon srl\r
+                               Via Sila 1/3\r
+                               Isola Vicentina  Vicenza  36033\r
                                IT\r
 \r
-70-B3-D5   (hex)               SENSONEO\r
-007000-007FFF     (base 16)            SENSONEO\r
-                               Kollarova 27\r
-                               Bratislava  Slovak Republic  84106\r
-                               SK\r
-\r
-70-B3-D5   (hex)               Digital Domain\r
-4E7000-4E7FFF     (base 16)            Digital Domain\r
-                               1700 Main St Ste 222\r
-                               Washougal  WA  98671\r
-                               US\r
+70-B3-D5   (hex)               Flexsolution APS\r
+C54000-C54FFF     (base 16)            Flexsolution APS\r
+                               Østervangsvej 39\r
+                               Esbjerg N  Jylland  6715\r
+                               DK\r
 \r
-70-B3-D5   (hex)               Contec DTx\r
-D10000-D10FFF     (base 16)            Contec DTx\r
-                               1800 Penn St Suite 1\r
-                               Melbourne  FL  32901\r
-                               US\r
+70-B3-D5   (hex)               Private\r
+E2D000-E2DFFF     (base 16)            Private\r
 \r
-70-B3-D5   (hex)               Shenzhen Virtual Clusters Information Technology Co.,Ltd.\r
-7F3000-7F3FFF     (base 16)            Shenzhen Virtual Clusters Information Technology Co.,Ltd.\r
-                               Room 201,Building A,No.1,Qianhai 1st Road,Shengang cooperation zone,Qianhai\r
-                               Shenzhen    518054\r
-                               CN\r
+70-B3-D5   (hex)               EXARA Group\r
+00C000-00CFFF     (base 16)            EXARA Group\r
+                               Andropova pr. 18 1\r
+                               Moscow    115432\r
+                               RU\r
 \r
-70-B3-D5   (hex)               Rollogo Limited\r
-C8C000-C8CFFF     (base 16)            Rollogo Limited\r
-                               22/F., Far East Finance Centre, 16 Harcourt Road, Admiralty,\r
-                               Hong Kong    000000\r
-                               HK\r
+70-B3-D5   (hex)               Orlaco Products B.V.\r
+620000-620FFF     (base 16)            Orlaco Products B.V.\r
+                               Albert Plesmanstraat 42\r
+                               Barneveld    3772MN\r
+                               NL\r
 \r
-70-B3-D5   (hex)               Elystec Technology Co., Ltd\r
-D4C000-D4CFFF     (base 16)            Elystec Technology Co., Ltd\r
-                               Room 601, Zhong Da Court,Zhong Guan Garden,No.1311 Liuxian Road\r
-                               Shenzhen  Guangdong  518000\r
+70-B3-D5   (hex)               LANSITEC TECHNOLOGY CO., LTD\r
+A4D000-A4DFFF     (base 16)            LANSITEC TECHNOLOGY CO., LTD\r
+                               No. 8 Huashen Avenue\r
+                               Nanjing  Jiangsu  210012\r
                                CN\r
 \r
-70-B3-D5   (hex)               FOCAL-JMLab\r
-96B000-96BFFF     (base 16)            FOCAL-JMLab\r
-                               108 rue de l'Avenir\r
-                               La Talaudière    42353\r
-                               FR\r
+70-B3-D5   (hex)               Tonbo Imaging Pte Ltd\r
+506000-506FFF     (base 16)            Tonbo Imaging Pte Ltd\r
+                                77 Science Park Drive,CINTECH III, Singapore Science Park I\r
+                               Singapore    118256\r
+                               SG\r
 \r
-70-B3-D5   (hex)               Quantum Design Inc.\r
-84D000-84DFFF     (base 16)            Quantum Design Inc.\r
-                               10307 Pacific Center Court\r
-                               San Diego  CA  92121\r
-                               US\r
+70-B3-D5   (hex)               OHASHI ENGINEERING CO.,LTD.\r
+556000-556FFF     (base 16)            OHASHI ENGINEERING CO.,LTD.\r
+                               1-471-8 TOYONODAI\r
+                               KAZO-CITY  SAITAMA  349-1148\r
+                               JP\r
 \r
-70-B3-D5   (hex)               Iradimed\r
-E57000-E57FFF     (base 16)            Iradimed\r
-                               1025 Willa Springs Dr.\r
-                               Winter Springs  FL  32708-____\r
-                               US\r
+70-B3-D5   (hex)               iMAR Navigation GmbH\r
+A42000-A42FFF     (base 16)            iMAR Navigation GmbH\r
+                               Im Reihersbruch 3\r
+                               St. Ingbert  Saarland  66386\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Securolytics, Inc.\r
-125000-125FFF     (base 16)            Securolytics, Inc.\r
-                               2002 Summit Boulevard, Suite 300\r
-                               Atlanta  GA  30319\r
-                               US\r
+70-B3-D5   (hex)               QUERCUS TECHNOLOGIES, S.L.\r
+40B000-40BFFF     (base 16)            QUERCUS TECHNOLOGIES, S.L.\r
+                               Av. Onze de Setembre 19\r
+                               Reus  Tarragona  43203\r
+                               ES\r
 \r
-70-B3-D5   (hex)               Orion Technologies, LLC\r
-C6E000-C6EFFF     (base 16)            Orion Technologies, LLC\r
-                               12605 Challenger Pkwy, Ste 130\r
-                               ORLANDO  FL  32826\r
-                               US\r
+70-B3-D5   (hex)               AVA Monitoring AB\r
+31D000-31DFFF     (base 16)            AVA Monitoring AB\r
+                               Vädursgatan 6\r
+                               Göteborg  Västra götaland  412 50\r
+                               SE\r
 \r
-70-B3-D5   (hex)               PROFEN COMMUNICATIONS\r
-CC8000-CC8FFF     (base 16)            PROFEN COMMUNICATIONS\r
-                               Famas Plaza A Blok Kat: 10 No:35 Okmeydani\r
-                               Istanbul    34384\r
-                               TR\r
+70-B3-D5   (hex)               PTYPE Co., LTD.\r
+6B0000-6B0FFF     (base 16)            PTYPE Co., LTD.\r
+                               B121, B-dong, Keumkang Penterium IT Tower, 810, Gwanyand 2-dong, Dongan-gu\r
+                               Anyang-si  Gyeonggi-do  14056\r
+                               KR\r
 \r
-70-B3-D5   (hex)               Design SHIFT\r
-FDB000-FDBFFF     (base 16)            Design SHIFT\r
-                               3475 Edison Way, Suite G\r
-                               Menlo Park  CA  94025\r
-                               US\r
+70-B3-D5   (hex)               comtime GmbH\r
+1E9000-1E9FFF     (base 16)            comtime GmbH\r
+                               Gutenbergring 22\r
+                               Norderstedt    22848\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Romteck Australia\r
-791000-791FFF     (base 16)            Romteck Australia\r
-                               37 Collingwood St Osborne Park\r
-                               Perth  Western Australia  6017\r
-                               AU\r
+70-B3-D5   (hex)               eeas gmbh\r
+86C000-86CFFF     (base 16)            eeas gmbh\r
+                               Bachstrasse 44\r
+                               Schwertberg    4311\r
+                               AT\r
 \r
-70-B3-D5   (hex)               Rheonics GmbH\r
-D20000-D20FFF     (base 16)            Rheonics GmbH\r
-                               Rheonics GmbH, Technoparkstr. 2\r
-                               Winterthur  Schweiz  8406\r
-                               CH\r
+70-B3-D5   (hex)               Vigilate srl\r
+B0C000-B0CFFF     (base 16)            Vigilate srl\r
+                               Via Napoleonica, 6\r
+                               Rezzato  BS  25086\r
+                               IT\r
 \r
-70-B3-D5   (hex)               T+A elektroakustik GmbH & Co.KG\r
-69F000-69FFFF     (base 16)            T+A elektroakustik GmbH & Co.KG\r
-                               Planckstr. 9-11\r
-                               Herford    32052\r
+70-B3-D5   (hex)               CODEC Co., Ltd.\r
+B37000-B37FFF     (base 16)            CODEC Co., Ltd.\r
+                               1-29-18 Tamagawa\r
+                               Choufu-shi  Tokyo  182-0025\r
+                               JP\r
+\r
+70-B3-D5   (hex)               VAPE RAIL INTERNATIONAL\r
+597000-597FFF     (base 16)            VAPE RAIL INTERNATIONAL\r
+                               9 RUE DES NOISETIERS\r
+                               MONTREAL LA CLUSE    01460\r
+                               FR\r
+\r
+70-B3-D5   (hex)               REO AG\r
+850000-850FFF     (base 16)            REO AG\r
+                               Brühlerstr. 100\r
+                               Solingen    42657\r
                                DE\r
 \r
-70-B3-D5   (hex)               Kazan Networks Corporation\r
-768000-768FFF     (base 16)            Kazan Networks Corporation\r
-                               660 Auburn Folsom Rd, Suite 204\r
-                               Auburn  CA  95722\r
+70-B3-D5   (hex)               APG Cash Drawer, LLC\r
+37A000-37AFFF     (base 16)            APG Cash Drawer, LLC\r
+                               5250 Industrial Blvd NE\r
+                               Minneapolis  MN  55421\r
                                US\r
 \r
-70-B3-D5   (hex)               CRDE\r
-6B2000-6B2FFF     (base 16)            CRDE\r
-                               ZI DES GRANDS CAMPS\r
-                               MERCUES  LOT  46090\r
-                               FR\r
+70-B3-D5   (hex)               CISTECH Solutions\r
+C3D000-C3DFFF     (base 16)            CISTECH Solutions\r
+                               170 JAMES ST\r
+                               TOOWOOMBA  QLD  4350\r
+                               AU\r
 \r
-70-B3-D5   (hex)               JASCO Applied Sciences Canada Ltd\r
-7F7000-7F7FFF     (base 16)            JASCO Applied Sciences Canada Ltd\r
-                               32 Troop Avenue, Suite 202\r
-                               Dartmouth  Nova Scotia  B3B 1Z1\r
-                               CA\r
+70-B3-D5   (hex)               IOOOTA Srl\r
+F8B000-F8BFFF     (base 16)            IOOOTA Srl\r
+                               Via Molino Rosso, 8\r
+                               Imola  BO  40026\r
+                               IT\r
 \r
-70-B3-D5   (hex)               Matsuhisa Corporation\r
-F42000-F42FFF     (base 16)            Matsuhisa Corporation\r
-                               55-20 Katayama-cho\r
-                               Fukui-shi    910-3611\r
-                               JP\r
+70-B3-D5   (hex)               Grupo Epelsa S.L.\r
+2EC000-2ECFFF     (base 16)            Grupo Epelsa S.L.\r
+                               C/ Punto Net,3\r
+                               Alcala de Henares  Madrid  28805\r
+                               ES\r
 \r
-70-B3-D5   (hex)               CRDE\r
-381000-381FFF     (base 16)            CRDE\r
-                               ZI DES GRANDS CAMPS\r
-                               MERCUES  LOT  46090\r
+70-B3-D5   (hex)               Trinity College Dublin\r
+99E000-99EFFF     (base 16)            Trinity College Dublin\r
+                               Dunlop Oriel House, Fenian Street\r
+                               Dublin 2    2\r
+                               IE\r
+\r
+70-B3-D5   (hex)               EarTex\r
+462000-462FFF     (base 16)            EarTex\r
+                               Flat 11 Princes Park Apartments South,, 52 Prince Of Wales Road\r
+                               London  England  NW5 3LN\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Agilack\r
+4CE000-4CEFFF     (base 16)            Agilack\r
+                               12 avenue Jules Verne\r
+                               Saint Sebastien sur loire    44230\r
                                FR\r
 \r
-70-B3-D5   (hex)               Cardinal Scale Mfg Co\r
-488000-488FFF     (base 16)            Cardinal Scale Mfg Co\r
-                               203 E. Daugherty\r
-                               Webb City  MO  64870\r
+70-B3-D5   (hex)               VITEC\r
+F17000-F17FFF     (base 16)            VITEC\r
+                               99 rue pierre sémard\r
+                               Chatillon  France  92320\r
+                               FR\r
+\r
+70-B3-D5   (hex)               Dakton Microlabs LLC\r
+11D000-11DFFF     (base 16)            Dakton Microlabs LLC\r
+                               520 Brickell Key Drive, A-1811\r
+                               Miami  FL  33131\r
                                US\r
 \r
-70-B3-D5   (hex)               WeVo Tech\r
-273000-273FFF     (base 16)            WeVo Tech\r
-                               2985 Drew Road\r
-                               Mississauga   Ontario  L4T0A4\r
-                               CA\r
+70-B3-D5   (hex)               Meridian Technologies Inc\r
+924000-924FFF     (base 16)            Meridian Technologies Inc\r
+                               700 Elmont Rd\r
+                               Elmont  NY  11003\r
+                               US\r
 \r
-70-B3-D5   (hex)               Vensi, Inc.\r
-379000-379FFF     (base 16)            Vensi, Inc.\r
-                               113 McHenry Rd #191\r
-                               Buffalo Grove  IL  60089\r
+70-B3-D5   (hex)               QUERCUS TECHNOLOGIES, S.L.\r
+03D000-03DFFF     (base 16)            QUERCUS TECHNOLOGIES, S.L.\r
+                               Av. Onze de Setembre 19\r
+                               Reus  Tarragona  43203\r
+                               ES\r
+\r
+70-B3-D5   (hex)               Canam Technology, Inc.\r
+B97000-B97FFF     (base 16)            Canam Technology, Inc.\r
+                               5318 East 2nd. St, #700\r
+                               Long Beach  CA  90803\r
                                US\r
 \r
-70-B3-D5   (hex)               ndb technologies\r
-0B2000-0B2FFF     (base 16)            ndb technologies\r
-                               1405-111 Av Saint-Jean-Baptiste\r
-                               Quebec  Quebec  G2E5K2\r
-                               CA\r
+70-B3-D5   (hex)               Globalcom Engineering SPA\r
+352000-352FFF     (base 16)            Globalcom Engineering SPA\r
+                               Via Volta 39\r
+                               CARDANO AL CAMPO  VA  21010\r
+                               IT\r
 \r
 70-B3-D5   (hex)               KST technology\r
-CB3000-CB3FFF     (base 16)            KST technology\r
-                               KST B/D 4-5, Wiryeseong-daero 12-gil\r
-                               Songpa-gu  Seoul  05636\r
+7F4000-7F4FFF     (base 16)            KST technology\r
+                               164-1, KST b/d., Bangi-dong, songpa-gu\r
+                               SEOUL  N/A  138-050\r
                                KR\r
 \r
-70-B3-D5   (hex)               Fiberbase\r
-30D000-30DFFF     (base 16)            Fiberbase\r
-                               #516 Complex-dong Heongduk IT Valley, Heonduk 1ro 13, Giheong-gu\r
-                               Young-in  Gyeong-gi  16954\r
-                               KR\r
+70-B3-D5   (hex)               Henri Systems Holland bv\r
+122000-122FFF     (base 16)            Henri Systems Holland bv\r
+                               Scheepmalersstraat 33\r
+                               Zwijndrecht  ZH  3334 KG\r
+                               NL\r
 \r
-70-B3-D5   (hex)               PLUTO Solution co.,ltd.\r
-842000-842FFF     (base 16)            PLUTO Solution co.,ltd.\r
-                               B-1018, Kumkang Penterium IT Tower, 282, Hagui-ro, Dongan-gu\r
-                               Anyang-si  Gyeonggi-do  14056\r
-                               KR\r
+70-B3-D5   (hex)               FRANKLIN FRANCE\r
+767000-767FFF     (base 16)            FRANKLIN FRANCE\r
+                               13 RUE LOUIS ARMAND\r
+                               OZOIR LA FERRIERE    77330\r
+                               FR\r
 \r
-70-B3-D5   (hex)               Thiel Audio Products Company, LLC\r
-EB9000-EB9FFF     (base 16)            Thiel Audio Products Company, LLC\r
-                               566 Mainstream Dr, Suite 500\r
-                               Nashville  TN  37228\r
+70-B3-D5   (hex)               ENERGISME\r
+465000-465FFF     (base 16)            ENERGISME\r
+                               88 avenue du General Leclerc\r
+                               Boulogne Billancourt    92100\r
+                               FR\r
+\r
+70-B3-D5   (hex)               L-3 communications ComCept Division\r
+E09000-E09FFF     (base 16)            L-3 communications ComCept Division\r
+                               1700 Science Place\r
+                               Rockwall   TX  75032\r
                                US\r
 \r
-70-B3-D5   (hex)               TATTILE SRL\r
-2CA000-2CAFFF     (base 16)            TATTILE SRL\r
-                               VIA DONIZETTI, 1/3/5\r
-                               MAIRANO  BRESCIA  25030\r
-                               IT\r
+70-B3-D5   (hex)               IoTrek Technology Private Limited\r
+A07000-A07FFF     (base 16)            IoTrek Technology Private Limited\r
+                               Paharganj, Delhi\r
+                               New Delhi  New Delhi  110055\r
+                               IN\r
 \r
-70-B3-D5   (hex)               DORLET SAU\r
-8E3000-8E3FFF     (base 16)            DORLET SAU\r
-                               Albert Eistein 34\r
-                               Alava  SPAIN  01510\r
-                               ES\r
+70-B3-D5   (hex)               iRF - Intelligent RF Solutions, LLC\r
+21D000-21DFFF     (base 16)            iRF - Intelligent RF Solutions, LLC\r
+                               14600 York Road, Suite B\r
+                               Sparks  MD  21152\r
+                               US\r
 \r
-70-B3-D5   (hex)               Gentec Systems  Co.\r
-469000-469FFF     (base 16)            Gentec Systems  Co.\r
-                               5F., No.51-3, Fuxing Rd., Xindian Dist., \r
-                               New Taipei City     23150\r
-                               TW\r
+70-B3-D5   (hex)               ATG UV Technology\r
+E9C000-E9CFFF     (base 16)            ATG UV Technology\r
+                               Genesis House\r
+                               Wigan    WN5 8AA\r
+                               GB\r
 \r
-70-B3-D5   (hex)               Exi Flow Measurement Ltd\r
-AAF000-AAFFFF     (base 16)            Exi Flow Measurement Ltd\r
-                               Unit 22 Ford Lane business Park\r
-                               Ford, ARUNDEL  West Sussex  BN164HP\r
-                               GB\r
+70-B3-D5   (hex)               Lanmark Controls Inc.\r
+39E000-39EFFF     (base 16)            Lanmark Controls Inc.\r
+                               125 Nagog Park\r
+                               Acton  MA  01720\r
+                               US\r
 \r
-70-B3-D5   (hex)               OÜ ELIKO Tehnoloogia Arenduskeskus\r
-D4A000-D4AFFF     (base 16)            OÜ ELIKO Tehnoloogia Arenduskeskus\r
-                               Mäealuse 2/1\r
-                               Tallinn  Harju  12618\r
-                               EE\r
+70-B3-D5   (hex)               Zehntner Testing Instruments\r
+267000-267FFF     (base 16)            Zehntner Testing Instruments\r
+                               Gewerbestrasse 4\r
+                               Sissach    4450\r
+                               CH\r
 \r
-70-B3-D5   (hex)               SEASON DESIGN TECHNOLOGY\r
-2C9000-2C9FFF     (base 16)            SEASON DESIGN TECHNOLOGY\r
-                               FLOOR 4, WARDS EXCHANGE, 199 ECCLESALL ROAD\r
-                               SHEFFIELD  SOUTH YORKSHIRE  S11 8HW\r
-                               GB\r
+70-B3-D5   (hex)               Dextera Labs\r
+0EF000-0EFFFF     (base 16)            Dextera Labs\r
+                               3175 Quatre-Bourgeois #104\r
+                               Quebec  Quebec  G1W2K7\r
+                               CA\r
 \r
-70-B3-D5   (hex)               BCD Audio\r
-728000-728FFF     (base 16)            BCD Audio\r
-                               5 Bristol Way, Stoke Gardens\r
-                               Slough  Berkshire  SL1 3QE\r
-                               GB\r
+70-B3-D5   (hex)               hera Laborsysteme GmbH\r
+4C2000-4C2FFF     (base 16)            hera Laborsysteme GmbH\r
+                               Hermann-Rapp-Str. 40\r
+                               Blaufelden    74572\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Resolution Systems\r
-D89000-D89FFF     (base 16)            Resolution Systems\r
-                               1/214 Greenhill Rd\r
-                               Eastwood  South Australia  6063\r
-                               AU\r
+70-B3-D5   (hex)               PTN Electronics Limited \r
+0A1000-0A1FFF     (base 16)            PTN Electronics Limited \r
+                               G2, JinXiongDa Technology Park, HuanGuan Road South 105th  GuanLan Block, LongHua New District \r
+                               ShenZhen City  guangdong  518000\r
+                               CN\r
 \r
-70-B3-D5   (hex)               WARECUBE,INC\r
-F06000-F06FFF     (base 16)            WARECUBE,INC\r
-                               #A-811, 142-10, Saneop-ro, 156beon-gil, Gwonseon-gu\r
-                               Suwon-si    16648\r
-                               KR\r
+70-B3-D5   (hex)               Pullnet Technology,S.L.\r
+AA4000-AA4FFF     (base 16)            Pullnet Technology,S.L.\r
+                               Parc Tecnologic BCNord\r
+                               Barcelona  Catalonia  08042\r
+                               ES\r
 \r
-70-B3-D5   (hex)               Roxford\r
-651000-651FFF     (base 16)            Roxford\r
-                               PO Box 231851\r
-                               Encinitas  CA  92023-1851\r
-                               US\r
+70-B3-D5   (hex)               Mini Solution Co. Ltd.\r
+C68000-C68FFF     (base 16)            Mini Solution Co. Ltd.\r
+                               2-98-85, Yarimizu\r
+                               Hachiouji  Toyko  1920375\r
+                               JP\r
 \r
-70-B3-D5   (hex)               Scenario Automation\r
-8B4000-8B4FFF     (base 16)            Scenario Automation\r
-                               Rua Paulo Elias, 216\r
-                               São Carlos  São Paulo  13564400\r
-                               BR\r
+70-B3-D5   (hex)               Joehl & Koeferli AG\r
+81A000-81AFFF     (base 16)            Joehl & Koeferli AG\r
+                               Wittenwilerstrasse 31\r
+                               Aadorf  TG  8355\r
+                               CH\r
 \r
-70-B3-D5   (hex)               Talleres de Escoriaza SA\r
-532000-532FFF     (base 16)            Talleres de Escoriaza SA\r
-                               Barrio Ventas, 35\r
-                               Irun  Gipuzkoa  20305\r
-                               ES\r
+70-B3-D5   (hex)               Profcon AB\r
+86E000-86EFFF     (base 16)            Profcon AB\r
+                               Victor Hasselblads gata 9\r
+                               Västra Frölunda    42131\r
+                               SE\r
 \r
-70-B3-D5   (hex)               MB connect line GmbH Fernwartungssysteme\r
-8D9000-8D9FFF     (base 16)            MB connect line GmbH Fernwartungssysteme\r
-                               Winnettener Straße 6\r
-                               Dinkelsbuehl  Bavaria  91550\r
-                               DE\r
+70-B3-D5   (hex)               Grossenbacher Systeme AG\r
+0E8000-0E8FFF     (base 16)            Grossenbacher Systeme AG\r
+                               Spinnereistrasse 10\r
+                               St. Gallen    9008\r
+                               CH\r
 \r
-70-B3-D5   (hex)               Eurotek Srl\r
-1D1000-1D1FFF     (base 16)            Eurotek Srl\r
-                               Strada Comunale Savonesa, 9\r
-                               Rivalta Scrivia  AL  15050\r
-                               IT\r
+70-B3-D5   (hex)               ATX Networks Corp\r
+9D9000-9D9FFF     (base 16)            ATX Networks Corp\r
+                               1-501 Clements Road West\r
+                               Ajax  Ontario  L1s7H4\r
+                               CA\r
 \r
-70-B3-D5   (hex)               Redcap Solutions s.r.o.\r
-027000-027FFF     (base 16)            Redcap Solutions s.r.o.\r
-                               Na Viničních Horách 16\r
-                               Praha 6    16000\r
-                               CZ\r
+70-B3-D5   (hex)               BÄR Bahnsicherung AG\r
+348000-348FFF     (base 16)            BÄR Bahnsicherung AG\r
+                               Luppmenstrasse 3\r
+                               Fehraltorf     8320\r
+                               CH\r
 \r
-70-B3-D5   (hex)               SiFive\r
-92F000-92FFFF     (base 16)            SiFive\r
-                               1875 S Grant St\r
-                               San Mateo  CA  94403\r
-                               US\r
+70-B3-D5   (hex)               SHEN ZHEN HUAWANG TECHNOLOGY CO; LTD\r
+A30000-A30FFF     (base 16)            SHEN ZHEN HUAWANG TECHNOLOGY CO; LTD\r
+                               Longhua New District Qing Xiang Road, Bao Neng Technology Park\r
+                               SHEN ZHEN  GUANG DONG  518109\r
+                               CN\r
 \r
-70-B3-D5   (hex)               Telefrank GmbH\r
-A82000-A82FFF     (base 16)            Telefrank GmbH\r
-                               Am Wildengrund 1\r
-                               Altenambach  TH  98553\r
-                               DE\r
+70-B3-D5   (hex)               Contiweb\r
+DFD000-DFDFFF     (base 16)            Contiweb\r
+                               Ir. Wagterstraat 10\r
+                               Boxmeer    5831 AZ\r
+                               NL\r
 \r
-70-B3-D5   (hex)               EIFFAGE ENERGIE ELECTRONIQUE\r
-037000-037FFF     (base 16)            EIFFAGE ENERGIE ELECTRONIQUE\r
-                               D937\r
-                               VERQUIN    62131\r
-                               FR\r
+70-B3-D5   (hex)               Systolé Hardware B.V.\r
+B30000-B30FFF     (base 16)            Systolé Hardware B.V.\r
+                               Hogehilweg, 5E\r
+                               Amsterdam    1101 CA\r
+                               NL\r
 \r
-70-B3-D5   (hex)               Blue Marble Communications, Inc.\r
-77E000-77EFFF     (base 16)            Blue Marble Communications, Inc.\r
-                               9520 Padgett St, Suite 101\r
-                               San Diego  CA  92126\r
+70-B3-D5   (hex)               Star Electronics GmbH & Co. KG \r
+3BF000-3BFFFF     (base 16)            Star Electronics GmbH & Co. KG \r
+                               Jahnstraße 86 \r
+                               Göppingen  BW  73037\r
+                               DE\r
+\r
+70-B3-D5   (hex)               TMSI LLC\r
+745000-745FFF     (base 16)            TMSI LLC\r
+                               9073 Pleasantwood Ave NW\r
+                               North Canton  OH  44720\r
                                US\r
 \r
-70-B3-D5   (hex)               D.T.S Illuminazione Srl \r
-D7C000-D7CFFF     (base 16)            D.T.S Illuminazione Srl \r
-                               Via Fagnano Selve,  12 / 14\r
-                               Misano Adriatico   Rimini   47843\r
-                               IT\r
+70-B3-D5   (hex)               Specialised Imaging Limited\r
+D1C000-D1CFFF     (base 16)            Specialised Imaging Limited\r
+                               6 Harvington Park\r
+                               Pitstone  Bucks  LU7 9GX\r
+                               GB\r
 \r
-70-B3-D5   (hex)               Duerkopp-Adler\r
-3C9000-3C9FFF     (base 16)            Duerkopp-Adler\r
-                               Potsdamerstr. 190\r
-                               Bielefeld    33719\r
-                               DE\r
+70-B3-D5   (hex)               Macnica Technology\r
+E8E000-E8EFFF     (base 16)            Macnica Technology\r
+                               380 Stevens Avenue\r
+                               Solana Beach  CA  92075\r
+                               US\r
 \r
-70-B3-D5   (hex)               DiTEST Fahrzeugdiagnose GmbH\r
-109000-109FFF     (base 16)            DiTEST Fahrzeugdiagnose GmbH\r
-                               ALTE POSTSTRASSE 152\r
-                               A-8020  GRAZ  STEIERMARK\r
+70-B3-D5   (hex)               Seraphim Optronics Ltd\r
+ADF000-ADFFFF     (base 16)            Seraphim Optronics Ltd\r
+                               2 hacarmel  st  \r
+                               Yokneam   Israel  20692\r
+                               IL\r
+\r
+70-B3-D5   (hex)               Hiquel Elektronik- und Anlagenbau GmbH\r
+22C000-22CFFF     (base 16)            Hiquel Elektronik- und Anlagenbau GmbH\r
+                               Bairisch Koelldorf 266\r
+                               Bad Gleichenberg    8344\r
                                AT\r
 \r
-70-B3-D5   (hex)               MSB Elektronik und Gerätebau GmbH\r
-E9E000-E9EFFF     (base 16)            MSB Elektronik und Gerätebau GmbH\r
-                               Hofwiesenstr. 23\r
+70-B3-D5   (hex)               Stahl GmbH\r
+DCE000-DCEFFF     (base 16)            Stahl GmbH\r
+                               Wilhelm-Maybach-Str. 3\r
                                Crailsheim    74564\r
                                DE\r
 \r
-70-B3-D5   (hex)               GL TECH CO.,LTD\r
-248000-248FFF     (base 16)            GL TECH CO.,LTD\r
-                               No. Ten Changchun Road\r
-                               ZHENGZHOU  HENAN  455000\r
-                               CN\r
-\r
-70-B3-D5   (hex)               CAPSYS\r
-A0A000-A0AFFF     (base 16)            CAPSYS\r
-                               ZI Parc technologique des Fontaines\r
-                               BERNIN    38190\r
-                               FR\r
+70-B3-D5   (hex)               Visualware, Inc.\r
+2A2000-2A2FFF     (base 16)            Visualware, Inc.\r
+                               937 SIERRA DRIVE\r
+                               TURLOCK  CA  95380\r
+                               US\r
 \r
-70-B3-D5   (hex)               Centero\r
-CE2000-CE2FFF     (base 16)            Centero\r
-                               1640 Powers Ferry Road Bldg.14-360\r
-                               Marietta  GA  30067\r
+70-B3-D5   (hex)               Veeco Instruments\r
+D08000-D08FFF     (base 16)            Veeco Instruments\r
+                               4875 Constellation Dr\r
+                               St. Paul  MN  55127\r
                                US\r
 \r
-70-B3-D5   (hex)               Ellenex Pty Ltd\r
-CD0000-CD0FFF     (base 16)            Ellenex Pty Ltd\r
-                               91 Tope Street\r
-                               South Melbourne  VIC  3205\r
-                               AU\r
+70-B3-D5   (hex)               LGE\r
+630000-630FFF     (base 16)            LGE\r
+                               2621, Nambusunhwan-ro, Gangnam-gu\r
+                               Seoul    06267\r
+                               KR\r
 \r
-70-B3-D5   (hex)               Tecsys do Brasil Industrial Ltda\r
-9AA000-9AAFFF     (base 16)            Tecsys do Brasil Industrial Ltda\r
-                               Rua Oros, 146\r
-                               Sao Jose dos Campos  SP  12237150\r
-                               BR\r
+70-B3-D5   (hex)               Vishay Nobel AB\r
+873000-873FFF     (base 16)            Vishay Nobel AB\r
+                               Box 423\r
+                               Karlskoga    SE-691 27\r
+                               SE\r
 \r
-70-B3-D5   (hex)               LINEAGE POWER PVT LTD.,\r
-0C9000-0C9FFF     (base 16)            LINEAGE POWER PVT LTD.,\r
-                               30-A1, KIADB, 1ST PHASE INDUSTRIAL ESTATE,KUMBALGODU, BANGALORE-MYSORE ROAD\r
-                               BANGALORE  KARNATAKA  560074\r
-                               IN\r
+70-B3-D5   (hex)               Luxar Tech, Inc.\r
+653000-653FFF     (base 16)            Luxar Tech, Inc.\r
+                               42840 Christy St, Suite 101\r
+                               Fremont  CA  94538\r
+                               US\r
 \r
-70-B3-D5   (hex)               Heng Dian Technology Co., Ltd\r
-FEA000-FEAFFF     (base 16)            Heng Dian Technology Co., Ltd\r
-                               No.9, Yunmei Road,Tianmulake Town\r
-                               Liyang  Jiangsu  213300\r
-                               CN\r
+70-B3-D5   (hex)               HKC Limited\r
+F1F000-F1FFFF     (base 16)            HKC Limited\r
+                               Parkway Business Centre\r
+                               Ballymount  Dublin  Dublin 24\r
+                               IE\r
 \r
-70-B3-D5   (hex)               TELEPLATFORMS\r
-5FB000-5FBFFF     (base 16)            TELEPLATFORMS\r
-                               Polbina st., 3/1\r
-                               Moscow    109388\r
-                               RU\r
+70-B3-D5   (hex)               S.C.E. srl\r
+AF6000-AF6FFF     (base 16)            S.C.E. srl\r
+                               Via Giardini 1271/A\r
+                               Modena  Italy  41126\r
+                               IT\r
 \r
-70-B3-D5   (hex)               Private\r
-401000-401FFF     (base 16)            Private\r
+70-B3-D5   (hex)               Mitsubishi Electric Micro-Computer Application Software Co.,Ltd. \r
+F37000-F37FFF     (base 16)            Mitsubishi Electric Micro-Computer Application Software Co.,Ltd. \r
+                               Inadera, 2-5-1\r
+                               Amagasaki  Hyogo  661-0981\r
+                               JP\r
 \r
-70-B3-D5   (hex)               LG Electronics\r
-9E3000-9E3FFF     (base 16)            LG Electronics\r
-                               10, Magokjungang 10-ro, Gangseo-gu\r
-                               Seoul    07796\r
-                               KR\r
+70-B3-D5   (hex)               Wyebot, Inc.\r
+8C3000-8C3FFF     (base 16)            Wyebot, Inc.\r
+                               2 Mount Royal Ave.\r
+                               Marlborough  MA  01752\r
+                               US\r
 \r
-70-B3-D5   (hex)               HORIZON TELECOM\r
-960000-960FFF     (base 16)            HORIZON TELECOM\r
-                               6 rue de GUEUGNON\r
-                               MONTCEAU LES MINES    71300\r
-                               FR\r
+70-B3-D5   (hex)               InnoSenT\r
+332000-332FFF     (base 16)            InnoSenT\r
+                               Am Roedertor 30  \r
+                               Donnersdorf  Bavaria  97499\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Beijing Daswell Science and Technology Co.LTD\r
-06F000-06FFFF     (base 16)            Beijing Daswell Science and Technology Co.LTD\r
-                               6th floor,Building B,Dachen Industry Park, NO.10 Jingyuan Street, BDA\r
-                               Beijing  Beijing  100176\r
-                               CN\r
+70-B3-D5   (hex)               CRDE\r
+DEE000-DEEFFF     (base 16)            CRDE\r
+                               ZI DES GRANDS CAMPS\r
+                               MERCUES  LOT  46090\r
+                               FR\r
 \r
-70-B3-D5   (hex)               Private\r
-73A000-73AFFF     (base 16)            Private\r
+70-B3-D5   (hex)               KANOA INC\r
+A47000-A47FFF     (base 16)            KANOA INC\r
+                               760 Bryant Street\r
+                               San Francisco  CA  94107\r
+                               US\r
 \r
-70-B3-D5   (hex)               Alere Technologies AS\r
-F52000-F52FFF     (base 16)            Alere Technologies AS\r
-                               Kjelsaasveien 161\r
-                               Oslo  Oslo  0382\r
+70-B3-D5   (hex)               Norbit ODM AS\r
+F45000-F45FFF     (base 16)            Norbit ODM AS\r
+                               Stiklestadveien 1\r
+                               Trondheim    7041\r
                                NO\r
 \r
-70-B3-D5   (hex)               Impolux GmbH\r
-EEC000-EECFFF     (base 16)            Impolux GmbH\r
-                               Boschstr. 7\r
-                               Kastellaun  RLP  56288\r
-                               DE\r
-\r
-70-B3-D5   (hex)               Beijing Nacao Technology Co., Ltd.\r
-105000-105FFF     (base 16)            Beijing Nacao Technology Co., Ltd.\r
-                               1912B, Zhongguancunkemao Building, Zhongguancun Da Jie\r
-                               Beijing    100080\r
-                               CN\r
+70-B3-D5   (hex)               Fracarro srl\r
+E59000-E59FFF     (base 16)            Fracarro srl\r
+                               VIA CAZZARO 3\r
+                               CASTELFRANCO VENETO  TV  31033\r
+                               IT\r
 \r
-70-B3-D5   (hex)               machineQ\r
-3E6000-3E6FFF     (base 16)            machineQ\r
-                               1900 market st\r
-                               philadelphia  PA  19103\r
-                               US\r
+70-B3-D5   (hex)               VITEC\r
+127000-127FFF     (base 16)            VITEC\r
+                               99, rue Pierre Semard\r
+                               CHATILLON    92320\r
+                               FR\r
 \r
-70-B3-D5   (hex)               eumig industrie-TV GmbH.\r
-AA2000-AA2FFF     (base 16)            eumig industrie-TV GmbH.\r
-                               Gewerbeparkstrasse 9\r
-                               Anif  Salzburg  5081\r
-                               AT\r
+00-1B-C5   (hex)               GÉANT\r
+046000-046FFF     (base 16)            GÉANT\r
+                               Singel 468D\r
+                               Amsterdam  Noord-Holland  1017AW\r
+                               NL\r
 \r
-70-B3-D5   (hex)               FSTUDIO CO LTD\r
-C0B000-C0BFFF     (base 16)            FSTUDIO CO LTD\r
-                               Yanagawa Bldg. 2F 5-16-13\r
-                               Watanabe-Dori Chuo-ku Fukuoka  Fukuoka  810-0004\r
-                               JP\r
+70-B3-D5   (hex)               System 11 Sp. z o.o.\r
+9DE000-9DEFFF     (base 16)            System 11 Sp. z o.o.\r
+                               Wieniawskiego 18\r
+                               Chorzow    41-506\r
+                               PL\r
 \r
-70-B3-D5   (hex)               YUYAMA MFG Co.,Ltd\r
-DB4000-DB4FFF     (base 16)            YUYAMA MFG Co.,Ltd\r
-                               3-3-1\r
-                               TOYONAKASHI  OSAKA  561-0841\r
-                               JP\r
+70-B3-D5   (hex)               MSB Elektronik und Gerätebau GmbH\r
+96D000-96DFFF     (base 16)            MSB Elektronik und Gerätebau GmbH\r
+                               Hofwiesenstr. 23\r
+                               Crailsheim    74564\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Smith Meter, Inc.\r
-706000-706FFF     (base 16)            Smith Meter, Inc.\r
-                               1602 Wagner Ave.\r
-                               Erie    16514\r
+70-B3-D5   (hex)               Potter Electric Signal Co. LLC\r
+C17000-C17FFF     (base 16)            Potter Electric Signal Co. LLC\r
+                               1609 Park 370 Place\r
+                               Hazelwood    63042\r
                                US\r
 \r
-70-B3-D5   (hex)               EGICON SRL\r
-6F7000-6F7FFF     (base 16)            EGICON SRL\r
-                               Via Posta Vecchia 36\r
-                               Mirandola  Modena  41037\r
+70-B3-D5   (hex)               TEX COMPUTER SRL \r
+108000-108FFF     (base 16)            TEX COMPUTER SRL \r
+                               VIA MERCADANTE 35\r
+                               CATTOLICA   RIMINI   47841\r
                                IT\r
 \r
-70-B3-D5   (hex)               Symetrics Industries d.b.a. Extant Aerospace\r
-0A8000-0A8FFF     (base 16)            Symetrics Industries d.b.a. Extant Aerospace\r
-                               1615 West NASA Blvd\r
+70-B3-D5   (hex)               SENSONEO\r
+007000-007FFF     (base 16)            SENSONEO\r
+                               Kollarova 27\r
+                               Bratislava  Slovak Republic  84106\r
+                               SK\r
+\r
+70-B3-D5   (hex)               Digital Domain\r
+4E7000-4E7FFF     (base 16)            Digital Domain\r
+                               1700 Main St Ste 222\r
+                               Washougal  WA  98671\r
+                               US\r
+\r
+70-B3-D5   (hex)               Contec DTx\r
+D10000-D10FFF     (base 16)            Contec DTx\r
+                               1800 Penn St Suite 1\r
                                Melbourne  FL  32901\r
                                US\r
 \r
-70-B3-D5   (hex)               CRESPRIT INC.\r
-C38000-C38FFF     (base 16)            CRESPRIT INC.\r
-                               D-315 ,177, Jeongjail-ro, Bundang-gu\r
-                               Seongnam-si    13557\r
-                               KR\r
+70-B3-D5   (hex)               Shenzhen Virtual Clusters Information Technology Co.,Ltd.\r
+7F3000-7F3FFF     (base 16)            Shenzhen Virtual Clusters Information Technology Co.,Ltd.\r
+                               Room 201,Building A,No.1,Qianhai 1st Road,Shengang cooperation zone,Qianhai\r
+                               Shenzhen    518054\r
+                               CN\r
 \r
-70-B3-D5   (hex)               alfamation spa\r
-675000-675FFF     (base 16)            alfamation spa\r
-                               via cadore 21\r
-                               lissone  mb  20851\r
-                               IT\r
+70-B3-D5   (hex)               Rollogo Limited\r
+C8C000-C8CFFF     (base 16)            Rollogo Limited\r
+                               22/F., Far East Finance Centre, 16 Harcourt Road, Admiralty,\r
+                               Hong Kong    000000\r
+                               HK\r
 \r
-70-B3-D5   (hex)               KST technology\r
-C05000-C05FFF     (base 16)            KST technology\r
-                               KST B/D 4-5, Wiryeseong-daero 12-gil\r
-                               Songpa-gu  Seoul  05636\r
-                               KR\r
+70-B3-D5   (hex)               Elystec Technology Co., Ltd\r
+D4C000-D4CFFF     (base 16)            Elystec Technology Co., Ltd\r
+                               Room 601, Zhong Da Court,Zhong Guan Garden,No.1311 Liuxian Road\r
+                               Shenzhen  Guangdong  518000\r
+                               CN\r
 \r
-70-B3-D5   (hex)               ETA Technology Pvt Ltd\r
-A94000-A94FFF     (base 16)            ETA Technology Pvt Ltd\r
-                               No. 484-D, 13th Cross, IV Phase, Peenya Industrial Area,\r
-                               Bangalore  Karnataka  560058\r
-                               IN\r
+70-B3-D5   (hex)               FOCAL-JMLab\r
+96B000-96BFFF     (base 16)            FOCAL-JMLab\r
+                               108 rue de l'Avenir\r
+                               La Talaudière    42353\r
+                               FR\r
 \r
-70-B3-D5   (hex)               Newshine\r
-A64000-A64FFF     (base 16)            Newshine\r
-                               Pingcheng Rd\r
-                               Shanghai  Shanghai  201800\r
-                               CN\r
+70-B3-D5   (hex)               Quantum Design Inc.\r
+84D000-84DFFF     (base 16)            Quantum Design Inc.\r
+                               10307 Pacific Center Court\r
+                               San Diego  CA  92121\r
+                               US\r
 \r
-70-B3-D5   (hex)               Guan Show Technologe Co., Ltd.\r
-E2B000-E2BFFF     (base 16)            Guan Show Technologe Co., Ltd.\r
-                               No.127, Jianguo 1st Rd., Lingya Dist.\r
-                                Kaohsiung City     802\r
-                               TW\r
+70-B3-D5   (hex)               Iradimed\r
+E57000-E57FFF     (base 16)            Iradimed\r
+                               1025 Willa Springs Dr.\r
+                               Winter Springs  FL  32708-____\r
+                               US\r
 \r
-70-B3-D5   (hex)               CMT Medical technologies\r
-950000-950FFF     (base 16)            CMT Medical technologies\r
-                               Hacarmel 7/2\r
-                               Yoqneam    20692\r
-                               IL\r
+70-B3-D5   (hex)               Securolytics, Inc.\r
+125000-125FFF     (base 16)            Securolytics, Inc.\r
+                               2002 Summit Boulevard, Suite 300\r
+                               Atlanta  GA  30319\r
+                               US\r
 \r
-70-B3-D5   (hex)               Harvard Technology Ltd\r
-56A000-56AFFF     (base 16)            Harvard Technology Ltd\r
-                               Tyler Close, Normanton\r
-                               Wakefield    WF6 1RL\r
-                               GB\r
+70-B3-D5   (hex)               Orion Technologies, LLC\r
+C6E000-C6EFFF     (base 16)            Orion Technologies, LLC\r
+                               12605 Challenger Pkwy, Ste 130\r
+                               ORLANDO  FL  32826\r
+                               US\r
+\r
+70-B3-D5   (hex)               PROFEN COMMUNICATIONS\r
+CC8000-CC8FFF     (base 16)            PROFEN COMMUNICATIONS\r
+                               Famas Plaza A Blok Kat: 10 No:35 Okmeydani\r
+                               Istanbul    34384\r
+                               TR\r
+\r
+70-B3-D5   (hex)               Design SHIFT\r
+FDB000-FDBFFF     (base 16)            Design SHIFT\r
+                               3475 Edison Way, Suite G\r
+                               Menlo Park  CA  94025\r
+                               US\r
+\r
+70-B3-D5   (hex)               Romteck Australia\r
+791000-791FFF     (base 16)            Romteck Australia\r
+                               37 Collingwood St Osborne Park\r
+                               Perth  Western Australia  6017\r
+                               AU\r
+\r
+70-B3-D5   (hex)               Rheonics GmbH\r
+D20000-D20FFF     (base 16)            Rheonics GmbH\r
+                               Rheonics GmbH, Technoparkstr. 2\r
+                               Winterthur  Schweiz  8406\r
+                               CH\r
+\r
+70-B3-D5   (hex)               T+A elektroakustik GmbH & Co.KG\r
+69F000-69FFFF     (base 16)            T+A elektroakustik GmbH & Co.KG\r
+                               Planckstr. 9-11\r
+                               Herford    32052\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Kazan Networks Corporation\r
+768000-768FFF     (base 16)            Kazan Networks Corporation\r
+                               660 Auburn Folsom Rd, Suite 204\r
+                               Auburn  CA  95722\r
+                               US\r
 \r
-70-B3-D5   (hex)               Keepen\r
-69C000-69CFFF     (base 16)            Keepen\r
-                               12, rue Anselme\r
-                               Saint-Ouen    93400\r
+70-B3-D5   (hex)               CRDE\r
+6B2000-6B2FFF     (base 16)            CRDE\r
+                               ZI DES GRANDS CAMPS\r
+                               MERCUES  LOT  46090\r
                                FR\r
 \r
-70-B3-D5   (hex)               Abionic\r
-BC1000-BC1FFF     (base 16)            Abionic\r
-                               Route de la Corniche 5\r
-                               Epalinges    1066\r
-                               CH\r
+70-B3-D5   (hex)               JASCO Applied Sciences Canada Ltd\r
+7F7000-7F7FFF     (base 16)            JASCO Applied Sciences Canada Ltd\r
+                               32 Troop Avenue, Suite 202\r
+                               Dartmouth  Nova Scotia  B3B 1Z1\r
+                               CA\r
 \r
-70-B3-D5   (hex)               MiWave Consulting, LLC\r
-0E1000-0E1FFF     (base 16)            MiWave Consulting, LLC\r
-                               1117 Paine Court\r
-                               Raleigh  NC  27609\r
+70-B3-D5   (hex)               Matsuhisa Corporation\r
+F42000-F42FFF     (base 16)            Matsuhisa Corporation\r
+                               55-20 Katayama-cho\r
+                               Fukui-shi    910-3611\r
+                               JP\r
+\r
+70-B3-D5   (hex)               CRDE\r
+381000-381FFF     (base 16)            CRDE\r
+                               ZI DES GRANDS CAMPS\r
+                               MERCUES  LOT  46090\r
+                               FR\r
+\r
+70-B3-D5   (hex)               Cardinal Scale Mfg Co\r
+488000-488FFF     (base 16)            Cardinal Scale Mfg Co\r
+                               203 E. Daugherty\r
+                               Webb City  MO  64870\r
                                US\r
 \r
-70-B3-D5   (hex)               PROEL TSI s.r.l.\r
-5CF000-5CFFFF     (base 16)            PROEL TSI s.r.l.\r
-                               VIA DIVISIONE JULIA, 10\r
-                               MANZANO  UD  33044\r
-                               IT\r
+70-B3-D5   (hex)               WeVo Tech\r
+273000-273FFF     (base 16)            WeVo Tech\r
+                               2985 Drew Road\r
+                               Mississauga   Ontario  L4T0A4\r
+                               CA\r
 \r
-70-B3-D5   (hex)               Compusign Systems Pty Ltd\r
-050000-050FFF     (base 16)            Compusign Systems Pty Ltd\r
-                               8/10 Clarice Road\r
-                               Box Hill  Victoria  3128\r
-                               AU\r
+70-B3-D5   (hex)               Vensi, Inc.\r
+379000-379FFF     (base 16)            Vensi, Inc.\r
+                               113 McHenry Rd #191\r
+                               Buffalo Grove  IL  60089\r
+                               US\r
 \r
-70-B3-D5   (hex)               Advansid \r
-3F7000-3F7FFF     (base 16)            Advansid \r
-                               Via Alla Cascata 56/C\r
-                               Trento    38123\r
-                               IT\r
+70-B3-D5   (hex)               ndb technologies\r
+0B2000-0B2FFF     (base 16)            ndb technologies\r
+                               1405-111 Av Saint-Jean-Baptiste\r
+                               Quebec  Quebec  G2E5K2\r
+                               CA\r
 \r
-70-B3-D5   (hex)               SCHMID electronic\r
-764000-764FFF     (base 16)            SCHMID electronic\r
-                               Badstrasse 39\r
-                               Reutlingen    72766\r
-                               DE\r
+70-B3-D5   (hex)               KST technology\r
+CB3000-CB3FFF     (base 16)            KST technology\r
+                               KST B/D 4-5, Wiryeseong-daero 12-gil\r
+                               Songpa-gu  Seoul  05636\r
+                               KR\r
 \r
-70-B3-D5   (hex)               dA Tomato Limited\r
-966000-966FFF     (base 16)            dA Tomato Limited\r
-                               8/2 Paribag, Hatirpool, Motaleb Tower, Tower 1, 11A\r
-                               Dhaka  DAC  1000\r
-                               BD\r
+70-B3-D5   (hex)               Fiberbase\r
+30D000-30DFFF     (base 16)            Fiberbase\r
+                               #516 Complex-dong Heongduk IT Valley, Heonduk 1ro 13, Giheong-gu\r
+                               Young-in  Gyeong-gi  16954\r
+                               KR\r
 \r
-70-B3-D5   (hex)               Dr. Zinngrebe GmbH\r
-42E000-42EFFF     (base 16)            Dr. Zinngrebe GmbH\r
-                               Schillerstraße 1/15\r
-                               Ulm  Baden-Württemberg  89077\r
-                               DE\r
+70-B3-D5   (hex)               PLUTO Solution co.,ltd.\r
+842000-842FFF     (base 16)            PLUTO Solution co.,ltd.\r
+                               B-1018, Kumkang Penterium IT Tower, 282, Hagui-ro, Dongan-gu\r
+                               Anyang-si  Gyeonggi-do  14056\r
+                               KR\r
 \r
-70-B3-D5   (hex)               Cooltera Limited\r
-DD5000-DD5FFF     (base 16)            Cooltera Limited\r
-                               Fircroft House, Fircroft Way\r
-                               Edenbridge  Kent  TN8 6EJ\r
-                               GB\r
+70-B3-D5   (hex)               Thiel Audio Products Company, LLC\r
+EB9000-EB9FFF     (base 16)            Thiel Audio Products Company, LLC\r
+                               566 Mainstream Dr, Suite 500\r
+                               Nashville  TN  37228\r
+                               US\r
 \r
 70-B3-D5   (hex)               TATTILE SRL\r
-937000-937FFF     (base 16)            TATTILE SRL\r
+2CA000-2CAFFF     (base 16)            TATTILE SRL\r
                                VIA DONIZETTI, 1/3/5\r
                                MAIRANO  BRESCIA  25030\r
                                IT\r
 \r
-70-B3-D5   (hex)               DAVE SRL\r
-189000-189FFF     (base 16)            DAVE SRL\r
-                               VIA TALPONEDO 29/A\r
-                               PORCIA  PORDENONE  330850\r
-                               IT\r
-\r
-70-B3-D5   (hex)               MB connect line GmbH Fernwartungssysteme\r
-BD8000-BD8FFF     (base 16)            MB connect line GmbH Fernwartungssysteme\r
-                               Winnettener Straße 6\r
-                               Dinkelsbuehl  Bavaria  91550\r
-                               DE\r
+70-B3-D5   (hex)               DORLET SAU\r
+8E3000-8E3FFF     (base 16)            DORLET SAU\r
+                               Albert Eistein 34\r
+                               Alava  SPAIN  01510\r
+                               ES\r
 \r
-70-B3-D5   (hex)               winsun AG\r
-F67000-F67FFF     (base 16)            winsun AG\r
-                               Beeschi Mattenstrasse 2\r
-                               Steg  Wallis  3940\r
-                               CH\r
+70-B3-D5   (hex)               Gentec Systems  Co.\r
+469000-469FFF     (base 16)            Gentec Systems  Co.\r
+                               5F., No.51-3, Fuxing Rd., Xindian Dist., \r
+                               New Taipei City     23150\r
+                               TW\r
 \r
-70-B3-D5   (hex)               Daatrics LTD\r
-A5F000-A5FFFF     (base 16)            Daatrics LTD\r
-                               4th Floor, 86-90 Paul Street\r
-                               LONDON    EC2A 4NE\r
+70-B3-D5   (hex)               Exi Flow Measurement Ltd\r
+AAF000-AAFFFF     (base 16)            Exi Flow Measurement Ltd\r
+                               Unit 22 Ford Lane business Park\r
+                               Ford, ARUNDEL  West Sussex  BN164HP\r
                                GB\r
 \r
-70-B3-D5   (hex)               Videoport S.A.\r
-441000-441FFF     (base 16)            Videoport S.A.\r
-                               Sigma Business Center, Building A Nivel 2\r
-                               San Pedro  San Jose  11501\r
-                               CR\r
-\r
-70-B3-D5   (hex)               Dokuen Co. Ltd.\r
-334000-334FFF     (base 16)            Dokuen Co. Ltd.\r
-                               12-3 minami-matsunoki-cho higashi-kujo minami-ku\r
-                               kyoto    6018023\r
-                               JP\r
-\r
-70-B3-D5   (hex)               NIRIT- Xinwei  Telecom Technology Co., Ltd.\r
-F27000-F27FFF     (base 16)            NIRIT- Xinwei  Telecom Technology Co., Ltd.\r
-                               2-й Кожуховский проезд, д.12, стр.2\r
-                               Moscow    115432\r
-                               RU\r
+70-B3-D5   (hex)               OÜ ELIKO Tehnoloogia Arenduskeskus\r
+D4A000-D4AFFF     (base 16)            OÜ ELIKO Tehnoloogia Arenduskeskus\r
+                               Mäealuse 2/1\r
+                               Tallinn  Harju  12618\r
+                               EE\r
 \r
-70-B3-D5   (hex)               AML\r
-759000-759FFF     (base 16)            AML\r
-                               2190 Regal Parkway\r
-                               Euless  TX  76040\r
-                               US\r
+70-B3-D5   (hex)               SEASON DESIGN TECHNOLOGY\r
+2C9000-2C9FFF     (base 16)            SEASON DESIGN TECHNOLOGY\r
+                               FLOOR 4, WARDS EXCHANGE, 199 ECCLESALL ROAD\r
+                               SHEFFIELD  SOUTH YORKSHIRE  S11 8HW\r
+                               GB\r
 \r
-70-B3-D5   (hex)               Beijing HuaLian Technology Co, Ltd.\r
-623000-623FFF     (base 16)            Beijing HuaLian Technology Co, Ltd.\r
-                               Floor4 16C, north district of Ufida software park, No. 68 Beiqing road, HaiDian district.\r
-                               Beijing  Beijing  100094\r
-                               CN\r
+70-B3-D5   (hex)               BCD Audio\r
+728000-728FFF     (base 16)            BCD Audio\r
+                               5 Bristol Way, Stoke Gardens\r
+                               Slough  Berkshire  SL1 3QE\r
+                               GB\r
 \r
-70-B3-D5   (hex)               Private\r
-B71000-B71FFF     (base 16)            Private\r
+70-B3-D5   (hex)               Resolution Systems\r
+D89000-D89FFF     (base 16)            Resolution Systems\r
+                               1/214 Greenhill Rd\r
+                               Eastwood  South Australia  6063\r
+                               AU\r
 \r
-70-B3-D5   (hex)               MicroElectronics System Co.Ltd\r
-8DA000-8DAFFF     (base 16)            MicroElectronics System Co.Ltd\r
-                               29 uchihata-cho Nishinokyo Nakagyoku\r
-                               Kyoto City  Kyoto-fu  604-8411\r
-                               JP\r
+70-B3-D5   (hex)               WARECUBE,INC\r
+F06000-F06FFF     (base 16)            WARECUBE,INC\r
+                               #A-811, 142-10, Saneop-ro, 156beon-gil, Gwonseon-gu\r
+                               Suwon-si    16648\r
+                               KR\r
 \r
-70-B3-D5   (hex)               Software Systems Plus\r
-7DC000-7DCFFF     (base 16)            Software Systems Plus\r
-                               9924 N. Ash Avenue\r
-                               Kansas City    64157\r
+70-B3-D5   (hex)               Roxford\r
+651000-651FFF     (base 16)            Roxford\r
+                               PO Box 231851\r
+                               Encinitas  CA  92023-1851\r
                                US\r
 \r
-70-B3-D5   (hex)               Telefire\r
-2E8000-2E8FFF     (base 16)            Telefire\r
-                               43 hasivim \r
-                               Petah Tikva  Israel  49000\r
-                               IL\r
+70-B3-D5   (hex)               Scenario Automation\r
+8B4000-8B4FFF     (base 16)            Scenario Automation\r
+                               Rua Paulo Elias, 216\r
+                               São Carlos  São Paulo  13564400\r
+                               BR\r
 \r
-70-B3-D5   (hex)               Opti-Sciences, Inc.\r
-338000-338FFF     (base 16)            Opti-Sciences, Inc.\r
-                               8 Winn Ave\r
-                               Hudson  NH  03051\r
-                               US\r
+70-B3-D5   (hex)               Talleres de Escoriaza SA\r
+532000-532FFF     (base 16)            Talleres de Escoriaza SA\r
+                               Barrio Ventas, 35\r
+                               Irun  Gipuzkoa  20305\r
+                               ES\r
 \r
-70-B3-D5   (hex)               eze System, Inc.\r
-2F5000-2F5FFF     (base 16)            eze System, Inc.\r
-                               785 Orchard Dr #100\r
-                               Folsom  CA  95630\r
-                               US\r
+70-B3-D5   (hex)               MB connect line GmbH Fernwartungssysteme\r
+8D9000-8D9FFF     (base 16)            MB connect line GmbH Fernwartungssysteme\r
+                               Winnettener Straße 6\r
+                               Dinkelsbuehl  Bavaria  91550\r
+                               DE\r
 \r
-00-1B-C5   (hex)               Corporate Systems Engineering \r
-015000-015FFF     (base 16)            Corporate Systems Engineering \r
-                               1215 Brookville Way\r
-                               Indianapolis   IN  46239\r
-                               US\r
+70-B3-D5   (hex)               Eurotek Srl\r
+1D1000-1D1FFF     (base 16)            Eurotek Srl\r
+                               Strada Comunale Savonesa, 9\r
+                               Rivalta Scrivia  AL  15050\r
+                               IT\r
+\r
+70-B3-D5   (hex)               Redcap Solutions s.r.o.\r
+027000-027FFF     (base 16)            Redcap Solutions s.r.o.\r
+                               Na Viničních Horách 16\r
+                               Praha 6    16000\r
+                               CZ\r
 \r
-70-B3-D5   (hex)               Private\r
-580000-580FFF     (base 16)            Private\r
+70-B3-D5   (hex)               SiFive\r
+92F000-92FFFF     (base 16)            SiFive\r
+                               1875 S Grant St\r
+                               San Mateo  CA  94403\r
+                               US\r
 \r
-70-B3-D5   (hex)               WICELL TECHNOLOGY\r
-BB0000-BB0FFF     (base 16)            WICELL TECHNOLOGY\r
-                               61 Dien Bien Phu\r
-                               Ho Chi Minh    700000\r
-                               VN\r
+70-B3-D5   (hex)               Telefrank GmbH\r
+A82000-A82FFF     (base 16)            Telefrank GmbH\r
+                               Am Wildengrund 1\r
+                               Altenambach  TH  98553\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Waldo System\r
-CA1000-CA1FFF     (base 16)            Waldo System\r
-                               4th Floor, 658, Yangcheon-ro, Gangseo-gu,\r
-                               Seoul     07554\r
-                               KR\r
+70-B3-D5   (hex)               EIFFAGE ENERGIE ELECTRONIQUE\r
+037000-037FFF     (base 16)            EIFFAGE ENERGIE ELECTRONIQUE\r
+                               D937\r
+                               VERQUIN    62131\r
+                               FR\r
 \r
-70-B3-D5   (hex)               DogWatch Inc\r
-302000-302FFF     (base 16)            DogWatch Inc\r
-                               10 Michigan Drive\r
-                               Natick  MA  01760\r
+70-B3-D5   (hex)               Blue Marble Communications, Inc.\r
+77E000-77EFFF     (base 16)            Blue Marble Communications, Inc.\r
+                               9520 Padgett St, Suite 101\r
+                               San Diego  CA  92126\r
                                US\r
 \r
-70-B3-D5   (hex)               Zumbach Electronic AG\r
-B10000-B10FFF     (base 16)            Zumbach Electronic AG\r
-                               Hauptstrasse 93\r
-                               Orpund  Bern  2552\r
-                               CH\r
+70-B3-D5   (hex)               D.T.S Illuminazione Srl \r
+D7C000-D7CFFF     (base 16)            D.T.S Illuminazione Srl \r
+                               Via Fagnano Selve,  12 / 14\r
+                               Misano Adriatico   Rimini   47843\r
+                               IT\r
 \r
-70-B3-D5   (hex)               EvoLogics GmbH\r
-F9B000-F9BFFF     (base 16)            EvoLogics GmbH\r
-                               Ackerstr. 76\r
-                               Berlin    13355\r
+70-B3-D5   (hex)               Duerkopp-Adler\r
+3C9000-3C9FFF     (base 16)            Duerkopp-Adler\r
+                               Potsdamerstr. 190\r
+                               Bielefeld    33719\r
                                DE\r
 \r
-70-B3-D5   (hex)               SOREL GmbH Mikroelektronik\r
-A84000-A84FFF     (base 16)            SOREL GmbH Mikroelektronik\r
-                               REME-Str. 12\r
-                               Wetter    58300\r
+70-B3-D5   (hex)               DiTEST Fahrzeugdiagnose GmbH\r
+109000-109FFF     (base 16)            DiTEST Fahrzeugdiagnose GmbH\r
+                               ALTE POSTSTRASSE 152\r
+                               A-8020  GRAZ  STEIERMARK\r
+                               AT\r
+\r
+70-B3-D5   (hex)               MSB Elektronik und Gerätebau GmbH\r
+E9E000-E9EFFF     (base 16)            MSB Elektronik und Gerätebau GmbH\r
+                               Hofwiesenstr. 23\r
+                               Crailsheim    74564\r
                                DE\r
 \r
-70-B3-D5   (hex)               Qingdao CNR HITACH Railway Signal&communication co.,ltd\r
-802000-802FFF     (base 16)            Qingdao CNR HITACH Railway Signal&communication co.,ltd\r
-                               231-2 Ruichang Road\r
-                               Qingdao    266031\r
+70-B3-D5   (hex)               GL TECH CO.,LTD\r
+248000-248FFF     (base 16)            GL TECH CO.,LTD\r
+                               No. Ten Changchun Road\r
+                               ZHENGZHOU  HENAN  455000\r
                                CN\r
 \r
-70-B3-D5   (hex)               WiSuite USA\r
-19A000-19AFFF     (base 16)            WiSuite USA\r
-                               13201 Stephens Road Suite E\r
-                               Warren  MI  48089\r
-                               US\r
-\r
-70-B3-D5   (hex)               Lightdrop\r
-072000-072FFF     (base 16)            Lightdrop\r
-                               Matiční 730/3\r
-                               Ostrava    70200\r
-                               CZ\r
-\r
-70-B3-D5   (hex)               dds\r
-F21000-F21FFF     (base 16)            dds\r
-                               606, Woolim Lions Valley 2Cha, 2, Gasan digital 1-ro Geumcheon-gu\r
-                               Seoul    08591\r
-                               KR\r
-\r
-70-B3-D5   (hex)               COPPERNIC SAS\r
-25F000-25FFFF     (base 16)            COPPERNIC SAS\r
-                               185 avenue Archimede\r
-                               Aix en Provence    13857\r
+70-B3-D5   (hex)               CAPSYS\r
+A0A000-A0AFFF     (base 16)            CAPSYS\r
+                               ZI Parc technologique des Fontaines\r
+                               BERNIN    38190\r
                                FR\r
 \r
-70-B3-D5   (hex)               Rhythm Engineering, LLC.\r
-57A000-57AFFF     (base 16)            Rhythm Engineering, LLC.\r
-                               11228 Thompson Ave.\r
-                               Lenexa  KS  66219\r
+70-B3-D5   (hex)               Centero\r
+CE2000-CE2FFF     (base 16)            Centero\r
+                               1640 Powers Ferry Road Bldg.14-360\r
+                               Marietta  GA  30067\r
                                US\r
 \r
-70-B3-D5   (hex)               Taejin InforTech\r
-A75000-A75FFF     (base 16)            Taejin InforTech\r
-                               40, Imi-ro, A-411\r
-                               Uiwang-si  Gyeonggi-do  16006\r
-                               KR\r
+70-B3-D5   (hex)               Ellenex Pty Ltd\r
+CD0000-CD0FFF     (base 16)            Ellenex Pty Ltd\r
+                               91 Tope Street\r
+                               South Melbourne  VIC  3205\r
+                               AU\r
 \r
-70-B3-D5   (hex)               MEGGITT\r
-1EE000-1EEFFF     (base 16)            MEGGITT\r
-                               14600 MYFORD RD\r
-                               IRVINE  CA  92606\r
-                               US\r
+70-B3-D5   (hex)               Tecsys do Brasil Industrial Ltda\r
+9AA000-9AAFFF     (base 16)            Tecsys do Brasil Industrial Ltda\r
+                               Rua Oros, 146\r
+                               Sao Jose dos Campos  SP  12237150\r
+                               BR\r
 \r
-70-B3-D5   (hex)               Smashtag Ltd\r
-F6F000-F6FFFF     (base 16)            Smashtag Ltd\r
-                               Unit B6 Beech House, Melbourn Science Park\r
-                               Royston  Hertfordshire  SG8 6HB\r
-                               GB\r
+70-B3-D5   (hex)               LINEAGE POWER PVT LTD.,\r
+0C9000-0C9FFF     (base 16)            LINEAGE POWER PVT LTD.,\r
+                               30-A1, KIADB, 1ST PHASE INDUSTRIAL ESTATE,KUMBALGODU, BANGALORE-MYSORE ROAD\r
+                               BANGALORE  KARNATAKA  560074\r
+                               IN\r
 \r
-70-B3-D5   (hex)               YUYAMA MFG Co.,Ltd\r
-2DE000-2DEFFF     (base 16)            YUYAMA MFG Co.,Ltd\r
-                               3-3-1\r
-                               TOYONAKASHI  OSAKA  561-0841\r
-                               JP\r
+70-B3-D5   (hex)               Heng Dian Technology Co., Ltd\r
+FEA000-FEAFFF     (base 16)            Heng Dian Technology Co., Ltd\r
+                               No.9, Yunmei Road,Tianmulake Town\r
+                               Liyang  Jiangsu  213300\r
+                               CN\r
 \r
-70-B3-D5   (hex)               CRDMDEVEOPPEMENTS\r
-B5F000-B5FFFF     (base 16)            CRDMDEVEOPPEMENTS\r
-                               13 Petit chemin de la generale\r
-                               Villenave d'Ornon  Gironde  33140\r
+70-B3-D5   (hex)               TELEPLATFORMS\r
+5FB000-5FBFFF     (base 16)            TELEPLATFORMS\r
+                               Polbina st., 3/1\r
+                               Moscow    109388\r
+                               RU\r
+\r
+70-B3-D5   (hex)               LG Electronics\r
+9E3000-9E3FFF     (base 16)            LG Electronics\r
+                               10, Magokjungang 10-ro, Gangseo-gu\r
+                               Seoul    07796\r
+                               KR\r
+\r
+70-B3-D5   (hex)               HORIZON TELECOM\r
+960000-960FFF     (base 16)            HORIZON TELECOM\r
+                               6 rue de GUEUGNON\r
+                               MONTCEAU LES MINES    71300\r
                                FR\r
 \r
-70-B3-D5   (hex)               Open System Solutions Limited\r
-FAB000-FABFFF     (base 16)            Open System Solutions Limited\r
-                               Unit 33, Mitchell Point, Ensign Way\r
-                               Southampton  Hampshire  SO31 4RF\r
-                               GB\r
+70-B3-D5   (hex)               Beijing Daswell Science and Technology Co.LTD\r
+06F000-06FFFF     (base 16)            Beijing Daswell Science and Technology Co.LTD\r
+                               6th floor,Building B,Dachen Industry Park, NO.10 Jingyuan Street, BDA\r
+                               Beijing  Beijing  100176\r
+                               CN\r
 \r
-70-B3-D5   (hex)               SOFTLAND INDIA LTD\r
-C29000-C29FFF     (base 16)            SOFTLAND INDIA LTD\r
-                               #14A, KINFRA SMALL INDUSTRIES PARK, MENAMKULAM, KAZHAKOOTTAM\r
-                               TRIVANDRUM  KERALA  695586\r
-                               IN\r
+70-B3-D5   (hex)               Private\r
+73A000-73AFFF     (base 16)            Private\r
 \r
-70-B3-D5   (hex)               Scame Sistemi srl\r
-F04000-F04FFF     (base 16)            Scame Sistemi srl\r
-                               Via Lombardia 5\r
-                               Arluno  Milan  20010\r
-                               IT\r
+70-B3-D5   (hex)               Alere Technologies AS\r
+F52000-F52FFF     (base 16)            Alere Technologies AS\r
+                               Kjelsaasveien 161\r
+                               Oslo  Oslo  0382\r
+                               NO\r
 \r
-70-B3-D5   (hex)               SYS TEC electronic GmbH\r
-41B000-41BFFF     (base 16)            SYS TEC electronic GmbH\r
-                               Am Windrad 2\r
-                               Heinsdorfergrund     D-08468\r
+70-B3-D5   (hex)               Impolux GmbH\r
+EEC000-EECFFF     (base 16)            Impolux GmbH\r
+                               Boschstr. 7\r
+                               Kastellaun  RLP  56288\r
                                DE\r
 \r
-70-B3-D5   (hex)               Alcohol Countermeasure Systems\r
-FD0000-FD0FFF     (base 16)            Alcohol Countermeasure Systems\r
-                               60 International Blvd\r
-                               Toronto  Ontario  M9W 6J2\r
-                               CA\r
+70-B3-D5   (hex)               Beijing Nacao Technology Co., Ltd.\r
+105000-105FFF     (base 16)            Beijing Nacao Technology Co., Ltd.\r
+                               1912B, Zhongguancunkemao Building, Zhongguancun Da Jie\r
+                               Beijing    100080\r
+                               CN\r
 \r
-70-B3-D5   (hex)               PEEK TRAFFIC\r
-0C7000-0C7FFF     (base 16)            PEEK TRAFFIC\r
-                               5401 N SAM HOUSTON PKWY W\r
-                               HOUSTON    77086\r
+70-B3-D5   (hex)               machineQ\r
+3E6000-3E6FFF     (base 16)            machineQ\r
+                               1900 market st\r
+                               philadelphia  PA  19103\r
                                US\r
 \r
-70-B3-D5   (hex)               Project Service S.r.l.\r
-A2D000-A2DFFF     (base 16)            Project Service S.r.l.\r
-                               Via Paderno 31/C\r
-                               Seriate (BG)    24068\r
-                               IT\r
+70-B3-D5   (hex)               eumig industrie-TV GmbH.\r
+AA2000-AA2FFF     (base 16)            eumig industrie-TV GmbH.\r
+                               Gewerbeparkstrasse 9\r
+                               Anif  Salzburg  5081\r
+                               AT\r
 \r
-70-B3-D5   (hex)               SwineTech, Inc.\r
-DC2000-DC2FFF     (base 16)            SwineTech, Inc.\r
-                               230 2nd Street SE, Ste 302\r
-                               Cedar Rapids  IA  52401\r
-                               US\r
+70-B3-D5   (hex)               FSTUDIO CO LTD\r
+C0B000-C0BFFF     (base 16)            FSTUDIO CO LTD\r
+                               Yanagawa Bldg. 2F 5-16-13\r
+                               Watanabe-Dori Chuo-ku Fukuoka  Fukuoka  810-0004\r
+                               JP\r
 \r
-70-B3-D5   (hex)               OSMOZIS\r
-A9B000-A9BFFF     (base 16)            OSMOZIS\r
-                               7 AVENUE DE L'EUROPE\r
-                               CLAPIERS  LANGUEDOC ROUSSSILLON  34830\r
-                               FR\r
+70-B3-D5   (hex)               YUYAMA MFG Co.,Ltd\r
+DB4000-DB4FFF     (base 16)            YUYAMA MFG Co.,Ltd\r
+                               3-3-1\r
+                               TOYONAKASHI  OSAKA  561-0841\r
+                               JP\r
+\r
+70-B3-D5   (hex)               Smith Meter, Inc.\r
+706000-706FFF     (base 16)            Smith Meter, Inc.\r
+                               1602 Wagner Ave.\r
+                               Erie    16514\r
+                               US\r
 \r
-70-B3-D5   (hex)               Electrónica Falcón S.A.U\r
-36E000-36EFFF     (base 16)            Electrónica Falcón S.A.U\r
-                               Polígono Industrial Escopar, Calle E, Nº 1\r
-                               Peralta  Navarra  31350\r
-                               ES\r
+70-B3-D5   (hex)               EGICON SRL\r
+6F7000-6F7FFF     (base 16)            EGICON SRL\r
+                               Via Posta Vecchia 36\r
+                               Mirandola  Modena  41037\r
+                               IT\r
 \r
-70-B3-D5   (hex)               WAVES SYSTEM\r
-CE4000-CE4FFF     (base 16)            WAVES SYSTEM\r
-                               La Ville en Bois\r
-                               BOUAYE  Loire Atlantique  44830\r
-                               FR\r
+70-B3-D5   (hex)               Symetrics Industries d.b.a. Extant Aerospace\r
+0A8000-0A8FFF     (base 16)            Symetrics Industries d.b.a. Extant Aerospace\r
+                               1615 West NASA Blvd\r
+                               Melbourne  FL  32901\r
+                               US\r
 \r
-70-B3-D5   (hex)               HeadsafeIP PTY LTD\r
-800000-800FFF     (base 16)            HeadsafeIP PTY LTD\r
-                               231 Birrell st\r
-                               bronte  nsw  2024\r
-                               AU\r
+70-B3-D5   (hex)               CRESPRIT INC.\r
+C38000-C38FFF     (base 16)            CRESPRIT INC.\r
+                               D-315 ,177, Jeongjail-ro, Bundang-gu\r
+                               Seongnam-si    13557\r
+                               KR\r
 \r
-70-B3-D5   (hex)               Tieline Research Pty Ltd\r
-FCB000-FCBFFF     (base 16)            Tieline Research Pty Ltd\r
-                               PO Box 2092\r
-                               MALAGA  Western Australia  6944\r
-                               AU\r
+70-B3-D5   (hex)               alfamation spa\r
+675000-675FFF     (base 16)            alfamation spa\r
+                               via cadore 21\r
+                               lissone  mb  20851\r
+                               IT\r
 \r
-70-B3-D5   (hex)               LG Electronics\r
-4F1000-4F1FFF     (base 16)            LG Electronics\r
-                               Science Park W5, 10, Magokjungang 10-ro, Gangseo-gu\r
-                               Seoul    07796\r
+70-B3-D5   (hex)               KST technology\r
+C05000-C05FFF     (base 16)            KST technology\r
+                               KST B/D 4-5, Wiryeseong-daero 12-gil\r
+                               Songpa-gu  Seoul  05636\r
                                KR\r
 \r
-70-B3-D5   (hex)                Zhiye Electronics Co., Ltd.\r
-8E2000-8E2FFF     (base 16)             Zhiye Electronics Co., Ltd.\r
-                               No. 1117, Pioneer Road, High-tech Zone\r
-                               Jinan City  Shandong Province  250101\r
-                               CN\r
+70-B3-D5   (hex)               ETA Technology Pvt Ltd\r
+A94000-A94FFF     (base 16)            ETA Technology Pvt Ltd\r
+                               No. 484-D, 13th Cross, IV Phase, Peenya Industrial Area,\r
+                               Bangalore  Karnataka  560058\r
+                               IN\r
 \r
-70-B3-D5   (hex)               ifak technology + service GmbH\r
-264000-264FFF     (base 16)            ifak technology + service GmbH\r
-                               Ludwig-Erhard-Allee 10\r
-                               Karlsruhe    76131\r
-                               DE\r
+70-B3-D5   (hex)               Newshine\r
+A64000-A64FFF     (base 16)            Newshine\r
+                               Pingcheng Rd\r
+                               Shanghai  Shanghai  201800\r
+                               CN\r
 \r
-70-B3-D5   (hex)               ABB S.p.A.\r
-5A7000-5A7FFF     (base 16)            ABB S.p.A.\r
-                               Via Pisani 16\r
-                               Milano  MI  20124\r
-                               IT\r
+70-B3-D5   (hex)               Guan Show Technologe Co., Ltd.\r
+E2B000-E2BFFF     (base 16)            Guan Show Technologe Co., Ltd.\r
+                               No.127, Jianguo 1st Rd., Lingya Dist.\r
+                                Kaohsiung City     802\r
+                               TW\r
 \r
-70-B3-D5   (hex)               OOO Alyans\r
-107000-107FFF     (base 16)            OOO Alyans\r
-                               9 maya, 20\r
-                               Krasnoyarsk  Krasnoyarski Krai  660125\r
-                               RU\r
+70-B3-D5   (hex)               CMT Medical technologies\r
+950000-950FFF     (base 16)            CMT Medical technologies\r
+                               Hacarmel 7/2\r
+                               Yoqneam    20692\r
+                               IL\r
 \r
-70-B3-D5   (hex)               Alere Technologies AS\r
-91C000-91CFFF     (base 16)            Alere Technologies AS\r
-                               Kjelsaasveien 161\r
-                               Oslo  Oslo  0382\r
-                               NO\r
+70-B3-D5   (hex)               Harvard Technology Ltd\r
+56A000-56AFFF     (base 16)            Harvard Technology Ltd\r
+                               Tyler Close, Normanton\r
+                               Wakefield    WF6 1RL\r
+                               GB\r
 \r
-70-B3-D5   (hex)               Transas Marine Limited\r
-ED8000-ED8FFF     (base 16)            Transas Marine Limited\r
-                               10 Eastgate Avenue, Eastgate Business Park\r
-                               Little Island, Cork    0\r
-                               IE\r
+70-B3-D5   (hex)               Keepen\r
+69C000-69CFFF     (base 16)            Keepen\r
+                               12, rue Anselme\r
+                               Saint-Ouen    93400\r
+                               FR\r
 \r
-70-B3-D5   (hex)               Private\r
-A03000-A03FFF     (base 16)            Private\r
+70-B3-D5   (hex)               Abionic\r
+BC1000-BC1FFF     (base 16)            Abionic\r
+                               Route de la Corniche 5\r
+                               Epalinges    1066\r
+                               CH\r
 \r
-70-B3-D5   (hex)               SA Photonics\r
-E17000-E17FFF     (base 16)            SA Photonics\r
-                               120 Knowles Drive\r
-                               Los Gatos  CA  95032\r
+70-B3-D5   (hex)               MiWave Consulting, LLC\r
+0E1000-0E1FFF     (base 16)            MiWave Consulting, LLC\r
+                               1117 Paine Court\r
+                               Raleigh  NC  27609\r
                                US\r
 \r
-70-B3-D5   (hex)               Private\r
-9EE000-9EEFFF     (base 16)            Private\r
+70-B3-D5   (hex)               PROEL TSI s.r.l.\r
+5CF000-5CFFFF     (base 16)            PROEL TSI s.r.l.\r
+                               VIA DIVISIONE JULIA, 10\r
+                               MANZANO  UD  33044\r
+                               IT\r
 \r
-70-B3-D5   (hex)               Elbit Systems of America\r
-B7E000-B7EFFF     (base 16)            Elbit Systems of America\r
-                               4700 Marine Creek Parkway\r
-                               Fort Worth  TX  76179\r
-                               US\r
+70-B3-D5   (hex)               Compusign Systems Pty Ltd\r
+050000-050FFF     (base 16)            Compusign Systems Pty Ltd\r
+                               8/10 Clarice Road\r
+                               Box Hill  Victoria  3128\r
+                               AU\r
 \r
-70-B3-D5   (hex)               QuestHouse, Inc.\r
-84B000-84BFFF     (base 16)            QuestHouse, Inc.\r
-                               Rm 204, 5 B/D, 20 Techno 1-ro, Yuseong-gu\r
-                               Daejeon    34016\r
-                               KR\r
+70-B3-D5   (hex)               Advansid \r
+3F7000-3F7FFF     (base 16)            Advansid \r
+                               Via Alla Cascata 56/C\r
+                               Trento    38123\r
+                               IT\r
 \r
-70-B3-D5   (hex)               Monnit Corporation\r
-D1A000-D1AFFF     (base 16)            Monnit Corporation\r
-                               3400 S West Temple\r
-                               Taylorsville  UT  84115\r
-                               US\r
+70-B3-D5   (hex)               SCHMID electronic\r
+764000-764FFF     (base 16)            SCHMID electronic\r
+                               Badstrasse 39\r
+                               Reutlingen    72766\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Smart Controls LLC\r
-199000-199FFF     (base 16)            Smart Controls LLC\r
-                               10000 St. Clair Ave.\r
-                               Fairview Heights  IL  62208\r
-                               US\r
+70-B3-D5   (hex)               dA Tomato Limited\r
+966000-966FFF     (base 16)            dA Tomato Limited\r
+                               8/2 Paribag, Hatirpool, Motaleb Tower, Tower 1, 11A\r
+                               Dhaka  DAC  1000\r
+                               BD\r
 \r
-70-B3-D5   (hex)               ENTEC Electric & Electronic Co., LTD.\r
-1DF000-1DFFFF     (base 16)            ENTEC Electric & Electronic Co., LTD.\r
-                               78-2 Buncheon-ri, Bongdam-eup\r
-                               Hwaseong-city  Gyungki-do  445-894\r
-                               KR\r
+70-B3-D5   (hex)               Dr. Zinngrebe GmbH\r
+42E000-42EFFF     (base 16)            Dr. Zinngrebe GmbH\r
+                               Schillerstraße 1/15\r
+                               Ulm  Baden-Württemberg  89077\r
+                               DE\r
 \r
-70-B3-D5   (hex)               GMI Ltd\r
-C93000-C93FFF     (base 16)            GMI Ltd\r
-                               Inchinnan Business Park\r
-                               Renfre    PA4 9RG\r
+70-B3-D5   (hex)               Cooltera Limited\r
+DD5000-DD5FFF     (base 16)            Cooltera Limited\r
+                               Fircroft House, Fircroft Way\r
+                               Edenbridge  Kent  TN8 6EJ\r
                                GB\r
 \r
-70-B3-D5   (hex)               YUYAMA MFG Co.,Ltd\r
-150000-150FFF     (base 16)            YUYAMA MFG Co.,Ltd\r
-                               3-3-1\r
-                               TOYONAKASHI  OSAKA  561-0841\r
-                               JP\r
-\r
-70-B3-D5   (hex)               OBSERVER FOUNDATION\r
-633000-633FFF     (base 16)            OBSERVER FOUNDATION\r
-                               Narva mnt 5\r
-                               Tallinn city  Harju county  10117\r
-                               EE\r
+70-B3-D5   (hex)               TATTILE SRL\r
+937000-937FFF     (base 16)            TATTILE SRL\r
+                               VIA DONIZETTI, 1/3/5\r
+                               MAIRANO  BRESCIA  25030\r
+                               IT\r
 \r
-70-B3-D5   (hex)               MECT SRL\r
-7C4000-7C4FFF     (base 16)            MECT SRL\r
-                               VIA E. FERMI 57/59\r
-                               ALPIGNANO    10091\r
+70-B3-D5   (hex)               DAVE SRL\r
+189000-189FFF     (base 16)            DAVE SRL\r
+                               VIA TALPONEDO 29/A\r
+                               PORCIA  PORDENONE  330850\r
                                IT\r
 \r
-70-B3-D5   (hex)               Benetel\r
-E15000-E15FFF     (base 16)            Benetel\r
-                               Guinness Enterprise Centre, Taylors Lane,\r
-                               Dublin    D08 XV25\r
-                               IE\r
+70-B3-D5   (hex)               MB connect line GmbH Fernwartungssysteme\r
+BD8000-BD8FFF     (base 16)            MB connect line GmbH Fernwartungssysteme\r
+                               Winnettener Straße 6\r
+                               Dinkelsbuehl  Bavaria  91550\r
+                               DE\r
 \r
-70-B3-D5   (hex)               XANTIA SA\r
-33F000-33FFFF     (base 16)            XANTIA SA\r
-                               Chemin du Longchamps 99\r
-                               Bienne    2504\r
+70-B3-D5   (hex)               winsun AG\r
+F67000-F67FFF     (base 16)            winsun AG\r
+                               Beeschi Mattenstrasse 2\r
+                               Steg  Wallis  3940\r
                                CH\r
 \r
-70-B3-D5   (hex)               Divelbiss Corporation\r
-F43000-F43FFF     (base 16)            Divelbiss Corporation\r
-                               9778 Mount Gilead Road\r
-                               Fredericktown  OH  43019\r
+70-B3-D5   (hex)               Daatrics LTD\r
+A5F000-A5FFFF     (base 16)            Daatrics LTD\r
+                               4th Floor, 86-90 Paul Street\r
+                               LONDON    EC2A 4NE\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Videoport S.A.\r
+441000-441FFF     (base 16)            Videoport S.A.\r
+                               Sigma Business Center, Building A Nivel 2\r
+                               San Pedro  San Jose  11501\r
+                               CR\r
+\r
+70-B3-D5   (hex)               Dokuen Co. Ltd.\r
+334000-334FFF     (base 16)            Dokuen Co. Ltd.\r
+                               12-3 minami-matsunoki-cho higashi-kujo minami-ku\r
+                               kyoto    6018023\r
+                               JP\r
+\r
+70-B3-D5   (hex)               AMS Controls, Inc.\r
+444000-444FFF     (base 16)            AMS Controls, Inc.\r
+                               12180 Prichard Farm Road\r
+                               Maryland Heights  MO  63043\r
                                US\r
 \r
-70-B3-D5   (hex)               INTERNET PROTOCOLO LOGICA SL\r
-275000-275FFF     (base 16)            INTERNET PROTOCOLO LOGICA SL\r
-                               Sector Foresta 43, local 26\r
-                               Tres Cantos  Madrid  28760\r
-                               ES\r
+70-B3-D5   (hex)               3S - Sensors, Signal Processing, Systems GmbH\r
+982000-982FFF     (base 16)            3S - Sensors, Signal Processing, Systems GmbH\r
+                               Saar-Lor-Lux-Straße 11\r
+                               Saarbrücken    66115\r
+                               DE\r
+\r
+70-B3-D5   (hex)               AMEDTEC Medizintechnik Aue GmbH\r
+50A000-50AFFF     (base 16)            AMEDTEC Medizintechnik Aue GmbH\r
+                               Schneeberger Str. 5\r
+                               Aue    08280\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Integrotech sp. z o.o.\r
-6BA000-6BAFFF     (base 16)            Integrotech sp. z o.o.\r
-                               plac Zwyciestwa 2 bud. D\r
-                               Lodz  lodzkie  90-312\r
-                               PL\r
+70-B3-D5   (hex)               RCH ITALIA SPA \r
+42D000-42DFFF     (base 16)            RCH ITALIA SPA \r
+                               Via Cendon 39\r
+                               SILEA  Treviso  31057\r
+                               IT\r
 \r
-70-B3-D5   (hex)               Invent Vision - iVision Sistemas de Imagem e Visão S.A.\r
-E29000-E29FFF     (base 16)            Invent Vision - iVision Sistemas de Imagem e Visão S.A.\r
-                               R. Prof. José Vieira de Mendonça, 770, 2° andar - BHTEC, Parque Tecnológico de Belo Horizonte\r
-                               Belo Horizonte  Minas Gerais  31310-260\r
-                               BR\r
+70-B3-D5   (hex)               BESO sp. z o.o.\r
+C00000-C00FFF     (base 16)            BESO sp. z o.o.\r
+                               Mlynska 1a\r
+                               Brzeg Dolny    56-120\r
+                               PL\r
 \r
-70-B3-D5   (hex)               Altaneos\r
-69A000-69AFFF     (base 16)            Altaneos\r
-                               Chaussée Verte, 93B\r
-                               Saint-Georges    4470\r
-                               BE\r
+70-B3-D5   (hex)               Carlo Gavazzi Industri\r
+EFF000-EFFFFF     (base 16)            Carlo Gavazzi Industri\r
+                               Over Hadstenvej 40\r
+                               Hadsten  Denmark  8370\r
+                               DK\r
 \r
-70-B3-D5   (hex)               Sicon srl\r
-BEE000-BEEFFF     (base 16)            Sicon srl\r
-                               Via Sila 1/3\r
-                               Isola Vicentina  Vicenza  36033\r
+70-B3-D5   (hex)               RCH ITALIA SPA \r
+99B000-99BFFF     (base 16)            RCH ITALIA SPA \r
+                               VIA CENDON 39\r
+                               SILEA   TREVISO   31057\r
                                IT\r
 \r
+70-B3-D5   (hex)               Arevita\r
+5E1000-5E1FFF     (base 16)            Arevita\r
+                               Baltu ave 145\r
+                               Kaunas  Select  47125\r
+                               LT\r
+\r
+70-B3-D5   (hex)               AutomationX GmbH\r
+CD7000-CD7FFF     (base 16)            AutomationX GmbH\r
+                               Lauzilgasse 13\r
+                               Graz  Styria  8020\r
+                               AT\r
+\r
 70-B3-D5   (hex)               Private\r
-E2D000-E2DFFF     (base 16)            Private\r
+580000-580FFF     (base 16)            Private\r
 \r
-70-B3-D5   (hex)               Flexsolution APS\r
-C54000-C54FFF     (base 16)            Flexsolution APS\r
-                               Østervangsvej 39\r
-                               Esbjerg N  Jylland  6715\r
-                               DK\r
+70-B3-D5   (hex)               Private\r
+401000-401FFF     (base 16)            Private\r
 \r
-70-B3-D5   (hex)               EXARA Group\r
-00C000-00CFFF     (base 16)            EXARA Group\r
-                               Andropova pr. 18 1\r
-                               Moscow    115432\r
-                               RU\r
+70-B3-D5   (hex)               Hermann Automation GmbH\r
+B2F000-B2FFFF     (base 16)            Hermann Automation GmbH\r
+                               Erlenwiese 15\r
+                               Mengerskirchen  Hessen  D-35794\r
+                               DE\r
 \r
-70-B3-D5   (hex)               Orlaco Products B.V.\r
-620000-620FFF     (base 16)            Orlaco Products B.V.\r
-                               Albert Plesmanstraat 42\r
-                               Barneveld    3772MN\r
-                               NL\r
+70-B3-D5   (hex)               INTERNET PROTOCOLO LOGICA SL\r
+B58000-B58FFF     (base 16)            INTERNET PROTOCOLO LOGICA SL\r
+                               Sector Foresta 43, local 26\r
+                               Tres Cantos  Madrid  28760\r
+                               ES\r
+\r
+70-B3-D5   (hex)               Legrand Electric Ltd\r
+093000-093FFF     (base 16)            Legrand Electric Ltd\r
+                               Unit 10 Cowley Road\r
+                               Blyth  Northumberland  NE24 5TF\r
+                               GB\r
 \r
 70-B3-D5   (hex)               Schildknecht AG\r
 494000-494FFF     (base 16)            Schildknecht AG\r
@@ -10058,12 +10256,6 @@ FAE000-FAEFFF     (base 16)            Silixa Ltd
                                Virginia Beach  VA  23452\r
                                US\r
 \r
-70-B3-D5   (hex)               RCH Italia SpA\r
-7FE000-7FEFFF     (base 16)            RCH Italia SpA\r
-                               Via Cendon 39\r
-                               SILEA  Treviso  31057\r
-                               IT\r
-\r
 70-B3-D5   (hex)               Korea Airports Corporation\r
 2CD000-2CDFFF     (base 16)            Korea Airports Corporation\r
                                78 Haneul-gil Gangseo-gu\r
@@ -10295,9 +10487,6 @@ C66000-C66FFF     (base 16)             Blue Access Inc
                                CATTOLICA   RIMINI   47841\r
                                IT\r
 \r
-70-B3-D5   (hex)               Private\r
-A9F000-A9FFFF     (base 16)            Private\r
-\r
 70-B3-D5   (hex)               Burk Technology\r
 985000-985FFF     (base 16)            Burk Technology\r
                                7 Beaver Brook road\r
@@ -10911,10 +11100,10 @@ BA8000-BA8FFF     (base 16)           Controlled Power Company
                                US\r
 \r
 70-B3-D5   (hex)               Private\r
-30E000-30EFFF     (base 16)            Private\r
+4F8000-4F8FFF     (base 16)            Private\r
 \r
 70-B3-D5   (hex)               Private\r
-4F8000-4F8FFF     (base 16)            Private\r
+30E000-30EFFF     (base 16)            Private\r
 \r
 70-B3-D5   (hex)               Vega-Absolute\r
 0AD000-0ADFFF     (base 16)            Vega-Absolute\r
@@ -10934,6 +11123,144 @@ DD9000-DD9FFF     (base 16)           MaNima Technologies BV
                                SWANSEA  WEST GLAMORGAN  SA6 8RH\r
                                GB\r
 \r
+70-B3-D5   (hex)               PAL Inc.\r
+05B000-05BFFF     (base 16)            PAL Inc.\r
+                               2217-2 Hayashicho\r
+                               Takamatsu  Kagawa  7610301\r
+                               JP\r
+\r
+70-B3-D5   (hex)               Clever Devices\r
+A2B000-A2BFFF     (base 16)            Clever Devices\r
+                               300 Crossways Park Dr\r
+                               Woodbury  NY  11797\r
+                               US\r
+\r
+70-B3-D5   (hex)               NanoSense\r
+8ED000-8EDFFF     (base 16)            NanoSense\r
+                               123 rue de Bellevue, RDC\r
+                               Boulogne Billancourt    92100\r
+                               FR\r
+\r
+70-B3-D5   (hex)               Blake UK\r
+9DA000-9DAFFF     (base 16)            Blake UK\r
+                               177-187, Rutland Road\r
+                               Sheffield  --select--  S3 9PT\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Angora Networks\r
+822000-822FFF     (base 16)            Angora Networks\r
+                               Alacaatli Mah. Park Cad 47/31, Cayyolu\r
+                               Ankara    06810\r
+                               TR\r
+\r
+70-B3-D5   (hex)               Thruvision Limited\r
+4FA000-4FAFFF     (base 16)            Thruvision Limited\r
+                               121 Olympic Avenue, Milton Park\r
+                               Abingdon  Oxfordshire  OX14 4SA\r
+                               GB\r
+\r
+70-B3-D5   (hex)               ABB\r
+080000-080FFF     (base 16)            ABB\r
+                               Fulachstrasse 150\r
+                               Schaffhausen    8200\r
+                               CH\r
+\r
+70-B3-D5   (hex)               Transit Solutions, LLC.\r
+019000-019FFF     (base 16)            Transit Solutions, LLC.\r
+                               114 West Grandview Avenue\r
+                               Zelienople    16063\r
+                               US\r
+\r
+70-B3-D5   (hex)               Virsae Group Ltd\r
+151000-151FFF     (base 16)            Virsae Group Ltd\r
+                               B:HIVE, 74 Taharoto Road, Smales Farm\r
+                               Takapuna  Auckland  0622\r
+                               NZ\r
+\r
+70-B3-D5   (hex)               FRESENIUS MEDICAL CARE\r
+4CC000-4CCFFF     (base 16)            FRESENIUS MEDICAL CARE\r
+                               496 So. Abbott Ave\r
+                               Milpitas  CA  95035\r
+                               US\r
+\r
+70-B3-D5   (hex)               Leonardo Sistemi Integrati S.r.l.\r
+111000-111FFF     (base 16)            Leonardo Sistemi Integrati S.r.l.\r
+                               Via Greto di Cornigliano, 6R\r
+                               Genova    16152\r
+                               IT\r
+\r
+70-B3-D5   (hex)               RCH ITALIA SPA \r
+7FE000-7FEFFF     (base 16)            RCH ITALIA SPA \r
+                               Via Cendon 39\r
+                               SILEA  Treviso  31057\r
+                               IT\r
+\r
+70-B3-D5   (hex)               AEye, Inc.\r
+B52000-B52FFF     (base 16)            AEye, Inc.\r
+                               5700 Stoneridge Drive, Suite 102\r
+                               Pleasanton  CA  94588\r
+                               US\r
+\r
+70-B3-D5   (hex)               GJD Manufacturing\r
+E25000-E25FFF     (base 16)            GJD Manufacturing\r
+                               Unit 2, Birch Business Park, Whittle Lane\r
+                               Heywood    OL10 2SX\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Melecs EWS GmbH\r
+E8A000-E8AFFF     (base 16)            Melecs EWS GmbH\r
+                               GZO-Technologiestrasse 1\r
+                               Siegendorf     7011\r
+                               AT\r
+\r
+70-B3-D5   (hex)               Umano Medical Inc.\r
+E1E000-E1EFFF     (base 16)            Umano Medical Inc.\r
+                               230, Boul. Nilus-Leclerc\r
+                               L'Islet  Québec  G0R 2C0\r
+                               CA\r
+\r
+70-B3-D5   (hex)               DORLET SAU\r
+8DF000-8DFFFF     (base 16)            DORLET SAU\r
+                               Albert Eistein 34\r
+                               Alava  SPAIN  01510\r
+                               ES\r
+\r
+70-B3-D5   (hex)               Private\r
+A9F000-A9FFFF     (base 16)            Private\r
+\r
+70-B3-D5   (hex)               KRONOTECH SRL\r
+D56000-D56FFF     (base 16)            KRONOTECH SRL\r
+                               VIALE UNGHERIA 125\r
+                               UDINE  ITALY/UDINE  33100\r
+                               IT\r
+\r
+70-B3-D5   (hex)               Ascon Tecnologic S.r.l.\r
+57E000-57EFFF     (base 16)            Ascon Tecnologic S.r.l.\r
+                               via Indipendenza, 56\r
+                               Vigevano  PV  27029\r
+                               IT\r
+\r
+70-B3-D5   (hex)               Private\r
+2D7000-2D7FFF     (base 16)            Private\r
+\r
+70-B3-D5   (hex)               GeoSpectrum Technologies Inc\r
+3CB000-3CBFFF     (base 16)            GeoSpectrum Technologies Inc\r
+                               10 Akerley Blvd, #19\r
+                               Dartmouth  Nova Scotia  B3B1J4\r
+                               CA\r
+\r
+70-B3-D5   (hex)               Heim- & Bürokommunikation Ilmert e.K.\r
+DF4000-DF4FFF     (base 16)            Heim- & Bürokommunikation Ilmert e.K.\r
+                               Jakobsbrunnenstr. 14\r
+                               Frankfurt am Main    60386\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Echogear\r
+571000-571FFF     (base 16)            Echogear\r
+                               12884 Frontrunner Blvd Ste 201\r
+                               Draper  UT  84020\r
+                               US\r
+\r
 70-B3-D5   (hex)               Innitive B.V.\r
 66B000-66BFFF     (base 16)            Innitive B.V.\r
                                Brouwerijstraat 20\r
@@ -13982,12 +14309,6 @@ A54000-A54FFF     (base 16)            provedo
                                Waterloo    1410\r
                                BE\r
 \r
-70-B3-D5   (hex)               RCH Italia SpA\r
-857000-857FFF     (base 16)            RCH Italia SpA\r
-                               Via Cendon 39\r
-                               SILEA  Treviso  31057\r
-                               IT\r
-\r
 70-B3-D5   (hex)               IONETECH\r
 876000-876FFF     (base 16)            IONETECH\r
                                #50,sicheongseo4gil\r
@@ -14687,6 +15008,138 @@ D3A000-D3AFFF     (base 16)           PROMOMED RUS LLC
                                SEONGNAM-SI  JUNGWON-GU  13376\r
                                KR\r
 \r
+70-B3-D5   (hex)               Clean-Lasersysteme GmbH\r
+C5F000-C5FFFF     (base 16)            Clean-Lasersysteme GmbH\r
+                               Dornkaulstr. 6-8\r
+                               Herzogenrath  NRW  52134\r
+                               DE\r
+\r
+70-B3-D5   (hex)               ELINKGATE JSC\r
+37E000-37EFFF     (base 16)            ELINKGATE JSC\r
+                               J4A Buu Long Dist 10\r
+                               Ho Chi Minh  Vietnam  70350\r
+                               VN\r
+\r
+70-B3-D5   (hex)               Automata GmbH & Co. KG\r
+1F9000-1F9FFF     (base 16)            Automata GmbH & Co. KG\r
+                               Gewerbering 5\r
+                               Ried  Bavaria  86510\r
+                               DE\r
+\r
+70-B3-D5   (hex)               EYEDEA\r
+FB9000-FB9FFF     (base 16)            EYEDEA\r
+                               Rm.367, 3Fl., Enterprise Support Hub, 815, Daewangpangyo-ro, Sujeong-gu \r
+                               Seongnam-si  Gyeonggi-do  13449\r
+                               KR\r
+\r
+70-B3-D5   (hex)               Automata Spa\r
+E14000-E14FFF     (base 16)            Automata Spa\r
+                               Via Carducci 705\r
+                               Caronno Pertusella  Varese  21042\r
+                               IT\r
+\r
+70-B3-D5   (hex)               Grossenbacher Systeme AG\r
+BB5000-BB5FFF     (base 16)            Grossenbacher Systeme AG\r
+                               Spinnereistrasse 10\r
+                               St. Gallen    9008\r
+                               CH\r
+\r
+70-B3-D5   (hex)               APE GmbH\r
+8C4000-8C4FFF     (base 16)            APE GmbH\r
+                               Plauener Str. 163-165, Haus N\r
+                               Berlin    13053\r
+                               DE\r
+\r
+70-B3-D5   (hex)               RCH ITALIA SPA \r
+857000-857FFF     (base 16)            RCH ITALIA SPA \r
+                               Via Cendon 39\r
+                               SILEA  Treviso  31057\r
+                               IT\r
+\r
+70-B3-D5   (hex)                Eastone Century Technology Co.,Ltd.\r
+210000-210FFF     (base 16)             Eastone Century Technology Co.,Ltd.\r
+                               A12 Floor, Information Port, 16 Keyun Road, Tianhe DistrictGuangzhou\r
+                               Guangzhou  GuangDong  510000\r
+                               CN\r
+\r
+70-B3-D5   (hex)               RITEC\r
+AC0000-AC0FFF     (base 16)            RITEC\r
+                               25 East Easy St\r
+                               Simi Valley  CA  93065\r
+                               US\r
+\r
+70-B3-D5   (hex)               INFRASAFE/ ADVANTOR SYSTEMS \r
+5BA000-5BAFFF     (base 16)            INFRASAFE/ ADVANTOR SYSTEMS \r
+                               12612 CHALLENGER PARKWAY \r
+                               ORLANDO  FL  32826\r
+                               US\r
+\r
+70-B3-D5   (hex)               Yite technology\r
+BC9000-BC9FFF     (base 16)            Yite technology\r
+                               No. 56, Xiaobei Rd., North Dist\r
+                               Tainan    70448\r
+                               TW\r
+\r
+70-B3-D5   (hex)               NTO IRE-POLUS\r
+6FE000-6FEFFF     (base 16)            NTO IRE-POLUS\r
+                               Akademika Vvedenskogo 1/2\r
+                               Fryazino    141190\r
+                               RU\r
+\r
+70-B3-D5   (hex)               Idneo Technologies S.A.U.\r
+CF8000-CF8FFF     (base 16)            Idneo Technologies S.A.U.\r
+                               Gran Via Carlos III , 98 Planta 5\r
+                               Barcelona  Barcelona  08028\r
+                               ES\r
+\r
+70-B3-D5   (hex)               Syscom Instruments SA\r
+BE7000-BE7FFF     (base 16)            Syscom Instruments SA\r
+                               industrie 21\r
+                               Sainte-Croix    1450\r
+                               CH\r
+\r
+70-B3-D5   (hex)               DAO QIN TECHNOLOGY CO.LTD.\r
+3BD000-3BDFFF     (base 16)            DAO QIN TECHNOLOGY CO.LTD.\r
+                               No. 359, Zhongxiao Rd\r
+                               Chishang Township  Taitung County  958\r
+                               TW\r
+\r
+70-B3-D5   (hex)               MB connect line GmbH Fernwartungssysteme\r
+CC6000-CC6FFF     (base 16)            MB connect line GmbH Fernwartungssysteme\r
+                               Winnettener Straße 6\r
+                               Dinkelsbuehl  Bavaria  91550\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Technological Application and Production One Member Liability Company (Tecapro company)\r
+456000-456FFF     (base 16)            Technological Application and Production One Member Liability Company (Tecapro company)\r
+                               18A Cong Hoa street\r
+                               Ho Chi Minh city  Ho Chi Minh city  700000\r
+                               VN\r
+\r
+70-B3-D5   (hex)               Yamamoto Works Ltd.\r
+DFB000-DFBFFF     (base 16)            Yamamoto Works Ltd.\r
+                               3-1-3 Kashiwaza\r
+                               Ageo  Saitama  3620075\r
+                               JP\r
+\r
+70-B3-D5   (hex)               BAYKON Endüstriyel Kontrol Sistemleri San. ve Tic. A.Ş.\r
+258000-258FFF     (base 16)            BAYKON Endüstriyel Kontrol Sistemleri San. ve Tic. A.Ş.\r
+                               Kimya Sanayicileri Org. San. Bolgesi Organik Cad. No:31\r
+                               Istanbul  Tuzla   34956\r
+                               TR\r
+\r
+70-B3-D5   (hex)               GlooVir Inc.\r
+47A000-47AFFF     (base 16)            GlooVir Inc.\r
+                               #413, 96 Gajeongbuk-Ro\r
+                               Daejeon  Yuseong  34111\r
+                               KR\r
+\r
+70-B3-D5   (hex)               WARECUBE,INC\r
+463000-463FFF     (base 16)            WARECUBE,INC\r
+                               #A-811, 142-10, Saneop-ro, 156beon-gil, Gwonseon-gu\r
+                               Suwon-si    16648\r
+                               KR\r
+\r
 70-B3-D5   (hex)               EMAC, Inc.\r
 8AB000-8ABFFF     (base 16)            EMAC, Inc.\r
                                2390 EMAC Way\r
@@ -18313,3 +18766,93 @@ BD4000-BD4FFF     (base 16)            YUYAMA MFG Co.,Ltd
                                7F, No. 143, Sec. 3, Cheng Gong Road,, Neihu District\r
                                Taipei  Taiwan  114\r
                                TW\r
+\r
+70-B3-D5   (hex)               Sikom AS\r
+237000-237FFF     (base 16)            Sikom AS\r
+                               Neptunvegen 6\r
+                               Verdal    7652\r
+                               NO\r
+\r
+70-B3-D5   (hex)               Cobo, Inc.\r
+EAD000-EADFFF     (base 16)            Cobo, Inc.\r
+                               3624 Alta Vista Avenue\r
+                               Santa Rosa  CA  95409\r
+                               US\r
+\r
+70-B3-D5   (hex)               ICT BUSINESS GROUP of Humanrights Center for disabled people\r
+B20000-B20FFF     (base 16)            ICT BUSINESS GROUP of Humanrights Center for disabled people\r
+                               #A1101-6,70 Gyeongin-ro 71-gil,\r
+                               Seoul  Yeongdeungpo-gu  07286\r
+                               KR\r
+\r
+70-B3-D5   (hex)               MULTIVOICE LLC\r
+B06000-B06FFF     (base 16)            MULTIVOICE LLC\r
+                               224 S. Main St #401\r
+                               Springville  UT  84660\r
+                               US\r
+\r
+70-B3-D5   (hex)               EMDEP CENTRO TECNOLOGICO MEXICO\r
+83A000-83AFFF     (base 16)            EMDEP CENTRO TECNOLOGICO MEXICO\r
+                               Circuito Corral de Piedras #36, Polígono Empresarial San Miguel\r
+                               San Miguel de Allende  Guanajuato  37880\r
+                               MX\r
+\r
+70-B3-D5   (hex)               OCEANCCTV LTD\r
+FD5000-FD5FFF     (base 16)            OCEANCCTV LTD\r
+                               4F., No. 1, Ln. 297, Xinyi Rd.,Banqiao Dist.,\r
+                               New Taipei City    220\r
+                               TW\r
+\r
+70-B3-D5   (hex)               Cetto Industries\r
+B73000-B73FFF     (base 16)            Cetto Industries\r
+                               Dechenstr. 9-15\r
+                               Ratingen    40878\r
+                               DE\r
+\r
+70-B3-D5   (hex)               Xiris Automation Inc.\r
+9BF000-9BFFFF     (base 16)            Xiris Automation Inc.\r
+                               1016 Sutton Dr, Unit C5\r
+                               Burlington  Ontario  L7L 6B8\r
+                               CA\r
+\r
+70-B3-D5   (hex)               wtec GmbH\r
+ABD000-ABDFFF     (base 16)            wtec GmbH\r
+                               Dornbachstrasse 1a\r
+                               Bad Homburg    61352\r
+                               DE\r
+\r
+70-B3-D5   (hex)               LG Electronics\r
+884000-884FFF     (base 16)            LG Electronics\r
+                               19, Yangje-daero 11gil, Seocho-gu\r
+                               Seoul    06772\r
+                               KR\r
+\r
+70-B3-D5   (hex)               Prolan Zrt.\r
+C04000-C04FFF     (base 16)            Prolan Zrt.\r
+                               Szentendrei út 1-3.\r
+                               Budakalasz    2011\r
+                               HU\r
+\r
+70-B3-D5   (hex)               Morgan Schaffer Inc.\r
+1F7000-1F7FFF     (base 16)            Morgan Schaffer Inc.\r
+                               8300 rue St-Patrick bureau 150\r
+                               LaSalle  Quebec  H8N 2H1\r
+                               CA\r
+\r
+70-B3-D5   (hex)               Season Electronics Ltd\r
+65E000-65EFFF     (base 16)            Season Electronics Ltd\r
+                               600 Nest Business Park \r
+                               Havant  Hampshire  PO9 5TL\r
+                               GB\r
+\r
+70-B3-D5   (hex)               Beijing PanGu Company\r
+E54000-E54FFF     (base 16)            Beijing PanGu Company\r
+                               Beijing agricultural college\r
+                               Beijing    100010\r
+                               CN\r
+\r
+70-B3-D5   (hex)               Innotas Elektronik GmbH\r
+C51000-C51FFF     (base 16)            Innotas Elektronik GmbH\r
+                               Rathenaustr. 18a\r
+                               Zittau    D-02763\r
+                               DE\r
index c986f78..2b4fe96 100644 (file)
@@ -1,8 +1,8 @@
 #
 #      List of PCI ID's
 #
-#      Version: 2019.02.13
-#      Date:    2019-02-13 03:15:01
+#      Version: 2019.04.06
+#      Date:    2019-04-06 03:15:02
 #
 #      Maintained by Albert Pool, Martin Mares, and other volunteers from
 #      the PCI ID Project at https://pci-ids.ucw.cz/.
 0eac  SHF Communication Technologies AG
        0008  Ethernet Powerlink Managing Node 01
 0f62  Acrox Technologies Co., Ltd.
-# Formerly NCR
-1000  LSI Logic / Symbios Logic
+1000  Broadcom / LSI
        0001  53c810
                1000 1000  LSI53C810AE PCI to SCSI I/O Processor
        0002  53c820
                1000 1000  LSI53C875A PCI to Ultra SCSI Controller
        0014  MegaRAID Tri-Mode SAS3516
                1028 1fd4  PERC H745P MX
+               1137 020e  UCSC-RAID-M5 12G Modular RAID Controller
                1d49 0602  ThinkSystem RAID 930-16i 4GB Flash PCIe 12Gb Adapter
                1d49 0604  ThinkSystem RAID 930-8e 4GB Flash PCIe 12Gb Adapter
                1d49 0607  ThinkSystem RAID 930-16i 8GB Flash PCIe 12Gb Adapter
                8086 3510  RMS25PB080 RAID Controller
                8086 3511  RMS25PB040 RAID Controller
                8086 3512  RMT3PB080 RAID Controller
-               8086 3513  RMS25CB080 RAID Controller
+               8086 3513  Integrated RAID Module RMS25CB080
                8086 3514  RMS25CB040 RAID Controller
                8086 351c  RMS25PB080N RAID Controller
                8086 351d  RMS25CB080N RAID Controller
        0062  SAS1078 PCI-Express Fusion-MPT SAS
                1000 0062  SAS1078 PCI-Express Fusion-MPT SAS
        0064  SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor]
+               1000 3030  9200-16e 6Gb/s SAS/SATA PCIe x8 External HBA
                1000 30c0  SAS 9201-16i
+               1000 30d0  9201-16e 6Gb/s SAS/SATA PCIe x8 External HBA
        0065  SAS2116 PCI-Express Fusion-MPT SAS-2 [Meteor]
        006e  SAS2308 PCI-Express Fusion-MPT SAS-2
        0070  SAS2004 PCI-Express Fusion-MPT SAS-2 [Spitfire]
                1000 9241  MegaRAID SAS 9240-4i
                1000 92a0  MegaRAID SAS 9220-8i
                1014 03b1  ServeRAID M1015 SAS/SATA Controller
+               1014 040d  ServeRAID M1115 SAS/SATA Controller
                1028 1f4e  PERC H310 Adapter
                1028 1f4f  PERC H310 Integrated
                1028 1f50  PERC H310 Mini Blades
        1636  Renoir
        1714  BeaverCreek HDMI Audio [Radeon HD 6500D and 6400G-6600G series]
                103c 168b  ProBook 4535s
-       2191  TU116M
        3150  RV380/M24 [Mobility Radeon X600]
                103c 0934  nx8220
        3151  RV380 GL [FireMV 2400]
                1462 3413  Radeon RX 480 Gaming X 8GB
                1462 3416  Radeon RX 570
                1462 3418  Radeon RX 580 Armor 4G OC
+               1462 8a92  Radeon RX 580
                148c 2372  Radeon RX 480
                148c 2373  Radeon RX 470
                1682 9470  Radeon RX 470
                1682 9480  Radeon RX 480
                1682 9588  Radeon RX 580 XTR
+               1682 c570  Radeon RX 570
                174b e347  Radeon RX 470/480
                174b e349  Radeon RX 470
                1787 a470  Radeon RX 470
        67e9  Baffin [Polaris11]
        67eb  Baffin [Radeon Pro V5300X]
        67ef  Baffin [Radeon RX 460/560D / Pro 450/455/460/555/555X/560/560X]
+               103c 3421  Radeon RX 460
                106b 0160  Radeon Pro 460
                106b 0166  Radeon Pro 455
                106b 0167  Radeon Pro 450
        6868  Vega 10 [Radeon PRO WX 8100/8200]
        686c  Vega 10 [Radeon Instinct MI25 MxGPU]
        687f  Vega 10 XL/XT [Radeon RX Vega 56/64]
+               1002 0b36  RX Vega64
+               1002 6b76  RX Vega56
        6880  Lexington [Radeon HD 6550M]
                103c 163c  Pavilion dv6 Radeon HD 6550M
        6888  Cypress XT [FirePro V8800]
        9613  RS780MC [Mobility Radeon HD 3100]
        9614  RS780D [Radeon HD 3300]
        9616  RS780L [Radeon 3000]
-       9640  BeaverCreek [Radeon HD 6550D]
-       9641  BeaverCreek [Radeon HD 6620G]
-       9642  Sumo [Radeon HD 6370D]
-       9643  Sumo [Radeon HD 6380G]
-       9644  Sumo [Radeon HD 6410D]
-       9645  Sumo [Radeon HD 6410D]
-       9647  BeaverCreek [Radeon HD 6520G]
+       9640  Sumo [Radeon HD 6550D]
+       9641  Sumo [Radeon HD 6620G]
+       9642  SuperSumo [Radeon HD 6370D]
+       9643  SuperSumo [Radeon HD 6380G]
+       9644  SuperSumo [Radeon HD 6410D]
+       9645  SuperSumo [Radeon HD 6410D]
+       9647  Sumo [Radeon HD 6520G]
        9648  Sumo [Radeon HD 6480G]
-       9649  Sumo [Radeon HD 6480G]
-       964a  BeaverCreek [Radeon HD 6530D]
+       9649  SuperSumo [Radeon HD 6480G]
+       964a  Sumo [Radeon HD 6530D]
        964b  Sumo
        964c  Sumo
        964e  Sumo
                174b aa98  Radeon HD 6450 1GB DDR3
        aaa0  Tahiti HDMI Audio [Radeon HD 7870 XT / 7950/7970]
        aab0  Oland/Hainan/Cape Verde/Pitcairn HDMI Audio [Radeon HD 7000 Series]
+       aab8  Tiran HDMI Audio
        aac0  Tobago HDMI Audio [Radeon R7 360 / R9 360 OEM]
        aac8  Hawaii HDMI Audio [Radeon R9 290/290X / 390/390X]
        aad8  Tonga HDMI Audio [Radeon R9 285/380]
        1434  Liverpool Processor SPLL Configuration
        1436  Liverpool Processor Root Complex
        1437  Liverpool I/O Memory Management Unit
-       1438  Liverpool Processor Root Port
+       1438  Liverpool UMI PCIe Dummy Host Bridge
        1439  Family 16h Processor Functions 5:1
        143a  Kingston/Clayton/Gladius/Montego Root Complex
        143b  Kingston/Clayton/Gladius/Montego P2P Bridge for UMI Link
        145c  Family 17h (Models 00h-0fh) USB 3.0 Host Controller
        145d  Zeppelin Switch Upstream (PCIE SW.US)
        145e  Zeppelin Switch Downstream (PCIE SW.DS)
-       145f  USB 3.0 Host controller
+       145f  Zeppelin USB 3.0 Host controller
        1460  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 0
        1461  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 1
        1462  Family 17h (Models 00h-0fh) Data Fabric: Device 18h; Function 2
        1645  Broadcom NetXtreme BCM5701 Gigabit Ethernet
        1801  T2 Bridge Controller
        1802  T2 Secure Enclave Processor
+       1803  Apple Audio Device
        2001  S1X NVMe Controller
        2002  S3ELab NVMe Controller
        2003  S3X NVMe Controller
                1077 02a7  QL45212-DE 25GbE Adapter
                1077 e4f6  FastLinQ QL45211H 25GbE Adapter
                1077 e4f7  FastLinQ QL45212H 25GbE Adapter
+               1590 0245  10/20/25GbE 2P 4820c CNA
        165c  FastLinQ QL45000 Series 10/25/40/50GbE Controller (FCoE)
                1077 0034  QL45262 Flex 50Gb 2-port Ethernet Adapter w/ iSCSI/FCoE
                1077 e4f1  FastLinQ QL45462H 40GbE FCoE Adapter
                1077 e4f2  FastLinQ QL45461H 40GbE FCoE Adapter
+               1590 0245  10/20/25GbE 2P 4820c CNA FCoE
        165e  FastLinQ QL45000 Series 10/25/40/50GbE Controller (iSCSI)
                1077 0034  QL45262 Flex 50Gb 2-port Ethernet Adapter w/ iSCSI/FCoE
                1077 e4f1  FastLinQ QL45462H 40GbE iSCSI Adapter
                1077 e4f2  FastLinQ QL45461H 40GbE iSCSI Adapter
+               1590 0245  10/20/25GbE 2P 4820c CNA iSCSI
        1664  FastLinQ QL45000 Series Gigabit Ethernet Controller (SR-IOV VF)
                1077 e4f1  FastLinQ QL45462H 40GbE Adapter (SR-IOV VF)
                1077 e4f2  FastLinQ QL45461H 40GbE Adapter (SR-IOV VF)
                1077 e4f6  FastLinQ QL45211H 25GbE Adapter (SR-IOV VF)
                1077 e4f7  FastLinQ QL45212H 25GbE Adapter (SR-IOV VF)
                1077 e4f8  FastLinQ QL45611H 100GbE Adapter (SR-IOV VF)
+               1590 0245  10/20/25GbE 2P 4820c CNA SRIOV
        2020  ISP2020A Fast!SCSI Basic Adapter
        2031  ISP8324-based 16Gb Fibre Channel to PCI Express Adapter
                103c 17e7  SN1000Q 16Gb Single Port Fibre Channel Adapter
                1077 029e  QLE2694 Quad Port 16Gb Fibre Channel to PCIe Adapter
                1077 02a2  QLE2694L Quad Port 16Gb Fibre Channel to PCIe Adapter
                1077 02ad  QLE2694U Quad Port 16/32Gb Fibre Channel to PCIe Adapter
+       2081  ISP2814-based 64/32G Fibre Channel to PCIe Controller
+               1077 02e1  QLE2874 Quad Port 64GFC PCIe Gen4 x16 Adapter
+               1077 02e3  QLE2774 Quad Port 32GFC PCIe Gen4 x16 Adapter
        2100  QLA2100 64-bit Fibre Channel Adapter
                1077 0001  QLA2100 64-bit Fibre Channel Adapter
        2200  QLA2200 64-bit Fibre Channel Adapter
                1590 00fa  StoreFabric SN1100Q 16Gb Dual Port Fibre Channel Host Bus Adapter
                1590 0203  StoreFabric SN1600Q 32Gb Single Port Fibre Channel Host Bus Adapter
                1590 0204  StoreFabric SN1600Q 32Gb Dual Port Fibre Channel Host Bus Adapter
+       2281  ISP2812-based 64/32G Fibre Channel to PCIe Controller
+               1077 02e2  QLE2872 Dual Port 64GFC PCIe Gen4 x8 Adapter
+               1077 02e4  QLE2772 Dual Port 32GFC PCIe Gen4 x8 Adapter
+               1077 02ee  QLE2870 Single Port 64GFC PCIe Gen4 x8 Adapter
+               1077 02f0  QLE2770 Single Port 32GFC PCIe Gen4 x8 Adapter
        2300  QLA2300 64-bit Fibre Channel Adapter
        2312  ISP2312-based 2Gb Fibre Channel to PCI-X HBA
                103c 0131  2Gb Fibre Channel - Single port [A7538A]
        0111  NV11 [GeForce2 MX200]
        0112  NV11M [GeForce2 Go]
        0113  NV11GL [Quadro2 MXR/EX/Go]
+               1028 00e5  Quadro2 Go
        0140  NV43 [GeForce 6600 GT]
                1458 3125  GV-NX66T128D
                1458 3126  GV-NX66T256DE
        06ca  GF100M [GeForce GTX 480M]
        06cb  GF100 [GeForce GTX 480]
        06cd  GF100 [GeForce GTX 470]
+       06d0  GF100GL
        06d1  GF100GL [Tesla C2050 / C2070]
                10de 0771  Tesla C2050
                10de 0772  Tesla C2070
        1022  GK110GL [Tesla K20c]
        1023  GK110BGL [Tesla K40m]
                10de 097e  12GB Computational Accelerator
-       1024  GK110BGL [Tesla K40c]
+       1024  GK180GL [Tesla K40c]
        1026  GK110GL [Tesla K20s]
        1027  GK110BGL [Tesla K40st]
        1028  GK110GL [Tesla K20m]
        1eb0  TU104GL [Quadro RTX 5000]
        1eb1  TU104GL [Quadro RTX 4000]
        1eb8  TU104GL [Tesla T4]
-       1ed0  TU104M [GeForce RTX 2080 Mobile]
+       1ed0  TU104BM [GeForce RTX 2080 Mobile]
        1f02  TU106 [GeForce RTX 2070]
                1043 8673  TURBO RTX 2070
        1f04  TU106
        1f10  TU106M [GeForce RTX 2070 Mobile]
        1f11  TU106M [GeForce RTX 2060 Mobile]
        1f2e  TU106M
-       1f50  TU106M [GeForce RTX 2070 Mobile]
-       1f51  TU106M [GeForce RTX 2060 Mobile]
-       1f82  TU107
-       1f92  TU107M
+       1f50  TU106BM [GeForce RTX 2070 Mobile]
+       1f51  TU106BM [GeForce RTX 2060 Mobile]
+       1f82  TU107 [GeForce GTX 1650]
+       1f92  TU107M [GeForce GTX 1650 Mobile]
        1fbf  TU107GL
-       2182  TU116 [GeForce GTX 1660 Ti Rev. A]
+       2182  TU116 [GeForce GTX 1660 Ti]
        2183  TU116
        2184  TU116 [GeForce GTX 1660]
-       2191  TU116M
+       2191  TU116M [GeForce GTX 1660 Mobile]
        21ae  TU116GL
        21bf  TU116GL
+       21d1  TU116BM [GeForce GTX 1660 Mobile]
 10df  Emulex Corporation
        0720  OneConnect NIC (Skyhawk)
                103c 1934  FlexFabric 20Gb 2-port 650M Adapter
                103c 1985  Pavilion 17-e163sg Notebook PC
                17aa 3832  Yoga 520
        522a  RTS522A PCI Express Card Reader
+               103c 8079  EliteBook 840 G3
        5249  RTS5249 PCI Express Card Reader
                103c 1909  ZBook 15
        524a  RTS524A PCI Express Card Reader
                1028 06dc  Latitude E7470
                1028 06e4  XPS 15 9550
                17aa 224f  ThinkPad X1 Carbon 5th Gen
+       5260  RTS5260 PCI Express Card Reader
        5286  RTS5286 PCI Express Card Reader
        5287  RTL8411B PCI Express Card Reader
        5288  RTS5288 PCI Express Card Reader
 112f  Dalsa Inc.
        0000  MVC IC-PCI
        0001  MVC IM-PCI Video frame grabber/processor
+       0004  PCDig Digital Image Capture
        0008  PC-CamLink PCI framegrabber
 1130  Computervision
 1131  Philips Semiconductors
        7820  MV78200 [Discovery Innovation] ARM SoC
        7823  MV78230 [Armada XP] ARM SoC
        7846  88F6820 [Armada 385] ARM SoC
+       d40f  Bobcat3 Ethernet Switch
        f003  GT-64010 Primary Image Piranha Image Generator
 11ac  Canon Information Systems Research Aust.
 11ad  Lite-On Communications Inc
                1590 0211  Ethernet 25Gb 2-port 631FLR-SFP28 Adapter
        16d8  BCM57416 NetXtreme-E Dual-Media 10G RDMA Ethernet Controller
                1028 1feb  NetXtreme-E 10Gb SFP+ Adapter
+               14e4 4163  BCM957416M4163C OCP 2x10GBT Type1 wRoCE
                1590 020c  Ethernet 10Gb 2-port 535T Adapter
                1590 0212  Ethernet 10Gb 2-port 535FLR-T Adapter
        16d9  BCM57417 NetXtreme-E 10GBASE-T RDMA Ethernet Controller
        0211  MT416842 Family [BlueField SoC Flash Recovery]
        0212  MT2892 Family [ConnectX-6 Dx Flash Recovery]
        0213  MT2892 Family [ConnectX-6 Dx Secure Flash Recovery]
+       0214  MT42822 Family [BlueField-2 SoC Flash Recovery]
+       0215  MT42822 Family [BlueField-2 Secure Flash Recovery]
        024e  MT53100 [Spectrum-2, Flash recovery mode]
        024f  MT53100 [Spectrum-2, Secure Flash recovery mode]
+       0250  Spectrum-3, Flash recovery mode
+       0251  Spectrum-3, Secure Flash recovery mode
        0262  MT27710 [ConnectX-4 Lx Programmable] EN
        0263  MT27710 [ConnectX-4 Lx Programmable Virtual Function] EN
        0264  Innova-2 Flex Burn image
        101b  MT28908 Family [ConnectX-6]
        101c  MT28908 Family [ConnectX-6 Virtual Function]
        101d  MT2892 Family [ConnectX-6 Dx]
-       101e  MT2892 Family [ConnectX-6 Dx Virtual Function]
+       101e  ConnectX Family mlx5Gen Virtual Function
        101f  MT28851
        1020  MT28860
        1021  MT28861
        1974  MT28800 Family [ConnectX-5 PCIe Bridge]
        1975  MT416842 Family [BlueField SoC PCIe Bridge]
+       1978  MT42822 Family [BlueField-2 SoC PCIe Bridge]
        4117  MT27712A0-FDCF-AE
                1bd4 0039  SN10XMP2P25
                1bd4 004d  SN10XMP2P25,YZPC-01191-101
        5a46  MT23108 PCI Bridge
        5e8c  MT24204 [InfiniHost III Lx HCA]
        5e8d  MT25204 [InfiniHost III Lx HCA Flash Recovery]
+       6001  NVMe SNAP Controller
        6274  MT25204 [InfiniHost III Lx HCA]
        6278  MT25208 InfiniHost III Ex (Tavor compatibility mode)
        6279  MT25208 [InfiniHost III Ex HCA Flash Recovery]
        a2d1  MT416842 BlueField SoC Crypto disabled
        a2d2  MT416842 BlueField integrated ConnectX-5 network controller
        a2d3  MT416842 BlueField multicore SoC family VF
+       a2d4  MT42822 BlueField-2 SoC Crypto enabled
+       a2d5  MT42822 BlueField-2 SoC Crypto disabled
+       a2d6  MT42822 BlueField-2 integrated ConnectX-6 Dx network controller
+       c2d2  MT416842 BlueField SoC management interfac
+       c2d3  MT42822 BlueField-2 SoC Management Interface
 # SwitchX-2, 40GbE switch
        c738  MT51136
        c739  MT51136 GW
        cb84  MT52100
        cf08  MT53236
        cf6c  MT53100 [Spectrum-2]
+       cf70  Spectrum-3
        d2f0  Quantum HDR (200Gbps) switch
 15b4  CCI/TRIAD
 15b5  Cimetrics Inc
        1915  Arria10 PCIe MainRef Design [DNPCIe_80G_A10_LL]
        1916  VirtexUS PCIe Accelerator Board [DNVUF2_HPC_PCIe]
        1917  UltrascalePlus PCIe Accelerator Board [DNPCIe_400G_VU_LL]
+       1918  VirtexUS+ ASIC Emulation Board [DNVUPF4A]
+       1919  UltrascalePlus PCIe Accelerator Board [DNPCIe_400G_VUP_HBM_LL]
        1a00  Virtex6 PCIe DMA Netlist Design
        1a01  Virtex6 PCIe Darklite Design [DNPCIe_HXT_10G_LL]
        1a02  Virtex7 PCIe DMA Netlist Design
        1a0a  VirtexUS PCIe Darklite Design [DNVUF2_HPC_PCIe]
        1a0b  UltrascalePlus PCIe Darklite Design [DNPCIe_400G_VU_LL]
        1a0c  KintexUS PCIe DRAM Packet Capture Design [DNPCIe_40G_KU_LL]
+       1a0d  KintexUS PCIe DRAM Packet Capture Design [DNPCIe_40G_KU_LL_2QSFP]
+       1a0e  UltrascalePlus PCIe Darklite Design [DNPCIe_400G_VUP_HBM_LL]
 17e4  Sectra AB
        0001  KK671 Cardbus encryption board
        0002  KK672 Cardbus encryption board
        0175  NT20E3-2-PTP Network Adapter 2x10Gb
        0185  NT40A01 Network Adapter
        01a5  NT200A01 Network Adapter
+       01c5  NT200A02 Network Adapter
 18f6  NextIO
        1000  [Nexsis] Switch Virtual P2P PCIe Bridge
        1001  [Texsis] Switch Virtual P2P PCIe Bridge
                1924 801d  x2522-R1 2000 Series 10/25G Adapter
                1924 801e  x2542-R1 2000 Series 40/100G Adapter
                1924 8022  XtremeScale X2522 10G Network Adapter
+               1924 8024  XtremeScale X2562 OCP 3.0 Dual Port SFP28
+               1924 8027  XtremeScale X2541 PCIe Single Port QSFP28
                1924 8028  XtremeScale X2522-25G Network Adapter
+               1924 802a  XtremeScale X2542 PCIe Dual Port QSFP28
+               1924 802b  XtremeScale X2552 OCP 2.0 Dual Port SFP28
+               1924 802c  XtremeScale X2522-25G PCIe Dual Port SFP28
+               1924 802d  XtremeScale X2562 OCP 3.0 Dual Port SFP28
        1803  SFC9020 10G Ethernet Controller (Virtual Function)
        1813  SFL9021 10GBASE-T Ethernet Controller (Virtual Function)
        1903  SFC9120 10G Ethernet Controller (Virtual Function)
                1028 1fd6  BOSS-S1 Adapter
                1028 1fdf  BOSS-S1 Modular
                1028 1fe2  BOSS-S1 Adapter
+               1028 2010  BOSS-S2 Adapter
                1d49 0300  ThinkSystem M.2 with Mirroring Enablement Kit
        9235  88SE9235 PCIe 2.0 x2 4-port SATA 6 Gb/s Controller
        9445  88SE9445 PCIe 2.0 x4 4-Port SAS/SATA 6 Gbps RAID Controller
        0011  MIPS SoC PCI Express Port
 1bf4  VTI Instruments Corporation
        0001  SentinelEX
+       7011  RX0xxx
 1bfd  EeeTOP
 1c09  CSP, Inc.
        4254  10G-PCIE3-8D-2S
        0001  82C101
 1c28  Lite-On IT Corp. / Plextor
        0122  M6e PCI Express SSD [Marvell 88SS9183]
-1c2c  Fiberblaze
+# previously Fiberblaze
+1c2c  Silicom Denmark
        000a  Capture
        000f  SmartNIC
        00a0  FBC4G Capture 4x1Gb
        00a5  FBC2XLG Capture 2x40Gb
        00a6  FBC1CG Capture 1x100Gb
        00a9  FBC2XGHH Capture 2x10Gb
-       00ad  FBC2CGG3HL Capture 2x200Gb
+       00ad  FBC2CGG3HL Capture 2x100Gb [Padua]
        00af  Capture slave device
-       a001  FBC2CGG3 Capture 2x200Gb
+       00e0  PacketMover 2x100Gb [Savona]
+       00e1  PacketMover 2x100Gb [Tivoli]
+       a001  FBC2CGG3 Capture 2x100Gb [Mango]
+       a00e  FB2CG Capture 2x100Gb [Savona]
+       a00f  FB2CG Capture 2x40Gb [Savona]
+       a011  FB2CG Capture 2x25Gb [Savona]
+       a012  FB2CG Capture 8x10Gb [Savona]
 # Used on V120 VME Crate Controller
 1c32  Highland Technology, Inc.
 1c33  Daktronics, Inc
 1cb5  Focusrite Audio Engineering Ltd
        0002  Clarett
 1cb8  Dawning Information Industry Co., Ltd.
+1cc4  Union Memory (Shenzhen)
+       17ab  NVMe 256G SSD device
 1cc5  Embedded Intelligence, Inc.
        0100  CAN-PCIe-02
 1cc7  Radian Memory Systems Inc.
        0100  RK3399 PCI Express Root Port
        1808  RK1808 Neural Network Processor Card
 1d8f  Enyx
+1d93  YADRO (KNS Group)
 1d94  Chengdu Haiguang IC Design Co., Ltd.
        1450  Root Complex
        1451  I/O Memory Management Unit
 1d95  Graphcore Ltd
        0001  Colossus GC2 [C2]
        0002  Colossus GC1 [S1]
+1d9b  Facebook, Inc.
+       0010  Networking DOM Engine
+       0011  IO Bridge
 1da1  Teko Telecom S.r.l.
 1da2  Sapphire Technology Limited
+1da3  Habana Labs Ltd.
+       0001  HL-1000 AI Inference Accelerator [Goya]
 1dbb  NGD Systems, Inc.
 1dbf  Guizhou Huaxintong Semiconductor Technology Co., Ltd
        0401  StarDragon4800 PCI Express Root Port
                1df3 0001  ENA2050F
                1df3 0002  ENA2050FS
        0203  ACE-NIC100 Programmable Network Accelerator
+               1df3 0000  Maintenance Mode
                1df3 0001  ENA2080F
                1df3 0002  ENA2080FS
                1df3 0003  ENA2100F
        0215  Acorn CLE-215
        021f  Acorn CLE-215+
        1525  Xilinx BCU-1525
+1e26  Fujitsu Client Computing Limited
 1e38  Thinci, Inc
 1e3d  Burlywood, Inc
 # nee Tumsan Oy
                1028 2005  Express Flash NVMe 4.0TB 2.5" U.2 (P4510)
                108e 4870  NVMe PCIe 3.0 SSD 6.4TB AIC (P4608)
                108e 4871  NVMe PCIe 3.0 SSD 6.4TB 2.5-inch (P4600)
+               108e 4879  NVMe PCIe 3.0 SSD v2 6.4TB AIC (P4618)
                108e 487a  NVMe PCIe 3.0 SSD v2 6.4TB 2.5-inch (P4610)
                1590 025d  NVMe Datacenter SSD [3DNAND] 1.0TB 2.5" U.2 (P4500)
                1590 025e  NVMe Datacenter SSD [3DNAND] 2.0TB 2.5" U.2 (P4500)
        0d16  Crystal Well Integrated Graphics Controller
        0d26  Crystal Well Integrated Graphics Controller
        0d36  Crystal Well Integrated Graphics Controller
+       0d4e  Ethernet Connection (10) I219-LM
+       0d4f  Ethernet Connection (10) I219-V
        0d58  Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
                8086 0000  Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
                8086 0001  Ethernet Controller XXV710 Intel(R) FPGA Programmable Acceleration Card N3000 for Networking
                103c 2159  Ethernet 10Gb 2-port 562i Adapter
                108e 7b11  Ethernet Server Adapter X520-2
                1170 004c  82599 DP 10G Mezzanine Adapter
+               15d9 0611  AOC-STGN-I2S [REV 1.01]
                1734 11a9  10 Gigabit Dual Port Network Connection
                17aa 1071  ThinkServer X520-2 AnyFabric
                17aa 4007  82599ES 10-Gigabit SFI/SFP+ Network Connection
        156d  DSL5520 Thunderbolt 2 Bridge [Falcon Ridge 4C 2013]
        156f  Ethernet Connection I219-LM
                1028 06dc  Latitude E7470
+               103c 8079  EliteBook 840 G3
        1570  Ethernet Connection I219-V
        1571  Ethernet Virtual Function 700 Series
        1572  Ethernet Controller X710 for 10GbE SFP+
                8086 0007  Ethernet Network Adapter OCP XXV710-1
                8086 0008  Ethernet Network Adapter OCP XXV710-1
                8086 0009  Ethernet 25G 2P XXV710 Adapter
+               8086 000a  Ethernet 25G 2P XXV710 OCP
                8086 4001  Ethernet Network Adapter XXV710-2
        1591  Ethernet Controller E810-C for backplane
        1592  Ethernet Controller E810-C for QSFP
        15f0  JHL7540 Thunderbolt 3 USB Controller [Titan Ridge DD 2018]
        15f6  I210 Gigabit Ethernet Connection
        15ff  Ethernet Controller X710 for 10GBASE-T
+               8086 0000  Ethernet Network Adapter X710-TL
+               8086 0001  Ethernet Network Adapter X710-T4L
+               8086 0002  Ethernet Network Adapter X710-T4L
+               8086 0003  Ethernet Network Adapter X710-T2L
+               8086 0004  Ethernet Network Adapter X710-T2L
                8086 0005  Ethernet 10G 2P X710-T2L-t Adapter
                8086 0006  Ethernet 10G 4P X710-T4L-t Adapter
                8086 0007  Ethernet 10G 2P X710-T2L-t OCP
        1904  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
                17aa 382a  B51-80 Laptop
        1905  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x8)
        1906  HD Graphics 510
        1916  Skylake GT2 [HD Graphics 520]
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
        1918  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers
        1919  Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Imaging Unit
        191b  HD Graphics 530
        2086  Sky Lake-E PCU Registers
        208d  Sky Lake-E CHA Registers
        208e  Sky Lake-E CHA Registers
+       2241  Larrabee
        2250  Xeon Phi coprocessor 5100 series
        225c  Xeon Phi coprocessor SE10/7120 series
        225d  Xeon Phi coprocessor 3120 series 
                1028 2000  Express Flash NVMe [Optane] 375GB 2.5" U.2 (P4800X)
                1028 2001  Express Flash NVMe [Optane] 750GB 2.5" U.2 (P4800X)
                1028 2002  Express Flash NVMe [Optane] 750GB AIC (P4800X)
+               1028 200a  Express Flash NVMe [Optane] 375GB AIC (P4800X)
                8086 3904  NVMe Datacenter SSD [Optane] x4 AIC (P4800X)
                8086 3905  NVMe Datacenter SSD [Optane] 15mm 2.5" U.2 (P4800X)
        2770  82945G/GZ/P/PL Memory Controller Hub
        372c  Xeon C5500/C3500 Reserved
        373f  Xeon C5500/C3500 IOxAPIC
        37c8  C62x Chipset QuickAssist Technology
+       37cc  Ethernet Connection X722
        37cd  Ethernet Virtual Function 700 Series
        37ce  Ethernet Connection X722 for 10GbE backplane
                1590 0215  Ethernet 10Gb 2-port 568i Adapter
        3e91  8th Gen Core Processor Gaussian Mixture Model
        3e92  UHD Graphics 630 (Desktop)
        3e93  UHD Graphics 610
+       3e98  UHD Graphics 630 (Desktop 9 Series)
        3e9b  UHD Graphics 630 (Mobile)
        3ea0  UHD Graphics 620 (Whiskey Lake)
+               1028 089e  Inspiron 5482
        3ea5  Iris Plus Graphics 655
        3ec2  8th Gen Core Processor Host Bridge/DRAM Registers
        3ec4  8th Gen Core Processor Host Bridge/DRAM Registers
        71a1  440GX - 82443GX AGP bridge
        71a2  440GX - 82443GX Host bridge (AGP disabled)
                4c53 1000  CC7/CR7/CP7/VC7/VP7/VR7 mainboard
+       7360  XMM7360 LTE Advanced Modem
        7600  82372FB PIIX5 ISA
        7601  82372FB PIIX5 IDE
        7602  82372FB PIIX5 USB
        9d03  Sunrise Point-LP SATA Controller [AHCI mode]
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
                17aa 225d  ThinkPad T480
                17aa 382a  B51-80 Laptop
        9d10  Sunrise Point-LP PCI Express Root Port #1
+       9d11  Sunrise Point-LP PCI Express Root Port #2
        9d12  Sunrise Point-LP PCI Express Root Port #3
+       9d13  Sunrise Point-LP PCI Express Root Port #4
        9d14  Sunrise Point-LP PCI Express Root Port #5
                17aa 382a  B51-80 Laptop
        9d15  Sunrise Point-LP PCI Express Root Port #6
        9d18  Sunrise Point-LP PCI Express Root Port #9
                17aa 382a  B51-80 Laptop
        9d19  Sunrise Point-LP PCI Express Root Port #10
+       9d1a  Sunrise Point-LP PCI Express Root Port #11
        9d21  Sunrise Point-LP PMC
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
                17aa 224f  ThinkPad X1 Carbon 5th Gen
                17aa 225d  ThinkPad T480
                17aa 382a  B51-80 Laptop
        9d23  Sunrise Point-LP SMBus
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
                17aa 2247  ThinkPad T570
                17aa 224f  ThinkPad X1 Carbon 5th Gen
                17aa 225d  ThinkPad T480
        9d2f  Sunrise Point-LP USB 3.0 xHCI Controller
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
                17aa 2247  ThinkPad T570
                17aa 225d  ThinkPad T480
                17aa 382a  B51-80 Laptop
        9d31  Sunrise Point-LP Thermal subsystem
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
                17aa 2247  ThinkPad T570
                17aa 224f  ThinkPad X1 Carbon 5th Gen
                17aa 225d  ThinkPad T480
        9d3a  Sunrise Point-LP CSME HECI #1
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
                17aa 2247  ThinkPad T570
                17aa 224f  ThinkPad X1 Carbon 5th Gen
                17aa 225d  ThinkPad T480
                17aa 382a  B51-80 Laptop
        9d3d  Sunrise Point-LP Active Management Technology - SOL
+               103c 8079  EliteBook 840 G3
        9d43  Sunrise Point-LP LPC Controller
                17aa 382a  B51-80 Laptop
        9d48  Sunrise Point-LP LPC Controller
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
        9d4e  Sunrise Point LPC Controller/eSPI Controller
                17aa 225d  ThinkPad T480
        9d50  Sunrise Point LPC Controller
                17aa 224f  ThinkPad X1 Carbon 5th Gen
        9d60  Sunrise Point-LP Serial IO I2C Controller #0
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
                17aa 225d  ThinkPad T480
                8086 9d60  100 Series PCH/Sunrise Point PCH I2C0 [Skylake/Kaby Lake LPSS I2C]
        9d61  Sunrise Point-LP Serial IO I2C Controller #1
        9d70  Sunrise Point-LP HD Audio
                1028 06dc  Latitude E7470
                1028 06f3  Latitude 3570
+               103c 8079  EliteBook 840 G3
                17aa 382a  B51-80 Laptop
        9d71  Sunrise Point-LP HD Audio
                17aa 225d  ThinkPad T480
        9d84  Cannon Point-LP LPC Controller
+               1028 089e  Inspiron 5482
        9da3  Cannon Point-LP SMBus Controller
        9da4  Cannon Point-LP SPI Controller
        9db0  Cannon Point-LP PCI Express Root Port #9
+       9db4  Cannon Point-LP PCI Express Root Port #13
+               1028 089e  Inspiron 5482
        9db6  Cannon Point-LP PCI Express Root Port #15
        9db8  Cannon Point-LP PCI Express Root Port #1
        9dbc  Cannon Point-LP PCI Express Root Port #5
        9dc8  Cannon Point-LP High Definition Audio Controller
+               1028 089e  Inspiron 5482
        9dd3  Cannon Point-LP SATA Controller [AHCI Mode]
        9de0  Cannon Point-LP MEI Controller #1
+       9de8  Cannon Point-LP Serial IO I2C Controller #0
+               1028 089e  Inspiron 5482
+       9de9  Cannon Point-LP Serial IO I2C Controller #1
+               1028 089e  Inspiron 5482
        9ded  Cannon Point-LP USB 3.1 xHCI Controller
        9def  Cannon Point-LP Shared SRAM
        9df0  Cannon Point-LP CNVi [Wireless-AC]
        9df9  Cannon Point-LP Thermal Controller
+       9dfc  Cannon Point-LP Integrated Sensor Hub
        a000  Atom Processor D4xx/D5xx/N4xx/N5xx DMI Bridge
                1458 5000  GA-D525TUD
                8086 4f4d  DeskTop Board D510MO
        d158  Core Processor Miscellaneous Registers
        f1a5  SSD 600P Series
        f1a6  SSD Pro 7600p/760p/E 6100p Series
+       f1a8  SSDPEKNW020T8 [660p, 2TB]
+               8086 390d  SSDPEKNW020T8 [660p, 2TB]
+8088  Beijing Wangxun Technology Co., Ltd.
+       1001  Ethernet Controller RP1000 for 10GbE SFP+
+               8088 0000  Ethernet Network Adaptor RP1000 for 10GbE SFP+
+       2001  Ethernet Controller RP2000 for 10GbE SFP+
+               8088 2000  Ethernet Network Adaptor RP2000 for 10GbE SFP+
 80ee  InnoTek Systemberatung GmbH
        beef  VirtualBox Graphics Adapter
        cafe  VirtualBox Guest Service
                103c 0701  Smart Array P204i-b SR Gen10
                103c 1100  Smart Array P816i-a SR Gen10
                103c 1101  Smart Array P416ie-m SR G10
+               105b 1211  HBA 8238-16i
+               105b 1321  HBA 8242-24i
+               13fe 8312  SKY-9200 MIC-8312BridgeB
                152d 8a22  QS-8204-8i
                152d 8a23  QS-8238-16i
                152d 8a24  QS-8236-16i
                152d 8a36  QS-8240-24i
                152d 8a37  QS-8242-24i
+               193d 8460  HBA H460-M1
+               193d 8461  HBA H460-B1
+               193d c460  RAID P460-M2
+               193d c461  RAID P460-B2
+               193d f460  RAID P460-M4
+               193d f461  RAID P460-B4
+               19e5 d227  SmartROC-HD SR465C-M 4G
+               19e5 d228  SmartROC SR455C-M 2G
+               19e5 d229  SmartIOC SR155-M
+               19e5 d22a  SmartIOC-HD SR765-M
+               19e5 d22b  SmartROC-e SR455C-ME 4G
+               19e5 d22c  SmartROC SR455C-M 4G
+               1bd4 0045  SMART-HBA 8242-24i
+               1bd4 0046  RAID 8236-16i
+               1bd4 0047  RAID 8240-24i
+               1bd4 0048  SMART-HBA 8238-16i
+               1bd4 004a  PM8222-SHBA
+               1bd4 004b  RAID PM8204-2GB
+               1bd4 004c  RAID PM8204-4GB
+               1bd4 004f  PM8222-HBA
                9005 0608  SmartRAID 3162-8i /e
                9005 0800  SmartRAID 3154-8i
                9005 0801  SmartRAID 3152-8i
@@ -31039,6 +31181,7 @@ bdbd  Blackmagic Design
        a144  DeckLink Mini Monitor 4K
        a148  DeckLink SDI Micro
        a14b  DeckLink 8K Pro
+       a14e  DeckLink Quad HDMI Recorder
        a1ff  eGPU RX580
 c001  TSI Telsys
 c0a9  Micron/Crucial Technology
@@ -31277,6 +31420,7 @@ f1d0  AJA Video
        db09  Corvid 24
        dcaf  Kona HD
        dfee  Xena HD-DA
+       eb0d  Corvid 88
        eb0e  Corvid 44
        eb1d  Kona 5
        efac  Xena SD-MM/SD-22-MM
index a27679a..0f21774 100644 (file)
@@ -9,8 +9,8 @@
 #      The latest version can be obtained from
 #              http://www.linux-usb.org/usb.ids
 #
-# Version: 2019.01.17
-# Date:    2019-01-17 20:34:05
+# Version: 2019.03.20
+# Date:    2019-03-20 20:34:05
 #
 
 # Vendors, devices and interfaces. Please keep sorted.
        7617  AT76C505AS Wireless Adapter
        7800  Mini Album
        800c  Airspy HF+
+       ff02  WootingTwo
        ff07  Tux Droid fish dongle
 03ec  Iwatsu America, Inc.
 03ed  Mitel Corp.
        0012  DeskJet 1125C Printer Port
        0024  KU-0316 Keyboard
        002a  LaserJet P1102
+       0053  DeskJet 2620 All-in-One Printer
        0101  ScanJet 4100c
        0102  PhotoSmart S20
        0104  DeskJet 880c/970c
        0512  DeckJet 450
        0517  LaserJet 1000
        051d  Bluetooth Interface
+       052a  LaserJet M1212nf MFP
        0601  ScanJet 6300c
        0604  DeskJet 840c
        0605  ScanJet 2200c
 0419  Samsung Info. Systems America, Inc.
        0001  IrDA Remote Controller / Creative Cordless Mouse
        0600  Desktop Wireless 6000
+       2694  Laila
        3001  Xerox P1202 Laser Printer
        3003  Olivetti PG L12L
        3201  Docuprint P8ex
        2228  9-in-2 Card Reader
        223a  8-in-1 Card Reader
        2503  USB 2.0 Hub
-       2504  USB 2.0 Hub
        2507  hub
        2512  USB 2.0 Hub
        2513  2.0 Hub
        2660  Hub
        2744  Hub
        274d  HTC Hub Controller
+       2807  Hub
        3fcc  RME MADIface
        4041  Hub and media card controller
        4060  Ultra Fast Media Reader
        5434  Hub
        5534  Hub
        5744  Hub
+       5807  Hub
        7500  LAN7500 Ethernet 10/100/1000 Adapter
        9500  LAN9500/LAN9500i
        9512  SMC9512/9514 USB Hub
        0799  Surface Pro embedded keyboard
        07a5  Wireless Receiver 1461C
        07b2  2.4GHz Transceiver v8.0 used by mouse Wireless Desktop 900
+       07b6  Comfort Curve Keyboard 3000
        07b9  Wired Keyboard 200
        07c6  RTL8153 GigE [Surface Dock Ethernet]
        07ca  Surface Pro 3 Docking Station Audio Device
        0100  Stor.E Slim USB 3.0
        0200  External Disk
        0820  Canvio Advance Disk
+       0821  Canvio Advance 2TB model DTC920
        a006  External Disk 1.5TB
        a007  External Disk USB 3.0
        a009  Stor.E Basics
        5730  Audio Speaker
        5731  Microphone
        5740  Virtual COM Port
+       5750  LED badge -- mini LED display -- 11x44
        7270  ST Micro Serial Bridge
        7554  56k SoftModem
        8213  ThermaData Logger Cradle
        9503  ITE it9503 feature-limited DVB-T transmission chip [ccHDtv]
        9507  ITE it9507 full featured DVB-T transmission chip [ccHDtv]
        9910  IT9910 chipset based grabber
+       ff59  Hdmi-CEC Bridge
 048f  Eicon Tech.
 0490  United Microelectronics Corp.
 0491  Capetronic
        1054  S90XS Keyboard/Music Synthesizer
        160f  P-105
        1613  Clavinova CLP535
+       1617  PSR-E353 digital keyboard
        1704  Steinberg UR44
        2000  DGP-7
        2001  DGP-5
        0428  D7000
        0429  D5100
        042a  D800 (ptp)
+       0430  D7100
        043f  D5600
        0f03  PD-10 Wireless Printer Adapter
        4000  Coolscan LS 40 ED
        9015  ICD 4 In-Circuit Debugger
        c001  PicoLCD 20x4
        e11c  TL866CS EEPROM Programmer [MiniPRO]
+       edb4  micro PLC (ATSAMD51G19A) [Black Brix ECU II]
+       edb5  ATMEGA32U4 [Black Brix ECU]
        f2c4  Macareux-labs Hygrometry Temperature Sensor
        f2f7  Yepkit YKUSH
        f3aa  Macareux-labs Usbce Bootloader mode
        3426  SCX-4500 Laser Printer
        342d  SCX-4x28 Series
        344f  SCX-3400 Series
+       347e  C48x Series Color Laser Multifunction Printer
        3605  InkJet Color Printer
        3606  InkJet Color Printer
        3609  InkJet Color Printer
        6125  D3 Station External Hard Drive
        61b5  M3 Portable Hard Drive 2TB
        61b6  M3 Portable Hard Drive 1TB
+       61b7  M3 Portable Hard Drive 4TB
        61f3  Portable SSD T3 (MU-PT250B, MU-PT500B)
        61f5  Portable SSD T5
        6601  Mobile Phone
        7061  eHome Infrared Receiver
        7080  Anycall SCH-W580
        7081  Human Interface Device
+       7301  Fingerprint Device
        8001  Handheld
        d003  GT-I9003
        e020  SERI E02 SCOM 6200 UMTS Phone
        02f4  2.4G Cordless Mouse
        0381  Touchscreen
        04a0  Dream Cheeky Stress/Panic Button
+       2234  Touchscreen
 04f4  Harting Elektronik, Inc.
 04f5  Fujitsu-ICL Systems, Inc.
 04f6  Norand Corp.
        2041  PT-2730 P-touch Label Printer
        2061  PT-P700 P-touch Label Printer
        2064  PT-P700 P-touch Label Printer RemovableDisk
+       209b  QL-800 P-touch Label Printer
+       209c  QL-810W P-touch Label Printer
+       209d  QL-820NWB P-touch Label Printer
        2100  Card Reader Writer
        2102  Sewing machine
        60a0  ADS-2000
        003c  VAIO-MX LCD Control
        0045  Digital Imaging Video
        0046  Network Walkman
+       0049  UP-D895
        004a  Memory Stick Hi-Fi System
        004b  Memory Stick Reader/Writer
        004e  DSC-xxx (ptp)
        01d0  DVD+RW External Drive DRU-700A
        01d5  IC RECORDER
        01de  VRD-VC10 [Video Capture]
+       01e7  UP-D897
        01e8  UP-DR150 Photo Printer
        01e9  Net MD
        01ea  Hi-MD WALKMAN
        0037  PL700
        0038  PL510
        0039  DTU-710
+       003a  DTI-520
+       003b  Integrated Hub
        003f  DTZ-2100 [Cintiq 21UX]
        0041  XD-0405-U [Intuos2 (4x5)]
        0042  XD-0608-U [Intuos2 (6x8)]
        006a  CTE-460 [Bamboo One Pen (S)]
        006b  CTE-660 [Bamboo One Pen (M)]
        0081  CTE-630BT [Graphire Wireless (6x8)]
-       0084  Wireless adapter for Bamboo tablets
+       0084  ACK-40401 [Wireless Accessory Kit]
        0090  TPC90
        0093  TPC93
        0097  TPC97
        00ec  TPCEC
        00ed  TPCED
        00ef  TPCEF
+       00f0  DTU-1631
        00f4  DTK-2400 [Cintiq 24HD] tablet
        00f6  DTH-2400 [Cintiq 24HD touch] touchscreen
        00f8  DTH-2400 [Cintiq 24HD touch] tablet
        0315  PTH-651 [Intuos pro (M)]
        0317  PTH-851 [Intuos pro (L)]
        0318  CTH-301 [Bamboo]
+       0319  CTH-300 [Bamboo Pad wireless]
+       0323  CTL-680 [Intuos Pen (M)]
+       032a  DTK-2700 [Cintiq 27QHD]
+       032b  DTH-2700 [Cintiq 27QHD touch] tablet
+       032c  DTH-2700 [Cintiq 27QHD touch] touchscreen
        032f  DTU-1031X
+       0331  ACK-411050 [ExpressKey Remote]
+       0333  DTH-1300 [Cintiq 13HD Touch] tablet
+       0335  DTH-1300 [Cintiq 13HD Touch] touchscreen
+       0336  DTU-1141
+       033b  CTL-490 [Intuos Draw (S)]
+       033c  CTH-490 [Intuos Art/Photo/Comic (S)]
+       033d  CTL-690 [Intuos Draw (M)]
+       033e  CTH-690 [Intuos Art (M)]
+       0343  DTK-1651
        0347  Integrated Hub
        0348  Integrated Hub
        034a  DTH-W1320 [MobileStudio Pro 13] touchscreen
        0356  DTH-3220 [Cintiq Pro 32] touchscreen
        0357  PTH-660 [Intuos Pro (M)]
        0358  PTH-860 [Intuos Pro (L)]
+       0359  DTU-1141B
        035a  DTH-1152 tablet
        0368  DTH-1152 touchscreen
        0374  CTL-4100 [Intuos (S)]
        0074  Optical mouse M-FW1UL
        0075  Laser mouse M-FW2DL
        0077  Laser mouse M-LY2UL
+       0079  Laser mouse M-D21DL
+       007b  Laser mouse M-D20DR
+       007c  Laser Bluetooth mouse M-BT5BL
        2003  JC-U3613M
        2004  JC-U3613M
        200c  LD-USB/TX
        3020  Hercules Webcam EC300
        a300  Dual Analog Leader GamePad
        b000  Hercules DJ Console
+       b121  Hercules P32 DJ
        c000  Hercules Muse Pocket
        d002  Hercules DJ Console
        e000  HWGUSB2-54 WLAN
        0070  NRP-Z57
        0083  NRP-Z85
        0095  NRP-Z86
+       0117  HMF / HMP / HMS-X / HMO series Oscilloscopes
+       0118  HMF / HMP / HMS-X / HMO series Oscilloscopes
+       0119  HMF / HMP / HMS-X / HMO series Oscilloscopes
 0aae  NEC infrontia Corp. (Nitsuko)
 0aaf  Digitalway Co., Ltd
 0ab0  Arrow Strong Electronics Co., Ltd
 22b9  eTurboTouch Technology, Inc.
        0006  Touch Screen
 22ba  Technology Innovation Holdings, Ltd
+22e0  secunet Security Networks AG
+       0002  SINA Flash Drive
+       0003  SINA ID Token A
 2304  Pinnacle Systems, Inc.
        0109  Studio PCTV USB (SECAM)
        0110  Studio PCTV USB (PAL)
        1213  MediaTV Pro III MiniPCIe (US)
 2676  Basler AG
        ba02  ace
+2717  Xiaomi Inc.
+       0011  100Mbps Network Card Adapter
+       0360  Mi3W
+       0368  Mi4 LTE
+       3801  Mi ANC & Type-C In-Ear Earphones
+       4106  MediaTek MT7601U [MI WiFi]
+       ff08  Redmi Note 3 (ADB Interface)
+       ff10  Mi/Redmi series (PTP)
+       ff18  Mi/Redmi series (PTP + ADB)
+       ff40  Mi/Redmi series (MTP)
+       ff48  Mi/Redmi series (MTP + ADB)
+       ff60  redmi prime 2
+       ff68  Mi-4c
+       ff80  Mi/Redmi series (RNDIS)
+       ff88  Mi/Redmi series (RNDIS + ADB)
 2730  Citizen
        200f  CT-S310 Label printer
 2735  DigitalWay
index a4e5082..8caeb56 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="binfmt.d" conditional='ENABLE_BINFMT'
     xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 9cfa9cc..a80a373 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="bootctl" conditional='ENABLE_EFI'
     xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <variablelist>
       <varlistentry>
-        <term><option>--path=</option></term>
-        <listitem><para>Path to the EFI System Partition (ESP). If not specified, <filename>/efi</filename>,
-        <filename>/boot</filename>, and <filename>/boot/efi</filename> are checked in turn.  It is recommended to mount
-        the ESP to <filename>/boot</filename>, if possible.</para></listitem>
+        <term><option>--esp-path=</option></term>
+        <listitem><para>Path to the EFI System Partition (ESP). If not specified, <filename>/efi/</filename>,
+        <filename>/boot/</filename>, and <filename>/boot/efi</filename> are checked in turn.  It is recommended to mount
+        the ESP to <filename>/efi/</filename>, if possible.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--boot-path=</option></term>
+        <listitem><para>Path to the Extended Boot Loader partition, as defined in the <ulink
+        url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>. If not
+        specified, <filename>/boot/</filename> are checked.  It is recommended to mount the Extended Boot
+        Loader partition to <filename>/boot/</filename>, if possible.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>-p</option></term>
-        <term><option>--print-path</option></term>
-        <listitem><para>This option modifies the behaviour of <command>status</command>.
-        Just print the path to the EFI System Partition (ESP) to standard output and
-        exit.</para></listitem>
+        <term><option>--print-esp-path</option></term>
+        <listitem><para>This option modifies the behaviour of <command>status</command>.  Prints only the
+        path to the EFI System Partition (ESP) to standard output and exits.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--print-boot-path</option></term>
+        <listitem><para>This option modifies the behaviour of <command>status</command>.  Prints only the
+        path to the Extended Boot Loader partition if it exists, and the path to the ESP otherwise to
+        standard output and exit. This command is useful to determine where to place boot loader entries, as
+        they are preferably placed in the Extended Boot Loader partition if it exists and in the ESP
+        otherwise.</para></listitem>
       </varlistentry>
 
       <varlistentry>
       <varlistentry>
         <term><option>install</option></term>
 
-        <listitem><para>Installs systemd-boot into the EFI system partition. A copy of <command>systemd-boot</command>
-        will be stored as the EFI default/fallback loader at
-        <filename><replaceable>ESP</replaceable>/EFI/BOOT/BOOT*.EFI</filename>. The boot loader is then added to the
-        top of the firmware's boot loader list.</para></listitem>
+        <listitem><para>Installs <command>systemd-boot</command> into the EFI system partition. A copy of
+        <command>systemd-boot</command> will be stored as the EFI default/fallback loader at
+        <filename><replaceable>ESP</replaceable>/EFI/BOOT/BOOT*.EFI</filename>. The boot loader is then added
+        to the top of the firmware's boot loader list.</para></listitem>
       </varlistentry>
 
       <varlistentry>
 
   <refsect1>
     <title>Environment</title>
-    <para>If <varname>$SYSTEMD_RELAX_ESP_CHECKS=1</varname> is set the validation checks for the ESP are relaxed, and
-    the path specified with <option>--path=</option> may refer to any kind of file system on any kind of
-    partition.</para>
+    <para>If <varname>$SYSTEMD_RELAX_ESP_CHECKS=1</varname> is set the validation checks for the ESP are
+    relaxed, and the path specified with <option>--esp-path=</option> may refer to any kind of file system on
+    any kind of partition.</para>
+
+    <para>Similarly, <varname>$SYSTEMD_RELAX_XBOOTLDR_CHECKS=1</varname> turns off some validation checks for
+    the Extended Boot Loader partition.</para>
   </refsect1>
 
   <refsect1>
index 5f63fe7..9468a61 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="bootup">
 
   <refsect1>
     <title>Description</title>
 
-    <para>A number of different components are involved in the system
-    boot. Immediately after power-up, the system BIOS will do minimal
-    hardware initialization, and hand control over to a boot loader
-    stored on a persistent storage device. This boot loader will then
-    invoke an OS kernel from disk (or the network). In the Linux case,
-    this kernel (optionally) extracts and executes an initial RAM disk
-    image (initrd), such as generated by
+    <para>A number of different components are involved in the boot of a Linux system. Immediately after
+    power-up, the system firmware will do minimal hardware initialization, and hand control over to a boot
+    loader (e.g.
+    <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> or
+    <ulink url="https://www.gnu.org/software/grub/">GRUB</ulink>) stored on a persistent storage device. This
+    boot loader will then invoke an OS kernel from disk (or the network). On systems using EFI or other types
+    of firmware, this firmware may also load the kernel directly.</para>
+
+    <para>The kernel (optionally) mounts an in-memory file system, often generated by
     <citerefentry project='die-net'><refentrytitle>dracut</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
-    which looks for the root file system (possibly using
-    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    for this). After the root file system is found and mounted, the
-    initrd hands over control to the host's system manager (such as
-    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>)
-    stored on the OS image, which is then responsible for probing all
-    remaining hardware, mounting all necessary file systems and
-    spawning all configured services.</para>
+    which looks for the root file system. Nowadays this is usually implemented as an initramfs — a compressed
+    archive which is extracted when the kernel boots up into a lightweight in-memory file system based on
+    tmpfs, but in the past normal file systems using an in-memory block device (ramdisk) were used, and the
+    name "initrd" is still used to describe both concepts. It's the boot loader or the firmware that loads
+    both the kernel and initrd/initramfs images into memory, but the kernel which interprets it as a file
+    system. <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry> may
+    be used to manage services in the initrd, similarly to the real system.</para>
+
+    <para>After the root file system is found and mounted, the initrd hands over control to the host's system
+    manager (such as
+    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>) stored in
+    the root file system, which is then responsible for probing all remaining hardware, mounting all
+    necessary file systems and spawning all configured services.</para>
 
     <para>On shutdown, the system manager stops all services, unmounts
     all file systems (detaching the storage technologies backing
index a5e3d92..e4c7fcb 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="busctl"
           xmlns:xi="http://www.w3.org/2001/XInclude">
         <term><option>--auto-start=</option><replaceable>BOOL</replaceable></term>
 
         <listitem>
-          <para>When used with the <command>call</command> command, specifies
+          <para>When used with the <command>call</command> or <command>emit</command> command, specifies
           whether the method call should implicitly activate the
           called service, should it not be running yet but is
           configured to be auto-started. Defaults to
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--destination=</option><replaceable>SERVICE</replaceable></term>
+
+        <listitem>
+          <para>Takes a service name. When used with the <command>emit</command> command, a signal is
+          emitted to the specified service.</para>
+        </listitem>
+      </varlistentry>
+
       <xi:include href="user-system-options.xml" xpointer="user" />
       <xi:include href="user-system-options.xml" xpointer="system" />
       <xi:include href="user-system-options.xml" xpointer="host" />
       </varlistentry>
 
       <varlistentry>
+        <term><command>emit</command> <arg choice="plain"><replaceable>OBJECT</replaceable></arg> <arg choice="plain"><replaceable>INTERFACE</replaceable></arg> <arg choice="plain"><replaceable>SIGNAL</replaceable></arg> <arg choice="opt"><replaceable>SIGNATURE</replaceable> <arg choice="opt" rep="repeat"><replaceable>ARGUMENT</replaceable></arg></arg></term>
+
+        <listitem><para>Emit a signal. Takes a object path, interface name and method name. If parameters
+        shall be passed, a signature string is required, followed by the arguments, individually formatted as
+        strings. For details on the formatting used, see below. To specify the destination of the signal,
+        use the <option>--destination=</option> option.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><command>get-property</command> <arg choice="plain"><replaceable>SERVICE</replaceable></arg> <arg choice="plain"><replaceable>OBJECT</replaceable></arg> <arg choice="plain"><replaceable>INTERFACE</replaceable></arg> <arg choice="plain" rep="repeat"><replaceable>PROPERTY</replaceable></arg></term>
 
         <listitem><para>Retrieve the current value of one or more
index 4ccc174..81cdc33 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="coredump.conf" conditional="ENABLE_COREDUMP"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 94d5626..5419bc1 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="coredumpctl" conditional='ENABLE_COREDUMP'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 3574ce0..5eb1c12 100644 (file)
@@ -1,6 +1,7 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!--
   SPDX-License-Identifier: LGPL-2.1+
 
       </varlistentry>
 
       <varlistentry>
+        <term><option>same-cpu-crypt</option></term>
+
+        <listitem><para>Perform encryption using the same cpu that IO was submitted on. The default is to use
+        an unbound workqueue so that encryption work is automatically balanced between available CPUs.</para>
+        <para>This requires kernel 4.0 or newer.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>submit-from-crypt-cpus</option></term>
+
+        <listitem><para>Disable offloading writes to a separate thread after encryption. There are some
+        situations where offloading write bios from the encryption threads to a single thread degrades
+        performance significantly. The default is to offload write bios to the same thread because it benefits
+        CFQ to have writes submitted using the same context.</para>
+        <para>This requires kernel 4.0 or newer.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option>skip=</option></term>
 
         <listitem><para>How many 512-byte sectors of the encrypted data to skip at the
index 7724bb4..79ea55b 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="daemon">
 
         <function>setsid()</function> to detach from any terminal and
         create an independent session.</para></listitem>
 
-        <listitem><para>In the child, call <function>fork()</function>
-        again, to ensure that the daemon can never re-acquire a
-        terminal again.</para></listitem>
+        <listitem><para>In the child, call <function>fork()</function> again, to ensure that the daemon can
+        never re-acquire a terminal again. (This relevant if the program — and all its dependencies — does
+        not carefully specify `O_NOCTTY` on each and every single `open()` call that might potentially open a
+        TTY device node.)</para></listitem>
 
         <listitem><para>Call <function>exit()</function> in the first
         child, so that only the second child (the actual daemon
         and
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
 
+        <listitem><para>As new-style daemons are invoked without a controlling TTY (but as their own session
+        leaders) care should be taken to always specify `O_NOCTTY` on `open()` calls that possibly reference
+        a TTY device node, so that no controlling TTY is accidentally acquired.</para></listitem>
+
       </orderedlist>
 
       <para>These recommendations are similar but not identical to the
index d5faee2..8b6394e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="dnssec-trust-anchors.d" conditional='ENABLE_RESOLVE'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 2257dcb..7021548 100644 (file)
@@ -1,6 +1,7 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!--
   SPDX-License-Identifier: LGPL-2.1+
 
index 23ee17d..497cb58 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="file-hierarchy">
 
 
       <varlistentry>
         <term><filename>/tmp/</filename></term>
-        <listitem><para>The place for small temporary files. This
-        directory is usually mounted as a <literal>tmpfs</literal>
-        instance, and should hence not be used for larger files. (Use
-        <filename>/var/tmp/</filename> for larger files.) Since the
-        directory is accessible to other users of the system, it is
-        essential that this directory is only written to with the
-        <citerefentry project='man-pages'><refentrytitle>mkstemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-        <citerefentry project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-        and related calls. This directory is usually flushed at
-        boot-up. Also, files that are not accessed within a certain
-        time are usually automatically deleted. If applications find
-        the environment variable <varname>$TMPDIR</varname> set, they
-        should prefer using the directory specified in it over
-        directly referencing <filename>/tmp/</filename> (see
-        <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry>
-        and
+        <listitem><para>The place for small temporary files. This directory is usually mounted as a
+        <literal>tmpfs</literal> instance, and should hence not be used for larger files. (Use
+        <filename>/var/tmp/</filename> for larger files.) Since the directory is accessible to other users of
+        the system, it is essential that this directory is only written to with the <citerefentry
+        project='man-pages'><refentrytitle>mkstemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+        <citerefentry
+        project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry> and
+        related calls. This directory is usually flushed at boot-up. Also, files that are not accessed within
+        a certain time are usually automatically deleted. If applications find the environment variable
+        <varname>$TMPDIR</varname> set, they should prefer using the directory specified in it over directly
+        referencing <filename>/tmp/</filename> (see <citerefentry
+        project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> and
         <ulink url="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03">IEEE
-        Std 1003.1</ulink> for details).</para></listitem>
+        Std 1003.1</ulink> for details). For further details about this directory, see <ulink
+        url="https://systemd.io/TEMPORARY_DIRECTORIES">Using /tmp/ And /var/tmp/
+        Safely</ulink>.</para></listitem>
       </varlistentry>
 
     </variablelist>
 
       <varlistentry>
         <term><filename>/var/tmp/</filename></term>
-        <listitem><para>The place for larger and persistent temporary
-        files. In contrast to <filename>/tmp/</filename>, this directory
-        is usually mounted from a persistent physical file system and
-        can thus accept larger files. (Use <filename>/tmp/</filename>
-        for smaller files.) This directory is generally not flushed at
-        boot-up, but time-based cleanup of files that have not been
-        accessed for a certain time is applied. The same security
-        restrictions as with <filename>/tmp/</filename> apply, and
-        hence only
-        <citerefentry project='man-pages'><refentrytitle>mkstemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-        <citerefentry project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-        or similar calls should be used to make use of this directory.
-        If applications find the environment variable
-        <varname>$TMPDIR</varname> set, they should prefer using the
-        directory specified in it over directly referencing
-        <filename>/var/tmp/</filename> (see
-        <citerefentry project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry>
-        for details). </para></listitem>
+        <listitem><para>The place for larger and persistent temporary files. In contrast to
+        <filename>/tmp/</filename>, this directory is usually mounted from a persistent physical file system
+        and can thus accept larger files. (Use <filename>/tmp/</filename> for smaller files.) This directory
+        is generally not flushed at boot-up, but time-based cleanup of files that have not been accessed for
+        a certain time is applied. The same security restrictions as with <filename>/tmp/</filename> apply,
+        and hence only <citerefentry
+        project='man-pages'><refentrytitle>mkstemp</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+        <citerefentry
+        project='man-pages'><refentrytitle>mkdtemp</refentrytitle><manvolnum>3</manvolnum></citerefentry> or
+        similar calls should be used to make use of this directory.  If applications find the environment
+        variable <varname>$TMPDIR</varname> set, they should prefer using the directory specified in it over
+        directly referencing <filename>/var/tmp/</filename> (see <citerefentry
+        project='man-pages'><refentrytitle>environ</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+        details). For further details about this directory, see <ulink
+        url="https://systemd.io/TEMPORARY_DIRECTORIES">Using /tmp/ And /var/tmp/
+        Safely</ulink>.</para></listitem>
       </varlistentry>
 
     </variablelist>
index 19857ce..75604b8 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="halt"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index de33a74..bb880c3 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="hostname">
   <refentryinfo>
index 013f126..ddbeb7e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="hostnamectl" conditional='ENABLE_HOSTNAMED'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 7d550c6..7ba5236 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="hwdb" conditional="ENABLE_HWDB">
   <refentryinfo>
index 8fa557c..ab3dfd0 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <!--
index 3dda301..6b946bf 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="journal-upload.conf" conditional='HAVE_MICROHTTPD'
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 7ff0a47..a3c67f5 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
   <refentry id="journalctl"
             xmlns:xi="http://www.w3.org/2001/XInclude">
       </varlistentry>
 
       <varlistentry>
-        <term><option>-b <optional><replaceable>ID</replaceable></optional><optional><replaceable>±offset</replaceable></optional></option></term>
-        <term><option>--boot=<optional><replaceable>ID</replaceable></optional><optional><replaceable>±offset</replaceable></optional></option></term>
+        <term><option>-b <optional><optional><replaceable>ID</replaceable></optional><optional><replaceable>±offset</replaceable></optional>|<constant>all</constant></optional></option></term>
+        <term><option>--boot<optional>=<optional><replaceable>ID</replaceable></optional><optional><replaceable>±offset</replaceable></optional>|<constant>all</constant></optional></option></term>
 
         <listitem><para>Show messages from a specific boot. This will
         add a match for <literal>_BOOT_ID=</literal>.</para>
         <replaceable>offset</replaceable> is not specified, a value of
         zero is assumed, and the logs for the boot given by
         <replaceable>ID</replaceable> are shown.</para>
+
+        <para>The special argument <constant>all</constant> can be
+        used to negate the effect of an earlier use of
+        <option>-b</option>.</para>
         </listitem>
       </varlistentry>
 
       </varlistentry>
 
       <varlistentry>
+        <term><option>--cursor-file=<replaceable>FILE</replaceable></option></term>
+
+        <listitem><para>If <replaceable>FILE</replaceable> exists and contains a
+        cursor, start showing entries <emphasis>after</emphasis> this location.
+        Otherwise the show entries according the other given options. At the end,
+        write the cursor of the last entry to <replaceable>FILE</replaceable>. Use
+        this option to continually read the journal by sequentially calling
+        <command>journalctl</command>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option>--after-cursor=</option></term>
 
         <listitem><para>Start showing entries from the location in the
index 2791678..57c2256 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="journald.conf"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 43dfc10..40b7766 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="kernel-command-line">
 
           enables fully state-less boots were the vendor-supplied OS is used as shipped, with only default
           configuration and no stored state in effect, as <filename>/etc</filename> and <filename>/var</filename> (as
           well as all other resources shipped in the root file system) are reset at boot and lost on shutdown. If this
-          setting is set to <literal>state</literal> the root file system is mounted as usual, however
+          setting is set to <literal>state</literal> the root file system is mounted read-only, however
           <filename>/var</filename> is mounted as a volatile memory file system (<literal>tmpfs</literal>), so that the
-          system boots up with the normal configuration applied, but all state reset at boot and lost at shutdown. For details,
-          see
+          system boots up with the normal configuration applied, but all state reset at boot and lost at shutdown. If
+          this setting is set to <literal>overlay</literal> the root file system is set up as
+          <literal>overlayfs</literal> mount combining the read-only root directory with a writable
+          <literal>tmpfs</literal>, so that no modifications are made to disk, but the file system may be modified
+          nonetheless with all changes being lost at reboot. For details, see
           <citerefentry><refentrytitle>systemd-volatile-root.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
           and
           <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
         <listitem>
           <para>Configures the root file system and its file system
           type and mount options, as well as whether it shall be
-          mounted read-only or read-writable initially. For details,
+          mounted read-only or read-write initially. For details,
           see
           <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>.</para>
         </listitem>
index 50e1320..34bb5d2 100644 (file)
@@ -1,12 +1,10 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
-
-<refentry id="kernel-install">
+<refentry id="kernel-install"
+          xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refentryinfo>
     <title>kernel-install</title>
@@ -27,6 +25,7 @@
     <cmdsynopsis>
       <command>kernel-install</command>
       <arg choice="plain">COMMAND</arg>
+      <arg choice="opt" rep="repeat">OPTIONS</arg>
       <arg choice="plain"><replaceable>KERNEL-VERSION</replaceable></arg>
       <arg choice="plain"><replaceable>KERNEL-IMAGE</replaceable></arg>
       <arg choice="opt" rep="repeat"><replaceable>INITRD-FILE</replaceable></arg>
@@ -35,9 +34,9 @@
 
   <refsect1>
     <title>Description</title>
-    <para>
-      <command>kernel-install</command> is used to install and remove kernel and
-      initramfs images to and from <filename>/boot</filename>.
+    <para><command>kernel-install</command> is used to install and remove kernel and initramfs images to and
+    from the boot loader partition, referred to as <varname>$BOOT</varname> here. It will usually be one of
+    <filename>/boot</filename>, <filename>/efi</filename>, or <filename>/boot/efi</filename>, see below.
     </para>
 
     <para><command>kernel-install</command> will execute the files
         <term><command>add <replaceable>KERNEL-VERSION</replaceable> <replaceable>KERNEL-IMAGE</replaceable> [<replaceable>INITRD-FILE</replaceable> ...]</command></term>
         <listitem>
           <para>This command expects a kernel version string and a path to a kernel image file as
-          arguments. <command>kernel-install</command> creates the directory
-          <filename>/boot/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename>
-          and calls the executables from <filename>/usr/lib/kernel/install.d/*.install</filename> and
+          arguments. <command>kernel-install</command> calls the executables from
+          <filename>/usr/lib/kernel/install.d/*.install</filename> and
           <filename>/etc/kernel/install.d/*.install</filename> with the following arguments:
 
-          <programlisting>add <replaceable>KERNEL-VERSION</replaceable> <filename>/boot/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename> <replaceable>KERNEL-IMAGE</replaceable> [<replaceable>INITRD-FILE</replaceable> ...]</programlisting>
+          <programlisting>add <replaceable>KERNEL-VERSION</replaceable> <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename> <replaceable>KERNEL-IMAGE</replaceable> [<replaceable>INITRD-FILE</replaceable> ...]</programlisting>
           </para>
 
-          <para>Two default plugins execute the following operations in this case:</para>
+          <para>Three default plugins execute the following operations in this case:</para>
 
           <itemizedlist>
+            <listitem><para><filename>00-entry-directory.install</filename> creates the directory
+            <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename>
+            if <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/</filename> already exists.
+            </para></listitem>
 
             <listitem><para><filename>50-depmod.install</filename> runs
             <citerefentry><refentrytitle>depmod</refentrytitle><manvolnum>8</manvolnum></citerefentry> for the
 
             <listitem><para><filename>90-loaderentry.install</filename> copies <replaceable>KERNEL-IMAGE</replaceable>
             to
-            <filename>/boot/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/linux</filename>.
+            <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/linux</filename>.
             If an <replaceable>INITRD-FILE</replaceable> is provided, it also copies <replaceable>INITRD-FILE</replaceable>
             to
-            <filename>/boot/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL_VERSION</replaceable>/<replaceable>INITRD-FILE</replaceable></filename>.
+            <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL_VERSION</replaceable>/<replaceable>INITRD-FILE</replaceable></filename>.
             It also creates a boot loader entry according to the <ulink
             url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> in
-            <filename>/boot/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.
+            <filename>$BOOT/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.
             The title of the entry is the <replaceable>PRETTY_NAME</replaceable> parameter specified in
             <filename>/etc/os-release</filename> or <filename>/usr/lib/os-release</filename> (if the former is
-            missing), or "Linux <replaceable>KERNEL-VERSION</replaceable>", if unset.</para></listitem>
+            missing), or "Linux <replaceable>KERNEL-VERSION</replaceable>", if unset.</para>
+
+            <para>If the entry directory
+            <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename>
+            does not exist, this plugin does nothing.</para></listitem>
           </itemizedlist>
         </listitem>
       </varlistentry>
           <filename>/usr/lib/kernel/install.d/*.install</filename> and
           <filename>/etc/kernel/install.d/*.install</filename> with the following arguments:
 
-          <programlisting>remove <replaceable>KERNEL-VERSION</replaceable> <filename>/boot/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename></programlisting>
+          <programlisting>remove <replaceable>KERNEL-VERSION</replaceable> <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename></programlisting>
           </para>
 
           <para>Afterwards, <command>kernel-install</command> removes the directory
-          <filename>/boot/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename>
+          <filename>$BOOT/<replaceable>MACHINE-ID</replaceable>/<replaceable>KERNEL-VERSION</replaceable>/</filename>
           and its contents.</para>
 
           <para>Two default plugins execute the following operations in this case:</para>
             <listitem><para><filename>50-depmod.install</filename> removes the files generated by <command>depmod</command> for this kernel again.</para></listitem>
 
             <listitem><para><filename>90-loaderentry.install</filename> removes the file
-            <filename>/boot/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.</para></listitem>
+            <filename>$BOOT/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>.conf</filename>.</para></listitem>
           </itemizedlist>
 
         </listitem>
       </varlistentry>
 
     </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>The <varname>$BOOT</varname> partition</title>
+    <para>The partition where the kernels and <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot
+    Loader Specification</ulink> snippets are located is called <varname>$BOOT</varname>.
+    <command>kernel-install</command> determines the location of this partition by checking
+    <filename>/efi/</filename>, <filename>/boot/</filename>, and <filename>/boot/efi</filename>
+    in turn. The first location where <filename>$BOOT/loader/entries/</filename> or
+    <filename>$BOOT/$MACHINE_ID/</filename> exists is used.</para>
+  </refsect1>
+
+  <refsect1>
+    <title>Options</title>
+    <para>The following options are understood:</para>
 
+    <variablelist>
+      <varlistentry>
+        <term><option>-v</option></term>
+        <term><option>--verbose</option></term>
+        <listitem>
+          <para>Output additional information about operations being performed.</para>
+        </listitem>
+      </varlistentry>
+
+      <xi:include href="standard-options.xml" xpointer="help" />
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Environment variables</title>
+    <para>If <option>--verbose</option> is used, <varname>$KERNEL_INSTALL_VERBOSE=1</varname> will be set for
+    the plugins. They may output additional logs in this case.</para>
   </refsect1>
 
   <refsect1>
           <listitem>
             <para>Read by <filename>90-loaderentry.install</filename>. If this file exists a numeric value is read from
             it and the naming of the generated entry file is slightly altered to include it as
-            <filename>/boot/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>+<replaceable>TRIES</replaceable>.conf</filename>. This
+            <filename>$BOOT/loader/entries/<replaceable>MACHINE-ID</replaceable>-<replaceable>KERNEL-VERSION</replaceable>+<replaceable>TRIES</replaceable>.conf</filename>. This
             is useful for boot loaders such as
             <citerefentry><refentrytitle>systemd-boot</refentrytitle><manvolnum>7</manvolnum></citerefentry> which
             implement boot attempt counting with a counter embedded in the entry file name.</para>
index eb332b5..c80534b 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-                 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refsect1>
   <title>Environment</title>
index a177fbe..e378c4d 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-          "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refsect1>
   <title>Notes</title>
index 382c1aa..c35bc29 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="libudev"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index f9d98dd..38a8086 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="loader.conf" conditional='ENABLE_EFI'
index 2f463de..a92cf50 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="locale.conf">
   <refentryinfo>
index 50c7e13..0752f78 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="localectl" conditional='ENABLE_LOCALED'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index f51c67f..0f1652e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="localtime">
   <refentryinfo>
index 67eeffd..7b0745f 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="loginctl" conditional='ENABLE_LOGIND'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index ac8032a..4cbfd09 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="logind.conf" conditional='ENABLE_LOGIND'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 7ed2dda..f4d94e8 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="machine-id">
   <refentryinfo>
index 5a268c9..4fb27ab 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="machine-info">
   <refentryinfo>
index 95823eb..357574f 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="machinectl" conditional='ENABLE_MACHINED'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 05197d6..ae9c941 100644 (file)
@@ -198,12 +198,9 @@ if git.found()
         custom_target(
                 'update-man-rules',
                 output : 'update-man-rules',
-                # slightly strange syntax because of
-                # https://github.com/mesonbuild/meson/issues/1643
-                # and https://github.com/mesonbuild/meson/issues/1512
                 command : ['sh', '-c',
                            'cd @0@ && '.format(meson.build_root()) +
-                           'python3 @0@/tools/make-man-rules.py `git ls-files ":/man/*.xml"` >t && '.format(meson.source_root()) +
+                           'python3 @0@/tools/make-man-rules.py $(git ls-files ":/man/*.xml") >t && '.format(project_source_root) +
                            'mv t @0@/rules/meson.build'.format(meson.current_source_dir())],
                 depend_files : custom_entities_ent)
 endif
index 57c4c68..d126634 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="modules-load.d" conditional='HAVE_KMOD'
     xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 7877755..6c28c4b 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="networkctl" conditional='ENABLE_NETWORKD'
           xmlns:xi="http://www.w3.org/2001/XInclude">
       <varlistentry>
         <term>
           <command>list</command>
-          <optional><replaceable>LINK…</replaceable></optional>
+          <optional><replaceable>PATTERN…</replaceable></optional>
         </term>
 
         <listitem>
-          <para>Show a list of existing links and their status. If no further arguments are specified shows all links,
+          <para>Show a list of existing links and their status. If one ore more
+          <replaceable>PATTERN</replaceable>s are specified, only links matching one of them are shown.
+          If no further arguments are specified shows all links,
           otherwise just the specified links. Produces output similar to:
 
           <programlisting>IDX LINK         TYPE     OPERATIONAL SETUP
                 </listitem>
               </varlistentry>
               <varlistentry>
+                <term>degraded-carrier</term>
+                <listitem>
+                  <para>for bond or bridge master, one of the bonding or bridge slave network interfaces is
+                  in off, no-carrier, or dormant state</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
                 <term>carrier</term>
                 <listitem>
-                  <para>the link has a carrier</para>
+                  <para>the link has a carrier, or for bond or bridge master, all bonding or bridge slave
+                  network interfaces are enslaved to the master.</para>
                 </listitem>
               </varlistentry>
               <varlistentry>
                 </listitem>
               </varlistentry>
               <varlistentry>
+                <term>enslaved</term>
+                <listitem>
+                  <para>the link has carrier and is enslaved to bond or bridge master network interface</para>
+                </listitem>
+              </varlistentry>
+              <varlistentry>
                 <term>routable</term>
                 <listitem>
                   <para>the link has carrier and routable address configured</para>
       <varlistentry>
         <term>
           <command>status</command>
-          <optional><replaceable>LINK…</replaceable></optional>
+          <optional><replaceable>PATTERN…</replaceable></optional>
         </term>
 
         <listitem>
-          <para>Show information about the specified links: type,
-          state, kernel module driver, hardware and IP address,
-          configured DNS servers, etc.</para>
+          <para>Show information about the specified links: type, state, kernel module driver, hardware and
+          IP address, configured DNS servers, etc. If one ore more <replaceable>PATTERN</replaceable>s are
+          specified, only links matching one of them are shown.</para>
 
           <para>When no links are specified, an overall network status is shown. Also see the option
           <option>--all</option>.</para>
       <varlistentry>
         <term>
           <command>lldp</command>
-          <optional><replaceable>LINK…</replaceable></optional>
+          <optional><replaceable>PATTERN…</replaceable></optional>
         </term>
 
         <listitem>
-          <para>Show discovered LLDP (Link Layer Discovery Protocol) neighbors. If one or more link names are specified
-          only neighbors on those interfaces are shown. Otherwise shows discovered neighbors on all interfaces. Note
-          that for this feature to work, <varname>LLDP=</varname> must be turned on for the specific interface, see
+          <para>Show discovered LLDP (Link Layer Discovery Protocol) neighbors. If one or more
+          <replaceable>PATTERN</replaceable>s are specified only neighbors on those interfaces are shown.
+          Otherwise shows discovered neighbors on all interfaces. Note that for this feature to work,
+          <varname>LLDP=</varname> must be turned on for the specific interface, see
           <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
           details.</para>
 
index c624d4d..5164554 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <!--
index e447420..908c91e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="nss-myhostname" conditional='ENABLE_NSS_MYHOSTNAME'>
 
index 5742d89..ed03035 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="nss-mymachines" conditional='ENABLE_NSS_MYMACHINES'>
 
index 960d580..e4ea4e1 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="nss-resolve" conditional='ENABLE_NSS_RESOLVE'>
 
index d3d6843..8fde118 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="nss-systemd" conditional='ENABLE_NSS_SYSTEMD'>
 
index 6de0cd7..5a5e318 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="os-release">
   <refentryinfo>
index e5e14c1..fd8e4fb 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="pam_systemd" conditional='HAVE_PAM'>
 
index 3a5517a..01f6a1d 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="portablectl" conditional='ENABLE_PORTABLED'
index defd592..f986e98 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="resolvectl" conditional='ENABLE_RESOLVE'
           xmlns:xi="http://www.w3.org/2001/XInclude">
index d37bf0d..c8ab694 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="resolved.conf" conditional='ENABLE_RESOLVE'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 0c990a0..d949900 100644 (file)
@@ -275,7 +275,9 @@ manpages = [
   ''],
  ['sd_bus_new',
   '3',
-  ['sd_bus_flush_close_unref',
+  ['sd_bus_close_unref',
+   'sd_bus_close_unrefp',
+   'sd_bus_flush_close_unref',
    'sd_bus_flush_close_unrefp',
    'sd_bus_ref',
    'sd_bus_unref',
index 8b5025d..d8bfcd7 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="runlevel"
     xmlns:xi="http://www.w3.org/2001/XInclude"
index a94022c..e5590c8 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd-bus-errors"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 4620590..6c925e3 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd-bus" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index a404213..84deda1 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd-daemon"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 2e6ab69..afdafff 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd-event" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 4425c45..74d838d 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd-id128"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 3fa6c75..a3ee1ea 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd-journal"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 3743957..2787bd7 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd-login" conditional='HAVE_PAM'
   xmlns:xi="http://www.w3.org/2001/XInclude">
index ace5417..6a6a620 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_booted"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index c4f24ae..a106544 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <!--
   SPDX-License-Identifier: LGPL-2.1+
index a2f7297..2a207d2 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_attach_event"
           xmlns:xi="http://www.w3.org/2001/XInclude">
     0 or a positive integer. On failure, they return a negative errno-style error code.</para>
 
     <para><function>sd_bus_get_event()</function> returns an event loop object or <constant>NULL</constant>.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection has been created in a different process.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus connection has been created in a different process.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 369afd8..b09f488 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_close"
           xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, <function>sd_bus_flush()</function> returns 0 or a positive integer. On failure, it returns a
     negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection has been created in a different process.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus connection has been created in a different process.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index e2383a0..8b759f4 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_creds_get_pid" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, these calls return 0 or a positive integer. On
     failure, these calls return a negative errno-style error code.
     </para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
-
-    <para>Returned errors may indicate the following problems:</para>
-
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENODATA</constant></term>
-
-        <listitem><para>The given field is not available in the
-        credentials object <parameter>c</parameter>.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
-
-        <listitem><para>The given field is not specified for the described
-        process or peer. This will be returned by
-        <function>sd_bus_creds_get_unit()</function>,
-        <function>sd_bus_creds_get_slice()</function>,
-        <function>sd_bus_creds_get_user_unit()</function>,
-        <function>sd_bus_creds_get_user_slice()</function>, and
-        <function>sd_bus_creds_get_session()</function> if the process is
-        not part of a systemd system unit, systemd user unit, systemd
-        slice, or logind session. It will be returned by
-        <function>sd_bus_creds_get_owner_uid()</function> if the process is
-        not part of a systemd user unit or logind session. It will also be
-        returned by <function>sd_bus_creds_get_exe()</function> and
-        <function>sd_bus_creds_get_cmdline()</function> for kernel
-        threads (since these are not started from an executable binary,
-        nor have a command line), and by
-        <function>sd_bus_creds_get_audit_session_id()</function> and
-        <function>sd_bus_creds_get_audit_login_uid()</function> when
-        the process is not part of an audit session, and
-        <function>sd_bus_creds_get_tty()</function> if the process has
-        no controlling TTY.
-        </para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
-
-        <listitem><para>Specified pointer parameter is <constant>NULL</constant>.
-        </para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
-
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+    <refsect2>
+      <title>Errors</title>
+
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENODATA</constant></term>
+
+          <listitem><para>The given field is not available in the credentials object
+          <parameter>c</parameter>.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
+
+          <listitem><para>The given field is not specified for the described process or peer. This will be
+          returned by <function>sd_bus_creds_get_unit()</function>,
+          <function>sd_bus_creds_get_slice()</function>, <function>sd_bus_creds_get_user_unit()</function>,
+          <function>sd_bus_creds_get_user_slice()</function>, and
+          <function>sd_bus_creds_get_session()</function> if the process is not part of a systemd system
+          unit, systemd user unit, systemd slice, or logind session. It will be returned by
+          <function>sd_bus_creds_get_owner_uid()</function> if the process is not part of a systemd user unit
+          or logind session. It will also be returned by <function>sd_bus_creds_get_exe()</function> and
+          <function>sd_bus_creds_get_cmdline()</function> for kernel threads (since these are not started
+          from an executable binary, nor have a command line), and by
+          <function>sd_bus_creds_get_audit_session_id()</function> and
+          <function>sd_bus_creds_get_audit_login_uid()</function> when the process is not part of an audit
+          session, and <function>sd_bus_creds_get_tty()</function> if the process has no controlling
+          TTY.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
+
+          <listitem><para>Specified pointer parameter is <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
+
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index eda5d17..f5ee01c 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_creds_new_from_pid" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     not needed anymore, this reference should be destroyed with
     <citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
     </para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-ESRCH</constant></term>
+        <varlistentry>
+          <term><constant>-ESRCH</constant></term>
 
-        <listitem><para>Specified <parameter>pid</parameter> could not
-        be found.</para></listitem>
-      </varlistentry>
+          <listitem><para>Specified <parameter>pid</parameter> could not be found.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Specified parameter is invalid
-        (<constant>NULL</constant> in case of output
-        parameters).</para></listitem>
-      </varlistentry>
+          <listitem><para>Specified parameter is invalid (<constant>NULL</constant> in case of output
+          parameters).</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EOPNOTSUPP</constant></term>
+        <varlistentry>
+          <term><constant>-EOPNOTSUPP</constant></term>
 
-        <listitem><para>One of the requested fields is unknown to the local system.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>One of the requested fields is unknown to the local system.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index dfb32b9..51c27f0 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_default" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, these calls return 0 or a positive
     integer. On failure, these calls return a negative
     errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The specified parameters are invalid.</para></listitem>
-      </varlistentry>
+          <listitem><para>The specified parameters are invalid.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESOCKTNOSUPPORT</constant></term>
+        <varlistentry>
+          <term><constant>-ESOCKTNOSUPPORT</constant></term>
 
-        <listitem><para>The protocol version required to connect to the selected bus is not supported.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The protocol version required to connect to the selected bus is not
+          supported.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
-    <para>In addition, any further connection-related errors may be
-    by returned. See <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+      <para>In addition, any further connection-related errors may be by returned. See
+      <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 36cdf4c..8616f7e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_error" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     the memory held by the structure itself after freeing its contents
     with <function>sd_bus_error_free()</function>.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Error was already set in
-        <structname>sd_bus_error</structname> structure when one the
-        error-setting functions was called.</para></listitem>
-      </varlistentry>
+          <listitem><para>Error was already set in <structname>sd_bus_error</structname> structure when one
+          the error-setting functions was called.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index dbe05a1..1dfc725 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_error_add_map"
           xmlns:xi="http://www.w3.org/2001/XInclude">
     tables. It returns zero when the same array was already added
     before. On error, a negative <varname>errno</varname>-style error
     code is returned. See below for known error codes.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The specified mapping array is invalid.</para></listitem>
-      </varlistentry>
+          <listitem><para>The specified mapping array is invalid.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 2a81bdd..6a022b1 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <!--
   SPDX-License-Identifier: LGPL-2.1+
 
     <para><function>sd_bus_get_timeout()</function> returns zero or positive on success, or a negative
     <varname>errno</varname>-style error code on error.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid bus object was passed.</para></listitem>
-      </varlistentry>
+          <listitem><para>An invalid bus object was passed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection was allocated in a parent process and is being reused in a child process
-        after <function>fork()</function>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection was allocated in a parent process and is being reused in a child
+          process after <function>fork()</function>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOTCONN</constant></term>
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
 
-        <listitem><para>The bus connection has been terminated.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection has been terminated.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>Two distinct file descriptors were passed for input and output using
-        <function>sd_bus_set_fd()</function>, which <function>sd_bus_get_fd()</function> cannot
-        return.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Two distinct file descriptors were passed for input and output using
+          <function>sd_bus_set_fd()</function>, which <function>sd_bus_get_fd()</function> cannot
+          return.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 76ad659..f949c93 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_get_n_queued_read">
 
 
     <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
     error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection was created in a different process.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection was created in a different process.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <refsect1>
index 0388db8..d993142 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_is_open"
           xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
     error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection has been created in a different process.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus connection has been created in a different process.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 1fdda51..b87468e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_append"
           xmlns:xi="http://www.w3.org/2001/XInclude">
@@ -230,12 +227,11 @@ sd_bus_message_append(m, "ynqiuxtd", y, n, q, i, u, x, t, d);</programlisting>
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a positive
-    integer. On failure, these functions return a negative
+    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative
     errno-style error code.</para>
-  </refsect1>
 
-  <xi:include href="sd_bus_message_append_basic.xml" xpointer="errors" />
+    <xi:include href="sd_bus_message_append_basic.xml" xpointer="errors" />
+  </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
 
index 746f9e3..b9595d6 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_append_array"
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these calls return 0 or a positive integer. On
-    failure, they return a negative errno-style error code.</para>
-  </refsect1>
+    <para>On success, these calls return 0 or a positive integer. On failure, they return a negative
+    errno-style error code.</para>
 
-  <xi:include href="sd_bus_message_append_basic.xml" xpointer="errors" />
+    <xi:include href="sd_bus_message_append_basic.xml" xpointer="errors" />
+  </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
 
index abd3bae..a180046 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_append_basic" xmlns:xi="http://www.w3.org/2001/XInclude">
 
 
     <para>On success, this call returns 0 or a positive integer. On
     failure, it returns a negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1 id='errors'>
-    <title>Errors</title>
+    <refsect2 id='errors'>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Specified parameter is invalid.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Specified parameter is invalid.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>Message has been sealed.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Message has been sealed.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>Message is in invalid state.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Message is in invalid state.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>Message cannot be appended to.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Message cannot be appended to.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 4224af0..c59b8a4 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_append_string_memfd"
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, those calls return 0 or a positive integer. On
-    failure, they returns a negative errno-style error code.</para>
-  </refsect1>
+    <para>On success, those calls return 0 or a positive integer. On failure, they return a negative
+    errno-style error code.</para>
 
-  <xi:include href="sd_bus_message_append_basic.xml" xpointer="errors" />
+    <xi:include href="sd_bus_message_append_basic.xml" xpointer="errors" />
+  </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
 
index 5f1a4f5..2ce3216 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_append_strv"
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, this call returns 0 or a positive integer. On
-    failure, a negative errno-style error code is returned.</para>
-  </refsect1>
+    <para>On success, this call returns 0 or a positive integer. On failure, a negative errno-style error
+    code is returned.</para>
 
-  <xi:include href="sd_bus_message_append_basic.xml" xpointer="errors" />
+    <xi:include href="sd_bus_message_append_basic.xml" xpointer="errors" />
+  </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
 
index ac2a4f3..cd8ad72 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_copy" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, this call returns true if anything was copied, and false if
     there was nothing to copy. On failure, it returns a negative errno-style error
     code.</para>
-  </refsect1>
 
-  <refsect1 id='errors'>
-    <title>Errors</title>
+    <refsect2 id='errors'>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para><parameter>source</parameter> or <parameter>m</parameter> are
-        <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para><parameter>source</parameter> or <parameter>m</parameter> are
+          <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>Message <parameter>m</parameter> has been sealed or
-        <parameter>source</parameter> has <emphasis>not</emphasis> been sealed.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Message <parameter>m</parameter> has been sealed or <parameter>source</parameter>
+          has <emphasis>not</emphasis> been sealed.  </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>Destination message is in invalid state.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Destination message is in invalid state.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>Destination message cannot be appended to.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Destination message cannot be appended to.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index cc9a445..7b9408c 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_get_cookie"
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these calls return 0 or a positive integer. On
-    failure, these calls return a negative errno-style error
-    code.</para>
+    <para>On success, these calls return 0 or a positive integer. On failure, they return a negative
+    errno-style error code.</para>
 
-    <para>On success, the cookie/reply cookie is returned in the
-    specified 64-bit unsigned integer variable.</para>
-  </refsect1>
+    <para>On success, the cookie/reply cookie is returned in the specified 64-bit unsigned integer
+    variable.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>A specified parameter
-        is invalid.</para></listitem>
-      </varlistentry>
+          <listitem><para>A specified parameter is invalid.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENODATA</constant></term>
+        <varlistentry>
+          <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>No cookie has been assigned to this message.
-        This either indicates that the message has not been sent yet
-        and hence has no cookie assigned, or that the message is not a
-        method response message and hence carries a reply cookie
-        field.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>No cookie has been assigned to this message.  This either indicates that the
+          message has not been sent yet and hence has no cookie assigned, or that the message is not a method
+          response message and hence carries a reply cookie field.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 06ea227..958b832 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_get_monotonic_usec"
           xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, the timestamp or sequence number is returned in
     the specified 64-bit unsigned integer variable.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>A specified parameter is
-        invalid.</para></listitem>
-      </varlistentry>
+          <listitem><para>A specified parameter is invalid.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENODATA</constant></term>
+        <varlistentry>
+          <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>No timestamp or sequence number information is
-        attached to the passed message. This error is returned if the
-        underlying transport does not support timestamping or
-        assigning of sequence numbers, or if this feature has not been
-        negotiated with
-        <citerefentry><refentrytitle>sd_bus_negotiate_timestamp</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>No timestamp or sequence number information is attached to the passed message. This
+          error is returned if the underlying transport does not support timestamping or assigning of
+          sequence numbers, or if this feature has not been negotiated with
+          <citerefentry><refentrytitle>sd_bus_negotiate_timestamp</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index bee6778..e3f4134 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 
     <para>The other functions return 0 or a positive integer on success. On failure, they return a
     negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>message</parameter> parameter is <constant>NULL</constant>.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>The <parameter>message</parameter> parameter is <constant>NULL</constant>.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>NULL</constant></term>
+        <varlistentry>
+          <term><constant>NULL</constant></term>
 
-        <listitem><para>The <parameter>message</parameter> parameter is <constant>NULL</constant>.
-        </para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The <parameter>message</parameter> parameter is <constant>NULL</constant>.
+          </para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 6f6b7d0..d8a45ce 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 
     <para>On success, those functions return 0 or a positive
     integer. On failure, it returns a negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>message</parameter> parameter or the output parameter are
-        <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The <parameter>message</parameter> parameter or the output parameter are
+          <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 78bca8a..efe650d 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
     <constant>NULL</constant>.</para>
 
     <para><function>sd_bus_message_get_bus()</function> always returns the bus object.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Specified <parameter>type</parameter> is invalid.</para></listitem>
-      </varlistentry>
+          <listitem><para>Specified <parameter>type</parameter> is invalid.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOTCONN</constant></term>
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
 
-        <listitem><para>The bus parameter <parameter>bus</parameter> is <constant>NULL</constant> or
-        the bus is not connected.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus parameter <parameter>bus</parameter> is <constant>NULL</constant> or
+          the bus is not connected.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index c643177..0d181ed 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_new_method_call"
 
     <para>This function returns 0 if the message object was successfully created, and a negative
     errno-style error code otherwise.</para>
-  </refsect1>
 
-  <refsect1 id='errors'>
-    <title>Errors</title>
+    <refsect2 id='errors'>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The output parameter <parameter>m</parameter> is
-        <constant>NULL</constant>.</para>
+          <listitem><para>The output parameter <parameter>m</parameter> is
+          <constant>NULL</constant>.</para>
 
-        <para>The <parameter>destination</parameter> parameter is non-null and is not a valid D-Bus
-        service name (<literal>org.somewhere.Something</literal>), the <parameter>path</parameter>
-        parameter is not a valid D-Bus path (<literal>/an/object/path</literal>), the
-        <parameter>interface</parameter> parameter is non-null and is not a valid D-Bus interface
-        name (<literal>an.interface.name</literal>), or the <parameter>member</parameter> parameter
-        is not a valid D-Bus member (<literal>Name</literal>).</para>
+          <para>The <parameter>destination</parameter> parameter is non-null and is not a valid D-Bus
+          service name (<literal>org.somewhere.Something</literal>), the <parameter>path</parameter>
+          parameter is not a valid D-Bus path (<literal>/an/object/path</literal>), the
+          <parameter>interface</parameter> parameter is non-null and is not a valid D-Bus interface
+          name (<literal>an.interface.name</literal>), or the <parameter>member</parameter> parameter
+          is not a valid D-Bus member (<literal>Name</literal>).</para>
 
-        <para>The <parameter>call</parameter> parameter is not a method call object.</para>
-        </listitem>
-      </varlistentry>
+          <para>The <parameter>call</parameter> parameter is not a method call object.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOTCONN</constant></term>
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
 
-        <listitem><para>The bus parameter <parameter>bus</parameter> is <constant>NULL</constant> or
-        the bus is not connected.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus parameter <parameter>bus</parameter> is <constant>NULL</constant> or
+          the bus is not connected.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem>
-        <para>The <parameter>call</parameter> parameter is not sealed.</para>
-        </listitem>
-      </varlistentry>
+          <listitem>
+            <para>The <parameter>call</parameter> parameter is not sealed.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EOPNOTSUPP</constant></term>
+        <varlistentry>
+          <term><constant>-EOPNOTSUPP</constant></term>
 
-        <listitem>
-        <para>The <parameter>call</parameter> message does not have a cookie.</para>
-        </listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem>
+            <para>The <parameter>call</parameter> message does not have a cookie.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 045c74f..27cec8e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_new_method_error"
           xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>These functions return 0 if the error reply was successfully created, and a
     negative errno-style error code otherwise.</para>
-  </refsect1>
 
-  <refsect1 id='errors'>
-    <title>Errors</title>
+    <refsect2 id='errors'>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The call message <parameter>call</parameter> or the output
-        parameter <parameter>m</parameter> are <constant>NULL</constant>.</para>
+          <listitem><para>The call message <parameter>call</parameter> or the output
+          parameter <parameter>m</parameter> are <constant>NULL</constant>.</para>
 
-        <para>Message <parameter>call</parameter> is not a method call
-        message.</para>
+          <para>Message <parameter>call</parameter> is not a method call
+          message.</para>
 
-        <para>The error <parameter>error</parameter> parameter to
-        <function>sd_bus_message_new_method_error</function> is not set, see
-        <citerefentry><refentrytitle>sd_bus_error_is_set</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
-        </para>
-        </listitem>
-      </varlistentry>
+          <para>The error <parameter>error</parameter> parameter to
+          <function>sd_bus_message_new_method_error</function> is not set, see
+          <citerefentry><refentrytitle>sd_bus_error_is_set</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+          </para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>Message <parameter>call</parameter> has been sealed.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Message <parameter>call</parameter> has been sealed.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOTCONN</constant></term>
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
 
-        <listitem><para>The bus to which message <parameter>call</parameter> is
-        attached is not connected.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus to which message <parameter>call</parameter> is
+          attached is not connected.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index c9ed0bc..6161930 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_new_signal"
 
     <para>This function returns 0 if the message object was successfully created, and a negative
     errno-style error code otherwise.</para>
-  </refsect1>
 
-  <refsect1 id='errors'>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The output parameter <parameter>m</parameter> is
-        <constant>NULL</constant>.</para>
+          <listitem><para>The output parameter <parameter>m</parameter> is
+          <constant>NULL</constant>.</para>
 
-        <para>The <parameter>path</parameter> parameter is not a valid D-Bus path
-        (<literal>/an/object/path</literal>), the <parameter>interface</parameter> parameter is not
-        a valid D-Bus interface name (<literal>an.interface.name</literal>), or the
-        <parameter>member</parameter> parameter is not a valid D-Bus member
-        (<literal>Name</literal>).</para></listitem>
-      </varlistentry>
+          <para>The <parameter>path</parameter> parameter is not a valid D-Bus path
+          (<literal>/an/object/path</literal>), the <parameter>interface</parameter> parameter is not
+          a valid D-Bus interface name (<literal>an.interface.name</literal>), or the
+          <parameter>member</parameter> parameter is not a valid D-Bus member
+          (<literal>Name</literal>).</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOTCONN</constant></term>
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
 
-        <listitem><para>The bus parameter <parameter>bus</parameter> is <constant>NULL</constant> or
-        the bus is not connected.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus parameter <parameter>bus</parameter> is <constant>NULL</constant> or
+          the bus is not connected.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 2815c01..526fb0e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_read"
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>
-      On success, <function>sd_bus_message_read()</function> and
-      <function>sd_bus_message_readv()</function> return 0 or a positive integer. On
-      failure, they return a negative errno-style error code.
-    </para>
-  </refsect1>
+    <para>On success, <function>sd_bus_message_read()</function> and
+    <function>sd_bus_message_readv()</function> return 0 or a positive integer. On failure, they return a
+    negative errno-style error code.</para>
 
-  <xi:include href="sd_bus_message_read_basic.xml" xpointer="errors" />
+    <xi:include href="sd_bus_message_read_basic.xml" xpointer="errors" />
+  </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
 
index 3148127..117afa9 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
       a positive integer. On failure, it returns a negative errno-style error
       code.
     </para>
-  </refsect1>
 
-  <refsect1 id='errors'>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Specified type is invalid or the message parameter or one of the output
-        parameters are <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para>Specified type is invalid or the message parameter or one of the output
+          parameters are <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EOPNOTSUPP</constant></term>
+        <varlistentry>
+          <term><constant>-EOPNOTSUPP</constant></term>
 
-        <listitem><para>The byte order in the message is different than native byte
-        order.</para></listitem>
-      </varlistentry>
+          <listitem><para>The byte order in the message is different than native byte
+          order.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>The message is not sealed.</para></listitem>
-      </varlistentry>
+          <listitem><para>The message is not sealed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EBADMSG</constant></term>
+        <varlistentry>
+          <term><constant>-EBADMSG</constant></term>
 
-        <listitem><para>The message cannot be parsed.</para></listitem>
-      </varlistentry>
+          <listitem><para>The message cannot be parsed.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <refsect1>
index 774d3fc..101f5d2 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <!--
   SPDX-License-Identifier: LGPL-2.1+
       a positive integer. On failure, it returns a negative errno-style error
       code.
     </para>
-  </refsect1>
 
-  <refsect1 id='errors'>
-    <title>Errors</title>
+    <refsect2 id='errors'>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Specified type string is invalid or the message parameter is
-        <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para>Specified type string is invalid or the message parameter is
+          <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>The message does not contain the specified type at current
-        position.</para></listitem>
-      </varlistentry>
+          <listitem><para>The message does not contain the specified type at current position.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EBADMSG</constant></term>
+        <varlistentry>
+          <term><constant>-EBADMSG</constant></term>
 
-        <listitem><para>The message cannot be parsed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The message cannot be parsed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <refsect1>
index c420c2f..aa8aea9 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
       container or whole message in case no container is open is empty, and positive otherwise. On
       failure, it returns a negative errno-style error code.
     </para>
-  </refsect1>
-
-  <xi:include href="libsystemd-pkgconfig.xml" />
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>m</parameter> parameter is <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The <parameter>m</parameter> parameter is <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>The message <parameter>m</parameter> has not been sealed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The message <parameter>m</parameter> has not been sealed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
+  <xi:include href="libsystemd-pkgconfig.xml" />
+
   <refsect1>
     <title>See Also</title>
 
index e8a1206..ca3e466 100644 (file)
@@ -1,9 +1,6 @@
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_message_set_destination" xmlns:xi="http://www.w3.org/2001/XInclude">
   <refentryinfo>
 
     <para>On success, these calls return 0 or a positive integer. On failure, these calls return a
     negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>message</parameter> parameter or the output parameter are
-        <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The <parameter>message</parameter> parameter or the output parameter are
+          <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>For <function>sd_bus_message_set_destination</function> or
-        <function>sd_bus_message_set_sender</function>, the message is already
-        sealed.</para></listitem>
-      </varlistentry>
+          <listitem><para>For <function>sd_bus_message_set_destination</function> or
+          <function>sd_bus_message_set_sender</function>, the message is already
+          sealed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EEXIST</constant></term>
+        <varlistentry>
+          <term><constant>-EEXIST</constant></term>
 
-        <listitem><para>The message already has a destination or sender field set.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The message already has a destination or sender field set.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 2dfabca..6f22e82 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 
     <para>On success, these functions return 0 or a positive integer. On failure, they return a
     negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>message</parameter> parameter is
-        <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The <parameter>message</parameter> parameter is
+          <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>The message <parameter>message</parameter> is sealed
-        when trying to set a flag.</para>
+          <listitem><para>The message <parameter>message</parameter> is sealed
+          when trying to set a flag.</para>
 
-        <para>The message <parameter>message</parameter> has wrong
-        type.</para>
-        </listitem>
-      </varlistentry>
-    </variablelist>
+          <para>The message <parameter>message</parameter> has wrong
+          type.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 384a791..0e740ab 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 
     <para>On success, <function>sd_bus_message_skip()</function> returns 0 or a positive integer. On
     failure, it returns a negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>m</parameter> parameter is
-        <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The <parameter>m</parameter> parameter is
+          <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EBADMSG</constant></term>
+        <varlistentry>
+          <term><constant>-EBADMSG</constant></term>
 
-        <listitem><para>The message cannot be parsed.</para></listitem>
-      </varlistentry>
+          <listitem><para>The message cannot be parsed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>The message is not sealed.</para></listitem>
-      </varlistentry>
+          <listitem><para>The message is not sealed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>The message end has been reached and the requested elements cannot be read.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>The message end has been reached and the requested elements cannot be read.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index fcb9f19..c3230e5 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
     <para>On success, this call returns true if the type matches and zero if not (the message
     <parameter>m</parameter> contains different data or the end of the message has been reached). On
     failure, it returns a negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1 id='errors'>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para><parameter>m</parameter> or both <parameter>type</parameter> and
-        <parameter>contents</parameter> are <constant>NULL</constant>.</para>
+          <listitem><para><parameter>m</parameter> or both <parameter>type</parameter> and
+          <parameter>contents</parameter> are <constant>NULL</constant>.</para>
 
-        <para>Arguments do not satisfy other contraints listed above.</para>
-        </listitem>
-      </varlistentry>
+          <para>Arguments do not satisfy other contraints listed above.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>Message <parameter>m</parameter> is not sealed.
-        </para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Message <parameter>m</parameter> is not sealed.
+          </para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index b2a4541..9991026 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_negotiate_fds" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, these functions return 0 or a
     positive integer. On failure, they return a negative errno-style
     error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>The bus connection has already been started.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus connection has already been started.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index cc08e6b..8506ee8 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_new" xmlns:xi="http://www.w3.org/2001/XInclude">
 
 
     <para><function>sd_bus_unref()</function> and <function>sd_bus_flush_close_unref()</function> always return
     <constant>NULL</constant>.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 03130a6..ade11bc 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_path_encode" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 66f22c2..8f35388 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <!--
   SPDX-License-Identifier: LGPL-2.1+
   <refsect1>
     <title>Return Value</title>
 
-    <para>If progress was made, a positive integer is returned. If no progress was made, 0 is returned. If an error
-    occurs, a negative <varname>errno</varname>-style error code is returned.</para>
-  </refsect1>
+    <para>If progress was made, a positive integer is returned. If no progress was made, 0 is returned. If an
+    error occurs, a negative <varname>errno</varname>-style error code is returned.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid bus object was passed.</para></listitem>
-      </varlistentry>
+          <listitem><para>An invalid bus object was passed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection was allocated in a parent process and is being reused in a child process
-        after <function>fork()</function>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection was allocated in a parent process and is being reused in a child
+          process after <function>fork()</function>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOTCONN</constant></term>
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
 
-        <listitem><para>The bus connection has been terminated already.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection has been terminated already.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECONNRESET</constant></term>
+        <varlistentry>
+          <term><constant>-ECONNRESET</constant></term>
 
-        <listitem><para>The bus connection has been terminated just now.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection has been terminated just now.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EBUSY</constant></term>
+        <varlistentry>
+          <term><constant>-EBUSY</constant></term>
 
-        <listitem><para>This function is already being called, i.e. <function>sd_bus_process()</function> has been
-        called from a callback function that itself was called by
-        <function>sd_bus_process()</function>.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>This function is already being called, i.e. <function>sd_bus_process()</function>
+          has been called from a callback function that itself was called by
+          <function>sd_bus_process()</function>.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index bbb916d..5a6cef6 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_reply_method_error"
           xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>These functions return 0 if the error reply was successfully sent or if
     none was expected, and a negative errno-style error code otherwise.</para>
-  </refsect1>
 
-  <refsect1 id='errors'>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The call message <parameter>call</parameter> is
-        <constant>NULL</constant>.</para>
+          <listitem><para>The call message <parameter>call</parameter> is
+          <constant>NULL</constant>.</para>
 
-        <para>Message <parameter>call</parameter> is not a method call message.
-        </para>
+          <para>Message <parameter>call</parameter> is not a method call message.
+          </para>
 
-        <para>Message <parameter>call</parameter> is not attached to a bus.</para>
+          <para>Message <parameter>call</parameter> is not attached to a bus.</para>
 
-        <para>The error <parameter>error</parameter> parameter to
-        <function>sd_bus_reply_method_error</function> is not set, see
-        <citerefentry><refentrytitle>sd_bus_error_is_set</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
-        </para>
-        </listitem>
-      </varlistentry>
+          <para>The error <parameter>error</parameter> parameter to
+          <function>sd_bus_reply_method_error</function> is not set, see
+          <citerefentry><refentrytitle>sd_bus_error_is_set</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+          </para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>Message <parameter>call</parameter> has been sealed.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Message <parameter>call</parameter> has been sealed.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOTCONN</constant></term>
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
 
-        <listitem><para>The bus to which message <parameter>call</parameter> is
-        attached is not connected.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus to which message <parameter>call</parameter> is attached is not
+          connected.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
-    <para>In addition, any error message returned by
-    <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    may be returned.</para>
+      <para>In addition, any error message returned by
+      <citerefentry><refentrytitle>sd_bus_send</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      may be returned.</para>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index cf0b552..0f6a4ec 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_request_name"
           xmlns:xi="http://www.w3.org/2001/XInclude">
     case, the caller can subscribe to <literal>NameOwnerChanged</literal> signals to be notified when the name is
     successfully acquired.  <function>sd_bus_request_name()</function> returns &gt; 0 when the name has immediately
     been acquired successfully.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EALREADY</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EALREADY</constant></term>
 
-        <listitem><para>The caller already is the owner of the specified name.</para></listitem>
-      </varlistentry>
+          <listitem><para>The caller already is the owner of the specified name.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EEXIST</constant></term>
+        <varlistentry>
+          <term><constant>-EEXIST</constant></term>
 
-        <listitem><para>The name has already been acquired by a different peer, and SD_BUS_NAME_REPLACE_EXISTING was
-        not specified or the other peer did not specify SD_BUS_NAME_ALLOW_REPLACEMENT while acquiring the
-        name.</para></listitem>
-      </varlistentry>
+          <listitem><para>The name has already been acquired by a different peer, and SD_BUS_NAME_REPLACE_EXISTING was
+          not specified or the other peer did not specify SD_BUS_NAME_ALLOW_REPLACEMENT while acquiring the
+          name.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESRCH</constant></term>
+        <varlistentry>
+          <term><constant>-ESRCH</constant></term>
 
-        <listitem><para>It was attempted to release a name that is currently not registered on the
-        bus.</para></listitem>
-      </varlistentry>
+          <listitem><para>It was attempted to release a name that is currently not registered on the
+          bus.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EADDRINUSE</constant></term>
+        <varlistentry>
+          <term><constant>-EADDRINUSE</constant></term>
 
-        <listitem><para>It was attempted to release a name that is owned by a different peer on the
-        bus.</para></listitem>
-      </varlistentry>
+          <listitem><para>It was attempted to release a name that is owned by a different peer on the
+          bus.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>A specified parameter is invalid. This is also generated when the requested name is a special
-        service name reserved by the D-Bus specification, or when the operation is requested on a connection that does
-        not refer to a bus.</para></listitem>
-      </varlistentry>
+          <listitem><para>A specified parameter is invalid. This is also generated when the requested name is
+          a special service name reserved by the D-Bus specification, or when the operation is requested on a
+          connection that does not refer to a bus.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOTCONN</constant></term>
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
 
-        <listitem><para>The bus connection has been disconnected.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection has been disconnected.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection has been created in a different process than the current
-        one.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus connection has been created in a different process than the current
+          one.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index dc4f6a3..751fc0a 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_set_close_on_exit"
           xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para><function>sd_bus_get_close_on_exit()</function> returns 0 if the feature is currently turned off or a
     positive integer if it is on. On failure, it returns a negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection has been created in a different process.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus connection has been created in a different process.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 32fc630..edb0df2 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_set_connected_signal"
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
-    error code.</para>
-  </refsect1>
+    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative
+    errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection has been created in a different process.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus connection has been created in a different process.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index af02c20..cfcebdf 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_set_description" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a positive integer. On failure,
-    they return a negative errno-style error code.</para>
-  </refsect1>
+    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative
+    errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An argument is invalid.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>An argument is invalid.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOPKG</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOPKG</constant></term>
 
-        <listitem><para>The bus cannot be resolved.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus cannot be resolved.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>The bus has already been started.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus has already been started.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus was created in a different process.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus was created in a different process.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 556e72c..b3f67d9 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_set_sender"
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
-    error code.</para>
-  </refsect1>
+    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative
+    errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection has been created in a different process.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection has been created in a different process.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EPERM</constant></term>
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
 
-        <listitem><para>The specified bus connection object is a not a direct but a brokered connection.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The specified bus connection object is a not a direct but a brokered
+          connection.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 129b98c..cbdc7dd 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_set_watch_bind"
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
-    error code.</para>
-  </refsect1>
+    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative
+    errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection has been created in a different process.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus connection has been created in a different process.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index c5f0506..c73f3c9 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
index 4bcb1e3..13dd6f8 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 
     <para>On success, these functions return 0 or a positive integer. On failure,
     they return a negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An required argument is <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>An required argument is <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>The bus slot object has no description.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus slot object has no description.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
 
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 80bfd86..c6fe72e 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_slot_set_destroy_callback"
     <title>Return Value</title>
 
     <para>On success, <function>sd_bus_slot_set_destroy_callback()</function> and
-    <function>sd_bus_track_set_destroy_callback()</function> return 0 or a positive integer. On failure, they return a
-    negative errno-style error code.</para>
+    <function>sd_bus_track_set_destroy_callback()</function> return 0 or a positive integer. On failure, they
+    return a negative errno-style error code.</para>
 
     <para><function>sd_bus_slot_get_destroy_callback()</function> and
-    <function>sd_bus_track_get_destroy_callback()</function> return positive if the destroy callback function is set, 0
-    if not. On failure, they return a negative errno-style error code.</para>
-  </refsect1>
+    <function>sd_bus_track_get_destroy_callback()</function> return positive if the destroy callback function
+    is set, 0 if not. On failure, they return a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>slot</parameter> or <parameter>track</parameter> parameter is
-        <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The <parameter>slot</parameter> or <parameter>track</parameter> parameter is
+          <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 2b8c900..f63907a 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_slot_set_floating" xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
-    error code.</para>
-  </refsect1>
+    <para>On success, these functions return 0 or a positive integer. On failure, they return a negative
+    errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>slot</parameter> parameter is <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The <parameter>slot</parameter> parameter is <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection has been created in a different process.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection has been created in a different process.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The bus object the specified bus slot object is associated with has already been freed, and
-        hence no change in the floating state can be made anymore.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus object the specified bus slot object is associated with has already been
+          freed, and hence no change in the floating state can be made anymore.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index dad708b..f0456b4 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
index ef304fc..29501ad 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_track_add_name" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para><function>sd_bus_track_first()</function> and <function>sd_bus_track_next()</function> return the first/next
     name contained in the bus peer tracking object, and <constant>NULL</constant> if the end of the enumeration is
     reached and on error.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EUNATCH</constant></term>
+        <varlistentry>
+          <term><constant>-EUNATCH</constant></term>
 
-        <listitem><para><function>sd_bus_track_remove_name()</function> or
-        <function>sd_bus_track_remove_sender()</function> have been invoked for a name not previously added to the bus
-        peer object.</para></listitem>
-      </varlistentry>
+          <listitem><para><function>sd_bus_track_remove_name()</function> or
+          <function>sd_bus_track_remove_sender()</function> have been invoked for a name not previously added
+          to the bus peer object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Specified parameter is invalid.</para></listitem>
-      </varlistentry>
+          <listitem><para>Specified parameter is invalid.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 711eca3..9b79eb4 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_bus_track_new" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     reference. When not needed anymore, this reference should be destroyed with
     <function>sd_bus_track_unref()</function>.
     </para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EBUSY</constant></term>
+        <varlistentry>
+          <term><constant>-EBUSY</constant></term>
 
-        <listitem><para>Bus peers have already been added to the bus peer tracking object and
-        <function>sd_bus_track_set_recursive()</function> was called to change tracking mode.</para></listitem>
-      </varlistentry>
+          <listitem><para>Bus peers have already been added to the bus peer tracking object and
+          <function>sd_bus_track_set_recursive()</function> was called to change tracking mode.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>Specified parameter is invalid
-        (<constant>NULL</constant> in case of output
-        parameters).</para></listitem>
-      </varlistentry>
+          <listitem><para>Specified parameter is invalid
+          (<constant>NULL</constant> in case of output
+          parameters).</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index e866eeb..7b97dc0 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <!--
   SPDX-License-Identifier: LGPL-2.1+
 
     <para>If any I/O was seen, a positive value is returned, zero otherwise. If an error occurs, a negative
     <varname>errno</varname>-style error code is returned.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid bus object was passed.</para></listitem>
-      </varlistentry>
+          <listitem><para>An invalid bus object was passed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The bus connection was allocated in a parent process and is being reused in a child process
-        after <function>fork()</function>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The bus connection was allocated in a parent process and is being reused in a child
+          process after <function>fork()</function>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOTCONN</constant></term>
+        <varlistentry>
+          <term><constant>-ENOTCONN</constant></term>
 
-        <listitem><para>The bus connection has been terminated already.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The bus connection has been terminated already.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index c1b38f8..23fa78e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_add_child" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, these functions return 0 or a positive
     integer. On failure, they return a negative errno-style error
     code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory to allocate an object.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory to allocate an object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid argument has been passed. This includes
-        specifying an empty mask in <parameter>options</parameter> or a mask
-        which contains values different than a combination of
-        <constant>WEXITED</constant>, <constant>WSTOPPED</constant>, and
-        <constant>WCONTINUED</constant>.
-        </para></listitem>
+          <listitem><para>An invalid argument has been passed. This includes
+          specifying an empty mask in <parameter>options</parameter> or a mask
+          which contains values different than a combination of
+          <constant>WEXITED</constant>, <constant>WSTOPPED</constant>, and
+          <constant>WCONTINUED</constant>.
+          </para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EBUSY</constant></term>
+        <varlistentry>
+          <term><constant>-EBUSY</constant></term>
 
-        <listitem><para>A handler is already installed for this
-        child process.</para></listitem>
+          <listitem><para>A handler is already installed for this
+          child process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem><para>The event loop is already terminated.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EDOM</constant></term>
+        <varlistentry>
+          <term><constant>-EDOM</constant></term>
 
-        <listitem><para>The passed event source is not a child process event source.</para></listitem>
-      </varlistentry>
+          <listitem><para>The passed event source is not a child process event source.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 82ddce6..636c61e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_add_defer" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, these functions return 0 or a positive
     integer. On failure, they return a negative errno-style error
     code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory to allocate an object.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory to allocate an object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid argument has been passed.</para></listitem>
-      </varlistentry>
+          <listitem><para>An invalid argument has been passed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop is already terminated.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 65765ea..3c9f2fb 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_add_inotify" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, these functions return 0 or a positive integer. On failure, they return a negative errno-style
     error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory to allocate an object.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory to allocate an object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid argument has been passed. This includes specifying a mask with
-        <constant>IN_MASK_ADD</constant> set.</para></listitem>
-      </varlistentry>
+          <listitem><para>An invalid argument has been passed. This includes specifying a mask with
+          <constant>IN_MASK_ADD</constant> set.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem><para>The event loop is already terminated.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EDOM</constant></term>
+        <varlistentry>
+          <term><constant>-EDOM</constant></term>
 
-        <listitem><para>The passed event source is not an inotify process event source.</para></listitem>
-      </varlistentry>
+          <listitem><para>The passed event source is not an inotify process event source.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <refsect1>
index 6b3da2b..398b938 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_add_io" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     "floating", and will be destroyed implicitly when the event loop
     itself is destroyed.</para>
 
+    <para>Note that this call does not take possession of the file descriptor passed in, ownership (and thus
+    the duty to close it when it is no longer needed) remains with the caller. However, with the
+    <function>sd_event_source_set_io_fd_own()</function> call (see below) the event source may optionally
+    take ownership of the file descriptor after the event source has been created. In that case the file
+    descriptor is closed automatically as soon as the event source is released.</para>
+
     <para>It is recommended to use
     <function>sd_event_add_io()</function> only in conjunction with
     file descriptors that have <constant>O_NONBLOCK</constant> set, to
     <para>On success, these functions return 0 or a positive
     integer. On failure, they return a negative errno-style error
     code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned values may indicate the following problems:</para>
+      <para>Returned values may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory to allocate an object.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory to allocate an object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid argument has been passed.</para></listitem>
+          <listitem><para>An invalid argument has been passed.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem><para>The event loop is already terminated.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EDOM</constant></term>
+        <varlistentry>
+          <term><constant>-EDOM</constant></term>
 
-        <listitem><para>The passed event source is not an I/O event source.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The passed event source is not an I/O event source.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 8f03d05..9bf777c 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_add_signal" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, these functions return 0 or a positive
     integer. On failure, they return a negative errno-style error
     code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory to allocate an object.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory to allocate an object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid argument has been passed.</para></listitem>
-      </varlistentry>
+          <listitem><para>An invalid argument has been passed.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EBUSY</constant></term>
+        <varlistentry>
+          <term><constant>-EBUSY</constant></term>
 
-        <listitem><para>A handler is already installed for this
-        signal or the signal was not blocked previously.</para></listitem>
-      </varlistentry>
+          <listitem><para>A handler is already installed for this
+          signal or the signal was not blocked previously.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop is already terminated.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EDOM</constant></term>
+        <varlistentry>
+          <term><constant>-EDOM</constant></term>
 
-        <listitem><para>The passed event source is not a signal event source.</para></listitem>
-      </varlistentry>
+          <listitem><para>The passed event source is not a signal event source.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index e6dbd15..7316364 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_add_time" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <para>On success, these functions return 0 or a positive
     integer. On failure, they return a negative errno-style error
     code. </para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned values may indicate the following problems:</para>
+      <para>Returned values may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory to allocate an object.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory to allocate an object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid argument has been passed.</para></listitem>
+          <listitem><para>An invalid argument has been passed.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem><para>The event loop is already terminated.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EOPNOTSUPP</constant></term>
+        <varlistentry>
+          <term><constant>-EOPNOTSUPP</constant></term>
 
-        <listitem><para>The selected clock is not supported by the event loop implementation.</para></listitem>
+          <listitem><para>The selected clock is not supported by the event loop implementation.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EDOM</constant></term>
+        <varlistentry>
+          <term><constant>-EDOM</constant></term>
 
-        <listitem><para>The passed event source is not a timer event source.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The passed event source is not a timer event source.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 2af275b..a02897a 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_exit" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, <function>sd_event_exit()</function> and
-    <function>sd_event_get_exit_code()</function> return 0 or a positive
-    integer. On failure, they return a negative errno-style error
-    code.</para>
-  </refsect1>
+    <para>On success, <function>sd_event_exit()</function> and <function>sd_event_get_exit_code()</function>
+    return 0 or a positive integer. On failure, they return a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The event loop object or error code pointer are invalid.</para></listitem>
+          <listitem><para>The event loop object or error code pointer are invalid.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop was created in a different process.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop was created in a different process.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop has exited already and all exit handlers are already processed.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop has exited already and all exit handlers are already processed.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENODATA</constant></term>
+        <varlistentry>
+          <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>The event loop has not been requested to exit yet.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop has not been requested to exit yet.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 5f66fbc..3e78182 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_get_fd" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, <function>sd_event_get_fd()</function> returns a
-    non-negative file descriptor. On failure, it returns a negative
-    errno-style error code.</para>
-  </refsect1>
+    <para>On success, <function>sd_event_get_fd()</function> returns a non-negative file descriptor. On
+    failure, it returns a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para><parameter>event</parameter> is not a valid
-        pointer to an <structname>sd_event</structname> structure.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para><parameter>event</parameter> is not a valid pointer to an
+          <structname>sd_event</structname> structure.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
-    </variablelist>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <refsect1>
index ddb8dac..3db39c9 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_new" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, <function>sd_event_new()</function>,
-    <function>sd_event_default()</function> and
-    <function>sd_event_get_tid()</function> return 0 or a positive
-    integer. On failure, they return a negative errno-style error
-    code. <function>sd_event_ref()</function> always returns a pointer
-    to the event loop object passed
-    in. <function>sd_event_unref()</function> always returns
+    <para>On success, <function>sd_event_new()</function>, <function>sd_event_default()</function> and
+    <function>sd_event_get_tid()</function> return 0 or a positive integer. On failure, they return a
+    negative errno-style error code. <function>sd_event_ref()</function> always returns a pointer to the
+    event loop object passed in. <function>sd_event_unref()</function> always returns
     <constant>NULL</constant>.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory to allocate the object.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory to allocate the object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EMFILE</constant></term>
+        <varlistentry>
+          <term><constant>-EMFILE</constant></term>
 
-        <listitem><para>The maximum number of event loops has been allocated.</para></listitem>
+          <listitem><para>The maximum number of event loops has been allocated.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para><function>sd_event_get_tid()</function> was
-        invoked on an event loop object that was not allocated with
-        <function>sd_event_default()</function>.</para></listitem>
-      </varlistentry>
+          <listitem><para><function>sd_event_get_tid()</function> was invoked on an event loop object that
+          was not allocated with <function>sd_event_default()</function>.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 1c8afb2..2d2b085 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_now" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>If the first event loop iteration has not run yet
-    <function>sd_event_now()</function> writes current time to
-    <parameter>usec</parameter> and returns a positive return value.
-    Otherwise, it will write the requested timestamp to <parameter>usec</parameter>
-    and return 0. On failure, the call returns a negative errno-style
-    error code.</para>
-  </refsect1>
+    <para>If the first event loop iteration has not run yet <function>sd_event_now()</function> writes
+    current time to <parameter>usec</parameter> and returns a positive return value.  Otherwise, it will
+    write the requested timestamp to <parameter>usec</parameter> and return 0. On failure, the call returns a
+    negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned values may indicate the following problems:</para>
+      <para>Returned values may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An invalid parameter was
-        passed.</para></listitem>
+          <listitem><para>An invalid parameter was passed.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EOPNOTSUPP</constant></term>
+        <varlistentry>
+          <term><constant>-EOPNOTSUPP</constant></term>
 
-        <listitem><para>Unsupported clock type.
-        </para></listitem>
-      </varlistentry>
+          <listitem><para>Unsupported clock type.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop object was created in a
-        different process.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The event loop object was created in a different process.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 1a44673..5c33d61 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_run" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     dispatched. <function>sd_event_loop()</function> returns the exit
     code specified when invoking
     <function>sd_event_exit()</function>.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>event</parameter> parameter is
-        invalid or <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The <parameter>event</parameter> parameter is invalid or
+          <constant>NULL</constant>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EBUSY</constant></term>
+        <varlistentry>
+          <term><constant>-EBUSY</constant></term>
 
-        <listitem><para>The event loop object is not in the right
-        state (see
-        <citerefentry><refentrytitle>sd_event_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-        for an explanation of possible states).</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop object is not in the right
+          state (see
+          <citerefentry><refentrytitle>sd_event_prepare</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+          for an explanation of possible states).</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem><para>The event loop is already terminated.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
 
-    <para>Other errors are possible, too.</para>
+      <para>Other errors are possible, too.</para>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 7d7155d..faaaad3 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_set_watchdog" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <title>Return Value</title>
 
     <para>On success, <function>sd_event_set_watchdog()</function> and
-    <function>sd_event_get_watchdog()</function> 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
-    <parameter>b</parameter> parameter. On failure, they return a
-    negative errno-style error
-    code.</para>
-  </refsect1>
+    <function>sd_event_get_watchdog()</function> 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
+    <parameter>b</parameter> parameter. On failure, they return a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The passed event loop object was invalid.</para></listitem>
-      </varlistentry>
+          <listitem><para>The passed event loop object was invalid.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 36e6c1b..2b059a3 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_source_get_event" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 75f2690..603d4ad 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_source_get_pending" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success,
-    <function>sd_event_source_get_pending()</function> 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.</para>
-  </refsect1>
+    <para>On success, <function>sd_event_source_get_pending()</function> 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.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para><parameter>source</parameter> is not a valid
-        pointer to an <structname>sd_event_source</structname>
-        object.</para></listitem>
-      </varlistentry>
+          <listitem><para><parameter>source</parameter> is not a valid pointer to an
+          <structname>sd_event_source</structname> object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EDOM</constant></term>
+        <varlistentry>
+          <term><constant>-EDOM</constant></term>
 
-        <listitem><para><parameter>source</parameter> refers to an
-        event source object created with
-        <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
-      </varlistentry>
+          <listitem><para><parameter>source</parameter> refers to an event source object created with
+          <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem><para>The event loop is already terminated.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index be3df3f..717cc5b 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_source_set_description" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <title>Return Value</title>
 
     <para>On success, <function>sd_event_source_set_description()</function> and
-    <function>sd_event_source_get_description()</function> return a
-    non-negative integer. On failure, they return a negative
-    errno-style error code.</para>
-  </refsect1>
+    <function>sd_event_source_get_description()</function> return a non-negative integer. On failure, they
+    return a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para><parameter>source</parameter> is not a valid
-        pointer to an <structname>sd_event_source</structname>
-        object or the <parameter>description</parameter> argument for
-        <function>sd_event_source_get_description()</function> is
-        <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para><parameter>source</parameter> is not a valid pointer to an
+          <structname>sd_event_source</structname> object or the <parameter>description</parameter> argument
+          for <function>sd_event_source_get_description()</function> is <constant>NULL</constant>.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory to copy the
-        name.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory to copy the name.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>No name was set for the event
-        source.</para></listitem>
-      </varlistentry>
+          <listitem><para>No name was set for the event source.</para></listitem>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index d9afb4d..2ffca9e 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_source_set_destroy_callback"
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, <function>sd_event_source_set_destroy_callback()</function> returns 0 or a positive integer. On
-    failure, it returns a negative errno-style error code.</para>
+    <para>On success, <function>sd_event_source_set_destroy_callback()</function> returns 0 or a positive
+    integer. On failure, it returns a negative errno-style error code.</para>
 
-    <para><function>sd_event_source_get_destroy_callback()</function> returns positive if the destroy callback function
-    is set, 0 if not. On failure, returns a negative errno-style error code.</para>
-  </refsect1>
+    <para><function>sd_event_source_get_destroy_callback()</function> returns positive if the destroy
+    callback function is set, 0 if not. On failure, returns a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>source</parameter> parameter is <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>The <parameter>source</parameter> parameter is <constant>NULL</constant>.
+          </para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 73f0184..6a7a39b 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_source_set_enabled" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <title>Return Value</title>
 
     <para>On success, <function>sd_event_source_set_enabled()</function> returns a non-negative
-    integer. <function>sd_event_source_get_enabled()</function> returns zero if the source is
-    disabled (<constant>SD_EVENT_OFF</constant>) and a positive integer otherwise. On failure, they
-    return a negative errno-style error code.</para>
-  </refsect1>
+    integer. <function>sd_event_source_get_enabled()</function> returns zero if the source is disabled
+    (<constant>SD_EVENT_OFF</constant>) and a positive integer otherwise. On failure, they return a negative
+    errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para><parameter>source</parameter> is not a valid
-        pointer to an <structname>sd_event_source</structname>
-        object.</para></listitem>
-      </varlistentry>
+          <listitem><para><parameter>source</parameter> is not a valid pointer to an
+          <structname>sd_event_source</structname> object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index ae71f74..63c33ca 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_source_set_prepare" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success,
-    <function>sd_event_source_set_prepare()</function> returns a
-    non-negative integer. On failure, it returns a negative
-    errno-style error code.</para>
-  </refsect1>
+    <para>On success, <function>sd_event_source_set_prepare()</function> returns a non-negative integer. On
+    failure, it returns a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para><parameter>source</parameter> is not a valid
-        pointer to an <structname>sd_event_source</structname>
-        object.</para></listitem>
-      </varlistentry>
+          <listitem><para><parameter>source</parameter> is not a valid pointer to an
+          <structname>sd_event_source</structname> object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem><para>The event loop is already terminated.</para></listitem>
 
-      </varlistentry>
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        </varlistentry>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EDOM</constant></term>
+        <varlistentry>
+          <term><constant>-EDOM</constant></term>
 
-        <listitem><para>The specified event source has been created
-        with
-        <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
+          <listitem><para>The specified event source has been created with
+          <citerefentry><refentrytitle>sd_event_add_exit</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index dd16628..d1cb416 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_source_set_priority" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success,
-    <function>sd_event_source_set_priority()</function> and
-    <function>sd_event_source_get_priority()</function> return a
-    non-negative integer. On failure, they return a negative
-    errno-style error code.</para>
-  </refsect1>
+    <para>On success, <function>sd_event_source_set_priority()</function> and
+    <function>sd_event_source_get_priority()</function> return a non-negative integer. On failure, they
+    return a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para><parameter>source</parameter> is not a valid
-        pointer to an <structname>sd_event_source</structname>
-        object.</para></listitem>
-      </varlistentry>
+          <listitem><para><parameter>source</parameter> is not a valid pointer to an
+          <structname>sd_event_source</structname> object.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Not enough memory.</para></listitem>
-      </varlistentry>
+          <listitem><para>Not enough memory.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem><para>The event loop is already terminated.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index e013282..fe31584 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_source_set_userdata" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index b11df3f..01e3008 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_source_unref" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index f01d18e..210a0c9 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_event_wait" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these functions return 0 or a positive integer.
-    On failure, they return a negative errno-style error code. In case
-    of <function>sd_event_prepare()</function> and
-    <function>sd_event_wait()</function>, 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
-    <function>sd_event_dispatch()</function>, a positive, non-zero
-    return code indicates that the event loop returned to its initial
-    state and zero indicates the event loop has
-    exited. <function>sd_event_get_state()</function> returns a
-    positive or zero state on success.</para>
-  </refsect1>
+    <para>On success, these functions return 0 or a positive integer.  On failure, they return a negative
+    errno-style error code. In case of <function>sd_event_prepare()</function> and
+    <function>sd_event_wait()</function>, 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
+    <function>sd_event_dispatch()</function>, a positive, non-zero return code indicates that the event loop
+    returned to its initial state and zero indicates the event loop has
+    exited. <function>sd_event_get_state()</function> returns a positive or zero state on success.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+      <variablelist>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>The <parameter>event</parameter> parameter is
-        invalid or <constant>NULL</constant>.</para></listitem>
-      </varlistentry>
+          <listitem><para>The <parameter>event</parameter> parameter is invalid or <constant>NULL</constant>.
+          </para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EBUSY</constant></term>
+        <varlistentry>
+          <term><constant>-EBUSY</constant></term>
 
-        <listitem><para>The event loop object is not in the right
-        state.</para></listitem>
-      </varlistentry>
+          <listitem><para>The event loop object is not in the right state.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ESTALE</constant></term>
+        <varlistentry>
+          <term><constant>-ESTALE</constant></term>
 
-        <listitem><para>The event loop is already terminated.</para></listitem>
+          <listitem><para>The event loop is already terminated.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ECHILD</constant></term>
+        <varlistentry>
+          <term><constant>-ECHILD</constant></term>
 
-        <listitem><para>The event loop has been created in a different process.</para></listitem>
+          <listitem><para>The event loop has been created in a different process.</para></listitem>
 
-      </varlistentry>
+        </varlistentry>
 
-    </variablelist>
+      </variablelist>
 
-    <para>Other errors are possible, too.</para>
+      <para>Other errors are possible, too.</para>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 925516d..ed4b77b 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_get_seats" conditional='HAVE_PAM'
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, <function>sd_get_seats()</function>,
-    <function>sd_get_sessions()</function>,
-    <function>sd_get_uids()</function> and
-    <function>sd_get_machine_names()</function> return the number of
-    entries in the arrays. On failure, these calls return a negative
-    errno-style error code.</para>
-  </refsect1>
+    <para>On success, <function>sd_get_seats()</function>, <function>sd_get_sessions()</function>,
+    <function>sd_get_uids()</function> and <function>sd_get_machine_names()</function> return the number of
+    entries in the arrays. On failure, these calls return a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 0bfe1b5..e665f73 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_id128_get_machine" xmlns:xi="http://www.w3.org/2001/XInclude">
 
     <title>Return Value</title>
 
     <para>Those calls return 0 on success (in which case <parameter>ret</parameter> is filled in),
-    or a negative errno-style error code. In particular,
-    <function>sd_id128_get_machine()</function>,
-    <function>sd_id128_get_machine_app_specific()</function>, and
-    <function>sd_id128_get_boot_app_specific()</function> return <constant>-ENOENT</constant> if
-    <filename>/etc/machine-id</filename> is missing, and <constant>-ENOMEDIUM</constant> if
-    <filename>/etc/machine-id</filename> is empty or all zeros.</para>
+    or a negative errno-style error code.</para>
+
+    <refsect2>
+      <title>Errors</title>
+      <para>Returned errors may indicate the following problems:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><constant>-ENOENT</constant></term>
+
+          <listitem><para>Returned by <function>sd_id128_get_machine()</function>,
+          <function>sd_id128_get_machine_app_specific()</function>, and
+          <function>sd_id128_get_boot_app_specific()</function> when <filename>/etc/machine-id</filename> is
+          missing.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENOMEDIUM</constant></term>
+
+          <listitem><para>Returned by <function>sd_id128_get_machine()</function>,
+          <function>sd_id128_get_machine_app_specific()</function>, and
+          <function>sd_id128_get_boot_app_specific()</function> when <filename>/etc/machine-id</filename> is
+          empty or all zeros.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
+
+          <listitem><para>Returned by <function>sd_id128_get_invocation()</function> if no invocation ID is
+          set.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EIO</constant></term>
+
+          <listitem><para>Returned by any of the functions described here when the configured value has
+          invalid format.</para></listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><constant>-EPERM</constant></term>
+
+          <listitem><para>Requested information could not be retrieved because of insufficient permissions.
+          </para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 4f5b160..9cf55dd 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_id128_randomize" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index ca07185..4f585e3 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_id128_to_string" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 05709d8..26a0db1 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_is_fifo"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index d82f71f..83f7fe9 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_add_match" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index c5704f5..791d1c7 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_enumerate_fields" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 80edc08..8c7058a 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_get_catalog" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index d5e465b..851bfde 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_get_cursor" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index b2a0634..a76855f 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_get_cutoff_realtime_usec" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 464fd16..0a0030e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_get_data" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 2186b68..fc55bbd 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_get_fd" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index e0f5c4d..f8150de 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_get_realtime_usec"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 39f53dd..6368371 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_get_usage" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 44fdc8d..4b0075c 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <!--
index 9a27d14..20d153d 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_next" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index cf787b7..723621c 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_open"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index e18cf88..ad9412e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_print" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 9adafa1..1bf8396 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_query_unique" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index da88d24..8e505f9 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_seek_head" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Description</title>
 
-    <para><function>sd_journal_seek_head()</function> seeks to the
-    beginning of the journal, i.e. the oldest available entry.</para>
+    <para><function>sd_journal_seek_head()</function> seeks to the beginning of the journal, i.e. to the
+    position before the oldest available entry.</para>
 
-    <para>Similarly, <function>sd_journal_seek_tail()</function> may
-    be used to seek to the end of the journal, i.e. the most recent
-    available entry.</para>
+    <para>Similarly, <function>sd_journal_seek_tail()</function> may be used to seek to the end of the
+    journal, i.e. the position after the most recent available entry.</para>
 
-    <para><function>sd_journal_seek_monotonic_usec()</function> seeks
-    to the entry with the specified monotonic timestamp, i.e.
-    <constant>CLOCK_MONOTONIC</constant>. Since monotonic time
-    restarts on every reboot a boot ID needs to be specified as
-    well.</para>
+    <para><function>sd_journal_seek_monotonic_usec()</function> seeks to a position with the specified
+    monotonic timestamp, i.e.  <constant>CLOCK_MONOTONIC</constant>. Since monotonic time restarts on every
+    reboot a boot ID needs to be specified as well.</para>
 
-    <para><function>sd_journal_seek_realtime_usec()</function> seeks
-    to the entry with the specified realtime (wallclock) timestamp,
-    i.e. <constant>CLOCK_REALTIME</constant>. Note that the realtime
-    clock is not necessarily monotonic. If a realtime timestamp is
-    ambiguous, it is not defined which position is sought to.</para>
+    <para><function>sd_journal_seek_realtime_usec()</function> seeks to a position with the specified
+    realtime (wallclock) timestamp, i.e. <constant>CLOCK_REALTIME</constant>. Note that the realtime clock is
+    not necessarily monotonic. If a realtime timestamp is ambiguous, it is not defined which position is
+    sought to.</para>
 
-    <para><function>sd_journal_seek_cursor()</function> seeks to the
-    entry located at the specified cursor string. For details on
-    cursors, see
+    <para><function>sd_journal_seek_cursor()</function> seeks to the position at the specified cursor
+    string. For details on cursors, see
     <citerefentry><refentrytitle>sd_journal_get_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
-    If no entry matching the specified cursor is found the call will
-    seek to the next closest entry (in terms of time) instead. To
-    verify whether the newly selected entry actually matches the
-    cursor, use
+    If no entry matching the specified cursor is found the call will seek to the next closest entry (in terms
+    of time) instead. To verify whether the newly selected entry actually matches the cursor, use
     <citerefentry><refentrytitle>sd_journal_test_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
 
-    <para>Note that these calls do not actually make any entry the new
-    current entry, this needs to be done in a separate step with a
-    subsequent
-    <citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    invocation (or a similar call). Only then, entry data may be
-    retrieved via
-    <citerefentry><refentrytitle>sd_journal_get_data</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
-    If no entry exists that matches exactly the specified seek
-    address, the next closest is sought to. If
+    <para>Note that these calls do not actually make any entry the new current entry, this needs to be done
+    in a separate step with a subsequent
     <citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    is used, the closest following entry will be sought to, if
+    invocation (or a similar call). Only then, entry data may be retrieved via
+    <citerefentry><refentrytitle>sd_journal_get_data</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+    or an entry cursor be retrieved via
+    <citerefentry><refentrytitle>sd_journal_get_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+    If no entry exists that matches exactly the specified seek address, the next closest is sought to. If
+    <citerefentry><refentrytitle>sd_journal_next</refentrytitle><manvolnum>3</manvolnum></citerefentry> is
+    used, the closest following entry will be sought to, if
     <citerefentry><refentrytitle>sd_journal_previous</refentrytitle><manvolnum>3</manvolnum></citerefentry>
     is used the closest preceding entry is sought to.</para>
   </refsect1>
index a3ff908..bdb27cc 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_journal_stream_fd" xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 3c3d2ff..9a66ee3 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_listen_fds"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index d914e51..be1c843 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_login_monitor_new" conditional='HAVE_PAM'
           xmlns:xi="http://www.w3.org/2001/XInclude">
@@ -209,29 +206,28 @@ else {
 
     <para><function>sd_login_monitor_unref()</function>
     always returns <constant>NULL</constant>.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that is not accepted). The specified category to
-        watch is not known.</para></listitem>
-      </varlistentry>
+          <listitem><para>An input parameter was invalid (out of range, or <constant>NULL</constant>, where
+          that is not accepted). The specified category to watch is not known.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index bacbe14..db6cf0d 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_machine_get_class" xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these calls return 0 or a positive integer. On
-    failure, these calls return a negative errno-style error
-    code.</para>
-  </refsect1>
+    <para>On success, these calls return 0 or a positive integer. On failure, these calls return a negative
+    errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>The specified machine does not exist or is currently not running.</para>
-        </listitem>
-      </varlistentry>
+          <listitem><para>The specified machine does not exist or is currently not running.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that is not accepted).</para></listitem>
-      </varlistentry>
+          <listitem><para>An input parameter was invalid (out of range, or <constant>NULL</constant>, where
+          that is not accepted).</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 79ae84b..0084bf3 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_notify"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index f4619b6..e9d7a8e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_pid_get_owner_uid" conditional='HAVE_PAM'
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, these calls return 0 or a positive integer. On
-    failure, these calls return a negative errno-style error
-    code.</para>
-  </refsect1>
+    <para>On success, these calls return 0 or a positive integer. On failure, these calls return a negative
+    errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-ESRCH</constant></term>
+        <varlistentry>
+          <term><constant>-ESRCH</constant></term>
 
-        <listitem><para>The specified PID does not refer to a running
-        process.</para>
-        </listitem>
-      </varlistentry>
+          <listitem><para>The specified PID does not refer to a running process.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EBADF</constant></term>
+        <varlistentry>
+          <term><constant>-EBADF</constant></term>
 
-        <listitem><para>The specified socket file descriptor was
-        invalid.</para></listitem>
-      </varlistentry>
+          <listitem><para>The specified socket file descriptor was invalid.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENODATA</constant></term>
+        <varlistentry>
+          <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>The given field is not specified for the described
-        process or peer.</para>
-        </listitem>
-      </varlistentry>
+          <listitem><para>The given field is not specified for the described process or peer.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that is not accepted).</para></listitem>
-      </varlistentry>
+          <listitem><para>An input parameter was invalid (out of range, or <constant>NULL</constant>, where
+          that is not accepted).</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <refsect1>
index 2fc5fde..2dba680 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_seat_get_active" conditional='HAVE_PAM'
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para> On success, <function>sd_seat_get_active()</function>
-    returns 0 or a positive integer. On success,
-    <function>sd_seat_get_sessions()</function> returns the number of
-    entries in the session identifier array. If the test succeeds,
-    <function>sd_seat_can_multi_session</function>,
-    <function>sd_seat_can_tty</function> and
-    <function>sd_seat_can_graphical</function> return a positive
-    integer, if it fails 0. On failure, these calls return a negative
-    errno-style error code.</para>
-  </refsect1>
+    <para> On success, <function>sd_seat_get_active()</function> returns 0 or a positive integer. On success,
+    <function>sd_seat_get_sessions()</function> returns the number of entries in the session identifier
+    array. If the test succeeds, <function>sd_seat_can_multi_session</function>,
+    <function>sd_seat_can_tty</function> and <function>sd_seat_can_graphical</function> return a positive
+    integer, if it fails 0. On failure, these calls return a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-ENODATA</constant></term>
+        <varlistentry>
+          <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>The given field is not specified for the described
-        seat.</para>
-        </listitem>
-      </varlistentry>
+          <listitem><para>The given field is not specified for the described seat.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>The specified seat is unknown.</para>
-        </listitem>
-      </varlistentry>
+          <listitem><para>The specified seat is unknown.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that is not accepted).</para></listitem>
-      </varlistentry>
+          <listitem><para>An input parameter was invalid (out of range, or <constant>NULL</constant>, where
+          that is not accepted).</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index a0f7a93..d4a12f5 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_session_is_active" conditional='HAVE_PAM'
           xmlns:xi="http://www.w3.org/2001/XInclude">
     <function>sd_session_get_tty()</function> return 0 or
     a positive integer. On failure, these calls return a
     negative errno-style error code.</para>
-  </refsect1>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>The specified session does not exist.</para>
-        </listitem>
-      </varlistentry>
+          <listitem><para>The specified session does not exist.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENODATA</constant></term>
+        <varlistentry>
+          <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>The given field is not specified for the described
-        session.</para>
-        </listitem>
-      </varlistentry>
+          <listitem><para>The given field is not specified for the described session.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that is not accepted).</para></listitem>
-      </varlistentry>
+          <listitem><para>An input parameter was invalid (out of range, or <constant>NULL</constant>, where
+          that is not accepted).</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index 02670e1..ed38559 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_uid_get_state" conditional='HAVE_PAM'
           xmlns:xi="http://www.w3.org/2001/XInclude">
   <refsect1>
     <title>Return Value</title>
 
-    <para>On success, <function>sd_uid_get_state()</function> returns
-    0 or a positive integer. If the test succeeds,
-    <function>sd_uid_is_on_seat()</function> returns a positive
-    integer; if it fails, 0.
-    <function>sd_uid_get_sessions()</function> and
-    <function>sd_uid_get_seats()</function> return the number of
-    entries in the returned arrays.
-    <function>sd_uid_get_display()</function> returns a non-negative
-    code on success. On failure, these calls return a negative
-    errno-style error code.</para>
-  </refsect1>
+    <para>On success, <function>sd_uid_get_state()</function> returns 0 or a positive integer. If the test
+    succeeds, <function>sd_uid_is_on_seat()</function> returns a positive integer; if it fails, 0.
+    <function>sd_uid_get_sessions()</function> and <function>sd_uid_get_seats()</function> return the number
+    of entries in the returned arrays. <function>sd_uid_get_display()</function> returns a non-negative code
+    on success. On failure, these calls return a negative errno-style error code.</para>
 
-  <refsect1>
-    <title>Errors</title>
+    <refsect2>
+      <title>Errors</title>
 
-    <para>Returned errors may indicate the following problems:</para>
+      <para>Returned errors may indicate the following problems:</para>
 
-    <variablelist>
+      <variablelist>
 
-      <varlistentry>
-        <term><constant>-ENODATA</constant></term>
+        <varlistentry>
+          <term><constant>-ENODATA</constant></term>
 
-        <listitem><para>The given field is not specified for the described
-        user.</para>
-        </listitem>
-      </varlistentry>
+          <listitem><para>The given field is not specified for the described user.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENXIO</constant></term>
+        <varlistentry>
+          <term><constant>-ENXIO</constant></term>
 
-        <listitem><para>The specified seat is unknown.</para>
-        </listitem>
-      </varlistentry>
+          <listitem><para>The specified seat is unknown.</para>
+          </listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-EINVAL</constant></term>
+        <varlistentry>
+          <term><constant>-EINVAL</constant></term>
 
-        <listitem><para>An input parameter was invalid (out of range,
-        or NULL, where that is not accepted). This is also returned if
-        the passed user ID is 0xFFFF or 0xFFFFFFFF, which are
-        undefined on Linux.</para></listitem>
-      </varlistentry>
+          <listitem><para>An input parameter was invalid (out of range, or NULL, where that is not
+          accepted). This is also returned if the passed user ID is <constant>0xFFFF</constant> or
+          <constant>0xFFFFFFFF</constant>, which are undefined on Linux.</para></listitem>
+        </varlistentry>
 
-      <varlistentry>
-        <term><constant>-ENOMEM</constant></term>
+        <varlistentry>
+          <term><constant>-ENOMEM</constant></term>
 
-        <listitem><para>Memory allocation failed.</para></listitem>
-      </varlistentry>
-    </variablelist>
+          <listitem><para>Memory allocation failed.</para></listitem>
+        </varlistentry>
+      </variablelist>
+    </refsect2>
   </refsect1>
 
   <xi:include href="libsystemd-pkgconfig.xml" />
index ad2cdd8..0aa5609 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="sd_watchdog_enabled"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 282a3ba..bc2fa60 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="shutdown"
     xmlns:xi="http://www.w3.org/2001/XInclude">
         <term><option>-c</option></term>
 
         <listitem><para>Cancel a pending shutdown. This may be used
-        cancel the effect of an invocation of
+        to cancel the effect of an invocation of
         <command>shutdown</command> with a time argument that is not
         <literal>+0</literal> or
         <literal>now</literal>.</para></listitem>
index f5c961a..1db859a 100644 (file)
   <refsection id='confd'>
     <title>Configuration Directories and Precedence</title>
 
-    <para>Configuration files are read from directories in
-    <filename>/etc/</filename>, <filename>/run/</filename>, and
-    <filename>/usr/lib/</filename>, in order of precedence.
-    Each configuration file in these configuration directories shall be named in
-    the style of <filename><replaceable>filename</replaceable>.conf</filename>.
-    Files in <filename>/etc/</filename> override files with the same name in
-    <filename>/run/</filename> and <filename>/usr/lib/</filename>. Files in
-    <filename>/run/</filename> override files with the same name in
-    <filename>/usr/lib/</filename>.</para>
+    <para>Configuration files are read from directories in <filename>/etc/</filename>, <filename>/run/</filename>,
+    <filename>/usr/local/lib/</filename>, and <filename>/usr/lib/</filename>, in order of precedence.  Each
+    configuration file in these configuration directories shall be named in the style of
+    <filename><replaceable>filename</replaceable>.conf</filename>.  Files in <filename>/etc/</filename> override files
+    with the same name in <filename>/run/</filename>, <filename>/usr/local/lib/</filename>, and
+    <filename>/usr/lib/</filename>. Files in <filename>/run/</filename> override files with the same name under
+    <filename>/usr/</filename>.</para>
 
-    <para>Packages should install their configuration files in
-    <filename>/usr/lib/</filename>. Files in <filename>/etc/</filename> are
+    <para>Packages should install their configuration files in <filename>/usr/lib/</filename> (distribution packages)
+    or <filename>/usr/local/lib/</filename> (local installs). Files in <filename>/etc/</filename> are
     reserved for the local administrator, who may use this logic to override the
     configuration files installed by vendor packages. All configuration files
     are sorted by their filename in lexicographic order, regardless of which of
@@ -52,7 +50,8 @@
 
     <para>When packages need to customize the configuration, they can
     install configuration snippets in
-    <filename>/usr/lib/systemd/*.conf.d/</filename>. Files in
+    <filename>/usr/lib/systemd/*.conf.d/</filename> or
+    <filename>/usr/local/lib/systemd/*.conf.d/</filename>. Files in
     <filename>/etc/</filename> are reserved for the local
     administrator, who may use this logic to override the
     configuration files installed by vendor packages. The main
index 51a4faf..6a61d9e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-          "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <variablelist>
   <varlistentry id='help'>
index 7c8fde0..0a8eeb6 100644 (file)
@@ -1,8 +1,7 @@
 <?xml version="1.0"?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="sysctl.d"
     xmlns:xi="http://www.w3.org/2001/XInclude">
 
diff --git a/man/system-only.xml b/man/system-only.xml
new file mode 100644 (file)
index 0000000..94aa08b
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+
+<!--
+  SPDX-License-Identifier: LGPL-2.1+
+-->
+
+<refsect1>
+
+<para id="singular">This option is only available for system services and is not supported for services
+running in per-user instances of the service manager.</para>
+
+<para id="plural">These options are only available for system services and are not supported for services
+running in per-user instances of the service manager.</para>
+
+</refsect1>
index 08aacd8..d991e97 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemctl"
           xmlns:xi="http://www.w3.org/2001/XInclude">
       </varlistentry>
 
       <varlistentry>
+        <term><option>-T</option></term>
+        <term><option>--show-transaction</option></term>
+
+        <listitem>
+          <para>When enqueuing a unit job (for example as effect of a <command>systemctl start</command>
+          invocation or similar), show brief information about all jobs enqueued, covering both the requested
+          job and any added because of unit dependencies. Note that the output will only include jobs
+          immediately part of the transaction requested. It is possible that service start-up program code
+          run as effect of the enqueued jobs might request further jobs to be pulled in. This means that
+          completion of the listed jobs might ultimately entail more jobs than the listed ones.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option>--fail</option></term>
 
         <listitem>
         <term><option>--firmware-setup</option></term>
 
         <listitem>
-          <para>When used with the <command>reboot</command> command,
-          indicate to the system's firmware to boot into setup
-          mode. Note that this is currently only supported on some EFI
-          systems and only if the system was booted in EFI
-          mode.</para>
+          <para>When used with the <command>reboot</command> command, indicate to the system's firmware to reboot into
+          the firmware setup interface. Note that this functionality is not available on all systems.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--boot-loader-menu=</option></term>
+
+        <listitem>
+          <para>When used with the <command>reboot</command> command, indicate to the system's boot loader to show the
+          boot loader menu on the following boot. Takes a time value as parameter — indicating the menu time-out. Pass
+          zero in order to disable the menu time-out. Note that not all boot loaders support this
+          functionality.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--boot-loader-entry=</option></term>
+
+        <listitem>
+          <para>When used with the <command>reboot</command> command, indicate to the system's boot loader to boot into
+          a specific boot loader entry on the following boot. Takes a boot loader entry identifier as argument, or
+          <literal>help</literal> in order to list available entries. Note that not all boot loaders support this
+          functionality.</para>
         </listitem>
       </varlistentry>
 
index 7becf01..f559b85 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-analyze"
     xmlns:xi="http://www.w3.org/2001/XInclude">
       <arg choice="plain">critical-chain</arg>
       <arg choice="opt" rep="repeat"><replaceable>UNIT</replaceable></arg>
     </cmdsynopsis>
+
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">plot</arg>
-      <arg choice="opt">&gt; file.svg</arg>
+      <arg choice="plain">log-level</arg>
+      <arg choice="opt"><replaceable>LEVEL</replaceable></arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">dot</arg>
-      <arg choice="opt" rep="repeat"><replaceable>PATTERN</replaceable></arg>
-      <arg choice="opt">&gt; file.dot</arg>
+      <arg choice="plain">log-target</arg>
+      <arg choice="opt"><replaceable>TARGET</replaceable></arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">dump</arg>
+      <arg choice="plain">service-watchdogs</arg>
+      <arg choice="opt"><replaceable>BOOL</replaceable></arg>
     </cmdsynopsis>
+
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">cat-config</arg>
-      <arg choice="plain" rep="repeat"><replaceable>NAME</replaceable>|<replaceable>PATH</replaceable></arg>
+      <arg choice="plain">dump</arg>
     </cmdsynopsis>
+
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">unit-paths</arg>
+      <arg choice="plain">plot</arg>
+      <arg choice="opt">>file.svg</arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">log-level</arg>
-      <arg choice="opt"><replaceable>LEVEL</replaceable></arg>
+      <arg choice="plain">dot</arg>
+      <arg choice="opt" rep="repeat"><replaceable>PATTERN</replaceable></arg>
+      <arg choice="opt">>file.dot</arg>
     </cmdsynopsis>
+
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">log-target</arg>
-      <arg choice="opt"><replaceable>TARGET</replaceable></arg>
+      <arg choice="plain">unit-paths</arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-analyze</command>
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">verify</arg>
-      <arg choice="opt" rep="repeat"><replaceable>FILES</replaceable></arg>
+      <arg choice="plain">calendar</arg>
+      <arg choice="plain" rep="repeat"><replaceable>SPECS</replaceable></arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">calendar</arg>
-      <arg choice="plain" rep="repeat"><replaceable>SPECS</replaceable></arg>
+      <arg choice="plain">timespan</arg>
+      <arg choice="plain" rep="repeat"><replaceable>SPAN</replaceable></arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">service-watchdogs</arg>
-      <arg choice="opt"><replaceable>BOOL</replaceable></arg>
+      <arg choice="plain">cat-config</arg>
+      <arg choice="plain" rep="repeat"><replaceable>NAME</replaceable>|<replaceable>PATH</replaceable></arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-analyze</command>
       <arg choice="opt" rep="repeat">OPTIONS</arg>
-      <arg choice="plain">timespan</arg>
-      <arg choice="plain" rep="repeat"><replaceable>SPAN</replaceable></arg>
+      <arg choice="plain">verify</arg>
+      <arg choice="opt" rep="repeat"><replaceable>FILE</replaceable></arg>
     </cmdsynopsis>
     <cmdsynopsis>
       <command>systemd-analyze</command>
     verify the correctness of unit files. It is also used to access
     special functions useful for advanced system manager debugging.</para>
 
-    <para><command>systemd-analyze time</command> prints the time
-    spent in the kernel before userspace has been reached, the time
-    spent in the initial RAM disk (initrd) before normal system
-    userspace has been reached, and the time normal system userspace
-    took to initialize. Note that these measurements simply measure
-    the time passed up to the point where all system services have
-    been spawned, but not necessarily until they fully finished
-    initialization or the disk is idle.</para>
-
-    <para><command>systemd-analyze blame</command> prints a list of
-    all running units, ordered by the time they took to initialize.
-    This information may be used to optimize boot-up times. Note that
-    the output might be misleading as the initialization of one
-    service might be slow simply because it waits for the
-    initialization of another service to complete.
-    Also note: <command>systemd-analyze blame</command> doesn't display
-    results for services with <varname>Type=simple</varname>,
-    because systemd considers such services to be started immediately,
-    hence no measurement of the initialization delays can be done.</para>
-
-    <para><command>systemd-analyze critical-chain
-    [<replaceable>UNIT…</replaceable>]</command> prints a tree of
-    the time-critical chain of units (for each of the specified
-    <replaceable>UNIT</replaceable>s or for the default target
-    otherwise). The time after the unit is active or started is
-    printed after the "@" character. The time the unit takes to start
-    is printed after the "+" character. Note that the output might be
-    misleading as the initialization of one service might depend on
-    socket activation and because of the parallel execution of
-    units.</para>
-
-    <para><command>systemd-analyze plot</command> prints an SVG
-    graphic detailing which system services have been started at what
-    time, highlighting the time they spent on initialization.</para>
-
-    <para><command>systemd-analyze dot</command> generates textual
-    dependency graph description in dot format for further processing
-    with the GraphViz
-    <citerefentry project='die-net'><refentrytitle>dot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
-    tool. Use a command line like <command>systemd-analyze dot | dot
-    -Tsvg > systemd.svg</command> to generate a graphical dependency
-    tree. Unless <option>--order</option> or
-    <option>--require</option> is passed, the generated graph will
-    show both ordering and requirement dependencies. Optional pattern
-    globbing style specifications (e.g. <filename>*.target</filename>)
-    may be given at the end. A unit dependency is included in the
-    graph if any of these patterns match either the origin or
-    destination node.</para>
-
-    <para><command>systemd-analyze dump</command> outputs a (usually
-    very long) human-readable serialization of the complete server
-    state. Its format is subject to change without notice and should
-    not be parsed by applications.</para>
-
-    <para><command>systemd-analyze cat-config</command> is similar
-    to <command>systemctl cat</command>, but operates on config files.
-    It will copy the contents of a config file and any drop-ins to standard
-    output, using the usual systemd set of directories and rules for
-    precedence. Each argument must be either an absolute path including
-    the prefix (such as <filename>/etc/systemd/logind.conf</filename> or
-    <filename>/usr/lib/systemd/logind.conf</filename>), or a name
-    relative to the prefix (such as <filename>systemd/logind.conf</filename>).
-    </para>
+    <para>If no command is passed, <command>systemd-analyze
+    time</command> is implied.</para>
 
-    <example>
-      <title>Showing logind configuration</title>
-      <programlisting>$ systemd-analyze cat-config systemd/logind.conf
+    <refsect2>
+      <title><command>systemd-analyze time</command></title>
+
+      <para>This command prints the time spent in the kernel before userspace has been reached, the time
+      spent in the initial RAM disk (initrd) before normal system userspace has been reached, and the time
+      normal system userspace took to initialize. Note that these measurements simply measure the time passed
+      up to the point where all system services have been spawned, but not necessarily until they fully
+      finished initialization or the disk is idle.</para>
+
+      <example>
+        <title><command>Show how long the boot took</command></title>
+
+        <programlisting># in a container
+$ systemd-analyze time
+Startup finished in 296ms (userspace)
+multi-user.target reached after 275ms in userspace
+
+# on a real machine
+$ systemd-analyze time
+Startup finished in 2.584s (kernel) + 19.176s (initrd) + 47.847s (userspace) = 1min 9.608s
+multi-user.target reached after 47.820s in userspace
+</programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze blame</command></title>
+
+      <para>This command prints a list of all running units, ordered by the time they took to initialize.
+      This information may be used to optimize boot-up times. Note that the output might be misleading as the
+      initialization of one service might be slow simply because it waits for the initialization of another
+      service to complete.  Also note: <command>systemd-analyze blame</command> doesn't display results for
+      services with <varname>Type=simple</varname>, because systemd considers such services to be started
+      immediately, hence no measurement of the initialization delays can be done.</para>
+
+      <example>
+        <title><command>Show which units took the most time during boot</command></title>
+
+        <programlisting>$ systemd-analyze blame
+         32.875s pmlogger.service
+         20.905s systemd-networkd-wait-online.service
+         13.299s dev-vda1.device
+         ...
+            23ms sysroot.mount
+            11ms initrd-udevadm-cleanup-db.service
+             3ms sys-kernel-config.mount
+        </programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze critical-chain <optional><replaceable>UNIT</replaceable>...</optional></command></title>
+
+      <para>This command prints a tree of the time-critical chain of units (for each of the specified
+      <replaceable>UNIT</replaceable>s or for the default target otherwise). The time after the unit is
+      active or started is printed after the "@" character. The time the unit takes to start is printed after
+      the "+" character. Note that the output might be misleading as the initialization of services might
+      depend on socket activation and because of the parallel execution of units.</para>
+
+      <example>
+        <title><command>systemd-analyze time</command></title>
+
+      <programlisting>$ systemd-analyze critical-chain
+multi-user.target @47.820s
+└─pmie.service @35.968s +548ms
+  └─pmcd.service @33.715s +2.247s
+    └─network-online.target @33.712s
+      └─systemd-networkd-wait-online.service @12.804s +20.905s
+        └─systemd-networkd.service @11.109s +1.690s
+          └─systemd-udevd.service @9.201s +1.904s
+            └─systemd-tmpfiles-setup-dev.service @7.306s +1.776s
+              └─kmod-static-nodes.service @6.976s +177ms
+                └─systemd-journald.socket
+                  └─system.slice
+                    └─-.slice
+</programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze log-level [<replaceable>LEVEL</replaceable>]</command></title>
+
+      <para><command>systemd-analyze log-level</command> prints the current log level of the
+      <command>systemd</command> daemon.  If an optional argument <replaceable>LEVEL</replaceable> is
+      provided, then the command changes the current log level of the <command>systemd</command> daemon to
+      <replaceable>LEVEL</replaceable> (accepts the same values as <option>--log-level=</option> described in
+      <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze log-target [<replaceable>TARGET</replaceable>]</command></title>
+
+      <para><command>systemd-analyze log-target</command> prints the current log target of the
+      <command>systemd</command> daemon.  If an optional argument <replaceable>TARGET</replaceable> is
+      provided, then the command changes the current log target of the <command>systemd</command> daemon to
+      <replaceable>TARGET</replaceable> (accepts the same values as <option>--log-target=</option>, described
+      in <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze service-watchdogs [yes|no]</command></title>
+
+      <para><command>systemd-analyze service-watchdogs</command> prints the current state of service runtime
+      watchdogs of the <command>systemd</command> daemon. If an optional boolean argument is provided, then
+      globally enables or disables the service runtime watchdogs (<option>WatchdogSec=</option>) and
+      emergency actions (e.g.  <option>OnFailure=</option> or <option>StartLimitAction=</option>); see
+      <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+      The hardware watchdog is not affected by this setting.</para>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze dump</command></title>
+
+      <para>This command outputs a (usually very long) human-readable serialization of the complete server
+      state. Its format is subject to change without notice and should not be parsed by applications.</para>
+
+      <example>
+        <title>Show the internal state of user manager</title>
+
+        <programlisting>$ systemd-analyze --user dump
+Timestamp userspace: Thu 2019-03-14 23:28:07 CET
+Timestamp finish: Thu 2019-03-14 23:28:07 CET
+Timestamp generators-start: Thu 2019-03-14 23:28:07 CET
+Timestamp generators-finish: Thu 2019-03-14 23:28:07 CET
+Timestamp units-load-start: Thu 2019-03-14 23:28:07 CET
+Timestamp units-load-finish: Thu 2019-03-14 23:28:07 CET
+-> Unit proc-timer_list.mount:
+        Description: /proc/timer_list
+        ...
+-> Unit default.target:
+        Description: Main user target
+...
+</programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze plot</command></title>
+
+      <para>This command prints an SVG graphic detailing which system services have been started at what
+      time, highlighting the time they spent on initialization.</para>
+
+      <example>
+        <title><command>Plot a bootchart</command></title>
+
+        <programlisting>$ systemd-analyze plot >bootup.svg
+$ eog bootup.svg&amp;
+</programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze dot [<replaceable>pattern</replaceable>...]</command></title>
+
+      <para>This command generates textual dependency graph description in dot format for further processing
+      with the GraphViz
+      <citerefentry project='die-net'><refentrytitle>dot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+      tool. Use a command line like <command>systemd-analyze dot | dot -Tsvg >systemd.svg</command> to
+      generate a graphical dependency tree. Unless <option>--order</option> or <option>--require</option> is
+      passed, the generated graph will show both ordering and requirement dependencies. Optional pattern
+      globbing style specifications (e.g. <filename>*.target</filename>) may be given at the end. A unit
+      dependency is included in the graph if any of these patterns match either the origin or destination
+      node.</para>
+
+      <example>
+        <title>Plot all dependencies of any unit whose name starts with <literal>avahi-daemon</literal>
+        </title>
+
+        <programlisting>$ systemd-analyze dot 'avahi-daemon.*' | dot -Tsvg >avahi.svg
+$ eog avahi.svg</programlisting>
+      </example>
+
+      <example>
+        <title>Plot the dependencies between all known target units</title>
+
+        <programlisting>$ systemd-analyze dot --to-pattern='*.target' --from-pattern='*.target' \
+      | dot -Tsvg >targets.svg
+$ eog targets.svg</programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze unit-paths</command></title>
+
+      <para>This command outputs a list of all directories from which unit files, <filename>.d</filename>
+      overrides, and <filename>.wants</filename>, <filename>.requires</filename> symlinks may be
+      loaded. Combine with <option>--user</option> to retrieve the list for the user manager instance, and
+      <option>--global</option> for the global configuration of user manager instances.</para>
+
+      <example>
+        <title><command>Show all paths for generated units</command></title>
+
+        <programlisting>$ systemd-analyze unit-paths | grep '^/run'
+/run/systemd/system.control
+/run/systemd/transient
+/run/systemd/generator.early
+/run/systemd/system
+/run/systemd/system.attached
+/run/systemd/generator
+/run/systemd/generator.late
+</programlisting>
+      </example>
+
+      <para>Note that this verb prints the list that is compiled into <command>systemd-analyze</command>
+      itself, and does not comunicate with the running manager. Use
+      <programlisting>systemctl [--user] [--global] show -p UnitPath --value</programlisting>
+      to retrieve the actual list that the manager uses, with any empty directories omitted.</para>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze syscall-filter <optional><replaceable>SET</replaceable>...</optional></command></title>
+
+      <para>This command will list system calls contained in the specified system call set
+      <replaceable>SET</replaceable>, or all known sets if no sets are specified. Argument
+      <replaceable>SET</replaceable> must include the <literal>@</literal> prefix.</para>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze calendar <replaceable>EXPRESSION</replaceable>...</command></title>
+
+      <para>This command will parse and normalize repetitive calendar time events, and will calculate when
+      they elapse next. This takes the same input as the <varname>OnCalendar=</varname> setting in
+      <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+      following the syntax described in
+      <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>. By
+      default, only the next time the calendar expression will elapse is shown; use
+      <option>--iterations=</option> to show the specified number of next times the expression
+      elapses.</para>
+
+      <example>
+        <title>Show leap days in the near future</title>
+
+        <programlisting>$ systemd-analyze calendar --iterations=5 '*-2-29 0:0:0'
+  Original form: *-2-29 0:0:0
+Normalized form: *-02-29 00:00:00
+    Next elapse: Sat 2020-02-29 00:00:00 UTC
+       From now: 11 months 15 days left
+       Iter. #2: Thu 2024-02-29 00:00:00 UTC
+       From now: 4 years 11 months left
+       Iter. #3: Tue 2028-02-29 00:00:00 UTC
+       From now: 8 years 11 months left
+       Iter. #4: Sun 2032-02-29 00:00:00 UTC
+       From now: 12 years 11 months left
+       Iter. #5: Fri 2036-02-29 00:00:00 UTC
+       From now: 16 years 11 months left
+</programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze timespan <replaceable>EXPRESSION</replaceable>...</command></title>
+
+      <para>This command parses a time span and outputs the normalized form and the equivalent value in
+      microseconds. The time span should adhere to the same syntax documented in
+      <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+      Values without associated magnitudes are parsed as seconds.</para>
+
+      <example>
+        <title>Show parsing of timespans</title>
+
+        <programlisting>$ systemd-analyze timespan 1s 300s '1year 0.000001s'
+Original: 1s
+      μs: 1000000
+   Human: 1s
+
+Original: 300s
+      μs: 300000000
+   Human: 5min
+
+Original: 1year 0.000001s
+      μs: 31557600000001
+   Human: 1y 1us
+</programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze cat-config</command>
+      <replaceable>NAME</replaceable>|<replaceable>PATH</replaceable>...</title>
+
+      <para>This command is similar to <command>systemctl cat</command>, but operates on config files. It
+      will copy the contents of a config file and any drop-ins to standard output, using the usual systemd
+      set of directories and rules for precedence. Each argument must be either an absolute path including
+      the prefix (such as <filename>/etc/systemd/logind.conf</filename> or
+      <filename>/usr/lib/systemd/logind.conf</filename>), or a name relative to the prefix (such as
+      <filename>systemd/logind.conf</filename>).</para>
+
+      <example>
+        <title>Showing logind configuration</title>
+        <programlisting>$ systemd-analyze cat-config systemd/logind.conf
 # /etc/systemd/logind.conf
 ...
 [Login]
@@ -207,94 +434,122 @@ NAutoVTs=8
 
 # /etc/systemd/logind.conf.d/50-override.conf
 ... some administrator override
-      </programlisting>
-    </example>
-
-    <para><command>systemd-analyze unit-paths</command> outputs a list of all
-    directories from which unit files, <filename>.d</filename> overrides, and
-    <filename>.wants</filename>, <filename>.requires</filename> symlinks may be
-    loaded. Combine with <option>--user</option> to retrieve the list for the user
-    manager instance, and <option>--global</option> for the global configuration of
-    user manager instances. Note that this verb prints the list that is compiled into
-    <command>systemd-analyze</command> itself, and does not comunicate with the
-    running manager. Use
-    <programlisting>systemctl [--user] [--global] show -p UnitPath --value</programlisting>
-    to retrieve the actual list that the manager uses, with any empty directories
-    omitted.</para>
-
-    <para><command>systemd-analyze log-level</command>
-    prints the current log level of the <command>systemd</command> daemon.
-    If an optional argument <replaceable>LEVEL</replaceable> is provided, then the command changes the current log
-    level of the <command>systemd</command> daemon to <replaceable>LEVEL</replaceable> (accepts the same values as
-    <option>--log-level=</option> described in
-    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
-
-    <para><command>systemd-analyze log-target</command>
-    prints the current log target of the <command>systemd</command> daemon.
-    If an optional argument <replaceable>TARGET</replaceable> is provided, then the command changes the current log
-    target of the <command>systemd</command> daemon to <replaceable>TARGET</replaceable> (accepts the same values as
-    <option>--log-target=</option>, described in
-    <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).</para>
-
-    <para><command>systemd-analyze syscall-filter <optional><replaceable>SET</replaceable>…</optional></command>
-    will list system calls contained in the specified system call set <replaceable>SET</replaceable>,
-    or all known sets if no sets are specified. Argument <replaceable>SET</replaceable> must include
-    the <literal>@</literal> prefix.</para>
-
-    <para><command>systemd-analyze verify</command> will load unit files and print
-    warnings if any errors are detected. Files specified on the command line will be
-    loaded, but also any other units referenced by them. The full unit search path is
-    formed by combining the directories for all command line arguments, and the usual unit
-    load paths (variable <varname>$SYSTEMD_UNIT_PATH</varname> is supported, and may be
-    used to replace or augment the compiled in set of unit load paths; see
-    <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
-    All units files present in the directories containing the command line arguments will
-    be used in preference to the other paths.</para>
-
-    <para><command>systemd-analyze calendar</command> will parse and normalize repetitive calendar time events, and
-    will calculate when they will elapse next. This takes the same input as the <varname>OnCalendar=</varname> setting
-    in <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>, following the
-    syntax described in
-    <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para>
-
-    <para><command>systemd-analyze service-watchdogs</command>
-    prints the current state of service runtime watchdogs of the <command>systemd</command> daemon.
-    If an optional boolean argument is provided, then globally enables or disables the service
-    runtime watchdogs (<option>WatchdogSec=</option>) and emergency actions (e.g.
-    <option>OnFailure=</option> or <option>StartLimitAction=</option>); see
-    <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
-    The hardware watchdog is not affected by this setting.</para>
-
-    <para><command>systemd-analyze timespan</command> parses a time span and outputs the equivalent value in microseconds, and as a reformatted timespan.
-    The time span should adhere to the same syntax documented in <citerefentry><refentrytitle>systemd.time</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
-    Values without associated magnitudes are parsed as seconds.</para>
-
-    <para><command>systemd-analyze security</command> analyzes the security and sandboxing settings of one or more
-    specified service units. If at least one unit name is specified the security settings of the specified service
-    units are inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded,
-    long-running service units are inspected and a terse table with results shown. The command checks for various
-    security-related service settings, assigning each a numeric "exposure level" value, depending on how important a
-    setting is. It then calculates an overall exposure level for the whole unit, which is an estimation in the range
-    0.0…10.0 indicating how exposed a service is security-wise. High exposure levels indicate very little applied
-    sandboxing. Low exposure levels indicate tight sandboxing and strongest security restrictions. Note that this only
-    analyzes the per-service security features systemd itself implements. This means that any additional security
-    mechanisms applied by the service code itself are not accounted for. The exposure level determined this way should
-    not be misunderstood: a high exposure level neither means that there is no effective sandboxing applied by the
-    service code itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels
-    do indicate however that most likely the service might benefit from additional settings applied to them. Please
-    note that many of the security and sandboxing settings individually can be circumvented — unless combined with
-    others. For example, if a service retains the privilege to establish or undo mount points many of the sandboxing
-    options can be undone by the service code itself. Due to that is essential that each service uses the most
-    comprehensive and strict sandboxing and security settings possible. The tool will take into account some of these
-    combinations and relationships between the settings, but not all. Also note that the security and sandboxing
-    settings analyzed here only apply to the operations executed by the service code itself. If a service has access to
-    an IPC system (such as D-Bus) it might request operations from other services that are not subject to the same
-    restrictions. Any comprehensive security and sandboxing analysis is hence incomplete if the IPC access policy is
-    not validated too.</para>
+        </programlisting>
+      </example>
+    </refsect2>
 
-    <para>If no command is passed, <command>systemd-analyze
-    time</command> is implied.</para>
+    <refsect2>
+      <title><command>systemd-analyze verify <replaceable>FILE</replaceable>...</command></title>
+
+      <para>This command will load unit files and print warnings if any errors are detected. Files specified
+      on the command line will be loaded, but also any other units referenced by them. The full unit search
+      path is formed by combining the directories for all command line arguments, and the usual unit load
+      paths (variable <varname>$SYSTEMD_UNIT_PATH</varname> is supported, and may be used to replace or
+      augment the compiled in set of unit load paths; see
+      <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>).  All
+      units files present in the directories containing the command line arguments will be used in preference
+      to the other paths.</para>
+
+      <para>The following errors are currently detected:</para>
+      <itemizedlist>
+        <listitem><para>unknown sections and directives,</para></listitem>
+
+        <listitem><para>missing dependencies which are required to start the given unit,</para></listitem>
+
+        <listitem><para>man pages listed in <varname>Documentation=</varname> which are not found in the
+        system,</para></listitem>
+
+        <listitem><para>commands listed in <varname>ExecStart=</varname> and similar which are not found in
+        the system or not executable.</para></listitem>
+      </itemizedlist>
+
+      <example>
+        <title>Misspelt directives</title>
+
+        <programlisting>$ cat ./user.slice
+[Unit]
+WhatIsThis=11
+Documentation=man:nosuchfile(1)
+Requires=different.service
+
+[Service]
+Description=x
+
+$ systemd-analyze verify ./user.slice
+[./user.slice:9] Unknown lvalue 'WhatIsThis' in section 'Unit'
+[./user.slice:13] Unknown section 'Service'. Ignoring.
+Error: org.freedesktop.systemd1.LoadFailed:
+   Unit different.service failed to load:
+   No such file or directory.
+Failed to create user.slice/start: Invalid argument
+user.slice: man nosuchfile(1) command failed with code 16
+        </programlisting>
+      </example>
+
+      <example>
+        <title>Missing service units</title>
+
+        <programlisting>$ tail ./a.socket ./b.socket
+==> ./a.socket &lt;==
+[Socket]
+ListenStream=100
 
+==> ./b.socket &lt;==
+[Socket]
+ListenStream=100
+Accept=yes
+
+$ systemd-analyze verify ./a.socket ./b.socket
+Service a.service not loaded, a.socket cannot be started.
+Service b@0.service not loaded, b.socket cannot be started.
+        </programlisting>
+      </example>
+    </refsect2>
+
+    <refsect2>
+      <title><command>systemd-analyze security <optional><replaceable>UNIT</replaceable>...</optional></command></title>
+
+      <para>This command analyzes the security and sandboxing settings of one or more specified service
+      units. If at least one unit name is specified the security settings of the specified service units are
+      inspected and a detailed analysis is shown. If no unit name is specified, all currently loaded,
+      long-running service units are inspected and a terse table with results shown. The command checks for
+      various security-related service settings, assigning each a numeric "exposure level" value, depending
+      on how important a setting is. It then calculates an overall exposure level for the whole unit, which
+      is an estimation in the range 0.0…10.0 indicating how exposed a service is security-wise. High exposure
+      levels indicate very little applied sandboxing. Low exposure levels indicate tight sandboxing and
+      strongest security restrictions. Note that this only analyzes the per-service security features systemd
+      itself implements. This means that any additional security mechanisms applied by the service code
+      itself are not accounted for. The exposure level determined this way should not be misunderstood: a
+      high exposure level neither means that there is no effective sandboxing applied by the service code
+      itself, nor that the service is actually vulnerable to remote or local attacks. High exposure levels do
+      indicate however that most likely the service might benefit from additional settings applied to
+      them.</para>
+
+      <para>Please note that many of the security and sandboxing settings individually can be circumvented —
+      unless combined with others. For example, if a service retains the privilege to establish or undo mount
+      points many of the sandboxing options can be undone by the service code itself. Due to that is
+      essential that each service uses the most comprehensive and strict sandboxing and security settings
+      possible. The tool will take into account some of these combinations and relationships between the
+      settings, but not all. Also note that the security and sandboxing settings analyzed here only apply to
+      the operations executed by the service code itself. If a service has access to an IPC system (such as
+      D-Bus) it might request operations from other services that are not subject to the same
+      restrictions. Any comprehensive security and sandboxing analysis is hence incomplete if the IPC access
+      policy is not validated too.</para>
+
+      <example>
+      <title>Analyze <filename noindex="true">systemd-logind.service</filename></title>
+
+      <programlisting>$ systemd-analyze security --no-pager systemd-logind.service
+  NAME                DESCRIPTION                              EXPOSURE
+✗ PrivateNetwork=     Service has access to the host's network      0.5
+✗ User=/DynamicUser=  Service runs as root user                     0.4
+✗ DeviceAllow=        Service has no device ACL                     0.2
+✓ IPAddressDeny=      Service blocks all IP address ranges
+...
+→ Overall exposure level for systemd-logind.service: 4.1 OK 🙂
+</programlisting>
+      </example>
+    </refsect2>
   </refsect1>
 
   <refsect1>
@@ -401,6 +656,13 @@ NAutoVTs=8
         the specified root path <replaceable>PATH</replaceable>.</para></listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><option>--iterations=<replaceable>NUMBER</replaceable></option></term>
+
+        <listitem><para>When used with the <command>calendar</command> command, show the specified number of
+        iterations the specified calendar expression will elapse next. Defaults to 1.</para></listitem>
+      </varlistentry>
+
       <xi:include href="user-system-options.xml" xpointer="host" />
       <xi:include href="user-system-options.xml" xpointer="machine" />
 
@@ -418,88 +680,6 @@ NAutoVTs=8
     otherwise.</para>
   </refsect1>
 
-  <refsect1>
-    <title>Examples for <command>dot</command></title>
-
-    <example>
-      <title>Plots all dependencies of any unit whose name starts with
-      <literal>avahi-daemon</literal></title>
-
-      <programlisting>$ systemd-analyze dot 'avahi-daemon.*' | dot -Tsvg > avahi.svg
-$ eog avahi.svg</programlisting>
-    </example>
-
-    <example>
-      <title>Plots the dependencies between all known target units</title>
-
-      <programlisting>$ systemd-analyze dot --to-pattern='*.target' --from-pattern='*.target' | dot -Tsvg > targets.svg
-$ eog targets.svg</programlisting>
-    </example>
-  </refsect1>
-
-  <refsect1>
-    <title>Examples for <command>verify</command></title>
-
-    <para>The following errors are currently detected:</para>
-    <itemizedlist>
-      <listitem><para>unknown sections and directives,
-      </para></listitem>
-
-      <listitem><para>missing dependencies which are required to start
-      the given unit,</para></listitem>
-
-      <listitem><para>man pages listed in
-      <varname>Documentation=</varname> which are not found in the
-      system,</para></listitem>
-
-      <listitem><para>commands listed in <varname>ExecStart=</varname>
-      and similar which are not found in the system or not
-      executable.</para></listitem>
-    </itemizedlist>
-
-    <example>
-      <title>Misspelt directives</title>
-
-      <programlisting>$ cat ./user.slice
-[Unit]
-WhatIsThis=11
-Documentation=man:nosuchfile(1)
-Requires=different.service
-
-[Service]
-Description=x
-
-$ systemd-analyze verify ./user.slice
-[./user.slice:9] Unknown lvalue 'WhatIsThis' in section 'Unit'
-[./user.slice:13] Unknown section 'Service'. Ignoring.
-Error: org.freedesktop.systemd1.LoadFailed:
-   Unit different.service failed to load:
-   No such file or directory.
-Failed to create user.slice/start: Invalid argument
-user.slice: man nosuchfile(1) command failed with code 16
-      </programlisting>
-    </example>
-
-    <example>
-      <title>Missing service units</title>
-
-      <programlisting>$ tail ./a.socket ./b.socket
-==> ./a.socket &lt;==
-[Socket]
-ListenStream=100
-
-==> ./b.socket &lt;==
-[Socket]
-ListenStream=100
-Accept=yes
-
-$ systemd-analyze verify ./a.socket ./b.socket
-Service a.service not loaded, a.socket cannot be started.
-Service b@0.service not loaded, b.socket cannot be started.
-      </programlisting>
-    </example>
-  </refsect1>
-
   <xi:include href="less-variables.xml" />
 
   <refsect1>
index 04f9596..8c0e8a8 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-ask-password-console.service">
 
   <refentryinfo>
index 2fe3e88..9bb045b 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-ask-password"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index a7865b2..6e836d6 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-backlight@.service" conditional='ENABLE_BACKLIGHT'>
 
   <refentryinfo>
index c197b62..27e3419 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-binfmt.service" conditional='ENABLE_BINFMT'
     xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 9809414..0c5144f 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-bless-boot-generator" conditional='ENABLE_EFI'>
 
   <refentryinfo>
index fb362ce..cd5e9ac 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-bless-boot.service" conditional='ENABLE_EFI'
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 55c2adf..d6d587f 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-boot-check-no-failures.service"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 4c914e6..3b13196 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-boot" conditional='ENABLE_EFI'
   <refsect1>
     <title>Description</title>
 
-    <para><command>systemd-boot</command> (short: <command>sd-boot</command>) is a simple UEFI boot manager. It
-    provides a graphical menu to select the entry to boot and an editor for the kernel command line. systemd-boot
-    supports systems with UEFI firmware only.</para>
+    <para><command>systemd-boot</command> (short: <command>sd-boot</command>) is a simple UEFI boot
+    manager. It provides a graphical menu to select the entry to boot and an editor for the kernel command
+    line. <command>systemd-boot</command> supports systems with UEFI firmware only.</para>
 
     <para>systemd-boot loads boot entry information from the EFI system partition (ESP), usually mounted at
-    <filename>/boot</filename>, <filename>/efi</filename>, or <filename>/boot/efi</filename> during OS
-    runtime. Configuration file fragments, kernels, initrds and other EFI images to boot generally need to reside on
-    the ESP. Linux kernels must be built with <option>CONFIG_EFI_STUB</option> to be able to be directly executed as an
-    EFI image. During boot systemd-boot automatically assembles a list of boot entries from the following
-    sources:</para>
+    <filename>/efi/</filename>, <filename>/boot/</filename>, or <filename>/boot/efi/</filename> during OS
+    runtime, as well as from the Extended Boot Loader partition if it exists (usually mounted to
+    <filename>/boot/</filename>). Configuration file fragments, kernels, initrds and other EFI images to boot
+    generally need to reside on the ESP or the Extended Boot Loader partition. Linux kernels must be built
+    with <option>CONFIG_EFI_STUB</option> to be able to be directly executed as an EFI image. During boot
+    systemd-boot automatically assembles a list of boot entries from the following sources:</para>
 
     <itemizedlist>
       <listitem><para>Boot entries defined with <ulink
-      url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
-      Specification</ulink> description files located in <filename>/loader/entries/</filename> on the ESP. These
-      usually describe Linux kernel images with associated initrd images, but alternatively may also describe
-      arbitrary other EFI executables.</para></listitem>
+      url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> description files
+      located in <filename>/loader/entries/</filename> on the ESP and the Extended Boot Loader
+      Partition. These usually describe Linux kernel images with associated initrd images, but alternatively
+      may also describe arbitrary other EFI executables.</para></listitem>
 
       <listitem><para>Unified kernel images following the <ulink
-      url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
-      Specification</ulink>, as executable EFI binaries in <filename>/EFI/Linux/</filename> on the ESP.
+      url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>, as executable EFI
+      binaries in <filename>/EFI/Linux/</filename> on the ESP and the Extended Boot Loader Partition.
       </para></listitem>
 
       <listitem><para>The Microsoft Windows EFI boot manager, if installed</para></listitem>
       <listitem><para>A reboot into the UEFI firmware setup option, if supported by the firmware</para></listitem>
     </itemizedlist>
 
-    <para><citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry> may be
-    used to copy kernel images onto the ESP and to generate description files compliant with the Boot Loader
-    Specification. <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry> may be
-    used from a running system to locate the ESP, list available entries, and install systemd-boot itself.</para>
+    <para><citerefentry><refentrytitle>kernel-install</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    may be used to copy kernel images onto the ESP or the Extended Boot Loader Partition and to generate
+    description files compliant with the Boot Loader
+    Specification. <citerefentry><refentrytitle>bootctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+    may be used from a running system to locate the ESP and the Extended Boot Loader Partition, list
+    available entries, and install <command>systemd-boot</command> itself.</para>
 
     <para>systemd-boot will provide information about the time spent in UEFI firmware using the <ulink
     url="https://systemd.io/BOOT_LOADER_INTERFACE">Boot Loader Interface</ulink>. This information can be displayed
   <refsect1>
     <title>Files</title>
 
-    <para>The files systemd-boot reads generally reside on the UEFI ESP which is usually mounted to
-    <filename>/boot/</filename>, <filename>/efi/</filename> or <filename>/boot/efi</filename> during OS
-    runtime. systemd-boot reads runtime configuration such as the boot timeout and default entry from
-    <filename>/loader/loader.conf</filename> on the ESP (in combination with data read from EFI variables). See
-    <citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Boot entry
-    description files following the <ulink
-    url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader
-    Specification</ulink> are read from <filename>/loader/entries/</filename> on the ESP. Unified kernel boot entries
-    following the <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot
-    Loader Specification</ulink> are read from <filename>/EFI/Linux/</filename> on the ESP.</para>
+    <para>The files <command>systemd-boot</command> processes generally reside on the UEFI ESP which is
+    usually mounted to <filename>/efi/</filename>, <filename>/boot/</filename> or
+    <filename>/boot/efi/</filename> during OS runtime. It also processes files on the Extended Boot Loader
+    partition which is typically mounted to <filename>/boot/</filename>, if it
+    exists. <command>systemd-boot</command> reads runtime configuration such as the boot timeout and default
+    entry from <filename>/loader/loader.conf</filename> on the ESP (in combination with data read from EFI
+    variables). See
+    <citerefentry><refentrytitle>loader.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Boot
+    entry description files following the <ulink url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot
+    Loader Specification</ulink> are read from <filename>/loader/entries/</filename> on the ESP and the
+    Extended Boot Loader partition. Unified kernel boot entries following the <ulink
+    url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink> are read from
+    <filename>/EFI/Linux/</filename> on the ESP and the Extended Boot Loader partition.</para>
   </refsect1>
 
   <refsect1>
index 446fa4b..f3d6f37 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-cat"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 0d7f2b6..6181cdf 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-cgls"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 32ed66b..a850a57 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-cgtop"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index b25f0c4..1ab7e59 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-        "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-coredump" conditional='ENABLE_COREDUMP'
           xmlns:xi="http://www.w3.org/2001/XInclude">
index e30d69b..e3c17d6 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-cryptsetup-generator" conditional='HAVE_LIBCRYPTSETUP'>
 
   <refentryinfo>
index 439e8e9..0324a67 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-cryptsetup@.service" conditional='HAVE_LIBCRYPTSETUP'>
 
   <refentryinfo>
index fa88e8a..1f9a79d 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-debug-generator">
 
   <refentryinfo>
index f86f205..02d7b88 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-delta"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index c4763fd..28d997c 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-detect-virt"
           xmlns:xi="http://www.w3.org/2001/XInclude">
           </row>
 
           <row>
-            <entry valign="top" morerows="5">Container</entry>
+            <entry><varname>acrn</varname></entry>
+            <entry><ulink url="https://projectacrn.org">ACRN hypervisor</ulink></entry>
+          </row>
+
+          <row>
+            <entry valign="top" morerows="6">Container</entry>
             <entry><varname>openvz</varname></entry>
             <entry>OpenVZ/Virtuozzo</entry>
           </row>
             <entry><varname>rkt</varname></entry>
             <entry>rkt app container runtime</entry>
           </row>
+
+          <row>
+            <entry><varname>wsl</varname></entry>
+            <entry><ulink url="https://docs.microsoft.com/en-us/windows/wsl/about">Windows Subsystem for Linux</ulink></entry>
+          </row>
         </tbody>
       </tgroup>
     </table>
     machine and container virtualization are used in
     conjunction, only the latter will be identified (unless
     <option>--vm</option> is passed).</para>
+    <para> Windows Subsystem for Linux is not a Linux container,
+    but an environment for running Linux userspace applications on
+    top of the Windows kernel using a Linux-compatible interface.
+    WSL is categorized as a container for practical purposes.
+    Multiple WSL environments share the same kernel and services
+    should generally behave like when being run in a container.</para>
   </refsect1>
 
   <refsect1>
         <term><option>-v</option></term>
         <term><option>--vm</option></term>
 
-        <listitem><para>Only detects hardware virtualization).</para></listitem>
+        <listitem><para>Only detects hardware virtualization.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index 44880e7..4c88bd5 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-environment-d-generator" conditional='ENABLE_ENVIRONMENT_D'>
 
   <refentryinfo>
@@ -37,7 +34,7 @@
     <para><filename>systemd-environment-d-generator</filename> is a
     <citerefentry><refentrytitle>systemd.environment-generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>
     that reads environment configuration specified by
-    <citerefentry><refentrytitle>environment.d</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+    <citerefentry><refentrytitle>environment.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     configuration files and passes it to the
     <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     user manager instance.</para>
@@ -49,7 +46,7 @@
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.environment-generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>5</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index f61c07a..86ef175 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-escape"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index a78e2d5..560649f 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-firstboot" conditional='ENABLE_FIRSTBOOT'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index e1996e4..121b0cd 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-fsck@.service">
 
   <refentryinfo>
index ab70642..82321c4 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-fstab-generator">
 
   <refentryinfo>
         lost at shutdown, as <filename>/etc</filename> and <filename>/var</filename> will be served from the (initially
         unpopulated) volatile memory file system.</para>
 
-        <para>If set to <option>state</option> the generator will leave the root
-        directory mount point unaltered, however will mount a <literal>tmpfs</literal> file system to
-        <filename>/var</filename>. In this mode the normal system configuration (i.e. the contents of
-        <literal>/etc</literal>) is in effect (and may be modified during system runtime), however the system state
-        (i.e. the contents of <literal>/var</literal>) is reset at boot and lost at shutdown.</para>
+        <para>If set to <option>state</option> the generator will leave the root directory mount point unaltered,
+        however will mount a <literal>tmpfs</literal> file system to <filename>/var</filename>. In this mode the normal
+        system configuration (i.e. the contents of <literal>/etc</literal>) is in effect (and may be modified during
+        system runtime), however the system state (i.e. the contents of <literal>/var</literal>) is reset at boot and
+        lost at shutdown.</para>
+
+        <para>If this setting is set to <literal>overlay</literal> the root file system is set up as
+        <literal>overlayfs</literal> mount combining the read-only root directory with a writable
+        <literal>tmpfs</literal>, so that no modifications are made to disk, but the file system may be modified
+        nonetheless with all changes being lost at reboot.</para>
 
         <para>Note that in none of these modes the root directory, <filename>/etc</filename>, <filename>/var</filename>
         or any other resources stored in the root file system are physically removed. It's thus safe to boot a system
         that is normally operated in non-volatile mode temporarily into volatile mode, without losing data.</para>
 
-        <para>Note that enabling this setting will only work correctly on operating systems that can boot up with only
-        <filename>/usr</filename> mounted, and are able to automatically populate <filename>/etc</filename>, and also
-        <filename>/var</filename> in case of <literal>systemd.volatile=yes</literal>.</para></listitem>
+        <para>Note that with the exception of <literal>overlay</literal> mode, enabling this setting will only work
+        correctly on operating systems that can boot up with only <filename>/usr</filename> mounted, and are able to
+        automatically populate <filename>/etc</filename>, and also <filename>/var</filename> in case of
+        <literal>systemd.volatile=yes</literal>.</para></listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
index b5a3006..4cc664d 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-getty-generator">
 
   <refentryinfo>
index d98ef20..0d6d4e3 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-gpt-auto-generator">
 
   <refentryinfo>
   <refsect1>
     <title>Description</title>
 
-    <para><filename>systemd-gpt-auto-generator</filename> is a unit
-    generator that automatically discovers root,
-    <filename>/home</filename>, <filename>/srv</filename> and swap
-    partitions and creates mount and swap units for them, based on the
-    partition type GUIDs of GUID partition tables (GPT),
-    see <ulink url="http://www.uefi.org/specifications">UEFI Specification</ulink>, chapter 5.
-    It implements the <ulink
-    url="https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable
-    Partitions Specification</ulink>. Note that this generator has no
-    effect on non-GPT systems, or where the directories under the
-    mount points are already non-empty. Also, on systems where the
-    units are explicitly configured (for example, listed in
-    <citerefentry
-    project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>),
-    the units this generator creates are overridden, but additional
-    implicit dependencies might be created.</para>
+    <para><filename>systemd-gpt-auto-generator</filename> is a unit generator that automatically discovers
+    root, <filename>/home/</filename>, <filename>/srv/</filename>, the EFI System Partition, the Extended
+    Boot Loader Partition and swap partitions and creates mount and swap units for them, based on the
+    partition type GUIDs of GUID partition tables (GPT), see <ulink
+    url="https://uefi.org/specifications">UEFI Specification</ulink>, chapter 5.  It implements the <ulink
+    url="https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable Partitions
+    Specification</ulink>. Note that this generator has no effect on non-GPT systems, and on specific mount
+    points that are directories already containing files. Also, on systems where the units are explicitly
+    configured (for example, listed in <citerefentry
+    project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>), the
+    units this generator creates are overridden, but additional implicit dependencies might be
+    created.</para>
 
     <para>This generator will only look for root partitions on the
     same physical disk the EFI System Partition (ESP) is located on.
       <tgroup cols='3' align='left' colsep='1' rowsep='1'>
         <colspec colname="guid" />
         <colspec colname="name" />
+        <colspec colname="where" />
         <colspec colname="explanation" />
         <thead>
           <row>
             <entry>Partition Type GUID</entry>
             <entry>Name</entry>
+            <entry>Mount Point</entry>
             <entry>Explanation</entry>
           </row>
         </thead>
           <row>
             <entry>44479540-f297-41b2-9af7-d131d5f0458a</entry>
             <entry><filename>Root Partition (x86)</filename></entry>
+            <entry><filename>/</filename></entry>
             <entry>On 32-bit x86 systems, the first x86 root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
           </row>
           <row>
             <entry>4f68bce3-e8cd-4db1-96e7-fbcaf984b709</entry>
             <entry><filename>Root Partition (x86-64)</filename></entry>
+            <entry><filename>/</filename></entry>
             <entry>On 64-bit x86 systems, the first x86-64 root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
           </row>
           <row>
             <entry>69dad710-2ce4-4e3c-b16c-21a1d49abed3</entry>
             <entry><filename>Root Partition (32-bit ARM)</filename></entry>
+            <entry><filename>/</filename></entry>
             <entry>On 32-bit ARM systems, the first ARM root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
           </row>
           <row>
             <entry>b921b045-1df0-41c3-af44-4c6f280d3fae</entry>
             <entry><filename>Root Partition (64-bit ARM)</filename></entry>
+            <entry><filename>/</filename></entry>
             <entry>On 64-bit ARM systems, the first ARM root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
           </row>
           <row>
             <entry>993d8d3d-f80e-4225-855a-9daf8ed7ea97</entry>
             <entry><filename>Root Partition (Itanium/IA-64)</filename></entry>
+            <entry><filename>/</filename></entry>
             <entry>On Itanium systems, the first Itanium root partition on the disk the EFI ESP is located on is mounted to the root directory <filename>/</filename>.</entry>
           </row>
           <row>
             <entry>933ac7e1-2eb4-4f13-b844-0e14e2aef915</entry>
             <entry>Home Partition</entry>
+            <entry><filename>/home/</filename></entry>
             <entry>The first home partition on the disk the root partition is located on is mounted to <filename>/home</filename>.</entry>
           </row>
           <row>
             <entry>3b8f8425-20e0-4f3b-907f-1a25a76f98e8</entry>
             <entry>Server Data Partition</entry>
+            <entry><filename>/srv/</filename></entry>
             <entry>The first server data partition on the disk the root partition is located on is mounted to <filename>/srv</filename>.</entry>
           </row>
           <row>
             <entry>0657fd6d-a4ab-43c4-84e5-0933c84b4f4f</entry>
             <entry>Swap</entry>
+            <entry>n/a</entry>
             <entry>All swap partitions located on the disk the root partition is located on are enabled.</entry>
           </row>
           <row>
             <entry>c12a7328-f81f-11d2-ba4b-00a0c93ec93b</entry>
             <entry>EFI System Partition (ESP)</entry>
+            <entry><filename>/efi/</filename> or <filename>/boot/</filename></entry>
             <entry>The first ESP located on the disk the root partition is located on is mounted to <filename>/boot</filename> or <filename>/efi</filename>, see below.</entry>
           </row>
+          <row>
+            <entry>bc13c2ff-59e6-4262-a352-b275fd6f7172</entry>
+            <entry>Extended Boot Loader Partition</entry>
+            <entry><filename>/boot/</filename></entry>
+            <entry>The first Extended Boot Loader Partition is mounted to <filename>/boot</filename>, see below.</entry>
+          </row>
         </tbody>
       </tgroup>
     </table>
           <row>
             <entry><constant>GPT_FLAG_READ_ONLY</constant></entry>
             <entry>0x1000000000000000</entry>
-            <entry><filename>/</filename>, <filename>/srv</filename>, <filename>/home</filename></entry>
+            <entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, Extended Boot Loader Partition</entry>
             <entry>Partition is mounted read-only</entry>
           </row>
 
           <row>
             <entry><constant>GPT_FLAG_NO_AUTO</constant></entry>
             <entry>0x8000000000000000</entry>
-            <entry><filename>/</filename>, <filename>/srv</filename>, <filename>/home</filename></entry>
+            <entry><filename>/</filename>, <filename>/home/</filename>, <filename>/srv/</filename>, Extended Boot Loader Partition</entry>
             <entry>Partition is not mounted automatically</entry>
           </row>
 
           <row>
             <entry><constant>GPT_FLAG_NO_BLOCK_IO_PROTOCOL</constant></entry>
             <entry>0x0000000000000002</entry>
-            <entry>ESP</entry>
+            <entry>EFI System Partition (ESP)</entry>
             <entry>Partition is not mounted automatically</entry>
           </row>
         </tbody>
       </tgroup>
     </table>
 
-    <para>The <filename>/home</filename> and <filename>/srv</filename>
-    partitions may be encrypted in LUKS format. In this case, a device
-    mapper device is set up under the names
-    <filename>/dev/mapper/home</filename> and
-    <filename>/dev/mapper/srv</filename>. Note that this might create
-    conflicts if the same partition is listed in
-    <filename>/etc/crypttab</filename> with a different device mapper
-    device name.</para>
-
-    <para>Mount and automount units for the EFI System Partition (ESP) are generated on EFI systems. The ESP is mounted
-    to <filename>/boot</filename>, unless a mount point directory <filename>/efi</filename> exists, in which case it is
-    mounted there. Since this generator creates an automount unit, the mount will only be activated on-demand, when
-    accessed. On systems where <filename>/boot</filename> (or <filename>/efi</filename> if it exists) is an explicitly
-    configured mount (for example, listed in <citerefentry
-    project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>) or where the
-    <filename>/boot</filename> (or <filename>/efi</filename>) mount point is non-empty, no mount units are
-    generated.</para>
+    <para>The <filename>/home/</filename> and <filename>/srv/</filename> partitions may be encrypted in LUKS
+    format. In this case, a device mapper device is set up under the names
+    <filename>/dev/mapper/home</filename> and <filename>/dev/mapper/srv</filename>. Note that this might
+    create conflicts if the same partition is listed in <filename>/etc/crypttab</filename> with a different
+    device mapper device name.</para>
+
+    <para>Mount and automount units for the EFI System Partition (ESP) are generated on EFI systems. The ESP
+    is mounted to <filename>/boot/</filename> (except if an Extended Boot Loader partition exists, see
+    below), unless a mount point directory <filename>/efi/</filename> exists, in which case it is mounted
+    there. Since this generator creates an automount unit, the mount will only be activated on-demand, when
+    accessed. On systems where <filename>/boot/</filename> (or <filename>/efi/</filename> if it exists) is an
+    explicitly configured mount (for example, listed in <citerefentry
+    project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>) or where
+    the <filename>/boot/</filename> (or <filename>/efi/</filename>) mount point is non-empty, no mount units
+    are generated.</para>
+
+    <para>If the disk contains an Extended Boot Loader partition, as defined in the <ulink
+    url="https://systemd.io/BOOT_LOADER_SPECIFICATION">Boot Loader Specification</ulink>, it is made
+    available at <filename>/boot</filename> (by means of an automount point, similar to the ESP, see
+    above). If both an EFI System Partition and an Extended Boot Loader partition exist the latter is
+    preferably mounted to <filename>/boot/</filename>. Make sure to create both <filename>/efi/</filename>
+    and <filename>/boot/</filename> to ensure both partitions are mounted.</para>
 
     <para>When using this generator in conjunction with btrfs file
     systems, make sure to set the correct default subvolumes on them,
   </refsect1>
 
   <refsect1>
+    <title>Kernel Command Line</title>
+
+    <para><filename>systemd-gpt-auto-generator</filename> understands the following kernel command line
+    parameters:</para>
+
+    <variablelist class='kernel-commandline-options'>
+
+      <varlistentry>
+        <term><varname>systemd.gpt_auto</varname></term>
+        <term><varname>rd.systemd.gpt_auto</varname></term>
+
+        <listitem><para>Those options take an optional boolean argument, and default to yes.
+        The generator is enabled by default, and a negative value may be used to disable it.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>root=</varname></term>
+
+        <listitem><para>When used with the special value <literal>gpt-auto</literal>, automatic discovery of
+        the root parition based on the GPT partition type is enabled.  Any other value disables this
+        generator.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>rw</varname></term>
+        <term><varname>ro</varname></term>
+
+        <listitem><para>Mount the root partition read-write or read-only <emphasis>initially</emphasis>.</para>
+
+        <para>Note that unlike most kernel command line options these settings do not override configuration
+        in the file system, and the file system may be remounted later. See
+        <citerefentry><refentrytitle>systemd-remount-fs.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
+        </para></listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
     <title>See Also</title>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
index a40384c..2b102cc 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-halt.service">
 
index 8f0cc5d..ff105d4 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-hibernate-resume-generator" conditional='ENABLE_HIBERNATE'>
 
   <refentryinfo>
index 0db49e3..88858ef 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-hibernate-resume@.service" conditional='ENABLE_HIBERNATE'>
 
   <refentryinfo>
index 95c8bb6..19bd4c0 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-hostnamed.service" conditional='ENABLE_HOSTNAMED'>
 
index 6c8487a..15a2c01 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-hwdb" conditional="ENABLE_HWDB"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 8a76ccc..b6906b0 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
index ec967c4..355e5b0 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-importd.service" conditional='ENABLE_IMPORTD'>
 
index 3fa5acf..e0399eb 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-inhibit"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index f9627c9..0345936 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-initctl.service">
 
index 13604a0..633b4cb 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-journal-gatewayd.service" conditional='HAVE_MICROHTTPD'
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 6e6819b..b28092d 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-journal-remote" conditional='HAVE_MICROHTTPD'
           xmlns:xi="http://www.w3.org/2001/XInclude">
index cdeaddd..1b8b0be 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-journal-upload" conditional='HAVE_MICROHTTPD'
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 9167993..8bbb993 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-journald.service">
 
index baf20c0..f620aad 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-localed.service" conditional='ENABLE_LOCALED'>
 
index 1c29b33..a66c53d 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-logind.service" conditional='ENABLE_LOGIND'>
 
index 06e70fc..781a984 100644 (file)
@@ -1,6 +1,7 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!--
   SPDX-License-Identifier: LGPL-2.1+
 
index aea13ca..31e0cdc 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-machine-id-setup"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index b5f3bc2..8771434 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-machined.service" conditional='ENABLE_MACHINED'>
 
index c8e201e..89662b8 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-makefs@.service">
 
   <refentryinfo>
index 5aa70b7..ca9edef 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-modules-load.service" conditional='HAVE_KMOD'>
 
   <refentryinfo>
index 610c97f..e557ee8 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-mount"
           xmlns:xi="http://www.w3.org/2001/XInclude">
     the service manager job queue, so that it may pull in further dependencies (such as parent mounts, or a file system
     checker to execute a priori), and may make use of the auto-mounting logic.</para>
 
-    <para>The command takes either one or two arguments. If only one argument is specified it should refer to a block
-    device or regular file containing a file system (e.g. <literal>/dev/sdb1</literal> or
-    <literal>/path/to/disk.img</literal>). If it is a block device, which is then probed for a label and other
-    metadata, and is mounted to a directory whose name is generated from the label. In this mode the block device must
-    exist at the time of invocation of the command, so that it may be probed. If the device is found to be a removable
-    block device (e.g. a USB stick) an automount point instead of a regular mount point is created (i.e. the
-    <option>--automount=</option> option is implied, see below).</para>
+    <para>The command takes either one or two arguments. If only one argument is specified it should refer to
+    a block device or regular file containing a file system (e.g. <literal>/dev/sdb1</literal> or
+    <literal>/path/to/disk.img</literal>). The block device or image file is then probed for a file system
+    label and other metadata, and is mounted to a directory below <filename>/run/media/system/</filename>
+    whose name is generated from the file system label. In this mode the block device or image file must
+    exist at the time of invocation of the command, so that it may be probed. If the device is found to be a
+    removable block device (e.g. a USB stick) an automount point instead of a regular mount point is created
+    (i.e. the <option>--automount=</option> option is implied, see below).</para>
 
     <para>If two arguments are specified the first indicates the mount source (the <replaceable>WHAT</replaceable>) and
     the second indicates the path to mount it on (the <replaceable>WHERE</replaceable>). In this mode no probing of the
   </refsect1>
 
   <refsect1>
+    <title>Example</title>
+
+    <para>Use a udev rule like the following to automatically mount all USB storage plugged in:</para>
+
+    <programlisting>ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_USAGE}=="filesystem", \
+        RUN{program}+="/usr/bin/systemd-mount --no-block --automount=yes --collect $devnode"</programlisting>
+  </refsect1>
+
+  <refsect1>
     <title>See Also</title>
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
index 95abf5b..7c82f68 100644 (file)
@@ -1,12 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
-
-<refentry id="systemd-networkd-wait-online.service" conditional='ENABLE_NETWORKD'>
+<refentry id="systemd-networkd-wait-online.service" conditional='ENABLE_NETWORKD'
+          xmlns:xi="http://www.w3.org/2001/XInclude">
 
   <refentryinfo>
     <title>systemd-networkd-wait-online.service</title>
@@ -37,8 +35,9 @@
     configured. By default, it will wait for all links it is aware of
     and which are managed by
     <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-    to be fully configured or failed, and for at least one link to
-    gain a carrier.</para>
+    to be fully configured or failed, and for at least one link to be online. Here, online means that
+    the link's operational state is equal or higher than <literal>degraded</literal>. The threshold
+    can be configured by <option>--operational-state=</option> option.</para>
   </refsect1>
 
   <refsect1>
 
     <variablelist>
       <varlistentry>
-        <term><option>-i</option></term>
-        <term><option>--interface=</option></term>
-
-        <listitem><para>Network interface to wait for before deciding
-        if the system is online. This is useful when a system has
-        several interfaces which will be configured, but a particular
-        one is necessary to access some network resources. This option
-        may be used more than once to wait for multiple network
-        interfaces. When used, all other interfaces are ignored.
+        <term><option>-i</option> <replaceable>INTERFACE</replaceable><optional>:<replaceable>OPERSTATE</replaceable></optional></term>
+        <term><option>--interface=</option><replaceable>INTERFACE</replaceable><optional>:<replaceable>OPERSTATE</replaceable></optional></term>
+
+        <listitem><para>Network interface to wait for before deciding if the system is online. This
+        is useful when a system has several interfaces which will be configured, but a particular
+        one is necessary to access some network resources. When used, all other interfaces are ignored.
+        This option may be used more than once to wait for multiple network interfaces. When this
+        option is specified multiple times, then <command>systemd-networkd-wait-online</command> waits
+        for all specified interfaces to be online. Optinally, required minimum operational state can be
+        specified after a colon <literal>:</literal>. Please see
+        <citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        for possible operational states. If the operational state is not specified here, then
+        the value from <varname>RequiredForOnline=</varname> in the corresponding
+        <filename>.network</filename> file is used if present, and <literal>degraded</literal> otherwise.
         </para></listitem>
       </varlistentry>
+
       <varlistentry>
-        <term><option>--ignore=</option></term>
+        <term><option>--ignore=</option><replaceable>INTERFACE</replaceable></term>
+
         <listitem><para>Network interfaces to be ignored when deciding
         if the system is online. By default, only the loopback
         interface is ignored. This option may be used more than once
         to ignore multiple network interfaces. </para></listitem>
       </varlistentry>
+
       <varlistentry>
-        <term><option>--timeout=</option></term>
+        <term><option>-o</option> <replaceable>OPERSTATE</replaceable></term>
+        <term><option>--operational-state=</option><replaceable>OPERSTATE</replaceable></term>
+
+        <listitem><para>Takes an operational state. Please see
+        <citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+        for possible operational states. If set, the specified value overrides
+        <varname>RequiredForOnline=</varname> settings in <filename>.network</filename> files.
+        But this does not override operational states specified in <option>--interface=</option> option.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--any</option></term>
+
+        <listitem><para>Even if several interfaces are in configuring state,
+        <command>systemd-networkd-wait-online</command> exits with success when at least one interface
+        becomes online. When this option is specified with <option>--interface=</option>, then
+        <command>systemd-networkd-wait-online</command> waits for one of the specified interfaces to be
+        online. This option is useful when some interfaces may not have carrier on boot.
+        </para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--timeout=</option> <replaceable>SECS</replaceable></term>
+
         <listitem><para>Fail the service if the network is not online
         by the time the timeout elapses. A timeout of 0 disables the
         timeout. Defaults to 120 seconds. </para></listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><option>-q</option></term>
+        <term><option>--quiet</option></term>
+
+        <listitem><para>Suppress log messages.</para></listitem>
+      </varlistentry>
+
+      <xi:include href="standard-options.xml" xpointer="help" />
+      <xi:include href="standard-options.xml" xpointer="version" />
     </variablelist>
   </refsect1>
 
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      <citerefentry><refentrytitle>systemd-networkd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index 2127bf1..b3ba621 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-networkd.service" conditional='ENABLE_NETWORKD'>
 
index 18d8732..8906068 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-notify"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index ff6b6a9..5ba162b 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY fedora_latest_version "28">
 <!ENTITY fedora_cloud_release "1.1">
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-nspawn"
     xmlns:xi="http://www.w3.org/2001/XInclude">
     <para>The following options are understood:</para>
 
     <variablelist>
+
+      <varlistentry>
+        <term><option>-q</option></term>
+        <term><option>--quiet</option></term>
+
+        <listitem><para>Turns off any status output by the tool
+        itself. When this switch is used, the only output from nspawn
+        will be the console output of the container OS
+        itself.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--settings=</option><replaceable>MODE</replaceable></term>
+
+        <listitem><para>Controls whether
+        <command>systemd-nspawn</command> shall search for and use
+        additional per-container settings from
+        <filename>.nspawn</filename> files. Takes a boolean or the
+        special values <option>override</option> or
+        <option>trusted</option>.</para>
+
+        <para>If enabled (the default), a settings file named after the
+        machine (as specified with the <option>--machine=</option>
+        setting, or derived from the directory or image file name)
+        with the suffix <filename>.nspawn</filename> is searched in
+        <filename>/etc/systemd/nspawn/</filename> and
+        <filename>/run/systemd/nspawn/</filename>. If it is found
+        there, its settings are read and used. If it is not found
+        there, it is subsequently searched in the same directory as the
+        image file or in the immediate parent of the root directory of
+        the container. In this case, if the file is found, its settings
+        will be also read and used, but potentially unsafe settings
+        are ignored. Note that in both these cases, settings on the
+        command line take precedence over the corresponding settings
+        from loaded <filename>.nspawn</filename> files, if both are
+        specified. Unsafe settings are considered all settings that
+        elevate the container's privileges or grant access to
+        additional resources such as files or directories of the
+        host. For details about the format and contents of
+        <filename>.nspawn</filename> files, consult
+        <citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+        <para>If this option is set to <option>override</option>, the
+        file is searched, read and used the same way, however, the order of
+        precedence is reversed: settings read from the
+        <filename>.nspawn</filename> file will take precedence over
+        the corresponding command line options, if both are
+        specified.</para>
+
+        <para>If this option is set to <option>trusted</option>, the
+        file is searched, read and used the same way, but regardless
+        of being found in <filename>/etc/systemd/nspawn/</filename>,
+        <filename>/run/systemd/nspawn/</filename> or next to the image
+        file or container root directory, all settings will take
+        effect, however, command line arguments still take precedence
+        over corresponding settings.</para>
+
+        <para>If disabled, no <filename>.nspawn</filename> file is read
+        and no settings except the ones on the command line are in
+        effect.</para></listitem>
+      </varlistentry>
+
+    </variablelist>
+
+    <refsect2>
+    <title>Image Options</title>
+
+    <variablelist>
+
       <varlistentry>
         <term><option>-D</option></term>
         <term><option>--directory=</option></term>
       <varlistentry>
         <term><option>--template=</option></term>
 
-        <listitem><para>Directory or <literal>btrfs</literal> subvolume to use as template for the container's root
-        directory. If this is specified and the container's root directory (as configured by
-        <option>--directory=</option>) does not yet exist it is created as <literal>btrfs</literal> snapshot (if
-        supported) or plain directory (otherwise) and populated from this template tree. Ideally, the specified
-        template path refers to the root of a <literal>btrfs</literal> subvolume, in which case a simple copy-on-write
-        snapshot is taken, and populating the root directory is instant. If the specified template path does not refer
-        to the root of a <literal>btrfs</literal> subvolume (or not even to a <literal>btrfs</literal> file system at
-        all), the tree is copied (though possibly in a copy-on-write scheme — if the file system supports that), which
-        can be substantially more time-consuming. May not be specified together with <option>--image=</option> or
-        <option>--ephemeral</option>.</para>
+        <listitem><para>Directory or <literal>btrfs</literal> subvolume to use as template for the
+        container's root directory. If this is specified and the container's root directory (as configured by
+        <option>--directory=</option>) does not yet exist it is created as <literal>btrfs</literal> snapshot
+        (if supported) or plain directory (otherwise) and populated from this template tree. Ideally, the
+        specified template path refers to the root of a <literal>btrfs</literal> subvolume, in which case a
+        simple copy-on-write snapshot is taken, and populating the root directory is instant. If the
+        specified template path does not refer to the root of a <literal>btrfs</literal> subvolume (or not
+        even to a <literal>btrfs</literal> file system at all), the tree is copied (though possibly in a
+        'reflink' copy-on-write scheme — if the file system supports that), which can be substantially more
+        time-consuming. Note that the snapshot taken is of the specified directory or subvolume, including
+        all subdirectories and subvolumes below it, but excluding any sub-mounts. May not be specified
+        together with <option>--image=</option> or <option>--ephemeral</option>.</para>
 
         <para>Note that this switch leaves host name, machine ID and
         all other settings that could identify the instance
         <listitem><para>If specified, the container is run with a temporary snapshot of its file system that is removed
         immediately when the container terminates. May not be specified together with
         <option>--template=</option>.</para>
-        <para>Note that this switch leaves host name, machine ID and
-        all other settings that could identify the instance
-        unmodified.</para></listitem>
+        <para>Note that this switch leaves host name, machine ID and all other settings that could identify
+        the instance unmodified. Please note that — as with <option>--template=</option> — taking the
+        temporary snapshot is more efficient on file systems that support subvolume snapshots or 'reflinks'
+        natively (<literal>btrfs</literal> or new <literal>xfs</literal>) than on more traditional file
+        systems that do not (<literal>ext4</literal>). Note that the snapshot taken is of the specified
+        directory or subvolume, including all subdirectories and subvolumes below it, but excluding any
+        sub-mounts.</para>
+
+        <para>With this option no modifications of the container image are retained. Use
+        <option>--volatile=</option> (described below) for other mechanisms to restrict persistency of
+        container images during runtime.</para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
       </varlistentry>
 
       <varlistentry>
+        <term><option>--oci-bundle=</option></term>
+
+        <listitem><para>Takes the path to an OCI runtime bundle to invoke, as specified in the <ulink
+        url="https://github.com/opencontainers/runtime-spec/blob/master/spec.md">OCI Runtime Specification</ulink>. In
+        this case no <filename>.nspawn</filename> file is loaded, and the root directory and various settings are read
+        from the OCI runtime JSON data (but data passed on the command line takes precedence).</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--read-only</option></term>
+
+        <listitem><para>Mount the container's root file system (and any other file systems container in the container
+        image) read-only. This has no effect on additional mounts made with <option>--bind=</option>,
+        <option>--tmpfs=</option> and similar options. This mode is implied if the container image file or directory is
+        marked read-only itself. It is also implied if <option>--volatile=</option> is used. In this case the container
+        image on disk is strictly read-only, while changes are permitted but kept non-persistently in memory only. For
+        further details, see below.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--volatile</option></term>
+        <term><option>--volatile=</option><replaceable>MODE</replaceable></term>
+
+        <listitem><para>Boots the container in volatile mode. When no mode parameter is passed or when mode is
+        specified as <option>yes</option>, full volatile mode is enabled. This means the root directory is mounted as a
+        mostly unpopulated <literal>tmpfs</literal> instance, and <filename>/usr/</filename> from the OS tree is
+        mounted into it in read-only mode (the system thus starts up with read-only OS image, but pristine state and
+        configuration, any changes are lost on shutdown). When the mode parameter is specified as
+        <option>state</option>, the OS tree is mounted read-only, but <filename>/var/</filename> is mounted as a
+        writable <literal>tmpfs</literal> instance into it (the system thus starts up with read-only OS resources and
+        configuration, but pristine state, and any changes to the latter are lost on shutdown). When the mode parameter
+        is specified as <option>overlay</option> the read-only root file system is combined with a writable
+        <filename>tmpfs</filename> instance through <literal>overlayfs</literal>, so that it appears at it normally
+        would, but any changes are applied to the temporary file system only and lost when the container is
+        terminated. When the mode parameter is specified as <option>no</option> (the default), the whole OS tree is
+        made available writable (unless <option>--read-only</option> is specified, see above).</para>
+
+        <para>Note that if one of the volatile modes is chosen, its effect is limited to the root file system (or
+        <filename>/var/</filename> in case of <option>state</option>), and any other mounts placed in the hierarchy are
+        unaffected — regardless if they are established automatically (e.g. the EFI system partition that might be
+        mounted to <filename>/efi/</filename> or <filename>/boot/</filename>) or explicitly (e.g. through an additional
+        command line option such as <option>--bind=</option>, see below). This means, even if
+        <option>--volatile=overlay</option> is used changes to <filename>/efi/</filename> or
+        <filename>/boot/</filename> are prohibited in case such a partition exists in the container image operated on,
+        and even if <option>--volatile=state</option> is used the hypothetical file <filename>/etc/foobar</filename> is
+        potentially writable if <option>--bind=/etc/foobar</option> if used to mount it from outside the read-only
+        container <filename>/etc</filename> directory.</para>
+
+        <para>The <option>--ephemeral</option> option is closely related to this setting, and provides similar
+        behaviour by making a temporary, ephemeral copy of the whole OS image and executing that. For further details,
+        see above.</para>
+
+        <para>The <option>--tmpfs=</option> and <option>--overlay=</option> options provide similar functionality, but
+        for specific sub-directories of the OS image only. For details, see below.</para>
+
+        <para>This option provides similar functionality for containers as the <literal>systemd.volatile=</literal>
+        kernel command line switch provides for host systems. See
+        <citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
+        details.</para>
+
+        <para>Note that setting this option to <option>yes</option> or <option>state</option> will only work correctly
+        with operating systems in the container that can boot up with only <filename>/usr</filename> mounted, and are
+        able to automatically populate <filename>/var</filename>, and also <filename>/etc</filename> in case of
+        <literal>--volatile=yes</literal>. The <option>overlay</option> option does not require any particular
+        preparations in the OS, but do note that <literal>overlayfs</literal> behaviour differs from regular file
+        systems in a number of ways, and hence compatibility is limited.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option>--root-hash=</option></term>
 
         <listitem><para>Takes a data integrity (dm-verity) root hash specified in hexadecimal. This option enables data
       </varlistentry>
 
       <varlistentry>
+        <term><option>--pivot-root=</option></term>
+
+        <listitem><para>Pivot the specified directory to <filename>/</filename> inside the container, and either unmount the
+        container's old root, or pivot it to another specified directory. Takes one of: a path argument — in which case the
+        specified path will be pivoted to <filename>/</filename> and the old root will be unmounted; or a colon-separated pair
+        of new root path and pivot destination for the old root. The new root path will be pivoted to <filename>/</filename>,
+        and the old <filename>/</filename> will be pivoted to the other directory. Both paths must be absolute, and are resolved
+        in the container's file system namespace.</para>
+
+        <para>This is for containers which have several bootable directories in them; for example, several
+        <ulink url="https://ostree.readthedocs.io/en/latest/">OSTree</ulink> deployments. It emulates the behavior of
+        the boot loader and initial RAM disk which normally select which directory to mount as the root and start the
+        container's PID 1 in.</para></listitem>
+      </varlistentry>
+    </variablelist>
+
+    </refsect2><refsect2>
+    <title>Execution Options</title>
+
+    <variablelist>
+      <varlistentry>
         <term><option>-a</option></term>
         <term><option>--as-pid2</option></term>
 
       </varlistentry>
 
       <varlistentry>
-        <term><option>--pivot-root=</option></term>
-
-        <listitem><para>Pivot the specified directory to <filename>/</filename> inside the container, and either unmount the
-        container's old root, or pivot it to another specified directory. Takes one of: a path argument — in which case the
-        specified path will be pivoted to <filename>/</filename> and the old root will be unmounted; or a colon-separated pair
-        of new root path and pivot destination for the old root. The new root path will be pivoted to <filename>/</filename>,
-        and the old <filename>/</filename> will be pivoted to the other directory. Both paths must be absolute, and are resolved
-        in the container's file system namespace.</para>
+        <term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
+        <term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
 
-        <para>This is for containers which have several bootable directories in them; for example, several
-        <ulink url="https://ostree.readthedocs.io/en/latest/">OSTree</ulink> deployments. It emulates the behavior of
-        the boot loader and initial RAM disk which normally select which directory to mount as the root and start the
-        container's PID 1 in.</para></listitem>
+        <listitem><para>Specifies an environment variable assignment
+        to pass to the init process in the container, in the format
+        <literal>NAME=VALUE</literal>. This may be used to override
+        the default variables or to set additional variables. This
+        parameter may be used more than once.</para></listitem>
       </varlistentry>
 
       <varlistentry>
       </varlistentry>
 
       <varlistentry>
+        <term><option>--kill-signal=</option></term>
+
+        <listitem><para>Specify the process signal to send to the container's PID 1 when nspawn itself receives
+        <constant>SIGTERM</constant>, in order to trigger an orderly shutdown of the container. Defaults to
+        <constant>SIGRTMIN+3</constant> if <option>--boot</option> is used (on systemd-compatible init systems
+        <constant>SIGRTMIN+3</constant> triggers an orderly shutdown). If <option>--boot</option> is not used and this
+        option is not specified the container's processes are terminated abruptly via <constant>SIGKILL</constant>. For
+        a list of valid signals, see <citerefentry
+        project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--notify-ready=</option></term>
+
+        <listitem><para>Configures support for notifications from the container's init process.
+        <option>--notify-ready=</option> takes a boolean (<option>no</option> and  <option>yes</option>).
+        With option <option>no</option> systemd-nspawn notifies systemd
+        with a <literal>READY=1</literal> message when the init process is created.
+        With option <option>yes</option> systemd-nspawn waits for the
+        <literal>READY=1</literal> message from the init process in the container
+        before sending its own to systemd. For more details about notifications
+        see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para></listitem>
+      </varlistentry>
+    </variablelist>
+
+    </refsect2><refsect2>
+    <title>System Identity Options</title>
+
+    <variablelist>
+      <varlistentry>
         <term><option>-M</option></term>
         <term><option>--machine=</option></term>
 
         <filename>/etc/machine-id</filename> in the container is
         unpopulated.</para></listitem>
       </varlistentry>
+    </variablelist>
+
+    </refsect2><refsect2>
+    <title>Property Options</title>
 
+    <variablelist>
       <varlistentry>
         <term><option>-S</option></term>
         <term><option>--slice=</option></term>
       </varlistentry>
 
       <varlistentry>
+        <term><option>--register=</option></term>
+
+        <listitem><para>Controls whether the container is registered with
+        <citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>.  Takes a
+        boolean argument, which defaults to <literal>yes</literal>.  This option should be enabled when the container
+        runs a full Operating System (more specifically: a system and service manager as PID 1), and is useful to
+        ensure that the container is accessible via
+        <citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> and shown by
+        tools such as <citerefentry
+        project='man-pages'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>.  If the container
+        does not run a service manager, it is recommended to set this option to
+        <literal>no</literal>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>--keep-unit</option></term>
+
+        <listitem><para>Instead of creating a transient scope unit to run the container in, simply use the service or
+        scope unit <command>systemd-nspawn</command> has been invoked in. If <option>--register=yes</option> is set
+        this unit is registered with
+        <citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>. This
+        switch should be used if <command>systemd-nspawn</command> is invoked from within a service unit, and the
+        service unit's sole purpose is to run a single <command>systemd-nspawn</command> container. This option is not
+        available if run from a user session.</para>
+        <para>Note that passing <option>--keep-unit</option> disables the effect of <option>--slice=</option> and
+        <option>--property=</option>. Use <option>--keep-unit</option> and <option>--register=no</option> in
+        combination to disable any kind of unit allocation or registration with
+        <command>systemd-machined</command>.</para></listitem>
+      </varlistentry>
+    </variablelist>
+
+    </refsect2><refsect2>
+    <title>User Namespacing Options</title>
+
+    <variablelist>
+      <varlistentry>
         <term><option>--private-users=</option></term>
 
         <listitem><para>Controls user namespacing. If enabled, the container will run with its own private set of UNIX
         </listitem>
       </varlistentry>
 
+    </variablelist>
+
+    </refsect2><refsect2>
+    <title>Networking Options</title>
+
+    <variablelist>
+
       <varlistentry>
         <term><option>--private-network</option></term>
 
       </varlistentry>
 
       <varlistentry>
-        <term><option>--network-namespace-path=</option></term>
-
-        <listitem><para>Takes the path to a file representing a kernel
-        network namespace that the container shall run in. The specified path
-        should refer to a (possibly bind-mounted) network namespace file, as
-        exposed by the kernel below <filename>/proc/$PID/ns/net</filename>.
-        This makes the container enter the given network namespace. One of the
-        typical use cases is to give a network namespace under
-        <filename>/run/netns</filename> created by <citerefentry
-        project='man-pages'><refentrytitle>ip-netns</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
-        for example, <option>--network-namespace-path=/run/netns/foo</option>.
-        Note that this option cannot be used together with other
-        network-related options, such as <option>--private-network</option>
-        or <option>--network-interface=</option>.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
         <term><option>--network-interface=</option></term>
 
         <listitem><para>Assign the specified network interface to the
 
         <para>Note that <option>--network-veth</option> is the default if the
         <filename>systemd-nspawn@.service</filename> template unit file is used.</para>
+
+        <para>Note that on Linux network interface names may have a length of 15 characters at maximum, while
+        container names may have a length up to 64 characters. As this option derives the host-side interface
+        name from the container name the name is possibly truncated. Thus, care needs to be taken to ensure
+        that interface names remain unique in this case, or even better container names are generally not
+        chosen longer than 12 characters, to avoid the truncation. Alternatively, the
+        <option>--network-veth-extra=</option> option may be used, which allows free configuration of the
+        host-side interface name independently of the container name — but might require a bit more
+        additional configuration in case bridging in a fashion similar to <option>--network-bridge=</option>
+        is desired.</para>
         </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>--network-bridge=</option></term>
 
-        <listitem><para>Adds the host side of the Ethernet link created with <option>--network-veth</option> to the
-        specified Ethernet bridge interface. Expects a valid network interface name of a bridge device as
-        argument. Note that <option>--network-bridge=</option> implies <option>--network-veth</option>. If this option
-        is used, the host side of the Ethernet link will use the <literal>vb-</literal> prefix instead of
-        <literal>ve-</literal>.</para></listitem>
+        <listitem><para>Adds the host side of the Ethernet link created with <option>--network-veth</option>
+        to the specified Ethernet bridge interface. Expects a valid network interface name of a bridge device
+        as argument. Note that <option>--network-bridge=</option> implies <option>--network-veth</option>. If
+        this option is used, the host side of the Ethernet link will use the <literal>vb-</literal> prefix
+        instead of <literal>ve-</literal>. Regardless of the used naming prefix the same network interface
+        name length limits imposed by Linux apply, along with the complications this creates (for details see
+        above).</para></listitem>
       </varlistentry>
 
       <varlistentry>
       </varlistentry>
 
       <varlistentry>
+        <term><option>--network-namespace-path=</option></term>
+
+        <listitem><para>Takes the path to a file representing a kernel
+        network namespace that the container shall run in. The specified path
+        should refer to a (possibly bind-mounted) network namespace file, as
+        exposed by the kernel below <filename>/proc/$PID/ns/net</filename>.
+        This makes the container enter the given network namespace. One of the
+        typical use cases is to give a network namespace under
+        <filename>/run/netns</filename> created by <citerefentry
+        project='man-pages'><refentrytitle>ip-netns</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+        for example, <option>--network-namespace-path=/run/netns/foo</option>.
+        Note that this option cannot be used together with other
+        network-related options, such as <option>--private-network</option>
+        or <option>--network-interface=</option>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option>-p</option></term>
         <term><option>--port=</option></term>
 
         <option>--network-veth</option>, <option>--network-zone=</option>
         <option>--network-bridge=</option>.</para></listitem>
       </varlistentry>
+    </variablelist>
 
-      <varlistentry>
-        <term><option>-Z</option></term>
-        <term><option>--selinux-context=</option></term>
-
-        <listitem><para>Sets the SELinux security context to be used
-        to label processes in the container.</para>
-        </listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-L</option></term>
-        <term><option>--selinux-apifs-context=</option></term>
-
-        <listitem><para>Sets the SELinux security context to be used
-        to label files in the virtual API file systems in the
-        container.</para>
-        </listitem>
-      </varlistentry>
+    </refsect2><refsect2>
+    <title>Security Options</title>
 
+    <variablelist>
       <varlistentry>
         <term><option>--capability=</option></term>
 
       </varlistentry>
 
       <varlistentry>
+        <term><option>-Z</option></term>
+        <term><option>--selinux-context=</option></term>
+
+        <listitem><para>Sets the SELinux security context to be used
+        to label processes in the container.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><option>-L</option></term>
+        <term><option>--selinux-apifs-context=</option></term>
+
+        <listitem><para>Sets the SELinux security context to be used
+        to label files in the virtual API file systems in the
+        container.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+
+    </refsect2><refsect2>
+    <title>Resource Options</title>
+
+    <variablelist>
+
+      <varlistentry>
         <term><option>--rlimit=</option></term>
 
         <listitem><para>Sets the specified POSIX resource limit for the container payload. Expects an assignment of the
       </varlistentry>
 
       <varlistentry>
-        <term><option>--kill-signal=</option></term>
-
-        <listitem><para>Specify the process signal to send to the container's PID 1 when nspawn itself receives
-        <constant>SIGTERM</constant>, in order to trigger an orderly shutdown of the container. Defaults to
-        <constant>SIGRTMIN+3</constant> if <option>--boot</option> is used (on systemd-compatible init systems
-        <constant>SIGRTMIN+3</constant> triggers an orderly shutdown). If <option>--boot</option> is not used and this
-        option is not specified the container's processes are terminated abrubtly via <constant>SIGKILL</constant>. For
-        a list of valid signals, see <citerefentry
-        project='man-pages'><refentrytitle>signal</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>--link-journal=</option></term>
-
-        <listitem><para>Control whether the container's journal shall
-        be made visible to the host system. If enabled, allows viewing
-        the container's journal files from the host (but not vice
-        versa). Takes one of <literal>no</literal>,
-        <literal>host</literal>, <literal>try-host</literal>,
-        <literal>guest</literal>, <literal>try-guest</literal>,
-        <literal>auto</literal>. If <literal>no</literal>, the journal
-        is not linked. If <literal>host</literal>, the journal files
-        are stored on the host file system (beneath
-        <filename>/var/log/journal/<replaceable>machine-id</replaceable></filename>)
-        and the subdirectory is bind-mounted into the container at the
-        same location. If <literal>guest</literal>, the journal files
-        are stored on the guest file system (beneath
-        <filename>/var/log/journal/<replaceable>machine-id</replaceable></filename>)
-        and the subdirectory is symlinked into the host at the same
-        location. <literal>try-host</literal> and
-        <literal>try-guest</literal> do the same but do not fail if
-        the host does not have persistent journaling enabled. If
-        <literal>auto</literal> (the default), and the right
-        subdirectory of <filename>/var/log/journal</filename> exists,
-        it will be bind mounted into the container. If the
-        subdirectory does not exist, no linking is performed.
-        Effectively, booting a container once with
-        <literal>guest</literal> or <literal>host</literal> will link
-        the journal persistently if further on the default of
-        <literal>auto</literal> is used.</para>
+        <term><option>--personality=</option></term>
 
-        <para>Note that <option>--link-journal=try-guest</option> is the default if the
-        <filename>systemd-nspawn@.service</filename> template unit file is used.</para></listitem>
+        <listitem><para>Control the architecture ("personality")
+        reported by
+        <citerefentry project='man-pages'><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+        in the container. Currently, only <literal>x86</literal> and
+        <literal>x86-64</literal> are supported. This is useful when
+        running a 32-bit container on a 64-bit host. If this setting
+        is not used, the personality reported in the container is the
+        same as the one reported on the host.</para></listitem>
       </varlistentry>
+    </variablelist>
 
-      <varlistentry>
-        <term><option>-j</option></term>
-
-        <listitem><para>Equivalent to
-        <option>--link-journal=try-guest</option>.</para></listitem>
-      </varlistentry>
+    </refsect2><refsect2>
+    <title>Integration Options</title>
 
+    <variablelist>
       <varlistentry>
         <term><option>--resolv-conf=</option></term>
 
       </varlistentry>
 
       <varlistentry>
-        <term><option>--read-only</option></term>
+        <term><option>--link-journal=</option></term>
 
-        <listitem><para>Mount the root file system read-only for the
-        container.</para></listitem>
+        <listitem><para>Control whether the container's journal shall
+        be made visible to the host system. If enabled, allows viewing
+        the container's journal files from the host (but not vice
+        versa). Takes one of <literal>no</literal>,
+        <literal>host</literal>, <literal>try-host</literal>,
+        <literal>guest</literal>, <literal>try-guest</literal>,
+        <literal>auto</literal>. If <literal>no</literal>, the journal
+        is not linked. If <literal>host</literal>, the journal files
+        are stored on the host file system (beneath
+        <filename>/var/log/journal/<replaceable>machine-id</replaceable></filename>)
+        and the subdirectory is bind-mounted into the container at the
+        same location. If <literal>guest</literal>, the journal files
+        are stored on the guest file system (beneath
+        <filename>/var/log/journal/<replaceable>machine-id</replaceable></filename>)
+        and the subdirectory is symlinked into the host at the same
+        location. <literal>try-host</literal> and
+        <literal>try-guest</literal> do the same but do not fail if
+        the host does not have persistent journaling enabled. If
+        <literal>auto</literal> (the default), and the right
+        subdirectory of <filename>/var/log/journal</filename> exists,
+        it will be bind mounted into the container. If the
+        subdirectory does not exist, no linking is performed.
+        Effectively, booting a container once with
+        <literal>guest</literal> or <literal>host</literal> will link
+        the journal persistently if further on the default of
+        <literal>auto</literal> is used.</para>
+
+        <para>Note that <option>--link-journal=try-guest</option> is the default if the
+        <filename>systemd-nspawn@.service</filename> template unit file is used.</para></listitem>
       </varlistentry>
 
       <varlistentry>
+        <term><option>-j</option></term>
+
+        <listitem><para>Equivalent to
+        <option>--link-journal=try-guest</option>.</para></listitem>
+      </varlistentry>
+
+    </variablelist>
+
+    </refsect2><refsect2>
+    <title>Mount Options</title>
+
+    <variablelist>
+
+      <varlistentry>
         <term><option>--bind=</option></term>
         <term><option>--bind-ro=</option></term>
 
       </varlistentry>
 
       <varlistentry>
+        <term><option>--inaccessible=</option></term>
+
+        <listitem><para>Make the specified path inaccessible in the container. This over-mounts the specified path
+        (which must exist in the container) with a file node of the same type that is empty and has the most
+        restrictive access mode supported. This is an effective way to mask files, directories and other file system
+        objects from the container payload. This option may be used more than once in case all specified paths are
+        masked.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option>--tmpfs=</option></term>
 
-        <listitem><para>Mount a tmpfs file system into the container.
-        Takes a single absolute path argument that specifies where to
-        mount the tmpfs instance to (in which case the directory
-        access mode will be chosen as 0755, owned by root/root), or
-        optionally a colon-separated pair of path and mount option
-        string that is used for mounting (in which case the kernel
-        default for access mode and owner will be chosen, unless
-        otherwise specified). This option is particularly useful for
-        mounting directories such as <filename>/var</filename> as
-        tmpfs, to allow state-less systems, in particular when
-        combined with <option>--read-only</option>.
-        Backslash escapes are interpreted in the path, so
-        <literal>\:</literal> may be used to embed colons in the path.
-        </para></listitem>
+        <listitem><para>Mount a tmpfs file system into the container.  Takes a single absolute path argument that
+        specifies where to mount the tmpfs instance to (in which case the directory access mode will be chosen as 0755,
+        owned by root/root), or optionally a colon-separated pair of path and mount option string that is used for
+        mounting (in which case the kernel default for access mode and owner will be chosen, unless otherwise
+        specified). Backslash escapes are interpreted in the path, so <literal>\:</literal> may be used to embed colons
+        in the path.</para>
+
+        <para>Note that this option cannot be used to replace the root file system of the container with a temporary
+        file system. However, the <option>--volatile=</option> option described below provides similar
+        functionality, with a focus on implementing stateless operating system images.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         be on the same file system as the top-most directory
         tree). Also note that the <literal>lowerdir=</literal> mount
         option receives the paths to stack in the opposite order of
-        this switch.</para></listitem>
-      </varlistentry>
+        this switch.</para>
 
-      <varlistentry>
-        <term><option>-E <replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
-        <term><option>--setenv=<replaceable>NAME</replaceable>=<replaceable>VALUE</replaceable></option></term>
-
-        <listitem><para>Specifies an environment variable assignment
-        to pass to the init process in the container, in the format
-        <literal>NAME=VALUE</literal>. This may be used to override
-        the default variables or to set additional variables. This
-        parameter may be used more than once.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>--register=</option></term>
-
-        <listitem><para>Controls whether the container is registered with
-        <citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>.  Takes a
-        boolean argument, which defaults to <literal>yes</literal>.  This option should be enabled when the container
-        runs a full Operating System (more specifically: a system and service manager as PID 1), and is useful to
-        ensure that the container is accessible via
-        <citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry> and shown by
-        tools such as <citerefentry
-        project='man-pages'><refentrytitle>ps</refentrytitle><manvolnum>1</manvolnum></citerefentry>.  If the container
-        does not run a service manager, it is recommended to set this option to
-        <literal>no</literal>.</para></listitem>
+        <para>Note that this option cannot be used to replace the root file system of the container with an overlay
+        file system. However, the <option>--volatile=</option> option described above provides similar functionality,
+        with a focus on implementing stateless operating system images.</para></listitem>
       </varlistentry>
+    </variablelist>
 
-      <varlistentry>
-        <term><option>--keep-unit</option></term>
-
-        <listitem><para>Instead of creating a transient scope unit to run the container in, simply use the service or
-        scope unit <command>systemd-nspawn</command> has been invoked in. If <option>--register=yes</option> is set
-        this unit is registered with
-        <citerefentry><refentrytitle>systemd-machined</refentrytitle><manvolnum>8</manvolnum></citerefentry>. This
-        switch should be used if <command>systemd-nspawn</command> is invoked from within a service unit, and the
-        service unit's sole purpose is to run a single <command>systemd-nspawn</command> container. This option is not
-        available if run from a user session.</para>
-        <para>Note that passing <option>--keep-unit</option> disables the effect of <option>--slice=</option> and
-        <option>--property=</option>. Use <option>--keep-unit</option> and <option>--register=no</option> in
-        combination to disable any kind of unit allocation or registration with
-        <command>systemd-machined</command>.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>--personality=</option></term>
-
-        <listitem><para>Control the architecture ("personality")
-        reported by
-        <citerefentry project='man-pages'><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
-        in the container. Currently, only <literal>x86</literal> and
-        <literal>x86-64</literal> are supported. This is useful when
-        running a 32-bit container on a 64-bit host. If this setting
-        is not used, the personality reported in the container is the
-        same as the one reported on the host.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>-q</option></term>
-        <term><option>--quiet</option></term>
-
-        <listitem><para>Turns off any status output by the tool
-        itself. When this switch is used, the only output from nspawn
-        will be the console output of the container OS
-        itself.</para></listitem>
-      </varlistentry>
-
-      <varlistentry>
-        <term><option>--volatile</option></term>
-        <term><option>--volatile=</option><replaceable>MODE</replaceable></term>
-
-        <listitem><para>Boots the container in volatile mode. When no
-        mode parameter is passed or when mode is specified as
-        <option>yes</option>, full volatile mode is enabled. This
-        means the root directory is mounted as a mostly unpopulated
-        <literal>tmpfs</literal> instance, and
-        <filename>/usr</filename> from the OS tree is mounted into it
-        in read-only mode (the system thus starts up with read-only OS
-        image, but pristine state and configuration, any changes
-        are lost on shutdown). When the mode parameter
-        is specified as <option>state</option>, the OS tree is
-        mounted read-only, but <filename>/var</filename> is mounted as
-        a <literal>tmpfs</literal> instance into it (the system thus
-        starts up with read-only OS resources and configuration, but
-        pristine state, and any changes to the latter are lost on
-        shutdown). When the mode parameter is specified as
-        <option>no</option> (the default), the whole OS tree is made
-        available writable.</para>
-
-        <para>This option provides similar functionality for containers as the <literal>systemd.volatile=</literal>
-        kernel command line switch provides for host systems. See
-        <citerefentry><refentrytitle>kernel-command-line</refentrytitle><manvolnum>7</manvolnum></citerefentry> for
-        details.</para>
-
-        <para>Note that enabling this setting will only work correctly with operating systems in the container that can
-        boot up with only <filename>/usr</filename> mounted, and are able to automatically populate
-        <filename>/var</filename>, and also <filename>/etc</filename> in case of
-        <literal>--volatile=yes</literal>.</para></listitem>
-      </varlistentry>
+    </refsect2><refsect2>
+    <title>Input/Output Options</title>
 
+    <variablelist>
       <varlistentry>
-        <term><option>--settings=</option><replaceable>MODE</replaceable></term>
-
-        <listitem><para>Controls whether
-        <command>systemd-nspawn</command> shall search for and use
-        additional per-container settings from
-        <filename>.nspawn</filename> files. Takes a boolean or the
-        special values <option>override</option> or
-        <option>trusted</option>.</para>
-
-        <para>If enabled (the default), a settings file named after the
-        machine (as specified with the <option>--machine=</option>
-        setting, or derived from the directory or image file name)
-        with the suffix <filename>.nspawn</filename> is searched in
-        <filename>/etc/systemd/nspawn/</filename> and
-        <filename>/run/systemd/nspawn/</filename>. If it is found
-        there, its settings are read and used. If it is not found
-        there, it is subsequently searched in the same directory as the
-        image file or in the immediate parent of the root directory of
-        the container. In this case, if the file is found, its settings
-        will be also read and used, but potentially unsafe settings
-        are ignored. Note that in both these cases, settings on the
-        command line take precedence over the corresponding settings
-        from loaded <filename>.nspawn</filename> files, if both are
-        specified. Unsafe settings are considered all settings that
-        elevate the container's privileges or grant access to
-        additional resources such as files or directories of the
-        host. For details about the format and contents of
-        <filename>.nspawn</filename> files, consult
-        <citerefentry><refentrytitle>systemd.nspawn</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
-
-        <para>If this option is set to <option>override</option>, the
-        file is searched, read and used the same way, however, the order of
-        precedence is reversed: settings read from the
-        <filename>.nspawn</filename> file will take precedence over
-        the corresponding command line options, if both are
-        specified.</para>
-
-        <para>If this option is set to <option>trusted</option>, the
-        file is searched, read and used the same way, but regardless
-        of being found in <filename>/etc/systemd/nspawn/</filename>,
-        <filename>/run/systemd/nspawn/</filename> or next to the image
-        file or container root directory, all settings will take
-        effect, however, command line arguments still take precedence
-        over corresponding settings.</para>
-
-        <para>If disabled, no <filename>.nspawn</filename> file is read
-        and no settings except the ones on the command line are in
-        effect.</para></listitem>
+        <term><option>--console=</option><replaceable>MODE</replaceable></term>
+
+        <listitem><para>Configures how to set up standard input, output and error output for the container payload, as
+        well as the <filename>/dev/console</filename> device for the container. Takes one of
+        <option>interactive</option>, <option>read-only</option>, <option>passive</option> or <option>pipe</option>. If
+        <option>interactive</option> a pseudo-TTY is allocated and made available as <filename>/dev/console</filename>
+        in the container. It is then bi-directionally connected to the standard input and output passed to
+        <command>systemd-nspawn</command>.  <option>read-only</option> is similar but only the output of the container
+        is propagated and no input from the caller is read. In <option>passive</option> mode a pseudo TTY is allocated,
+        but it is not connected anywhere. Finally, in <option>pipe</option> mode no pseudo TTY is allocated, but the
+        passed standard input, output and error output file descriptors are passed on — as they are — to the container
+        payload. In this mode <filename>/dev/console</filename> will not exist in the container. Note that in this mode
+        the container payload generally cannot be a full init system as init systems tend to require
+        <filename>/dev/console</filename> to be available. On the other hand, in this mode container invocations can be
+        used within shell pipelines. This is because intermediary pseudo TTYs do not permit independent bidirectional
+        propagation of the end-of-file (EOF) condition, which is necessary for shell pipelines to work
+        correctly.</para>
+
+        <para>Note that the <option>pipe</option> mode should be used carefully, as passing arbitrary file descriptors
+        to less trusted container payloads might open up unwanted interfaces for access by the container payload. For
+        example, if a passed file descriptor refers to a TTY of some form, APIs such as <constant>TIOCSTI</constant>
+        may be used to synthesize input that might be used for escaping the container. Hence <option>pipe</option> mode
+        should only be used if the payload is sufficiently trusted or when the standard input/output/error output file
+        descriptors are known safe, for example pipes. Defaults to <option>interactive</option> if
+        <command>systemd-nspawn</command> is invoked from a terminal, and <option>read-only</option>
+        otherwise.</para></listitem>
       </varlistentry>
 
       <varlistentry>
-        <term><option>--notify-ready=</option></term>
+        <term><option>--pipe</option></term>
+        <term><option>-P</option></term>
 
-        <listitem><para>Configures support for notifications from the container's init process.
-        <option>--notify-ready=</option> takes a boolean (<option>no</option> and  <option>yes</option>).
-        With option <option>no</option> systemd-nspawn notifies systemd
-        with a <literal>READY=1</literal> message when the init process is created.
-        With option <option>yes</option> systemd-nspawn waits for the
-        <literal>READY=1</literal> message from the init process in the container
-        before sending its own to systemd. For more details about notifications
-        see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).</para></listitem>
+        <listitem><para>Equivalent to <option>--console=pipe</option>.</para></listitem>
       </varlistentry>
 
+      <xi:include href="standard-options.xml" xpointer="no-pager" />
       <xi:include href="standard-options.xml" xpointer="help" />
       <xi:include href="standard-options.xml" xpointer="version" />
     </variablelist>
-
+   </refsect2>
   </refsect1>
 
+  <xi:include href="less-variables.xml" />
+
   <refsect1>
     <title>Examples</title>
 
index b610af6..91a8786 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-path"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 8c5e4cc..3363a1d 100644 (file)
@@ -1,7 +1,6 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-portabled.service" conditional='ENABLE_PORTABLED'>
index c7cf237..9ba9f39 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-quotacheck.service" conditional='ENABLE_QUOTACHECK'>
 
   <refentryinfo>
index dc5c884..35c6e2f 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-random-seed.service" conditional='ENABLE_RANDOMSEED'>
 
   <refentryinfo>
index 3474a8f..514d102 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-rc-local-generator">
 
   <refentryinfo>
index 988a617..a744df7 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-remount-fs.service">
 
   <refentryinfo>
   <refsect1>
     <title>Description</title>
 
-    <para><filename>systemd-remount-fs.service</filename> is an
-    early boot service that applies mount options listed in
-    <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-    to the root file system, the <filename>/usr</filename> file system,
-    and the kernel API file systems. This is required so that the
-    mount options of these file systems — which are pre-mounted by
-    the kernel, the initial RAM disk, container environments or system
-    manager code — are updated to those listed in
-    <filename>/etc/fstab</filename>. This service ignores normal file
-    systems and only changes the root file system (i.e.
-    <filename>/</filename>), <filename>/usr</filename> and the virtual
-    kernel API file systems such as <filename>/proc</filename>,
-    <filename>/sys</filename> or <filename>/dev</filename>. This
-    service executes no operation if <filename>/etc/fstab</filename>
-    does not exist or lists no entries for the mentioned file
-    systems.</para>
+    <para><filename>systemd-remount-fs.service</filename> is an early boot service that applies mount options
+    listed in <citerefentry
+    project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>, or
+    gathered from the partition table (when
+    <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+    is active) to the root file system, the <filename>/usr</filename> file system, and the kernel API file
+    systems. This is required so that the mount options of these file systems — which are pre-mounted by the
+    kernel, the initial RAM disk, container environments or system manager code — are updated to those
+    configured in <filename>/etc/fstab</filename> and the other sources. This service ignores normal file
+    systems and only changes the root file system (i.e.  <filename>/</filename>), <filename>/usr</filename>,
+    and the virtual kernel API file systems such as <filename>/proc</filename>, <filename>/sys</filename> or
+    <filename>/dev</filename>. This service executes no operation if no configuration is found
+    (<filename>/etc/fstab</filename> does not exist or lists no entries for the mentioned file systems, or
+    the partition table does not contain relevant entries).</para>
 
     <para>For a longer discussion of kernel API file systems see
     <ulink url="https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems">API
     File Systems</ulink>.</para>
+
+    <para>Note: <filename>systemd-remount-fs.service</filename> is usually pulled in by
+    <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+    hence it is also affected by the kernel command line option <varname>fstab=</varname>, which may be used
+    to disable the generator. It may also pulled in by
+    <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+    which is affected by <varname>systemd.gpt_auto</varname> and other options.</para>
   </refsect1>
 
   <refsect1>
@@ -57,7 +61,9 @@
     <para>
       <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
       <citerefentry project='man-pages'><refentrytitle>fstab</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-      <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+      <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+      <citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
     </para>
   </refsect1>
 
index d7334e0..807c323 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-resolved.service" conditional='ENABLE_RESOLVE'>
 
         <command>systemd-resolved</command> will flush all caches it maintains. Note that it should normally not be
         necessary to request this explicitly – except for debugging purposes – as <command>systemd-resolved</command>
         flushes the caches automatically anyway any time the host's network configuration changes. Sending this signal
-        to <command>systemd-resolved</command> is equivalent to the <command>resolvectl --flush-caches</command>
+        to <command>systemd-resolved</command> is equivalent to the <command>resolvectl flush-caches</command>
         command, however the latter is recommended since it operates in a synchronous way.</para></listitem>
       </varlistentry>
 
         should normally not be necessary to request this explicitly – except for debugging purposes – as
         <command>systemd-resolved</command> automatically forgets learnt information any time the DNS server
         configuration changes. Sending this signal to <command>systemd-resolved</command> is equivalent to the
-        <command>resolvectl --reset-server-features</command> command, however the latter is recommended since it
+        <command>resolvectl reset-server-features</command> command, however the latter is recommended since it
         operates in a synchronous way.</para></listitem>
       </varlistentry>
     </variablelist>
index d8c2ee2..bc3322c 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-rfkill.service" conditional='ENABLE_RFKILL'>
 
   <refentryinfo>
index 20eb691..db84cf7 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-run-generator">
 
   <refentryinfo>
index 3c60340..8f7a622 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-run"
           xmlns:xi="http://www.w3.org/2001/XInclude">
       </varlistentry>
 
       <varlistentry>
+        <term><option>--on-clock-change</option></term>
+        <term><option>--on-timezone-change</option></term>
+
+        <listitem><para>Defines a trigger based on system clock jumps or timezone changes for starting the
+        specified command. See <varname>OnClockChange=</varname> and <varname>OnTimezoneChange=</varname> in
+        <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>. These
+        options are shortcuts for <command>--timer-property=OnClockChange=yes</command> and
+        <command>--timer-property=OnTimezoneChange=yes</command>. These options may not be combined with
+        <option>--scope</option> or <option>--pty</option>.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><option>--path-property=</option></term>
         <term><option>--socket-property=</option></term>
         <term><option>--timer-property=</option></term>
index af61947..3311a04 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-sleep.conf"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index c370705..f3dbb47 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-socket-activate"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 1869465..a72ac1b 100644 (file)
@@ -1,10 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-     "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-socket-proxyd"
     xmlns:xi="http://www.w3.org/2001/XInclude">
 
index cef7adb..2310e6f 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-suspend.service"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 2712402..7b04f4b 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-sysctl.service"
     xmlns:xi="http://www.w3.org/2001/XInclude">
 
index a7b62b5..d816c0b 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-system-update-generator">
 
   <refentryinfo>
index 27242b3..d23b3fb 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-system.conf"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 6c9b921..cc02625 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-sysusers"
     xmlns:xi="http://www.w3.org/2001/XInclude">
@@ -98,7 +95,7 @@
           placing <filename>/etc/sysusers.d/radvd.conf</filename> or even
           <filename>/etc/sysusers.d/00-overrides.conf</filename>.</para>
 
-          <para>Note that this is the expanded from, and when used in a package, this
+          <para>Note that this is the expanded form, and when used in a package, this
           would be written using a macro with "radvd" and a file containing the
           configuration line as arguments.</para>
         </example>
index 0b07cc3..795d9ee 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-sysv-generator" conditional="HAVE_SYSV_COMPAT">
 
   <refentryinfo>
index 5667c88..d51b272 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-time-wait-sync.service" conditional='ENABLE_TIMESYNCD'>
 
index e334e8a..3626e8b 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-timedated.service" conditional='ENABLE_TIMEDATED'>
 
index cdea106..3dff637 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-timesyncd.service" conditional='ENABLE_TIMESYNCD'>
 
index 9978d95..f05e5ea 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-tmpfiles"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 75ab032..8d9e9e0 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-tty-ask-password-agent"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 330700d..cf8087c 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd-udevd.service"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index fa88e66..ad41269 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-update-done.service">
 
   <refentryinfo>
index a3822ac..e1059ec 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-update-utmp.service" conditional="ENABLE_UTMP">
 
   <refentryinfo>
index 52fc0d7..ab33d46 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-user-sessions.service" conditional='HAVE_PAM'>
 
   <refentryinfo>
index 08c5d81..268e69c 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-vconsole-setup.service" conditional='ENABLE_VCONSOLE'>
 
   <refentryinfo>
index f9f645f..305dda4 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-veritysetup-generator" conditional='HAVE_LIBCRYPTSETUP'>
 
   <refentryinfo>
index 7701409..2c71c3e 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-veritysetup@.service" conditional='HAVE_LIBCRYPTSETUP'>
 
   <refentryinfo>
index 651832f..440e9ea 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd-volatile-root.service">
 
   <refentryinfo>
index 2e55ad0..48deb02 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.automount">
   <refentryinfo>
index 0144704..ff7ab9c 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.device">
   <refentryinfo>
index dc00591..1ac760e 100644 (file)
@@ -1,9 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.dnssd" conditional='ENABLE_RESOLVE'>
 
     <para>The main network service file must have the extension <filename>.dnssd</filename>; other
     extensions are ignored.</para>
 
-    <para>The <filename>.dnssd</filename> files are read from the files located in the system
-    network directory <filename>/usr/lib/systemd/dnssd</filename>, the volatile runtime network
-    directory <filename>/run/systemd/dnssd</filename> and the local administration network
-    directory <filename>/etc/systemd/dnssd</filename>. All configuration files are collectively
-    sorted and processed in lexical order, regardless of the directories in which they live.
-    However, files with identical filenames replace each other. Files in <filename>/etc</filename>
-    have the highest priority, files in <filename>/run</filename> take precedence over files with
-    the same name in <filename>/usr/lib</filename>. This can be used to override a system-supplied
-    configuration file with a local file if needed.</para>
+    <para>The <filename>.dnssd</filename> files are read from the files located in the system network
+    directories <filename>/usr/lib/systemd/dnssd</filename> and
+    <filename>/usr/local/lib/systemd/dnssd</filename>, the volatile runtime network directory
+    <filename>/run/systemd/dnssd</filename> and the local administration network directory
+    <filename>/etc/systemd/dnssd</filename>. All configuration files are collectively sorted and processed in
+    lexical order, regardless of the directories in which they live. However, files with identical filenames
+    replace each other. Files in <filename>/etc</filename> have the highest priority, files in
+    <filename>/run</filename> take precedence over files with the same name in
+    <filename>/usr/lib</filename>. This can be used to override a system-supplied configuration file with a
+    local file if needed.</para>
 
     <para>Along with the network service file <filename>foo.dnssd</filename>, a "drop-in" directory
     <filename>foo.dnssd.d/</filename> may exist. All files with the suffix
     parsed. This is useful to alter or add configuration settings, without having to modify the main
     configuration file. Each drop-in file must have appropriate section headers.</para>
 
-    <para>In addition to <filename>/etc/systemd/dnssd</filename>, drop-in <literal>.d</literal>
-    directories can be placed in <filename>/usr/lib/systemd/dnssd</filename> or
-    <filename>/run/systemd/dnssd</filename> directories. Drop-in files in
-    <filename>/etc</filename> take precedence over those in <filename>/run</filename> which in turn
-    take precedence over those in <filename>/usr/lib</filename>. Drop-in files under any of these
-    directories take precedence over the main network service file wherever located. (Of course, since
-    <filename>/run</filename> is temporary and <filename>/usr/lib</filename> is for vendors, it is
-    unlikely drop-ins should be used in either of those places.)</para>
+    <para>In addition to <filename>/etc/systemd/dnssd</filename>, drop-in <literal>.d</literal> directories
+    can be placed in <filename>/usr/lib/systemd/dnssd</filename> or <filename>/run/systemd/dnssd</filename>
+    directories. Drop-in files in <filename>/etc</filename> take precedence over those in
+    <filename>/run</filename> which in turn take precedence over those in <filename>/usr/lib</filename> or
+    <filename>/usr/local/lib</filename>. Drop-in files under any of these directories take precedence over
+    the main network service file wherever located.</para>
   </refsect1>
 
   <refsect1>
index 4595a99..a806f7b 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.environment-generator" conditional='ENABLE_ENVIRONMENT_D'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 2f46f03..ef1c392 100644 (file)
@@ -1,12 +1,9 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
-
-<refentry id="systemd.exec">
+<refentry id="systemd.exec" xmlns:xi="http://www.w3.org/2001/XInclude">
   <refentryinfo>
     <title>systemd.exec</title>
     <productname>systemd</productname>
         dependencies to be added to the unit (see above).</para>
 
         <para>The <varname>MountAPIVFS=</varname> and <varname>PrivateUsers=</varname> settings are particularly useful
-        in conjunction with <varname>RootDirectory=</varname>. For details, see below.</para></listitem>
+        in conjunction with <varname>RootDirectory=</varname>. For details, see below.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
         url="https://www.freedesktop.org/wiki/Specifications/DiscoverablePartitionsSpec/">Discoverable Partitions
         Specification</ulink>.</para>
 
-        <para>When <varname>DevicePolicy=</varname> is set to <literal>closed</literal> or <literal>strict</literal>,
-        or set to <literal>auto</literal> and <varname>DeviceAllow=</varname> is set, then this setting adds
-        <filename>/dev/loop-control</filename> with <constant>rw</constant> mode, <literal>block-loop</literal> and
-        <literal>block-blkext</literal> with <constant>rwm</constant> mode to <varname>DeviceAllow=</varname>. See
+        <para>When <varname>DevicePolicy=</varname> is set to <literal>closed</literal> or
+        <literal>strict</literal>, or set to <literal>auto</literal> and <varname>DeviceAllow=</varname> is
+        set, then this setting adds <filename>/dev/loop-control</filename> with <constant>rw</constant> mode,
+        <literal>block-loop</literal> and <literal>block-blkext</literal> with <constant>rwm</constant> mode
+        to <varname>DeviceAllow=</varname>. See
         <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
         for the details about <varname>DevicePolicy=</varname> or <varname>DeviceAllow=</varname>. Also, see
-        <varname>PrivateDevices=</varname> below, as it may change the setting of <varname>DevicePolicy=</varname>.
-        </para></listitem>
+        <varname>PrivateDevices=</varname> below, as it may change the setting of
+        <varname>DevicePolicy=</varname>.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
         will be a 1:1 copy of the host's, and include these three mounts. Note that the <filename>/dev</filename> file
         system of the host is bind mounted if this option is used without <varname>PrivateDevices=</varname>. To run
         the service with a private, minimal version of <filename>/dev/</filename>, combine this option with
-        <varname>PrivateDevices=</varname>.</para></listitem>
+        <varname>PrivateDevices=</varname>.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
 
         <para>This option is particularly useful when <varname>RootDirectory=</varname>/<varname>RootImage=</varname>
         is used. In this case the source path refers to a path on the host file system, while the destination path
-        refers to a path below the root directory of the unit.</para></listitem>
+        refers to a path below the root directory of the unit.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
     </variablelist>
   <refsect1>
     <title>Credentials</title>
 
+    <xi:include href="system-only.xml" xpointer="plural"/>
+
     <variablelist class='unit-directives'>
 
       <varlistentry>
       <varlistentry>
         <term><varname>DynamicUser=</varname></term>
 
-        <listitem><para>Takes a boolean parameter. If set, a UNIX user and group pair is allocated dynamically when the
-        unit is started, and released as soon as it is stopped. The user and group will not be added to
-        <filename>/etc/passwd</filename> or <filename>/etc/group</filename>, but are managed transiently during
-        runtime. The <citerefentry><refentrytitle>nss-systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-        glibc NSS module provides integration of these dynamic users/groups into the system's user and group
+        <listitem><para>Takes a boolean parameter. If set, a UNIX user and group pair is allocated
+        dynamically when the unit is started, and released as soon as it is stopped. The user and group will
+        not be added to <filename>/etc/passwd</filename> or <filename>/etc/group</filename>, but are managed
+        transiently during runtime. The
+        <citerefentry><refentrytitle>nss-systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry> glibc
+        NSS module provides integration of these dynamic users/groups into the system's user and group
         databases. The user and group name to use may be configured via <varname>User=</varname> and
-        <varname>Group=</varname> (see above). If these options are not used and dynamic user/group allocation is
-        enabled for a unit, the name of the dynamic user/group is implicitly derived from the unit name. If the unit
-        name without the type suffix qualifies as valid user name it is used directly, otherwise a name incorporating a
-        hash of it is used. If a statically allocated user or group of the configured name already exists, it is used
-        and no dynamic user/group is allocated. Note that if <varname>User=</varname> is specified and the static group
-        with the name exists, then it is required that the static user with the name already exists. Similarly, if
-        <varname>Group=</varname> is specified and the static user with the name exists, then it is required that the
-        static group with the name already exists. Dynamic users/groups are allocated from the UID/GID range
-        61184…65519. It is recommended to avoid this range for regular system or login users.  At any point in time
-        each UID/GID from this range is only assigned to zero or one dynamically allocated users/groups in
-        use. However, UID/GIDs are recycled after a unit is terminated. Care should be taken that any processes running
-        as part of a unit for which dynamic users/groups are enabled do not leave files or directories owned by these
-        users/groups around, as a different unit might get the same UID/GID assigned later on, and thus gain access to
-        these files or directories. If <varname>DynamicUser=</varname> is enabled, <varname>RemoveIPC=</varname>,
-        <varname>PrivateTmp=</varname> are implied. This ensures that the lifetime of IPC objects and temporary files
-        created by the executed processes is bound to the runtime of the service, and hence the lifetime of the dynamic
-        user/group. Since <filename>/tmp</filename> and <filename>/var/tmp</filename> are usually the only
-        world-writable directories on a system this ensures that a unit making use of dynamic user/group allocation
-        cannot leave files around after unit termination. Moreover <varname>ProtectSystem=strict</varname> and
-        <varname>ProtectHome=read-only</varname> are implied, thus prohibiting the service to write to arbitrary file
-        system locations. In order to allow the service to write to certain directories, they have to be whitelisted
-        using <varname>ReadWritePaths=</varname>, but care must be taken so that UID/GID recycling doesn't create
-        security issues involving files created by the service. Use <varname>RuntimeDirectory=</varname> (see below) in
-        order to assign a writable runtime directory to a service, owned by the dynamic user/group and removed
-        automatically when the unit is terminated. Use <varname>StateDirectory=</varname>,
-        <varname>CacheDirectory=</varname> and <varname>LogsDirectory=</varname> in order to assign a set of writable
-        directories for specific purposes to the service in a way that they are protected from vulnerabilities due to
-        UID reuse (see below). Defaults to off.</para></listitem>
+        <varname>Group=</varname> (see above). If these options are not used and dynamic user/group
+        allocation is enabled for a unit, the name of the dynamic user/group is implicitly derived from the
+        unit name. If the unit name without the type suffix qualifies as valid user name it is used directly,
+        otherwise a name incorporating a hash of it is used. If a statically allocated user or group of the
+        configured name already exists, it is used and no dynamic user/group is allocated. Note that if
+        <varname>User=</varname> is specified and the static group with the name exists, then it is required
+        that the static user with the name already exists. Similarly, if <varname>Group=</varname> is
+        specified and the static user with the name exists, then it is required that the static group with
+        the name already exists. Dynamic users/groups are allocated from the UID/GID range 61184…65519. It is
+        recommended to avoid this range for regular system or login users.  At any point in time each UID/GID
+        from this range is only assigned to zero or one dynamically allocated users/groups in use. However,
+        UID/GIDs are recycled after a unit is terminated. Care should be taken that any processes running as
+        part of a unit for which dynamic users/groups are enabled do not leave files or directories owned by
+        these users/groups around, as a different unit might get the same UID/GID assigned later on, and thus
+        gain access to these files or directories. If <varname>DynamicUser=</varname> is enabled,
+        <varname>RemoveIPC=</varname>, <varname>PrivateTmp=</varname> are implied. This ensures that the
+        lifetime of IPC objects and temporary files created by the executed processes is bound to the runtime
+        of the service, and hence the lifetime of the dynamic user/group. Since <filename>/tmp</filename> and
+        <filename>/var/tmp</filename> are usually the only world-writable directories on a system this
+        ensures that a unit making use of dynamic user/group allocation cannot leave files around after unit
+        termination. Furthermore <varname>NoNewPrivileges=</varname> and <varname>RestrictSUIDSGID=</varname>
+        are implicitly enabled to ensure that processes invoked cannot take benefit or create SUID/SGID files
+        or directories. Moreover <varname>ProtectSystem=strict</varname> and
+        <varname>ProtectHome=read-only</varname> are implied, thus prohibiting the service to write to
+        arbitrary file system locations. In order to allow the service to write to certain directories, they
+        have to be whitelisted using <varname>ReadWritePaths=</varname>, but care must be taken so that
+        UID/GID recycling doesn't create security issues involving files created by the service. Use
+        <varname>RuntimeDirectory=</varname> (see below) in order to assign a writable runtime directory to a
+        service, owned by the dynamic user/group and removed automatically when the unit is terminated. Use
+        <varname>StateDirectory=</varname>, <varname>CacheDirectory=</varname> and
+        <varname>LogsDirectory=</varname> in order to assign a set of writable directories for specific
+        purposes to the service in a way that they are protected from vulnerabilities due to UID reuse (see
+        below). If this option is enabled, care should be taken that the unit's processes do not get access
+        to directories outside of these explicitly configured and managed ones. Specifically, do not use
+        <varname>BindPaths=</varname> and be careful with <constant>AF_UNIX</constant> file descriptor
+        passing for directory file descriptors, as this would permit processes to create files or directories
+        owned by the dynamic user/group that are not subject to the lifecycle and access guarantees of the
+        service. Defaults to off.</para></listitem>
       </varlistentry>
 
       <varlistentry>
   <refsect1>
     <title>Capabilities</title>
 
+    <xi:include href="system-only.xml" xpointer="plural"/>
+
     <variablelist class='unit-directives'>
 
       <varlistentry>
@@ -360,19 +381,21 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
       <varlistentry>
         <term><varname>NoNewPrivileges=</varname></term>
 
-        <listitem><para>Takes a boolean argument. If true, ensures that the service process and all its children can
-        never gain new privileges through <function>execve()</function> (e.g. via setuid or setgid bits, or filesystem
-        capabilities). This is the simplest and most effective way to ensure that a process and its children can never
-        elevate privileges again. Defaults to false, but certain settings override this and ignore the value of this
-        setting.  This is the case when <varname>SystemCallFilter=</varname>,
-        <varname>SystemCallArchitectures=</varname>, <varname>RestrictAddressFamilies=</varname>,
-        <varname>RestrictNamespaces=</varname>, <varname>PrivateDevices=</varname>,
-        <varname>ProtectKernelTunables=</varname>, <varname>ProtectKernelModules=</varname>,
-        <varname>MemoryDenyWriteExecute=</varname>, <varname>RestrictRealtime=</varname>, or
-        <varname>LockPersonality=</varname> are specified. Note that even if this setting is overridden by them,
-        <command>systemctl show</command> shows the original value of this setting. Also see
-        <ulink url="https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html">No New Privileges
-        Flag</ulink>.  </para></listitem>
+        <listitem><para>Takes a boolean argument. If true, ensures that the service process and all its
+        children can never gain new privileges through <function>execve()</function> (e.g. via setuid or
+        setgid bits, or filesystem capabilities). This is the simplest and most effective way to ensure that
+        a process and its children can never elevate privileges again. Defaults to false, but certain
+        settings override this and ignore the value of this setting.  This is the case when
+        <varname>SystemCallFilter=</varname>, <varname>SystemCallArchitectures=</varname>,
+        <varname>RestrictAddressFamilies=</varname>, <varname>RestrictNamespaces=</varname>,
+        <varname>PrivateDevices=</varname>, <varname>ProtectKernelTunables=</varname>,
+        <varname>ProtectKernelModules=</varname>, <varname>MemoryDenyWriteExecute=</varname>,
+        <varname>RestrictRealtime=</varname>, <varname>RestrictSUIDSGID=</varname>,
+        <varname>DynamicUser=</varname> or <varname>LockPersonality=</varname> are specified. Note that even
+        if this setting is overridden by them, <command>systemctl show</command> shows the original value of
+        this setting. Also see <ulink
+        url="https://www.kernel.org/doc/html/latest/userspace-api/no_new_privs.html">No New Privileges
+        Flag</ulink>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -393,6 +416,9 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
 
   <refsect1>
     <title>Mandatory Access Control</title>
+
+    <xi:include href="system-only.xml" xpointer="plural"/>
+
     <variablelist class='unit-directives'>
 
       <varlistentry>
@@ -806,7 +832,9 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
         ones), to ensure they cannot get access to private user data, unless the services actually require access to
         the user's private data. This setting is implied if <varname>DynamicUser=</varname> is set. This setting cannot
         ensure protection in all cases. In general it has the same limitations as <varname>ReadOnlyPaths=</varname>,
-        see below.</para></listitem>
+        see below.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -827,40 +855,40 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
           <tgroup cols='4'>
             <thead>
               <row>
-                <entry>Locations</entry>
-                <entry>for system</entry>
-                <entry>for users</entry>
-                <entry>Environment variable</entry>
+                <entry>Directory</entry>
+                <entry>Below path for system units</entry>
+                <entry>Below path for user units</entry>
+                <entry>Environment variable set</entry>
               </row>
             </thead>
             <tbody>
               <row>
                 <entry><varname>RuntimeDirectory=</varname></entry>
-                <entry><filename>/run</filename></entry>
+                <entry><filename>/run/</filename></entry>
                 <entry><varname>$XDG_RUNTIME_DIR</varname></entry>
                 <entry><varname>$RUNTIME_DIRECTORY</varname></entry>
               </row>
               <row>
                 <entry><varname>StateDirectory=</varname></entry>
-                <entry><filename>/var/lib</filename></entry>
+                <entry><filename>/var/lib/</filename></entry>
                 <entry><varname>$XDG_CONFIG_HOME</varname></entry>
                 <entry><varname>$STATE_DIRECTORY</varname></entry>
               </row>
               <row>
                 <entry><varname>CacheDirectory=</varname></entry>
-                <entry><filename>/var/cache</filename></entry>
+                <entry><filename>/var/cache/</filename></entry>
                 <entry><varname>$XDG_CACHE_HOME</varname></entry>
                 <entry><varname>$CACHE_DIRECTORY</varname></entry>
               </row>
               <row>
                 <entry><varname>LogsDirectory=</varname></entry>
-                <entry><filename>/var/log</filename></entry>
-                <entry><varname>$XDG_CONFIG_HOME</varname><filename>/log</filename></entry>
+                <entry><filename>/var/log/</filename></entry>
+                <entry><varname>$XDG_CONFIG_HOME</varname><filename>/log/</filename></entry>
                 <entry><varname>$LOGS_DIRECTORY</varname></entry>
               </row>
               <row>
                 <entry><varname>ConfigurationDirectory=</varname></entry>
-                <entry><filename>/etc</filename></entry>
+                <entry><filename>/etc/</filename></entry>
                 <entry><varname>$XDG_CONFIG_HOME</varname></entry>
                 <entry><varname>$CONFIGURATION_DIRECTORY</varname></entry>
               </row>
@@ -868,10 +896,10 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
           </tgroup>
         </table>
 
-        <para>In case of <varname>RuntimeDirectory=</varname> the lowest subdirectories are removed when the unit is
-        stopped. It is possible to preserve the specified directories in this case if
-        <varname>RuntimeDirectoryPreserve=</varname> is configured to <option>restart</option> or <option>yes</option>
-        (see below). The directories specified with <varname>StateDirectory=</varname>,
+        <para>In case of <varname>RuntimeDirectory=</varname> the innermost subdirectories are removed when
+        the unit is stopped. It is possible to preserve the specified directories in this case if
+        <varname>RuntimeDirectoryPreserve=</varname> is configured to <option>restart</option> or
+        <option>yes</option> (see below). The directories specified with <varname>StateDirectory=</varname>,
         <varname>CacheDirectory=</varname>, <varname>LogsDirectory=</varname>,
         <varname>ConfigurationDirectory=</varname> are not removed when the unit is stopped.</para>
 
@@ -1014,7 +1042,9 @@ StateDirectory=aaa/bbb ccc</programlisting>
         <para>Note that the effect of these settings may be undone by privileged processes. In order to set up an
         effective sandboxed environment for a unit it is thus recommended to combine these settings with either
         <varname>CapabilityBoundingSet=~CAP_SYS_ADMIN</varname> or
-        <varname>SystemCallFilter=~@mount</varname>.</para></listitem>
+        <varname>SystemCallFilter=~@mount</varname>.</para>
+
+        <xi:include href="system-only.xml" xpointer="plural"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1037,7 +1067,9 @@ StateDirectory=aaa/bbb ccc</programlisting>
         <programlisting>TemporaryFileSystem=/var:ro
 BindReadOnlyPaths=/var/lib/systemd</programlisting>
         then the invoked processes by the unit cannot see any files or directories under <filename>/var</filename> except for
-        <filename>/var/lib/systemd</filename> or its contents.</para></listitem>
+        <filename>/var/lib/systemd</filename> or its contents.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1062,7 +1094,9 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
 
         <para>Note that the implementation of this setting might be impossible (for example if mount namespaces are not
         available), and the unit should be written in a way that does not solely rely on this setting for
-        security.</para></listitem>
+        security.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1092,7 +1126,9 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
 
         <para>Note that the implementation of this setting might be impossible (for example if mount namespaces are not
         available), and the unit should be written in a way that does not solely rely on this setting for
-        security.</para></listitem>
+        security.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1114,7 +1150,33 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
 
         <para>Note that the implementation of this setting might be impossible (for example if network namespaces are
         not available), and the unit should be written in a way that does not solely rely on this setting for
-        security.</para></listitem>
+        security.</para>
+
+        <para>When this option is used on a socket unit any sockets bound on behalf of this unit will be
+        bound within a private network namespace. This may be combined with
+        <varname>JoinsNamespaceOf=</varname> to listen on sockets inside of network namespaces of other
+        services.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>NetworkNamespacePath=</varname></term>
+
+        <listitem><para>Takes an absolute file system path refererring to a Linux network namespace
+        pseudo-file (i.e. a file like <filename>/proc/$PID/ns/net</filename> or a bind mount or symlink to
+        one). When set the invoked processes are added to the network namespace referenced by that path. The
+        path has to point to a valid namespace file at the moment the processes are forked off. If this
+        option is used <varname>PrivateNetwork=</varname> has no effect. If this option is used together with
+        <varname>JoinsNamespaceOf=</varname> then it only has an effect if this unit is started before any of
+        the listed units that have <varname>PrivateNetwork=</varname> or
+        <varname>NetworkNamespacePath=</varname> configured, as otherwise the network namespace of those
+        units is reused.</para>
+
+        <para>When this option is used on a socket unit any sockets bound on behalf of this unit will be
+        bound within the specified network namespace.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1140,7 +1202,26 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
 
         <para>Note that the implementation of this setting might be impossible (for example if user namespaces are not
         available), and the unit should be written in a way that does not solely rely on this setting for
-        security.</para></listitem>
+        security.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term><varname>ProtectHostname=</varname></term>
+
+        <listitem><para>Takes a boolean argument. When set, sets up a new UTS namespace for the executed
+        processes. In addition, changing hostname or domainname is prevented. Defaults to off.</para>
+
+        <para>Note that the implementation of this setting might be impossible (for example if UTS namespaces
+        are not available), and the unit should be written in a way that does not solely rely on this setting
+        for security.</para>
+
+        <para>Note that when this option is enabled for a service hostname changes no longer propagate from
+        the system into the service, it is hence not suitable for services that need to take notice of system
+        hostname changes dynamically.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1161,7 +1242,9 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
         option does not prevent indirect changes to kernel tunables effected by IPC calls to other processes. However,
         <varname>InaccessiblePaths=</varname> may be used to make relevant IPC file system objects inaccessible. If
         <varname>ProtectKernelTunables=</varname> is set, <varname>MountAPIVFS=yes</varname> is
-        implied.</para></listitem>
+        implied.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1180,7 +1263,9 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
         <constant>kernel.modules_disabled</constant> mechanism and
         <filename>/proc/sys/kernel/modules_disabled</filename> documentation.  If turned on and if running in user
         mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant> capability (e.g. setting
-        <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname> is implied.</para></listitem>
+        <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname> is implied.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1193,7 +1278,9 @@ BindReadOnlyPaths=/var/lib/systemd</programlisting>
         it is hence recommended to turn this on for most services. For this setting the same restrictions regarding
         mount propagation and privileges apply as for <varname>ReadOnlyPaths=</varname> and related calls, see
         above. Defaults to off. If <varname>ProtectControlGroups=</varname> is set, <varname>MountAPIVFS=yes</varname>
-        is implied.</para></listitem>
+        is implied.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1324,6 +1411,23 @@ RestrictNamespaces=~cgroup net</programlisting>
       </varlistentry>
 
       <varlistentry>
+        <term><varname>RestrictSUIDSGID=</varname></term>
+
+        <listitem><para>Takes a boolean argument. If set, any attempts to set the set-user-ID (SUID) or
+        set-group-ID (SGID) bits on files or directories will be denied (for details on these bits see
+        <citerefentry
+        project='man-pages'><refentrytitle>inode</refentrytitle><manvolnum>7</manvolnum></citerefentry>). If
+        running in user mode, or in system mode, but without the <constant>CAP_SYS_ADMIN</constant>
+        capability (e.g. setting <varname>User=</varname>), <varname>NoNewPrivileges=yes</varname> is
+        implied. As the SUID/SGID bits are mechanisms to elevate privileges, and allows users to acquire the
+        identity of other users, it is recommended to restrict creation of SUID/SGID files to the few
+        programs that actually require them. Note that this restricts marking of any type of file system
+        object with these bits, including both regular files and directories (where the SGID is a different
+        meaning than for files, see documentation). This option is implied if <varname>DynamicUser=</varname>
+        is enabled. Defaults to off.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><varname>RemoveIPC=</varname></term>
 
         <listitem><para>Takes a boolean parameter. If set, all System V and POSIX IPC objects owned by the user and
@@ -1332,7 +1436,9 @@ RestrictNamespaces=~cgroup net</programlisting>
         <varname>DynamicUser=</varname> are used. It has no effect on IPC objects owned by the root user. Specifically,
         this removes System V semaphores, as well as System V and POSIX shared memory segments and message queues. If
         multiple units use the same user or group the IPC objects are removed when the last of these units is
-        stopped. This setting is implied if <varname>DynamicUser=</varname> is set.</para></listitem>
+        stopped. This setting is implied if <varname>DynamicUser=</varname> is set.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1365,7 +1471,9 @@ RestrictNamespaces=~cgroup net</programlisting>
         <varname>ProtectHome=</varname>, <varname>ReadOnlyPaths=</varname>, <varname>InaccessiblePaths=</varname>,
         <varname>ReadWritePaths=</varname>, … — also enable file system namespacing in a fashion equivalent to this
         option. Hence it is primarily useful to explicitly request this behaviour if none of the other settings are
-        used.</para></listitem>
+        used.</para>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1394,7 +1502,8 @@ RestrictNamespaces=~cgroup net</programlisting>
 
         <para>Usually, it is best to leave this setting unmodified, and use higher level file system namespacing
         options instead, in particular <varname>PrivateMounts=</varname>, see above.</para>
-        </listitem>
+
+        <xi:include href="system-only.xml" xpointer="singular"/></listitem>
       </varlistentry>
 
     </variablelist>
@@ -2482,6 +2591,18 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
 
         </listitem>
       </varlistentry>
+
+      <varlistentry>
+        <term><varname>$PIDFILE</varname></term>
+
+        <listitem><para>The path to the configured PID file, in case the process is forked off on behalf of a
+        service that uses the <varname>PIDFile=</varname> setting, see
+        <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+        for details. Service code may use this environment variable to automatically generate a PID file at
+        the location configured in the unit file. This field is set to an absolute path in the file
+        system.</para></listitem>
+      </varlistentry>
+
     </variablelist>
 
     <para>For system services, when <varname>PAMName=</varname> is enabled and <command>pam_systemd</command> is part
index 5007563..c77afda 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.generator">
   <refentryinfo>
       </listitem>
 
       <listitem>
-        <para>It is a good idea to use the <varname>SourcePath=</varname> directive
-        in generated unit files to specify the source configuration file you are
-        generating the unit from. This makes things more easily understood by the
-        user and also has the benefit that systemd can warn the user about
-        configuration files that changed on disk but have not been read yet by
-        systemd.</para>
+        <para>The generator should always include its own name in a comment at the top of the generated file,
+        so that the user can easily figure out which component created or amended a particular unit.</para>
+
+        <para>The <varname>SourcePath=</varname> directive should be used in generated files to specify the
+        source configuration file they are generated from. This makes things more easily understood by the
+        user and also has the benefit that systemd can warn the user about configuration files that changed
+        on disk but have not been read yet by systemd. The <varname>SourcePath=</varname> value does not have
+        to be a file in a physical filesystem. For example, in the common case of the generator looking at
+        the kernel command line, <option>SourcePath=/proc/cmdline</option> should be used.</para>
       </listitem>
 
       <listitem>
index 76e1de7..960b2ec 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.journal-fields">
 
index 1b4a4a8..1f9d622 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.kill">
   <refentryinfo>
         group and the control group continues to exist after stop
         unless it is empty.</para>
 
-        <para>Processes will first be terminated via
-        <constant>SIGTERM</constant> (unless the signal to send is
-        changed via <varname>KillSignal=</varname>). Optionally, this
-        is immediately followed by a <constant>SIGHUP</constant> (if
-        enabled with <varname>SendSIGHUP=</varname>). If then, after a
-        delay (configured via the <varname>TimeoutStopSec=</varname>
-        option), processes still remain, the termination request is
-        repeated with the <constant>SIGKILL</constant> signal or the
-        signal specified via <varname>FinalKillSignal=</varname> (unless
-        this is disabled via the <varname>SendSIGKILL=</varname>
-        option). See
-        <citerefentry><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>
-        for more information.</para>
-
-        <para>Defaults to
-        <option>control-group</option>.</para></listitem>
+        <para>Processes will first be terminated via <constant>SIGTERM</constant> (unless the signal to send
+        is changed via <varname>KillSignal=</varname>). Optionally, this is immediately followed by a
+        <constant>SIGHUP</constant> (if enabled with <varname>SendSIGHUP=</varname>). If processes still
+        remain after the main process of a unit has exited or the delay configured via the
+        <varname>TimeoutStopSec=</varname> has passed, the termination request is repeated with the
+        <constant>SIGKILL</constant> signal or the signal specified via <varname>FinalKillSignal=</varname>
+        (unless this is disabled via the <varname>SendSIGKILL=</varname> option). See
+        <citerefentry><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry> for more
+        information.</para>
+
+        <para>Defaults to <option>control-group</option>.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <constant>SIGKILL</constant> (or the signal specified by
         <varname>FinalKillSignal=</varname>) to remaining processes
         after a timeout, if the normal shutdown procedure left
-        processes of the service around. Takes a boolean value.
-        Defaults to "yes".
+        processes of the service around. When disabled, a
+        <varname>KillMode=</varname> of <constant>control-group</constant>
+        or <constant>mixed</constant> service will not restart if
+        processes from prior services exist within the control group.
+        Takes a boolean value. Defaults to "yes".
         </para></listitem>
       </varlistentry>
 
index 178f9b8..af9799e 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.link">
   <refentryinfo>
       <varlistentry>
         <term><varname>Host=</varname></term>
         <listitem>
-          <para>Matches against the hostname or machine
-          ID of the host. See <varname>ConditionHost=</varname> in
+          <para>Matches against the hostname or machine ID of the host. See <varname>ConditionHost=</varname> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-          for details.</para>
+          for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
+          </para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Virtualization=</varname></term>
         <listitem>
-          <para>Checks whether the system is executed in
-          a virtualized environment and optionally test
-          whether it is a specific implementation. See
-          <varname>ConditionVirtualization=</varname> in
+          <para>Checks whether the system is executed in a virtualized environment and optionally test
+          whether it is a specific implementation. See <varname>ConditionVirtualization=</varname> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-          for details.</para>
+          for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
+          </para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>KernelCommandLine=</varname></term>
         <listitem>
-          <para>Checks whether a specific kernel command line option
-          is set (or if prefixed with the exclamation mark unset). See
+          <para>Checks whether a specific kernel command line option is set. See
           <varname>ConditionKernelCommandLine=</varname> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-          for details.</para>
-        </listitem>
-      </varlistentry>
-        <varlistentry>
-          <term><varname>KernelVersion=</varname></term>
-          <listitem>
-            <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a certain
-            expression (or if prefixed with the exclamation mark does not match it). See
-            <varname>ConditionKernelVersion=</varname> in
-            <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
-            details.
-            </para>
-          </listitem>
-        </varlistentry>
+          for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
+          </para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>KernelVersion=</varname></term>
+        <listitem>
+          <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a certain
+          expression. See <varname>ConditionKernelVersion=</varname> in
+          <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+          details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
+          </para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><varname>Architecture=</varname></term>
         <listitem>
-          <para>Checks whether the system is running on a specific
-          architecture. See <varname>ConditionArchitecture=</varname>
-          in
+          <para>Checks whether the system is running on a specific architecture. See
+          <varname>ConditionArchitecture=</varname> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-          for details.</para>
+          for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
+          </para>
         </listitem>
       </varlistentry>
     </variablelist>
         <listitem>
           <para>An ordered, space-separated list of policies by which the interface name should be set.
           <varname>NamePolicy=</varname> may be disabled by specifying <option>net.ifnames=0</option> on the
-          kernel command line.  Each of the policies may fail, and the first successful one is used. The name
+          kernel command line. Each of the policies may fail, and the first successful one is used. The name
           is not set directly, but is exported to udev as the property <option>ID_NET_NAME</option>, which
-          is, by default, used by a udev rule to set <varname>NAME</varname>. The available policies are:
+          is, by default, used by a
+          <citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+          rule to set <varname>NAME</varname>. The available policies are:
           </para>
 
           <variablelist>
       <varlistentry>
         <term><varname>Name=</varname></term>
         <listitem>
-          <para>The interface name to use in case all the
-          policies specified in
-          <varname>NamePolicy=</varname> fail, or in case
-          <varname>NamePolicy=</varname> is missing or
-          disabled.</para>
+          <para>The interface name to use. This option has lower precedence than
+          <varname>NamePolicy=</varname>, so for this setting to take effect, <varname>NamePolicy=</varname>
+          must either be unset, empty, disabled, or all policies configured there must fail. Also see the
+          example below with <literal>Name=dmz0</literal>.</para>
 
           <para>Note that specifying a name that the kernel might use for another
           interface (for example <literal>eth0</literal>) is dangerous because the
@@ -618,8 +619,7 @@ MACAddressPolicy=persistent</programlisting>
     <example>
       <title>/etc/systemd/network/10-dmz.link</title>
 
-      <para>This example assigns the fixed name
-      <literal>dmz0</literal> to the interface with the MAC address
+      <para>This example assigns the fixed name <literal>dmz0</literal> to the interface with the MAC address
       00:a0:de:63:7a:e6:</para>
 
       <programlisting>[Match]
@@ -627,6 +627,62 @@ MACAddress=00:a0:de:63:7a:e6
 
 [Link]
 Name=dmz0</programlisting>
+
+      <para><varname>NamePolicy=</varname> is not set, so <varname>Name=</varname> takes effect. We use the
+      <literal>10-</literal> prefix to order this file early in the list. Note that it needs to before
+      <literal>99-link</literal>, i.e. it needs a numerical prefix, to have any effect at all.</para>
+    </example>
+
+    <example>
+      <title>Debugging <varname>NamePolicy=</varname> assignments</title>
+
+      <programlisting>$ sudo SYSTEMD_LOG_LEVEL=debug udevadm test-builtin net_setup_link /sys/class/net/hub0
+…
+Parsed configuration file /usr/lib/systemd/network/99-default.link
+Parsed configuration file /etc/systemd/network/10-eth0.link
+ID_NET_DRIVER=cdc_ether
+Config file /etc/systemd/network/10-eth0.link applies to device hub0
+link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.
+hub0: Device has name_assign_type=4
+Using default interface naming scheme 'v240'.
+hub0: Policies didn't yield a name, using specified Name=hub0.
+ID_NET_LINK_FILE=/etc/systemd/network/10-eth0.link
+ID_NET_NAME=hub0
+…</programlisting>
+
+     <para>Explicit <varname>Name=</varname> configuration wins in this case.</para>
+
+     <programlisting>sudo SYSTEMD_LOG_LEVEL=debug udevadm test-builtin net_setup_link /sys/class/net/enp0s31f6
+…
+Parsed configuration file /usr/lib/systemd/network/99-default.link
+Parsed configuration file /etc/systemd/network/10-eth0.link
+Created link configuration context.
+ID_NET_DRIVER=e1000e
+Config file /usr/lib/systemd/network/99-default.link applies to device enp0s31f6
+link_config: autonegotiation is unset or enabled, the speed and duplex are not writable.
+enp0s31f6: Device has name_assign_type=4
+Using default interface naming scheme 'v240'.
+enp0s31f6: Policy *keep*: keeping existing userspace name
+enp0s31f6: Device has addr_assign_type=0
+enp0s31f6: MAC on the device already matches policy *persistent*
+ID_NET_LINK_FILE=/usr/lib/systemd/network/99-default.link
+…
+</programlisting>
+
+     <para>In this case, the interface was already renamed, so the <option>keep</option> policy specified as
+     the first option in <filename noindex='true'>99-default.link</filename> means that the existing name is
+     preserved. If <option>keep</option> was removed, or if were in boot before the renaming has happened,
+     we might get the following instead:</para>
+
+     <programlisting>enp0s31f6: Policy *path* yields "enp0s31f6".
+enp0s31f6: Device has addr_assign_type=0
+enp0s31f6: MAC on the device already matches policy *persistent*
+ID_NET_LINK_FILE=/usr/lib/systemd/network/99-default.link
+ID_NET_NAME=enp0s31f6
+…
+</programlisting>
+
+      <para>Please note that the details of output are subject to change.</para>
     </example>
 
     <example>
index 61e97b1..d0ccd39 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.mount">
   <refentryinfo>
     disabled. For a longer discussion see <ulink
     url="https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems">API
     File Systems</ulink>.</para>
+
+    <para>The
+    <citerefentry><refentrytitle>systemd-mount</refentrytitle><manvolnum>1</manvolnum></citerefentry> command
+    allows creating <filename>.mount</filename> and <filename>.automount</filename> units dynamically and
+    transiently from the command line.</para>
   </refsect1>
 
   <refsect1>
         <citerefentry project='man-pages'><refentrytitle>proc</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
         <citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
-        <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+        <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>systemd-mount</refentrytitle><manvolnum>1</manvolnum></citerefentry>
       </para>
   </refsect1>
 
index 74281f2..1836b5f 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.netdev" conditional='ENABLE_NETWORKD'>
 
           <entry>A Level 2 GRE tunnel over IPv4.</entry></row>
 
           <row><entry><varname>erspan</varname></entry>
-          <entry>ERSPAN mirrors traffic on one or more source ports and delivers the mirrored traffic to one or more destination ports on another switch.
-          The traffic is encapsulated in generic routing encapsulation (GRE) and is therefore routable across a layer 3 network between the source switch
-          and the destination switch.</entry></row>
+          <entry>ERSPAN mirrors traffic on one or more source ports and delivers the mirrored traffic to one or more destination ports on another switch. The traffic is encapsulated in generic routing encapsulation (GRE) and is therefore routable across a layer 3 network between the source switch and the destination switch.</entry></row>
 
           <row><entry><varname>ip6gre</varname></entry>
           <entry>A Level 3 GRE tunnel over IPv6.</entry></row>
           <row><entry><varname>geneve</varname></entry>
           <entry>A GEneric NEtwork Virtualization Encapsulation (GENEVE) netdev driver.</entry></row>
 
+          <row><entry><varname>l2tp</varname></entry>
+          <entry>A Layer 2 Tunneling Protocol (L2TP) is a tunneling protocol used to support virtual private networks (VPNs) or as part of the delivery of services by ISPs. It does not provide any encryption or confidentiality by itself</entry></row>
+
           <row><entry><varname>vrf</varname></entry>
           <entry>A Virtual Routing and Forwarding (<ulink url="https://www.kernel.org/doc/Documentation/networking/vrf.txt">VRF</ulink>) interface to create separate routing and forwarding domains.</entry></row>
 
       <varlistentry>
         <term><varname>Host=</varname></term>
         <listitem>
-          <para>Matches against the hostname or machine ID of the
-          host. See <literal>ConditionHost=</literal> in
+          <para>Matches against the hostname or machine ID of the host. See
+          <literal>ConditionHost=</literal> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-          for details.
+          for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
           </para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Virtualization=</varname></term>
         <listitem>
-          <para>Checks whether the system is executed in a virtualized
-          environment and optionally test whether it is a specific
-          implementation. See
-          <literal>ConditionVirtualization=</literal> in
+          <para>Checks whether the system is executed in a virtualized environment and optionally test
+          whether it is a specific implementation. See <literal>ConditionVirtualization=</literal> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-          for details.
+          for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
           </para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>KernelCommandLine=</varname></term>
         <listitem>
-          <para>Checks whether a specific kernel command line option
-          is set (or if prefixed with the exclamation mark unset). See
+          <para>Checks whether a specific kernel command line option is set. See
           <literal>ConditionKernelCommandLine=</literal> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-          for details.
+          for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
           </para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>KernelVersion=</varname></term>
         <listitem>
-          <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a certain
-          expression (or if prefixed with the exclamation mark does not match it). See
-          <literal>ConditionKernelVersion=</literal> in
-          <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details.
+          <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a
+          certain expression. See <literal>ConditionKernelVersion=</literal> in
+          <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+          for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
           </para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Architecture=</varname></term>
         <listitem>
-          <para>Checks whether the system is running on a specific
-          architecture. See <literal>ConditionArchitecture=</literal> in
+          <para>Checks whether the system is running on a specific architecture. See
+          <literal>ConditionArchitecture=</literal> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-          for details.
+          for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+          If an empty string is assigned, then previously assigned value is cleared.
           </para>
         </listitem>
       </varlistentry>
     </variablelist>
   </refsect1>
   <refsect1>
+    <title>[L2TP] Section Options</title>
+    <para>The <literal>[L2TP]</literal> section only applies for
+    netdevs of kind <literal>l2tp</literal>, and accepts the
+    following keys:</para>
+
+    <variablelist class='network-directives'>
+      <varlistentry>
+        <term><varname>TunnelId=</varname></term>
+        <listitem>
+          <para>Specifies the tunnel id. The value used must match the <literal>PeerTunnelId=</literal> value being used at the peer.
+          Ranges a number between 1 and 4294967295). This option is compulsory.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>PeerTunnelId=</varname></term>
+        <listitem>
+          <para>Specifies the peer tunnel id. The value used must match the <literal>PeerTunnelId=</literal> value being used at the peer.
+          Ranges a number between 1 and 4294967295). This option is compulsory.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>Remote=</varname></term>
+        <listitem>
+          <para>Specifies the IP address of the remote peer. This option is compulsory.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>Local=</varname></term>
+        <listitem>
+          <para>Specifies the IP address of the local interface. Takes an IP address, or the special values
+          <literal>auto</literal>, <literal>static</literal>, or <literal>dynamic</literal>. When an address
+          is set, then the local interface must have the address. If <literal>auto</literal>, then one of the
+          addresses on the local interface is used. Similarly, if <literal>static</literal> or
+          <literal>dynamic</literal> is set, then one of the static or dynamic addresses on the local
+          interface is used. Defaults to <literal>auto</literal>.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>EncapsulationType=</varname></term>
+        <listitem>
+          <para>Specifies the encapsulation type of the tunnel. Takes one of <literal>udp</literal> or <literal>ip</literal>.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>UDPSourcePort=</varname></term>
+        <listitem>
+          <para>Specifies the UDP source port to be used for the tunnel. When UDP encapsulation is selected it's mandotory. Ignored when ip
+          encapsulation is selected.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>DestinationPort=</varname></term>
+        <listitem>
+          <para>Specifies destination port. When UDP encapsulation is selected it's mandotory. Ignored when ip
+          encapsulation is selected.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>UDPChecksum=</varname></term>
+        <listitem>
+          <para>Takes a boolean. When true, specifies if UDP checksum is calculated for transmitted packets over IPv4.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>UDP6ZeroChecksumTx=</varname></term>
+        <listitem>
+          <para>Takes a boolean. When true, skip UDP checksum calculation for transmitted packets over IPv6.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>UDP6ZeroChecksumRx=</varname></term>
+        <listitem>
+          <para>Takes a boolean. When true, allows incoming UDP packets over IPv6 with zero checksum field.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>[L2TPSession] Section Options</title>
+    <para>The <literal>[L2TPSession]</literal> section only applies for
+    netdevs of kind <literal>l2tp</literal>, and accepts the
+    following keys:</para>
+    <variablelist class='network-directives'>
+      <varlistentry>
+        <term><varname>Name=</varname></term>
+        <listitem>
+          <para>Specifies the name of the sesssion. This option is compulsory.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>SessionId=</varname></term>
+        <listitem>
+          <para>Specifies the sesssion id. The value used must match the <literal>SessionId=</literal> value being used at the peer.
+          Ranges a number between 1 and 4294967295). This option is compulsory.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>PeerSessionId=</varname></term>
+        <listitem>
+          <para>Specifies the peer session id. The value used must match the <literal>PeerSessionId=</literal> value being used at the peer.
+          Ranges a number between 1 and 4294967295). This option is compulsory.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
+        <term><varname>Layer2SpecificHeader=</varname></term>
+        <listitem>
+          <para>Specifies layer2specific header type of the session. One of <literal>none</literal> or <literal>default</literal>. Defaults to <literal>default</literal>.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
     <title>[Tunnel] Section Options</title>
 
     <para>The <literal>[Tunnel]</literal> section only applies for
     <literal>ip6gre</literal>,
     <literal>ip6gretap</literal>,
     <literal>vti</literal>,
-    <literal>vti6</literal>, and
-    <literal>ip6tnl</literal> and accepts
+    <literal>vti6</literal>,
+    <literal>ip6tnl</literal>, and
+    <literal>erspan</literal> and accepts
     the following keys:</para>
 
     <variablelist class='network-directives'>
       <varlistentry>
         <term><varname>Local=</varname></term>
         <listitem>
-          <para>A static local address for tunneled packets. It must
-          be an address on another interface of this host.</para>
+          <para>A static local address for tunneled packets. It must be an address on another interface of
+          this host, or the special value <literal>any</literal>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Remote=</varname></term>
         <listitem>
-          <para>The remote endpoint of the tunnel.</para>
+          <para>The remote endpoint of the tunnel. Takes an IP address or the special value
+          <literal>any</literal>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
           It is used as mark-configured SAD/SPD entry as part of the lookup key (both in data
           and control path) in ip xfrm (framework used to implement IPsec protocol).
           See <ulink url="http://man7.org/linux/man-pages/man8/ip-xfrm.8.html">
-          ip-xfrm — transform configuration</ulink> for details. It is only used for VTI/VTI6
-          tunnels.</para>
+          ip-xfrm — transform configuration</ulink> for details. It is only used for VTI/VTI6,
+          GRE, GRETAP, and ERSPAN tunnels.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>InputKey=</varname></term>
         <listitem>
           <para>The <varname>InputKey=</varname> parameter specifies the key to use for input.
-          The format is same as <varname>Key=</varname>. It is only used for VTI/VTI6 tunnels.</para>
+          The format is same as <varname>Key=</varname>. It is only used for VTI/VTI6, GRE, GRETAP,
+          and ERSPAN tunnels.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>OutputKey=</varname></term>
         <listitem>
           <para>The <varname>OutputKey=</varname> parameter specifies the key to use for output.
-          The format is same as <varname>Key=</varname>. It is only used for VTI/VTI6 tunnels.</para>
+          The format is same as <varname>Key=</varname>. It is only used for VTI/VTI6, GRE, GRETAP,
+          and ERSPAN tunnels.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>FooOverUDP=</varname></term>
         <listitem>
           <para>Takes a boolean. Specifies whether <varname>FooOverUDP=</varname> tunnel is to be configured.
-          Defaults to false. For more detail information see
+          Defaults to false. This takes effects only for IPIP, SIT, GRE, and GRETAP tunnels.
+          For more detail information see
           <ulink url="https://lwn.net/Articles/614348">Foo over UDP</ulink></para>
         </listitem>
       </varlistentry>
         <term><varname>FOUDestinationPort=</varname></term>
         <listitem>
           <para>This setting specifies the UDP destination port for encapsulation.
-          This field is mandatory and is not set by default.</para>
+          This field is mandatory when <varname>FooOverUDP=yes</varname>, and is not set by default.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
       <varlistentry>
         <term><varname>Encapsulation=</varname></term>
         <listitem>
-          <para>Accepts the same key as <literal>[FooOverUDP]</literal></para>
+          <para>Accepts the same key as in the <literal>[FooOverUDP]</literal> section.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
       <varlistentry>
         <term><varname>SerializeTunneledPackets=</varname></term>
         <listitem>
-          <para>Takes a boolean. If set to yes, then packets are serialized. Only applies for ERSPAN tunnel.
-          When unset, the kernel's default will be used.
+          <para>Takes a boolean. If set to yes, then packets are serialized. Only applies for GRE,
+          GRETAP, and ERSPAN tunnels. When unset, the kernel's default will be used.
           </para>
         </listitem>
       </varlistentry>
 
     <variablelist class='network-directives'>
       <varlistentry>
-        <term><varname>Protocol=</varname></term>
-        <listitem>
-          <para>The <varname>Protocol=</varname> specifies the protocol number of the
-          packets arriving at the UDP port. This field is mandatory and is not set by default. Valid range is 1-255.</para>
-        </listitem>
-      </varlistentry>
-      <varlistentry>
         <term><varname>Encapsulation=</varname></term>
         <listitem>
           <para>Specifies the encapsulation mechanism used to store networking packets of various protocols inside the UDP packets. Supports the following values:
           for delivery to the real destination. This option is mandatory.</para>
         </listitem>
         </varlistentry>
-      </variablelist>
+      <varlistentry>
+        <term><varname>Protocol=</varname></term>
+        <listitem>
+          <para>The <varname>Protocol=</varname> specifies the protocol number of the packets arriving
+          at the UDP port. When <varname>Encapsulation=FooOverUDP</varname>, this field is mandatory
+          and is not set by default. Takes an IP protocol name such as <literal>gre</literal> or
+          <literal>ipip</literal>, or an integer within the range 1-255. When
+          <varname>Encapsulation=GenericUDPEncapsulation</varname>, this must not be specified.</para>
+        </listitem>
+      </varlistentry>
+    </variablelist>
   </refsect1>
   <refsect1>
     <title>[Peer] Section Options</title>
           <para>The Base64 encoded private key for the interface. It can be
             generated using the <command>wg genkey</command> command
             (see <citerefentry project="wireguard"><refentrytitle>wg</refentrytitle><manvolnum>8</manvolnum></citerefentry>).
-            This option is mandatory to use WireGuard.
+            This option or <varname>PrivateKeyFile=</varname> is mandatory to use WireGuard.
             Note that because this information is secret, you may want to set
             the permissions of the .netdev file to be owned by <literal>root:systemd-network</literal>
             with a <literal>0640</literal> file mode.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
+        <term><varname>PrivateKeyFile=</varname></term>
+        <listitem>
+          <para>Takes an absolute path to a file which contains the Base64 encoded private key for the interface.
+          When this option is specified, then <varname>PrivateKey=</varname> is ignored.
+          Note that the file must be readable by the user <literal>systemd-network</literal>, so it
+          should be, e.g., owned by <literal>root:systemd-network</literal> with a
+          <literal>0640</literal> file mode.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
         <term><varname>ListenPort=</varname></term>
         <listitem>
           <para>Sets UDP port for listening. Takes either value between 1 and 65535
         </listitem>
       </varlistentry>
       <varlistentry>
+        <term><varname>PresharedKeyFile=</varname></term>
+        <listitem>
+          <para>Takes an absolute path to a file which contains the Base64 encoded preshared key for the
+          peer. When this option is specified, then <varname>PresharedKey=</varname> is ignored.
+          Note that the file must be readable by the user <literal>systemd-network</literal>, so it
+          should be, e.g., owned by <literal>root:systemd-network</literal> with a
+          <literal>0640</literal> file mode.</para>
+        </listitem>
+      </varlistentry>
+      <varlistentry>
         <term><varname>AllowedIPs=</varname></term>
         <listitem>
           <para>Sets a comma-separated list of IP (v4 or v6) addresses with CIDR masks
index ee464ff..4127084 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.network" conditional='ENABLE_NETWORKD'>
 
     <para>The main network file must have the extension <filename>.network</filename>; other
     extensions are ignored. Networks are applied to links whenever the links appear.</para>
 
-    <para>The <filename>.network</filename> files are read from the files located in the system
-    network directory <filename>/usr/lib/systemd/network</filename>, the volatile runtime network
-    directory <filename>/run/systemd/network</filename> and the local administration network
-    directory <filename>/etc/systemd/network</filename>. All configuration files are collectively
-    sorted and processed in lexical order, regardless of the directories in which they live.
-    However, files with identical filenames replace each other. Files in <filename>/etc</filename>
-    have the highest priority, files in <filename>/run</filename> take precedence over files with
-    the same name in <filename>/usr/lib</filename>. This can be used to override a system-supplied
-    configuration file with a local file if needed. As a special case, an empty file (file size 0)
-    or symlink with the same name pointing to <filename>/dev/null</filename> disables the
-    configuration file entirely (it is "masked").</para>
+    <para>The <filename>.network</filename> files are read from the files located in the system network
+    directories <filename>/usr/lib/systemd/network</filename> and
+    <filename>/usr/local/lib/systemd/network</filename>, the volatile runtime network directory
+    <filename>/run/systemd/network</filename> and the local administration network directory
+    <filename>/etc/systemd/network</filename>. All configuration files are collectively sorted and processed
+    in lexical order, regardless of the directories in which they live. However, files with identical
+    filenames replace each other. Files in <filename>/etc</filename> have the highest priority, files in
+    <filename>/run</filename> take precedence over files with the same name under
+    <filename>/usr</filename>. This can be used to override a system-supplied configuration file with a local
+    file if needed. As a special case, an empty file (file size 0) or symlink with the same name pointing to
+    <filename>/dev/null</filename> disables the configuration file entirely (it is "masked").</para>
 
     <para>Along with the network file <filename>foo.network</filename>, a "drop-in" directory
     <filename>foo.network.d/</filename> may exist. All files with the suffix
@@ -60,9 +57,7 @@
     <filename>/run/systemd/network</filename> directories. Drop-in files in
     <filename>/etc</filename> take precedence over those in <filename>/run</filename> which in turn
     take precedence over those in <filename>/usr/lib</filename>. Drop-in files under any of these
-    directories take precedence over the main netdev file wherever located. (Of course, since
-    <filename>/run</filename> is temporary and <filename>/usr/lib</filename> is for vendors, it is
-    unlikely drop-ins should be used in either of those places.)</para>
+    directories take precedence over the main netdev file wherever located.</para>
 
     <para>Note that an interface without any static IPv6 addresses configured, and neither DHCPv6
     nor IPv6LL enabled, shall be considered to have no IPv6 support. IPv6 will be automatically
         <varlistentry>
           <term><varname>Host=</varname></term>
           <listitem>
-            <para>Matches against the hostname or machine ID of the
-            host. See <literal>ConditionHost=</literal> in
+            <para>Matches against the hostname or machine ID of the host. See
+            <literal>ConditionHost=</literal> in
             <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-            for details.
+            for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+            If an empty string is assigned, then previously assigned value is cleared.
             </para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>Virtualization=</varname></term>
           <listitem>
-            <para>Checks whether the system is executed in a virtualized
-            environment and optionally test whether it is a specific
-            implementation. See <literal>ConditionVirtualization=</literal> in
+            <para>Checks whether the system is executed in a virtualized environment and optionally test
+            whether it is a specific implementation. See <literal>ConditionVirtualization=</literal> in
             <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-            for details.
+            for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+            If an empty string is assigned, then previously assigned value is cleared.
             </para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>KernelCommandLine=</varname></term>
           <listitem>
-            <para>Checks whether a specific kernel command line option is
-            set (or if prefixed with the exclamation mark unset). See
+            <para>Checks whether a specific kernel command line option is set. See
             <literal>ConditionKernelCommandLine=</literal> in
             <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-            for details.
+            for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+            If an empty string is assigned, then previously assigned value is cleared.
             </para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>KernelVersion=</varname></term>
           <listitem>
-            <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a certain
-            expression (or if prefixed with the exclamation mark does not match it). See
-            <literal>ConditionKernelVersion=</literal> in
-            <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
-            details.
+            <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a
+            certain expression. See <literal>ConditionKernelVersion=</literal> in
+            <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+            for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+            If an empty string is assigned, then previously assigned value is cleared.
             </para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>Architecture=</varname></term>
           <listitem>
-            <para>Checks whether the system is running on a specific
-            architecture. See <literal>ConditionArchitecture=</literal> in
+            <para>Checks whether the system is running on a specific architecture. See
+            <literal>ConditionArchitecture=</literal> in
             <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-            for details.
+            for details. When prefixed with an exclamation mark (<literal>!</literal>), the result is negated.
+            If an empty string is assigned, then previously assigned value is cleared.
             </para>
           </listitem>
         </varlistentry>
       <varlistentry>
         <term><varname>RequiredForOnline=</varname></term>
         <listitem>
-          <para>Takes a boolean. When <literal>yes</literal>, the network is deemed
-          required when determining whether the system is online when running
-          <literal>systemd-networkd-wait-online</literal>.
-          When <literal>no</literal>, the network is ignored when checking for
-          online state. Defaults to <literal>yes</literal>.</para>
+          <para>Takes a boolean or operational state. Please see
+          <citerefentry><refentrytitle>networkctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+          for possible operational states. When <literal>yes</literal>, the network is deemed required when
+          determining whether the system is online when running
+          <command>systemd-networkd-wait-online</command>. When <literal>no</literal>, the network is ignored
+          when checking for online state. When an operational state is set, <literal>yes</literal> is implied,
+          and this controls the operational state required for the network interface to be considered online.
+          Defaults to <literal>yes</literal>.</para>
+
           <para>The network will be brought up normally in all cases, but in
           the event that there is no address being assigned by DHCP or the
           cable is not plugged in, the link will simply remain offline and be
-          skipped automatically by <literal>systemd-networkd-wait-online</literal>
+          skipped automatically by <command>systemd-networkd-wait-online</command>
           if <literal>RequiredForOnline=no</literal>.</para>
         </listitem>
       </varlistentry>
         <varlistentry>
           <term><varname>DHCPServer=</varname></term>
           <listitem>
-            <para>Takes a boolean. If set to <literal>yes</literal>, DHCPv4 server will be start. Defaults
+            <para>Takes a boolean. If set to <literal>yes</literal>, DHCPv4 server will be started. Defaults
             to <literal>no</literal>. Further settings for the DHCP
             server may be set in the <literal>[DHCPServer]</literal>
             section described below.</para>
         <varlistentry>
           <term><varname>LinkLocalAddressing=</varname></term>
           <listitem>
-            <para>Enables link-local address autoconfiguration. Accepts
-            <literal>yes</literal>, <literal>no</literal>,
-            <literal>ipv4</literal>, or <literal>ipv6</literal>. Defaults to
-            <literal>ipv6</literal>.</para>
+            <para>Enables link-local address autoconfiguration. Accepts <literal>yes</literal>,
+            <literal>no</literal>, <literal>ipv4</literal>, or <literal>ipv6</literal>. If
+            <varname>Bridge=</varname> is set, defaults to <literal>no</literal>, and if not,
+            defaults to <literal>ipv6</literal>.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
             specified more than once.
             </para>
 
-            <para>If the specified address is 0.0.0.0 (for IPv4) or
-            [::] (for IPv6), a new address range of the requested size
-            is automatically allocated from a system-wide pool of
-            unused ranges. The allocated range is checked against all
-            current network interfaces and all known network
-            configuration files to avoid address range conflicts. The
-            default system-wide pool consists of 192.168.0.0/16,
-            172.16.0.0/12 and 10.0.0.0/8 for IPv4, and fc00::/7 for
-            IPv6. This functionality is useful to manage a large
-            number of dynamically created network interfaces with the
-            same network configuration and automatic address range
-            assignment.</para>
+            <para>If the specified address is <literal>0.0.0.0</literal> (for IPv4) or <literal>::</literal>
+            (for IPv6), a new address range of the requested size is automatically allocated from a
+            system-wide pool of unused ranges. Note that the prefix length must be equal or larger than 8 for
+            IPv4, and 64 for IPv6. The allocated range is checked against all current network interfaces and
+            all known network configuration files to avoid address range conflicts. The default system-wide
+            pool consists of 192.168.0.0/16, 172.16.0.0/12 and 10.0.0.0/8 for IPv4, and fd00::/8 for IPv6.
+            This functionality is useful to manage a large number of dynamically created network interfaces
+            with the same network configuration and automatic address range assignment.</para>
 
           </listitem>
         </varlistentry>
           url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink> in the kernel
           documentation regarding <literal>accept_ra</literal>, but note that systemd's setting of
           <constant>1</constant> (i.e. true) corresponds to kernel's setting of <constant>2</constant>.</para>
+
+          <para>Note that if this option is enabled a userspace implementation of the IPv6 RA protocol is
+          used, and the kernel's own implementation remains disabled, since `networkd` needs to know all
+          details supplied in the advertisements, and these are not available from the kernel if the kernel's
+          own implemenation is used.</para>
         </listitem>
         </varlistentry>
         <varlistentry>
           </para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>IgnoreCarrierLoss=</varname></term>
+        <listitem>
+          <para>A boolean. Allows networkd to retain both the static and dynamic configuration of the
+          interface even if its carrier is lost. Defaults to false.
+          </para>
+        </listitem>
+      </varlistentry>
+
       </variablelist>
 
   </refsect1>
         <varlistentry>
           <term><varname>Address=</varname></term>
           <listitem>
-            <para>As in the <literal>[Network]</literal> section. This
-            key is mandatory.</para>
+            <para>As in the <literal>[Network]</literal> section. This key is mandatory. Each
+            <literal>[Address]</literal> section can contain one <varname>Address=</varname> setting.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><varname>Peer=</varname></term>
           <listitem>
             <para>The peer address in a point-to-point connection.
-            Accepts the same format as the <literal>Address</literal>
+            Accepts the same format as the <varname>Address=</varname>
             key.</para>
           </listitem>
         </varlistentry>
             described in
             <citerefentry project='man-pages'><refentrytitle>inet_pton</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
             This key only applies to IPv4 addresses. If it is not
-            given, it is derived from the <literal>Address</literal>
+            given, it is derived from the <varname>Address=</varname>
             key.</para>
           </listitem>
         </varlistentry>
           </listitem>
         </varlistentry>
          <varlistentry>
-           <term><varname>GatewayOnlink=</varname></term>
+           <term><varname>GatewayOnLink=</varname></term>
            <listitem>
              <para>Takes a boolean. If set to true, the kernel does not have
              to check if the gateway is reachable directly by the current machine (i.e., the kernel does
             <varname>UseRoutes=</varname>, <varname>SendHostname=</varname>,
             <varname>UseMTU=</varname>, <varname>VendorClassIdentifier=</varname>,
             <varname>UseTimezone=</varname>.</para>
+
+            <para>With this option enabled DHCP requests will mimic those generated by Microsoft Windows, in
+            order to reduce the ability to fingerprint and recognize installations. This means DHCP request
+            sizes will grow and lease data will be more comprehensive than normally, though most of the
+            requested data is not actually used.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
             </para>
           </listitem>
         </varlistentry>
+
+        <varlistentry>
+          <term><varname>UseAutonomousPrefix=</varname></term>
+          <listitem>
+            <para>When true (the default), the autonomous prefix received in the Router Advertisement will be used and take
+            precedence over any statically configured ones.</para>
+          </listitem>
+        </varlistentry>
+
+        <varlistentry>
+          <term><varname>UseOnLinkPrefix=</varname></term>
+          <listitem>
+            <para>When true (the default), the onlink prefix received in the Router Advertisement will be used and take
+            precedence over any statically configured ones.</para>
+          </listitem>
+        </varlistentry>
+
       </variablelist>
   </refsect1>
 
           </listitem>
         </varlistentry>
         <varlistentry>
+          <term><varname>MulticastFlood=</varname></term>
+          <listitem>
+            <para>Takes a boolean. Controls whether the bridge should flood
+            traffic for which an MDB entry is missing and the destination
+            is unknown through this port. When unset, the kernel's default will be used.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
           <term><varname>MulticastToUnicast=</varname></term>
           <listitem>
             <para>Takes a boolean. Multicast to unicast works on top of the multicast snooping feature of
           </listitem>
         </varlistentry>
         <varlistentry>
+          <term><varname>NeighborSuppression=</varname></term>
+          <listitem>
+            <para>Takes a boolean. Configures whether ARP and ND neighbor suppression is enabled for
+            this port. When unset, the kernel's default will be used.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
+          <term><varname>Learning=</varname></term>
+          <listitem>
+            <para>Takes a boolean. Configures whether MAC address learning is enabled for
+            this port. When unset, the kernel's default will be used.
+            </para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
           <term><varname>HairPin=</varname></term>
           <listitem>
             <para>Takes a boolean. Configures whether traffic may be sent back
             automatic restart off. By default automatic restart is disabled.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>TripleSampling=</varname></term>
+          <listitem>
+            <para>Takes a boolean. When <literal>yes</literal>, three samples (instead of one) are used to determine
+            the value of a received bit by majority rule. When unset, the kernel's default will be used.</para>
+          </listitem>
+        </varlistentry>
       </variablelist>
   </refsect1>
 
index 7924641..1485a26 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.nspawn">
 
       </varlistentry>
 
       <varlistentry>
+        <term><varname>Inaccessible=</varname></term>
+
+        <listitem><para>Masks the specified file or directly in the container, by over-mounting it with an empty file
+        node of the same type with the most restrictive access mode. Takes a file system path as arugment. This option
+        may be used multiple times to mask multiple files or directories. This option is equivalent to the command line
+        switch <option>--inaccessible=</option>, see
+        <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry> for details
+        about the specific options supported. This setting is privileged (see above).</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><varname>Overlay=</varname></term>
         <term><varname>OverlayReadOnly=</varname></term>
 
index 13fdfc2..cd9c1b5 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.offline-updates">
   <refentryinfo>
index e513fe6..de284d8 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.path">
   <refentryinfo>
index cf807bd..30c838b 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="systemd.preset">
 
   <refentryinfo>
index a4d793c..4a8c57f 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.resource-control">
   <refentryinfo>
       </varlistentry>
 
       <varlistentry>
+        <term><varname>CPUQuotaPeriodSec=</varname></term>
+
+        <listitem>
+          <para>Assign the duration over which the CPU time quota specified by <varname>CPUQuota=</varname> is measured.
+          Takes a time duration value in seconds, with an optional suffix such as "ms" for milliseconds (or "s" for seconds.)
+          The default setting is 100ms. The period is clamped to the range supported by the kernel, which is [1ms, 1000ms].
+          Additionally, the period is adjusted up so that the quota interval is also at least 1ms.
+          Setting <varname>CPUQuotaPeriodSec=</varname> to an empty value resets it to the default.</para>
+
+          <para>This controls the second field of <literal>cpu.max</literal> attribute on the unified control group hierarchy
+          and <literal>cpu.cfs_period_us</literal> on legacy. For details about these control group attributes, see
+          <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink> and
+          <ulink url="https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt">sched-design-CFS.txt</ulink>.</para>
+
+          <para>Example: <varname>CPUQuotaPeriodSec=10ms</varname> to request that the CPU quota is measured in periods of 10ms.</para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><varname>MemoryAccounting=</varname></term>
 
         <listitem>
         <term><varname>IPAddressDeny=<replaceable>ADDRESS[/PREFIXLENGTH]…</replaceable></varname></term>
 
         <listitem>
-          <para>Turn on address range network traffic filtering for packets sent and received over AF_INET and AF_INET6
-          sockets.  Both directives take a space separated list of IPv4 or IPv6 addresses, each optionally suffixed
-          with an address prefix length (separated by a <literal>/</literal> character). If the latter is omitted, the
-          address is considered a host address, i.e. the prefix covers the whole address (32 for IPv4, 128 for IPv6).
-          </para>
-
-          <para>The access lists configured with this option are applied to all sockets created by processes of this
-          unit (or in the case of socket units, associated with it). The lists are implicitly combined with any lists
-          configured for any of the parent slice units this unit might be a member of. By default all access lists are
-          empty. When configured the lists are enforced as follows:</para>
+          <para>Turn on address range network traffic filtering for IP packets sent and received over
+          <constant>AF_INET</constant> and <constant>AF_INET6</constant> sockets.  Both directives take a
+          space separated list of IPv4 or IPv6 addresses, each optionally suffixed with an address prefix
+          length in bits (separated by a <literal>/</literal> character). If the latter is omitted, the
+          address is considered a host address, i.e. the prefix covers the whole address (32 for IPv4, 128
+          for IPv6).</para>
+
+          <para>The access lists configured with this option are applied to all sockets created by processes
+          of this unit (or in the case of socket units, associated with it). The lists are implicitly
+          combined with any lists configured for any of the parent slice units this unit might be a member
+          of. By default all access lists are empty. Both ingress and egress traffic is filtered by these
+          settings. In case of ingress traffic the source IP address is checked against these access lists,
+          in case of egress traffic the destination IP address is checked. When configured the lists are
+          enforced as follows:</para>
 
           <itemizedlist>
-            <listitem><para>Access will be granted in case its destination/source address matches any entry in the
-            <varname>IPAddressAllow=</varname> setting.</para></listitem>
+            <listitem><para>Access will be granted in case an IP packet's destination/source address matches
+            any entry in the <varname>IPAddressAllow=</varname> setting.</para></listitem>
 
-            <listitem><para>Otherwise, access will be denied in case its destination/source address matches any entry
-            in the <varname>IPAddressDeny=</varname> setting.</para></listitem>
+            <listitem><para>Otherwise, access will be denied in case its destination/source address matches
+            any entry in the <varname>IPAddressDeny=</varname> setting.</para></listitem>
 
             <listitem><para>Otherwise, access will be granted.</para></listitem>
           </itemizedlist>
index 18560fb..503a480 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.scope">
   <refentryinfo>
index f0f9aee..5b88417 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.service">
   <refentryinfo>
     about the incompatibilities, see the <ulink
     url="https://www.freedesktop.org/wiki/Software/systemd/Incompatibilities">Incompatibilities
     with SysV</ulink> document.</para>
+
+    <para>The <citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+    command allows creating <filename>.service</filename> and <filename>.scope</filename> units dynamically
+    and transiently from the command line.</para>
   </refsect1>
 
   <refsect1>
               </row>
 
               <row>
+                <entry><literal>:</literal></entry>
+                <entry>If the executable path is prefixed with <literal>:</literal>, environment variable substitution (as described by the "Command Lines" section below) is not applied.</entry>
+              </row>
+
+              <row>
                 <entry><literal>+</literal></entry>
                 <entry>If the executable path is prefixed with <literal>+</literal> then the process is executed with full privileges. In this mode privilege restrictions configured with <varname>User=</varname>, <varname>Group=</varname>, <varname>CapabilityBoundingSet=</varname> or the various file system namespacing options (such as <varname>PrivateDevices=</varname>, <varname>PrivateTmp=</varname>) are not applied to the invoked command line (but still affect any other <varname>ExecStart=</varname>, <varname>ExecStop=</varname>, … lines).</entry>
               </row>
           </tgroup>
         </table>
 
-        <para><literal>@</literal>, <literal>-</literal>, and one of
+        <para><literal>@</literal>, <literal>-</literal>, <literal>:</literal>, and one of
         <literal>+</literal>/<literal>!</literal>/<literal>!!</literal> may be used together and they can appear in any
         order. However, only one of <literal>+</literal>, <literal>!</literal>, <literal>!!</literal> may be used at a
         time. Note that these prefixes are also supported for the other command line settings,
         start-up failed, for example because any of the commands specified in <varname>ExecStart=</varname>,
         <varname>ExecStartPre=</varname> or <varname>ExecStartPost=</varname> failed (and weren't prefixed with
         <literal>-</literal>, see above) or timed out. Use <varname>ExecStopPost=</varname> to invoke commands when a
-        service failed to start up correctly and is shut down again. Also note that, service restart requests are
-        implemented as stop operations followed by start operations. This means that <varname>ExecStop=</varname> and
-        <varname>ExecStopPost=</varname> are executed during a service restart operation.</para>
-
-        <para>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
-        <varname>ExecStopPost=</varname> instead.</para></listitem>
+        service failed to start up correctly and is shut down again. Also note that the stop operation is always
+        performed if the service started successfully, even if the processes in the service terminated on their
+        own or were killed. The stop commands must be prepared to deal with that case. <varname>$MAINPID</varname>
+        will be unset if systemd knows that the main process exited by the time the stop commands are called.</para>
+
+        <para>Service restart requests are implemented as stop operations followed by start operations. This
+        means that <varname>ExecStop=</varname> and <varname>ExecStopPost=</varname> are executed during a
+        service restart operation.</para>
+
+        <para>It is recommended to use this setting for commands that communicate with the service requesting
+        clean termination. For post-mortem clean-up steps use <varname>ExecStopPost=</varname> instead.
+        </para></listitem>
       </varlistentry>
 
       <varlistentry>
 
       <varlistentry>
         <term><varname>RestartPreventExitStatus=</varname></term>
-        <listitem><para>Takes a list of exit status definitions that,
-        when returned by the main service process, will prevent
-        automatic service restarts, regardless of the restart setting
-        configured with <varname>Restart=</varname>. Exit status
-        definitions can either be numeric exit codes or termination
-        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:
+
+        <listitem><para>Takes a list of exit status definitions that, when returned by the main service
+        process, will prevent automatic service restarts, regardless of the restart setting configured with
+        <varname>Restart=</varname>. Exit status definitions can either be numeric exit codes or termination
+        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:
 
         <programlisting>RestartPreventExitStatus=1 6 SIGABRT</programlisting>
 
-        ensures that exit codes 1 and 6 and the termination signal
-        <constant>SIGABRT</constant> 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.</para></listitem>
+        ensures that exit codes 1 and 6 and the termination signal <constant>SIGABRT</constant> 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.</para>
+
+        <para>Note that this setting has no effect on processes configured via
+        <varname>ExecStartPre=</varname>, <varname>ExecStartPost=</varname>, <varname>ExecStop=</varname>,
+        <varname>ExecStopPost=</varname> or <varname>ExecReload=</varname>, but only on the main service
+        process, i.e. either the one invoked by <varname>ExecStart=</varname> or (depending on
+        <varname>Type=</varname>, <varname>PIDFile=</varname>, …) the otherwise configured main
+        process.</para></listitem>
       </varlistentry>
 
       <varlistentry>
@@ -1421,7 +1433,8 @@ WantedBy=multi-user.target</programlisting>
         <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
         <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-        <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+        <citerefentry><refentrytitle>systemd.directives</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
+        <citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry>
       </para>
   </refsect1>
 
index 43e7c6a..5019bf9 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.slice">
   <refentryinfo>
index 7547071..e29602b 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.socket">
   <refentryinfo>
index fd5639b..248fb92 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.special">
 
     <filename>sysinit.target</filename>,
     <filename>system-update.target</filename>,
     <filename>system-update-pre.target</filename>,
+    <filename>time-set.target</filename>,
     <filename>time-sync.target</filename>,
     <filename>timers.target</filename>,
     <filename>umount.target</filename>,
+    <filename>usb-gadget.target</filename>,
     <!-- slices --><filename>-.slice</filename>,
     <filename>system.slice</filename>,
     <filename>user.slice</filename>,
             dynamically when audio hardware is found.</para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><filename>usb-gadget.target</filename></term>
+          <listitem>
+            <para>This target is started automatically as soon as a
+            USB Device Controller becomes available at boot.</para>
+
+            <para>This may be used to pull in usb gadget
+            dynamically when UDC hardware is found.</para>
+          </listitem>
+        </varlistentry>
       </variablelist>
     </refsect2>
 
           </listitem>
         </varlistentry>
         <varlistentry>
+          <term><filename>time-set.target</filename></term>
+          <listitem>
+            <para>Services responsible for setting the system clock from
+            a local source (such as a maintained timestamp file or
+            imprecise real-time clock) should pull in this target and
+            order themselves before it.  Services where approximate time
+            is desired should be ordered after this unit, but not pull
+            it in.  This target does not provide the accuracy guarantees
+            of <filename>time-sync.target</filename>.</para>
+          </listitem>
+        </varlistentry>
+        <varlistentry>
           <term><filename>time-sync.target</filename></term>
           <listitem>
             <para>Services responsible for synchronizing the system
       <title>Special User Units</title>
 
       <para>When systemd runs as a user instance, the following special
-      units are available, which have similar definitions as their
+      units are available:</para>
+
+      <variablelist>
+        <varlistentry>
+          <term><filename>default.target</filename></term>
+          <listitem>
+            <para>This is the main target of the user session, started by default. Various services that
+            compose the normal user session should be pulled into this target. In this regard,
+            <filename>default.target</filename> is similar to <filename>multi-user.target</filename> in the
+            system instance, but it is a real unit, not an alias.</para>
+          </listitem>
+        </varlistentry>
+      </variablelist>
+
+      <para>In addition, the following units are available which have definitions similar to their
       system counterparts:
       <filename>exit.target</filename>,
-      <filename>default.target</filename>,
       <filename>shutdown.target</filename>,
       <filename>sockets.target</filename>,
       <filename>timers.target</filename>,
index cf00451..66d6350 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.swap"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 67cd640..3b58e45 100644 (file)
@@ -1,10 +1,9 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.syntax">
@@ -66,7 +65,7 @@
 
     <para>Each file is a plain text file divided into sections, with configuration entries in the
     style <replaceable>key</replaceable>=<replaceable>value</replaceable>.
-    Empty lines and lines starting with <literal>#</literal> or <literal>;</literal> are
+    Whitespace immediately before or after the <literal>=</literal> is ignored. Empty lines and lines starting with <literal>#</literal> or <literal>;</literal> are
     ignored, which may be used for commenting.</para>
 
     <para>Lines ending in a backslash are concatenated with the following line while reading and the
index 10aa91a..a706a45 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.target">
   <refentryinfo>
index 24df5ab..4a6b808 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.time">
 
index d254c77..6a13e52 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.timer">
   <refentryinfo>
         <term><varname>OnUnitInactiveSec=</varname></term>
 
         <listitem><para>Defines monotonic timers relative to different
-        starting points: <varname>OnActiveSec=</varname> defines a
-        timer relative to the moment the timer itself is activated.
-        <varname>OnBootSec=</varname> defines a timer relative to when
-        the machine was booted up. <varname>OnStartupSec=</varname>
-        defines a timer relative to when systemd was first started.
-        <varname>OnUnitActiveSec=</varname> defines a timer relative
-        to when the unit the timer is activating was last activated.
-        <varname>OnUnitInactiveSec=</varname> defines a timer relative
-        to when the unit the timer is activating was last
-        deactivated.</para>
-
-        <para>Multiple directives may be combined of the same and of
-        different types. For example, by combining
-        <varname>OnBootSec=</varname> and
-        <varname>OnUnitActiveSec=</varname>, it is possible to define
-        a timer that elapses in regular intervals and activates a
-        specific service each time.</para>
+        starting points:</para>
+
+        <table>
+          <title>Settings and their starting points</title>
+
+          <tgroup cols='2'>
+            <thead>
+              <row>
+                <entry>Setting</entry>
+                <entry>Meaning</entry>
+              </row>
+            </thead>
+            <tbody>
+              <row>
+                <entry><varname>OnActiveSec=</varname></entry>
+                <entry>Defines a timer relative to the moment the timer unit itself is activated.</entry>
+              </row>
+              <row>
+                <entry><varname>OnBootSec=</varname></entry>
+                <entry>Defines a timer relative to when the machine was booted up. In containers, for the system manager instance, this is mapped to <varname>OnStartupSec=</varname>, making both equivalent.</entry>
+              </row>
+              <row>
+                <entry><varname>OnStartupSec=</varname></entry>
+                <entry>Defines a timer relative to when the service manager was first started. For system timer units this is very similar to <varname>OnBootSec=</varname> as the system service manager is generally started very early at boot. It's primarily useful when configured in units running in the per-user service manager, as the user service manager is generally started on first login only, not already during boot.</entry>
+              </row>
+              <row>
+                <entry><varname>OnUnitActiveSec=</varname></entry>
+                <entry>Defines a timer relative to when the unit the timer unit is activating was last activated.</entry>
+              </row>
+              <row>
+                <entry><varname>OnUnitInactiveSec=</varname></entry>
+                <entry>Defines a timer relative to when the unit the timer unit is activating was last deactivated.</entry>
+              </row>
+            </tbody>
+          </tgroup>
+        </table>
+
+        <para>Multiple directives may be combined of the same and of different types, in which case the timer
+        unit will trigger whenever any of the specified timer expressions elapse. For example, by combining
+        <varname>OnBootSec=</varname> and <varname>OnUnitActiveSec=</varname>, it is possible to define a
+        timer that elapses in regular intervals and activates a specific service each time. Moreover, both
+        monotonic time expressions and <varname>OnCalendar=</varname> calendar expressions may be combined in
+        the same timer unit.</para>
 
         <para>The arguments to the directives are time spans
         configured in seconds. Example: "OnBootSec=50" means 50s after
         and the configured unit is started. This is not the case for
         timers defined in the other directives.</para>
 
-        <para>These are monotonic timers, independent of wall-clock
-        time and timezones. If the computer is temporarily suspended,
-        the monotonic clock stops too.</para>
+        <para>These are monotonic timers, independent of wall-clock time and timezones. If the computer is
+        temporarily suspended, the monotonic clock pauses, too.</para>
 
-        <para>If the empty string is assigned to any of these options,
-        the list of timers is reset, and all prior assignments will
-        have no effect.</para>
+        <para>If the empty string is assigned to any of these options, the list of timers is reset (both
+        monotonic timers and <varname>OnCalendar=</varname> timers, see below), and all prior assignments
+        will have no effect.</para>
 
         <para>Note that timers do not necessarily expire at the
         precise time configured with these settings, as they are
         the <varname>AccuracySec=</varname> setting
         below.</para>
 
-       <para>May be specified more than once.</para></listitem>
+        <para>May be specified more than once, in which case the timer unit will trigger whenever any of the
+        specified expressions elapse. Moreover calendar timers and monotonic timers (see above) may be
+        combined within the same timer unit.</para>
+
+        <para>If the empty string is assigned to any of these options, the list of timers is reset (both
+        <varname>OnCalendar=</varname> timers and monotonic timers, see above), and all prior assignments
+        will have no effect.</para></listitem>
       </varlistentry>
 
       <varlistentry>
       </varlistentry>
 
       <varlistentry>
+        <term><varname>OnClockChange=</varname></term>
+        <term><varname>OnTimezoneChange=</varname></term>
+
+        <listitem><para>These options take boolean arguments. When true, the service unit will be triggered
+        when the system clock (<constant>CLOCK_REALTIME</constant>) jumps relative to the monotonic clock
+        (<constant>CLOCK_MONOTONIC</constant>), or when the local system timezone is modified. These options
+        can be used alone or in combination with other timer expressions (see above) within the same timer
+        unit. These options default to false.</para></listitem>
+      </varlistentry>
+
+      <varlistentry>
         <term><varname>Unit=</varname></term>
 
         <listitem><para>The unit to activate when this timer elapses.
index f21f9ea..81a0225 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd.unit">
 
           </row>
           <row>
             <entry><filename>/etc/systemd/system</filename></entry>
-            <entry>Local configuration</entry>
+            <entry>System units created by the administrator</entry>
           </row>
           <row>
             <entry><filename>/run/systemd/system</filename></entry>
           </row>
           <row>
             <entry><filename>/usr/local/lib/systemd/system</filename></entry>
-            <entry morerows="1">Units of installed packages</entry>
+            <entry>System units installed by the administrator </entry>
           </row>
           <row>
             <entry><filename>/usr/lib/systemd/system</filename></entry>
+            <entry>System units installed by the distribution package manager</entry>
           </row>
           <row>
             <entry><filename>/run/systemd/generator.late</filename></entry>
           </row>
           <row>
             <entry><filename>/etc/systemd/user</filename></entry>
-            <entry>Local configuration</entry>
+            <entry>User units created by the administrator</entry>
           </row>
           <row>
             <entry><filename>$XDG_RUNTIME_DIR/systemd/user</filename></entry>
           </row>
           <row>
             <entry><filename>/usr/local/lib/systemd/user</filename></entry>
-            <entry morerows="1">Units of packages that have been installed system-wide</entry>
+            <entry>User units installed by the administrator</entry>
           </row>
           <row>
             <entry><filename>/usr/lib/systemd/user</filename></entry>
+            <entry>User units installed by the distribution package manager</entry>
           </row>
           <row>
             <entry><filename>$XDG_RUNTIME_DIR/systemd/generator.late</filename></entry>
       <varlistentry>
         <term><varname>JoinsNamespaceOf=</varname></term>
 
-        <listitem><para>For units that start processes (such as
-        service units), lists one or more other units whose network
-        and/or temporary file namespace to join. This only applies to
-        unit types which support the
-        <varname>PrivateNetwork=</varname> and
+        <listitem><para>For units that start processes (such as service units), lists one or more other units
+        whose network and/or temporary file namespace to join. This only applies to unit types which support
+        the <varname>PrivateNetwork=</varname>, <varname>NetworkNamespacePath=</varname> and
         <varname>PrivateTmp=</varname> directives (see
-        <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry>
-        for details). If a unit that has this setting set is started,
-        its processes will see the same <filename>/tmp</filename>,
-        <filename>/var/tmp</filename> and network namespace as one
-        listed unit that is started. If multiple listed units are
-        already started, it is not defined which namespace is joined.
-        Note that this setting only has an effect if
-        <varname>PrivateNetwork=</varname> and/or
-        <varname>PrivateTmp=</varname> is enabled for both the unit
-        that joins the namespace and the unit whose namespace is
-        joined.</para></listitem>
+        <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+        details). If a unit that has this setting set is started, its processes will see the same
+        <filename>/tmp</filename>, <filename>/var/tmp</filename> and network namespace as one listed unit
+        that is started. If multiple listed units are already started, it is not defined which namespace is
+        joined.  Note that this setting only has an effect if
+        <varname>PrivateNetwork=</varname>/<varname>NetworkNamespacePath=</varname> and/or
+        <varname>PrivateTmp=</varname> is enabled for both the unit that joins the namespace and the unit
+        whose namespace is joined.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>ConditionUser=</varname></term>
         <term><varname>ConditionGroup=</varname></term>
         <term><varname>ConditionControlGroupController=</varname></term>
+        <term><varname>ConditionMemory=</varname></term>
+        <term><varname>ConditionCPUs=</varname></term>
 
         <!-- We do not document ConditionNull=
              here, as it is not particularly
         <para><varname>ConditionArchitecture=</varname> may be used to
         check whether the system is running on a specific
         architecture. Takes one of
-        <varname>x86</varname>,
-        <varname>x86-64</varname>,
-        <varname>ppc</varname>,
-        <varname>ppc-le</varname>,
-        <varname>ppc64</varname>,
-        <varname>ppc64-le</varname>,
-        <varname>ia64</varname>,
-        <varname>parisc</varname>,
-        <varname>parisc64</varname>,
-        <varname>s390</varname>,
-        <varname>s390x</varname>,
-        <varname>sparc</varname>,
-        <varname>sparc64</varname>,
-        <varname>mips</varname>,
-        <varname>mips-le</varname>,
-        <varname>mips64</varname>,
-        <varname>mips64-le</varname>,
-        <varname>alpha</varname>,
-        <varname>arm</varname>,
-        <varname>arm-be</varname>,
-        <varname>arm64</varname>,
-        <varname>arm64-be</varname>,
-        <varname>sh</varname>,
-        <varname>sh64</varname>,
-        <varname>m68k</varname>,
-        <varname>tilegx</varname>,
-        <varname>cris</varname>,
-        <varname>arc</varname>,
-        <varname>arc-be</varname> to test
+        <literal>x86</literal>,
+        <literal>x86-64</literal>,
+        <literal>ppc</literal>,
+        <literal>ppc-le</literal>,
+        <literal>ppc64</literal>,
+        <literal>ppc64-le</literal>,
+        <literal>ia64</literal>,
+        <literal>parisc</literal>,
+        <literal>parisc64</literal>,
+        <literal>s390</literal>,
+        <literal>s390x</literal>,
+        <literal>sparc</literal>,
+        <literal>sparc64</literal>,
+        <literal>mips</literal>,
+        <literal>mips-le</literal>,
+        <literal>mips64</literal>,
+        <literal>mips64-le</literal>,
+        <literal>alpha</literal>,
+        <literal>arm</literal>,
+        <literal>arm-be</literal>,
+        <literal>arm64</literal>,
+        <literal>arm64-be</literal>,
+        <literal>sh</literal>,
+        <literal>sh64</literal>,
+        <literal>m68k</literal>,
+        <literal>tilegx</literal>,
+        <literal>cris</literal>,
+        <literal>arc</literal>,
+        <literal>arc-be</literal> to test
         against a specific architecture. The architecture is
         determined from the information returned by
         <citerefentry project='man-pages'><refentrytitle>uname</refentrytitle><manvolnum>2</manvolnum></citerefentry>
         <citerefentry><refentrytitle>personality</refentrytitle><manvolnum>2</manvolnum></citerefentry>.
         Note that a <varname>Personality=</varname> setting in the
         same unit file has no effect on this condition. A special
-        architecture name <varname>native</varname> is mapped to the
+        architecture name <literal>native</literal> is mapped to the
         architecture the system manager itself is compiled for. The
         test may be negated by prepending an exclamation mark.</para>
 
         environment and optionally test whether it is a specific
         implementation. Takes either boolean value to check if being
         executed in any virtualized environment, or one of
-        <varname>vm</varname> and
-        <varname>container</varname> to test against a generic type of
+        <literal>vm</literal> and
+        <literal>container</literal> to test against a generic type of
         virtualization solution, or one of
-        <varname>qemu</varname>,
-        <varname>kvm</varname>,
-        <varname>zvm</varname>,
-        <varname>vmware</varname>,
-        <varname>microsoft</varname>,
-        <varname>oracle</varname>,
-        <varname>xen</varname>,
-        <varname>bochs</varname>,
-        <varname>uml</varname>,
-        <varname>bhyve</varname>,
-        <varname>qnx</varname>,
-        <varname>openvz</varname>,
-        <varname>lxc</varname>,
-        <varname>lxc-libvirt</varname>,
-        <varname>systemd-nspawn</varname>,
-        <varname>docker</varname>,
-        <varname>rkt</varname> to test
+        <literal>qemu</literal>,
+        <literal>kvm</literal>,
+        <literal>zvm</literal>,
+        <literal>vmware</literal>,
+        <literal>microsoft</literal>,
+        <literal>oracle</literal>,
+        <literal>xen</literal>,
+        <literal>bochs</literal>,
+        <literal>uml</literal>,
+        <literal>bhyve</literal>,
+        <literal>qnx</literal>,
+        <literal>openvz</literal>,
+        <literal>lxc</literal>,
+        <literal>lxc-libvirt</literal>,
+        <literal>systemd-nspawn</literal>,
+        <literal>docker</literal>,
+        <literal>rkt</literal>,
+        <literal>wsl</literal>,
+        <literal>acrn</literal> to test
         against a specific implementation, or
-        <varname>private-users</varname> to check whether we are running in a user namespace. See
+        <literal>private-users</literal> to check whether we are running in a user namespace. See
         <citerefentry><refentrytitle>systemd-detect-virt</refentrytitle><manvolnum>1</manvolnum></citerefentry>
         for a full list of known virtualization technologies and their
         identifiers. If multiple virtualization technologies are
         the exact assignment is looked for with right and left hand
         side matching.</para>
 
-        <para><varname>ConditionKernelVersion=</varname> may be used to check whether the kernel version (as reported
-        by <command>uname -r</command>) matches a certain expression (or if prefixed with the exclamation mark does not
-        match it). The argument must be a single string. If the string starts with one of <literal>&lt;</literal>,
-        <literal>&lt;=</literal>, <literal>=</literal>, <literal>&gt;=</literal>, <literal>&gt;</literal> a relative
-        version comparison is done, otherwise the specified string is matched with shell-style globs.</para>
+        <para><varname>ConditionKernelVersion=</varname> may be used to check whether the kernel version (as
+        reported by <command>uname -r</command>) matches a certain expression (or if prefixed with the
+        exclamation mark does not match it). The argument must be a single string. If the string starts with
+        one of <literal>&lt;</literal>, <literal>&lt;=</literal>, <literal>=</literal>,
+        <literal>!=</literal>, <literal>&gt;=</literal>, <literal>&gt;</literal> a relative version
+        comparison is done, otherwise the specified string is matched with shell-style globs.</para>
 
         <para>Note that using the kernel version string is an unreliable way to determine which features are supported
         by a kernel, because of the widespread practice of backporting drivers, features, and fixes from newer upstream
         <para><varname>ConditionSecurity=</varname> may be used to check
         whether the given security technology is enabled on the
         system. Currently, the recognized values are
-        <varname>selinux</varname>, <varname>apparmor</varname>,
-        <varname>tomoyo</varname>, <varname>ima</varname>,
-        <varname>smack</varname>, <varname>audit</varname> and
-        <varname>uefi-secureboot</varname>. The test may be negated by
+        <literal>selinux</literal>, <literal>apparmor</literal>,
+        <literal>tomoyo</literal>, <literal>ima</literal>,
+        <literal>smack</literal>, <literal>audit</literal> and
+        <literal>uefi-secureboot</literal>. The test may be negated by
         prepending an exclamation mark.</para>
 
         <para><varname>ConditionCapability=</varname> may be used to
         <para><varname>ConditionACPower=</varname> may be used to
         check whether the system has AC power, or is exclusively
         battery powered at the time of activation of the unit. This
-        takes a boolean argument. If set to <varname>true</varname>,
+        takes a boolean argument. If set to <literal>true</literal>,
         the condition will hold only if at least one AC connector of
         the system is connected to a power source, or if no AC
         connectors are known. Conversely, if set to
-        <varname>false</varname>, the condition will hold only if
+        <literal>false</literal>, the condition will hold only if
         there is at least one AC connector known and all AC connectors
         are disconnected from a power source.</para>
 
         does not have a special value <literal>@system</literal>.</para>
 
         <para><varname>ConditionControlGroupController=</varname> takes a
-        cgroup controller name (eg. <option>cpu</option>), verifying that it is
+        cgroup controller name (eg. <literal>cpu</literal>), verifying that it is
         available for use on the system. For example, a particular controller
         may not be available if it was disabled on the kernel command line with
         <varname>cgroup_disable=controller</varname>. Multiple controllers may
         be passed with a space separating them; in this case the condition will
         only pass if all listed controllers are available for use. Controllers
         unknown to systemd are ignored. Valid controllers are
-        <option>cpu</option>, <option>cpuacct</option>, <option>io</option>,
-        <option>blkio</option>, <option>memory</option>,
-        <option>devices</option>, and <option>pids</option>.</para>
+        <literal>cpu</literal>, <literal>cpuacct</literal>, <literal>io</literal>,
+        <literal>blkio</literal>, <literal>memory</literal>,
+        <literal>devices</literal>, and <literal>pids</literal>.</para>
+
+        <para><varname>ConditionMemory=</varname> verifies if the specified amount of system memory is
+        available to the current system. Takes a memory size in bytes as argument, optionally prefixed with a
+        comparison operator <literal>&lt;</literal>, <literal>&lt;=</literal>, <literal>=</literal>,
+        <literal>!=</literal>, <literal>&gt;=</literal>, <literal>&gt;</literal>. On bare-metal systems
+        compares the amount of physical memory in the system with the specified size, adhering to the
+        specified comparison operator. In containers compares the amount of memory assigned to the container
+        instead.</para>
+
+        <para><varname>ConditionCPUs=</varname> verifies if the specified number of CPUs is available to the
+        current system. Takes a number of CPUs as argument, optionally prefixed with a comparison operator
+        <literal>&lt;</literal>, <literal>&lt;=</literal>, <literal>=</literal>, <literal>!=</literal>,
+        <literal>&gt;=</literal>, <literal>&gt;</literal>. Compares the number of CPUs in the CPU affinity mask
+        configured of the service manager itself with the specified number, adhering to the specified
+        comparision operator. On physical systems the number of CPUs in the affinity mask of the service
+        manager usually matches the number of physical CPUs, but in special and virtual environments might
+        differ. In particular, in containers the affinity mask usually matches the number of CPUs assigned to
+        the container and not the physically available ones.</para>
 
         <para>If multiple conditions are specified, the unit will be
         executed if all of them apply (i.e. a logical AND is applied).
index 5287bda..c51f0bf 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="systemd"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index e47d36c..4314732 100644 (file)
@@ -1,9 +1,8 @@
 <?xml version="1.0"?>
 <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 <refentry id="sysusers.d" conditional='ENABLE_SYSUSERS'
     xmlns:xi="http://www.w3.org/2001/XInclude">
 
index 5a48caf..43871eb 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="telinit"
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 7985f4a..49de344 100644 (file)
@@ -1,9 +1,7 @@
 <?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refsect1>
 
index b75b4cc..b4b9910 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="timedatectl" conditional='ENABLE_TIMEDATECTL'
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 8ba639f..c64d015 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="timesyncd.conf" conditional='ENABLE_TIMESYNCD'
     xmlns:xi="http://www.w3.org/2001/XInclude">
index 3f2ef7e..67bd1dc 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!--
   SPDX-License-Identifier: LGPL-2.1+
 
@@ -367,15 +368,11 @@ L     /tmp/foobar -    -    -     -   /dev/null</programlisting>
           <listitem><para>Set file/directory attributes. Lines of this type
           accept shell-style globs in place of normal path names.</para>
 
-          <para>The format of the argument field is
-          <varname>[+-=][aAcCdDeijsStTu] </varname>. The prefix
-          <varname>+</varname> (the default one) causes the
-          attribute(s) to be added; <varname>-</varname> causes the
-          attribute(s) to be removed; <varname>=</varname> causes the
-          attributes to be set exactly as the following letters. The
-          letters <literal>aAcCdDeijsStTu</literal> select the new
-          attributes for the files, see
-          <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle>
+          <para>The format of the argument field is <varname>[+-=][aAcCdDeijPsStTu] </varname>. The prefix
+          <varname>+</varname> (the default one) causes the attribute(s) to be added; <varname>-</varname>
+          causes the attribute(s) to be removed; <varname>=</varname> causes the attributes to be set exactly
+          as the following letters. The letters <literal>aAcCdDeijPsStTu</literal> select the new attributes
+          for the files, see <citerefentry project='man-pages'><refentrytitle>chattr</refentrytitle>
           <manvolnum>1</manvolnum></citerefentry> for further information.
           </para>
           <para>Passing only <varname>=</varname> as argument resets
@@ -545,6 +542,14 @@ w- /proc/sys/vm/swappiness - - - - 10</programlisting></para>
       (ctime). Any of these three (or two) values will prevent cleanup
       if it is more recent than the current time minus the age
       field.</para>
+
+      <para>Note that while the aging algorithm is run a 'shared' BSD file lock (see <citerefentry
+      project='man-pages'><refentrytitle>flock</refentrytitle><manvolnum>2</manvolnum></citerefentry>) is
+      taken on each directory the algorithm descends into (and each directory below that, and so on). If the
+      aging algorithm finds a lock is already taken on some directory, it (and everything below it) is
+      skipped. Applications may use this to temporarily exclude certain directory subtrees from the aging
+      algorithm: the applications can take a BSD file lock themselves, and as long as they keep it aging of
+      the directory and everything below it is disabled.</para>
     </refsect2>
 
     <refsect2>
index d1878f8..04301c8 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev.conf"
           xmlns:xi="http://www.w3.org/2001/XInclude">
index 74aab8e..5a78be3 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 
 <!--
   </refsect1>
 
   <refsect1><title>Rules Files</title>
-      <para>The udev rules are read from the files located in the
-      system rules directory <filename>/usr/lib/udev/rules.d</filename>,
-      the volatile runtime directory <filename>/run/udev/rules.d</filename>
-      and the local administration directory <filename>/etc/udev/rules.d</filename>.
-      All rules files are collectively sorted and processed in lexical order,
-      regardless of the directories in which they live. However, files with
-      identical filenames replace each other. Files in <filename>/etc</filename>
-      have the highest priority, files in <filename>/run</filename> take precedence
-      over files with the same name in <filename>/usr/lib</filename>. This can be
-      used to override a system-supplied rules file with a local file if needed;
-      a symlink in <filename>/etc</filename> with the same name as a rules file in
-      <filename>/usr/lib</filename>, pointing to <filename>/dev/null</filename>,
-      disables the rules file entirely. Rule files must have the extension
-      <filename>.rules</filename>; other extensions are ignored.</para>
+      <para>The udev rules are read from the files located in the system rules directories
+      <filename>/usr/lib/udev/rules.d</filename> and <filename>/usr/local/lib/udev/rules.d</filename>, the
+      volatile runtime directory <filename>/run/udev/rules.d</filename> and the local administration
+      directory <filename>/etc/udev/rules.d</filename>.  All rules files are collectively sorted and
+      processed in lexical order, regardless of the directories in which they live. However, files with
+      identical filenames replace each other. Files in <filename>/etc</filename> have the highest priority,
+      files in <filename>/run</filename> take precedence over files with the same name under
+      <filename>/usr</filename>. This can be used to override a system-supplied rules file with a local
+      file if needed; a symlink in <filename>/etc</filename> with the same name as a rules file in
+      <filename>/usr/lib</filename>, pointing to <filename>/dev/null</filename>, disables the rules file
+      entirely. Rule files must have the extension <filename>.rules</filename>; other extensions are
+      ignored.</para>
 
       <para>Every line in the rules file contains at least one key-value pair.
       Except for empty lines or lines beginning with <literal>#</literal>, which are ignored.
index d4dc799..0deb1d0 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_device_get_syspath"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index e27b770..9c64a4b 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_device_has_tag"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 8e207b4..118adfa 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_device_new_from_syspath"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index a45ca5d..0dbb926 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_enumerate_add_match_subsystem"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 3ece35e..013d5cc 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_enumerate_new"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 770ddb9..d3dddd4 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_enumerate_scan_devices"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 0b1d28a..9f44812 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_list_entry"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index f5e4d07..88a19f1 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_monitor_filter_update"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 47fa5ab..cc37d21 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_monitor_new_from_netlink"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 6a4aae9..5b3f097 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_monitor_receive_device"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index 3971acb..89fa05e 100644 (file)
@@ -1,13 +1,10 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
 <!ENTITY % entities SYSTEM "custom-entities.ent" >
 %entities;
 ]>
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udev_new"
   xmlns:xi="http://www.w3.org/2001/XInclude">
index b7a2494..467402c 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="udevadm"
           xmlns:xi="http://www.w3.org/2001/XInclude">
       </title>
       <para>Request device events from the kernel. Primarily used to replay events at system coldplug time.</para>
 
-      <para>Takes a device specification as a positional argument. See the description of <command>info</command>
+      <para>Takes device specifications as positional arguments. See the description of <command>info</command>
       above.</para>
 
       <variablelist>
           <term><option>-c</option></term>
           <term><option>--action=<replaceable>ACTION</replaceable></option></term>
           <listitem>
-            <para>Type of event to be triggered. The default value is
-            <command>change</command>.</para>
+            <para>Type of event to be triggered. Possible actions are <literal>add</literal>,
+            <literal>remove</literal>, <literal>change</literal>, <literal>move</literal>,
+            <literal>online</literal>, <literal>offline</literal>, <literal>bind</literal>,
+            and <literal>unbind</literal>. The default value is <literal>change</literal>.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><option>--name-match=<replaceable>NAME</replaceable></option></term>
           <listitem>
             <para>Trigger events for devices with a matching device path. When this option is specified more than once,
-            the last <replaceable>NAME</replaceable> is used.</para>
+            then each matching result is ORed, that is, all specified devices are triggered.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
           <term><option>--parent-match=<replaceable>SYSPATH</replaceable></option></term>
           <listitem>
             <para>Trigger events for all children of a given device. When this option is specified more than once,
-            the last <replaceable>NAME</replaceable> is used.</para>
+            then each matching result is ORed, that is, all children of each specified device are triggered.</para>
           </listitem>
         </varlistentry>
         <varlistentry>
         <xi:include href="standard-options.xml" xpointer="help" />
       </variablelist>
 
-      <para>In addition, an optional positional argument can be used
-      to specify device name or sys path. It must start with
+      <para>In addition, optional positional arguments can be used
+      to specify device names or sys paths. They must start with
       <filename>/dev</filename> or <filename>/sys</filename>
       respectively.</para>
     </refsect2>
           <term><option>-e</option></term>
           <term><option>--exit</option></term>
           <listitem>
-            <para>Signal and wait for systemd-udevd to exit. Note that <filename>systemd-udevd.service</filename>
-            contains <option>Restart=always</option> and so as a result, this option restarts systemd-udevd.
+            <para>Signal and wait for systemd-udevd to exit. No option except for
+            <option>--timeout</option> can be specified after this option.
+            Note that <filename>systemd-udevd.service</filename> contains
+            <option>Restart=always</option> and so as a result, this option restarts systemd-udevd.
             If you want to stop <filename>systemd-udevd.service</filename>, please use the following:
             <programlisting>systemctl stop systemd-udevd-control.socket systemd-udevd-kernel.socket systemd-udevd.service</programlisting>
             </para>
index 4ad2d3b..195c2e4 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version="1.0"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
-          "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <variablelist>
   <varlistentry id='user'>
index 30af3c8..e748c03 100644 (file)
@@ -1,5 +1,6 @@
 <?xml version="1.0"?>
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+  "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
 <!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="user@.service">
index a0ca835..2e2223c 100644 (file)
@@ -1,10 +1,7 @@
 <?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  SPDX-License-Identifier: LGPL-2.1+
--->
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
 
 <refentry id="vconsole.conf" conditional='ENABLE_VCONSOLE'>
   <refentryinfo>
index fef1974..a484e51 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
 project('systemd', 'c',
-        version : '241',
+        version : '242',
         license : 'LGPLv2+',
         default_options: [
                 'c_std=gnu99',
@@ -12,8 +12,8 @@ project('systemd', 'c',
         meson_version : '>= 0.46',
        )
 
-libsystemd_version = '0.25.0'
-libudev_version = '1.6.13'
+libsystemd_version = '0.26.0'
+libudev_version = '1.6.14'
 
 # We need the same data in two different formats, ugh!
 # Also, for hysterical reasons, we use different variable
@@ -26,6 +26,10 @@ substs = configuration_data()
 substs.set('PROJECT_URL',          'https://www.freedesktop.org/wiki/Software/systemd')
 substs.set('PROJECT_VERSION',      meson.project_version())
 
+# This is to be used instead of meson.source_root(), as the latter will return
+# the wrong result when systemd is being built as a meson subproject
+project_source_root = meson.current_source_dir()
+
 want_ossfuzz = get_option('oss-fuzz')
 want_libfuzzer = get_option('llvm-fuzz')
 if want_ossfuzz and want_libfuzzer
@@ -36,7 +40,7 @@ fuzzer_build = want_ossfuzz or want_libfuzzer
 #####################################################################
 
 # Try to install the git pre-commit hook
-git_hook = run_command(join_paths(meson.source_root(), 'tools/add-git-hook.sh'))
+git_hook = run_command(join_paths(project_source_root, 'tools/add-git-hook.sh'))
 if git_hook.returncode() == 0
         message(git_hook.stdout().strip())
 endif
@@ -66,6 +70,7 @@ rootprefix_default = split_usr ? '/' : '/usr'
 if rootprefixdir == ''
         rootprefixdir = rootprefix_default
 endif
+rootprefixdir_noslash = rootprefixdir == '/' ? '' : rootprefixdir
 
 sysvinit_path = get_option('sysvinit-path')
 sysvrcnd_path = get_option('sysvrcnd-path')
@@ -76,7 +81,7 @@ conf.set10('BUMP_PROC_SYS_FS_FILE_MAX', get_option('bump-proc-sys-fs-file-max'))
 conf.set10('BUMP_PROC_SYS_FS_NR_OPEN',  get_option('bump-proc-sys-fs-nr-open'))
 conf.set('HIGH_RLIMIT_NOFILE',          512*1024)
 
-# join_paths ignore the preceding arguments if an absolute component is
+# join_paths ignores the preceding arguments if an absolute component is
 # encountered, so this should canonicalize various paths when they are
 # absolute or relative.
 prefixdir = get_option('prefix')
@@ -135,7 +140,6 @@ systemsleepdir = join_paths(rootlibexecdir, 'system-sleep')
 systemunitdir = join_paths(rootprefixdir, 'lib/systemd/system')
 systempresetdir = join_paths(rootprefixdir, 'lib/systemd/system-preset')
 udevlibexecdir = join_paths(rootprefixdir, 'lib/udev')
-udevhomedir = udevlibexecdir
 udevrulesdir = join_paths(udevlibexecdir, 'rules.d')
 udevhwdbdir = join_paths(udevlibexecdir, 'hwdb.d')
 catalogdir = join_paths(prefixdir, 'lib/systemd/catalog')
@@ -235,11 +239,13 @@ conf.set10('MEMORY_ACCOUNTING_DEFAULT',                       memory_accounting_
 conf.set_quoted('MEMORY_ACCOUNTING_DEFAULT_YES_NO',           memory_accounting_default ? 'yes' : 'no')
 
 substs.set('prefix',                                          prefixdir)
+substs.set('rootprefix',                                      rootprefixdir)
+substs.set('rootprefix_noslash',                              rootprefixdir_noslash)
 substs.set('exec_prefix',                                     prefixdir)
 substs.set('libdir',                                          libdir)
 substs.set('rootlibdir',                                      rootlibdir)
 substs.set('includedir',                                      includedir)
-substs.set('pkgsysconfdir',                                   pkgsysconfdir)
+substs.set('sysconfdir',                                      sysconfdir)
 substs.set('bindir',                                          bindir)
 substs.set('rootbindir',                                      rootbindir)
 substs.set('rootlibexecdir',                                  rootlibexecdir)
@@ -334,6 +340,8 @@ possible_cc_flags = [
         '-Wno-missing-field-initializers',
         '-Wno-unused-result',
         '-Wno-format-signedness',
+        '-Wno-error=#warnings',  # clang
+        '-Wno-string-plus-int',  # clang
 
         # work-around for gcc 7.1 turning this on on its own.
         '-Wno-error=nonnull',
@@ -375,6 +383,16 @@ if get_option('buildtype') != 'debug'
         possible_link_flags += '-Wl,--gc-sections'
 endif
 
+if get_option('b_ndebug') == 'true'
+        # With asserts disabled with get a bunch of warnings about variables which
+        # are used only in the asserts. This is not useful at all, so let's just silence
+        # those warnings.
+        possible_cc_flags += [
+                '-Wno-unused-variable',
+                '-Wno-unused-but-set-variable',
+        ]
+endif
+
 add_project_arguments(cc.get_supported_arguments(possible_cc_flags), language : 'c')
 add_project_link_arguments(cc.get_supported_link_arguments(possible_link_flags), language : 'c')
 
@@ -409,15 +427,11 @@ conf.set('SIZEOF_RLIM_T', cc.sizeof('rlim_t', prefix : '#include <sys/resource.h
 
 decl_headers = '''
 #include <uchar.h>
-#include <linux/ethtool.h>
-#include <linux/fib_rules.h>
 #include <sys/stat.h>
 '''
 
 foreach decl : ['char16_t',
                 'char32_t',
-                'struct fib_rule_uid_range',
-                'struct fib_rule_port_range',
                 'struct statx',
                ]
 
@@ -485,8 +499,8 @@ endif
 
 #####################################################################
 
-vcs_tagger = [meson.source_root() + '/tools/meson-vcs-tag.sh',
-              meson.source_root(),
+vcs_tagger = [project_source_root + '/tools/meson-vcs-tag.sh',
+              project_source_root,
               get_option('version-tag'),
               meson.project_version()]
 
@@ -505,7 +519,7 @@ git = find_program('git', required : false)
 env = find_program('env')
 perl = find_program('perl', required : false)
 
-meson_make_symlink = meson.source_root() + '/tools/meson-make-symlink.sh'
+meson_make_symlink = project_source_root + '/tools/meson-make-symlink.sh'
 mkdir_p = 'mkdir -p $DESTDIR/@0@'
 test_efi_create_disk_sh = find_program('test/test-efi-create-disk.sh')
 splash_bmp = files('test/splash.bmp')
@@ -725,7 +739,9 @@ conf.set10('ENABLE_WHEEL_GROUP', get_option('wheel-group'))
 dev_kvm_mode = get_option('dev-kvm-mode')
 substs.set('DEV_KVM_MODE', dev_kvm_mode)
 conf.set10('DEV_KVM_UACCESS', dev_kvm_mode != '0666')
-substs.set('GROUP_RENDER_MODE', get_option('group-render-mode'))
+group_render_mode = get_option('group-render-mode')
+substs.set('GROUP_RENDER_MODE', group_render_mode)
+conf.set10('GROUP_RENDER_UACCESS', group_render_mode != '0666')
 
 kill_user_processes = get_option('default-kill-user-processes')
 conf.set10('KILL_USER_PROCESSES', kill_user_processes)
@@ -1352,6 +1368,7 @@ includes = include_directories('src/basic',
                                'src/udev',
                                'src/libudev',
                                'src/core',
+                               'src/shutdown',
                                'src/libsystemd/sd-bus',
                                'src/libsystemd/sd-device',
                                'src/libsystemd/sd-event',
@@ -1383,7 +1400,7 @@ libjournal_core = static_library(
         include_directories : includes,
         install : false)
 
-libsystemd_sym_path = '@0@/@1@'.format(meson.current_source_dir(), libsystemd_sym)
+libsystemd_sym_path = '@0@/@1@'.format(project_source_root, libsystemd_sym)
 libsystemd = shared_library(
         'systemd',
         disable_mempool_c,
@@ -1438,6 +1455,7 @@ public_programs = []
 subdir('src/libudev')
 subdir('src/shared')
 subdir('src/core')
+subdir('src/shutdown')
 subdir('src/udev')
 subdir('src/network')
 
@@ -1485,7 +1503,7 @@ foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
                 module = tuple[0]
 
                 sym = 'src/nss-@0@/nss-@0@.sym'.format(module)
-                version_script_arg = join_paths(meson.source_root(), sym)
+                version_script_arg = join_paths(project_source_root, sym)
 
                 nss = shared_library(
                         'nss_' + module,
@@ -1496,8 +1514,7 @@ foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'],
                         # Note that we link NSS modules with '-z nodelete' so that mempools never get orphaned
                         link_args : ['-Wl,-z,nodelete',
                                      '-shared',
-                                     '-Wl,--version-script=' + version_script_arg,
-                                     '-Wl,--undefined'],
+                                     '-Wl,--version-script=' + version_script_arg],
                         link_with : [libsystemd_static,
                                      libbasic],
                         dependencies : [threads,
@@ -1528,7 +1545,8 @@ executable('systemd',
            include_directories : includes,
            link_with : [libcore,
                         libshared],
-           dependencies : [threads,
+           dependencies : [versiondep,
+                           threads,
                            librt,
                            libseccomp,
                            libselinux,
@@ -1547,7 +1565,8 @@ exe = executable('systemd-analyze',
                  include_directories : includes,
                  link_with : [libcore,
                               libshared],
-                 dependencies : [threads,
+                 dependencies : [versiondep,
+                                 threads,
                                  librt,
                                  libseccomp,
                                  libselinux,
@@ -1620,9 +1639,9 @@ executable('systemd-run-generator',
 
 executable('systemd-fstab-generator',
            'src/fstab-generator/fstab-generator.c',
-           'src/core/mount-setup.c',
            include_directories : includes,
-           link_with : [libshared],
+           link_with : [libcore_shared,
+                        libshared],
            install_rpath : rootlibexecdir,
            install : true,
            install_dir : systemgeneratordir)
@@ -1749,7 +1768,7 @@ if conf.get('ENABLE_LOGIND') == 1
         public_programs += exe
 
         if conf.get('HAVE_PAM') == 1
-                version_script_arg = join_paths(meson.source_root(), pam_systemd_sym)
+                version_script_arg = join_paths(project_source_root, pam_systemd_sym)
                 pam_systemd = shared_library(
                         'pam_systemd',
                         pam_systemd_c,
@@ -1848,7 +1867,10 @@ else
                                libbasic_gcrypt]
 endif
 
-exe = executable('systemctl', 'src/systemctl/systemctl.c',
+exe = executable('systemctl',
+                 'src/systemctl/systemctl.c',
+                 'src/systemctl/sysv-compat.h',
+                 'src/systemctl/sysv-compat.c',
                  include_directories : includes,
                  link_with : systemctl_link_with,
                  dependencies : [threads,
@@ -2093,7 +2115,8 @@ if conf.get('ENABLE_IMPORTD') == 1
                                   systemd_pull_sources,
                                   include_directories : includes,
                                   link_with : [libshared],
-                                  dependencies : [libcurl,
+                                  dependencies : [versiondep,
+                                                  libcurl,
                                                   libz,
                                                   libbzip2,
                                                   libxz,
@@ -2142,7 +2165,8 @@ if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_LIBCURL') == 1
                          systemd_journal_upload_sources,
                          include_directories : includes,
                          link_with : [libshared],
-                         dependencies : [threads,
+                         dependencies : [versiondep,
+                                         threads,
                                          libcurl,
                                          libgnutls,
                                          libxz,
@@ -2258,20 +2282,18 @@ endif
 
 executable('systemd-remount-fs',
            'src/remount-fs/remount-fs.c',
-           'src/core/mount-setup.c',
-           'src/core/mount-setup.h',
            include_directories : includes,
-           link_with : [libshared],
+           link_with : [libcore_shared,
+                        libshared],
            install_rpath : rootlibexecdir,
            install : true,
            install_dir : rootlibexecdir)
 
 executable('systemd-machine-id-setup',
            'src/machine-id-setup/machine-id-setup-main.c',
-           'src/core/machine-id-setup.c',
-           'src/core/machine-id-setup.h',
            include_directories : includes,
-           link_with : [libshared],
+           link_with : [libcore_shared,
+                        libshared],
            install_rpath : rootlibexecdir,
            install : true,
            install_dir : rootbindir)
@@ -2480,6 +2502,7 @@ exe = executable('systemd-stdio-bridge',
                  'src/stdio-bridge/stdio-bridge.c',
                  include_directories : includes,
                  link_with : [libshared],
+                 dependencies : [versiondep],
                  install_rpath : rootlibexecdir,
                  install : true)
 public_programs += exe
@@ -2563,7 +2586,8 @@ exe = executable('systemd-udevd',
                  link_with : [libudev_core,
                               libsystemd_network,
                               libudev_static],
-                 dependencies : [threads,
+                 dependencies : [versiondep,
+                                 threads,
                                  libkmod,
                                  libidn,
                                  libacl,
@@ -2580,7 +2604,8 @@ exe = executable('udevadm',
                  link_with : [libudev_core,
                               libsystemd_network,
                               libudev_static],
-                 dependencies : [threads,
+                 dependencies : [versiondep,
+                                 threads,
                                  libkmod,
                                  libidn,
                                  libacl,
@@ -2593,7 +2618,8 @@ public_programs += exe
 executable('systemd-shutdown',
            systemd_shutdown_sources,
            include_directories : includes,
-           link_with : [libshared],
+           link_with : [libcore_shared,
+                        libshared],
            dependencies : [libmount],
            install_rpath : rootlibexecdir,
            install : true,
@@ -2634,14 +2660,12 @@ endif
 
 exe = executable('systemd-nspawn',
                  systemd_nspawn_sources,
-                 'src/core/mount-setup.c', # FIXME: use a variable?
-                 'src/core/mount-setup.h',
-                 'src/core/loopback-setup.c',
-                 'src/core/loopback-setup.h',
                  include_directories : includes,
-                 link_with : [libnspawn_core,
+                 link_with : [libcore_shared,
+                              libnspawn_core,
                               libshared],
-                 dependencies : [libblkid],
+                 dependencies : [libblkid,
+                                 libseccomp],
                  install_rpath : rootlibexecdir,
                  install : true)
 public_programs += exe
@@ -2693,7 +2717,7 @@ custom_target(
         'systemd-runtest.env',
         output : 'systemd-runtest.env',
         command : ['sh', '-c', '{ ' +
-                   'echo SYSTEMD_TEST_DATA=@0@; '.format(join_paths(meson.current_source_dir(), 'test')) +
+                   'echo SYSTEMD_TEST_DATA=@0@; '.format(join_paths(project_source_root, 'test')) +
                    'echo SYSTEMD_CATALOG_DIR=@0@; '.format(join_paths(meson.current_build_dir(), 'catalog')) +
                    '} >@OUTPUT@'],
         build_by_default : true)
@@ -2720,7 +2744,8 @@ foreach tuple : tests
                         sources,
                         include_directories : incs,
                         link_with : link_with,
-                        dependencies : dependencies,
+                        dependencies : [versiondep,
+                                        dependencies],
                         c_args : defs,
                         build_by_default : want_tests != 'false',
                         install_rpath : rootlibexecdir,
@@ -2922,7 +2947,7 @@ foreach tuple : sanitizers
                                 test('@0@:@1@:@2@'.format(b, c, sanitizer),
                                      env,
                                      args : [exe.full_path(),
-                                             join_paths(meson.source_root(), p)])
+                                             join_paths(project_source_root, p)])
                         endif
                 endforeach
         endif
@@ -2934,7 +2959,7 @@ endforeach
 if git.found()
         all_files = run_command(
                 git,
-                ['--git-dir=@0@/.git'.format(meson.source_root()),
+                ['--git-dir=@0@/.git'.format(project_source_root),
                  'ls-files',
                  ':/*.[ch]'])
         all_files = files(all_files.stdout().split())
@@ -2942,10 +2967,10 @@ if git.found()
         custom_target(
                 'tags',
                 output : 'tags',
-                command : [env, 'etags', '-o', '@0@/TAGS'.format(meson.source_root())] + all_files)
+                command : [env, 'etags', '-o', '@0@/TAGS'.format(project_source_root)] + all_files)
         run_target(
                 'ctags',
-                command : [env, 'ctags', '-o', '@0@/tags'.format(meson.source_root())] + all_files)
+                command : [env, 'ctags', '-o', '@0@/tags'.format(project_source_root)] + all_files)
 endif
 
 if git.found()
@@ -2958,17 +2983,17 @@ endif
 if git.found()
         git_head = run_command(
                 git,
-                ['--git-dir=@0@/.git'.format(meson.source_root()),
+                ['--git-dir=@0@/.git'.format(project_source_root),
                  'rev-parse', 'HEAD']).stdout().strip()
         git_head_short = run_command(
                 git,
-                ['--git-dir=@0@/.git'.format(meson.source_root()),
+                ['--git-dir=@0@/.git'.format(project_source_root),
                  'rev-parse', '--short=7', 'HEAD']).stdout().strip()
 
         run_target(
                 'git-snapshot',
                 command : ['git', 'archive',
-                           '-o', '@0@/systemd-@1@.tar.gz'.format(meson.source_root(),
+                           '-o', '@0@/systemd-@1@.tar.gz'.format(project_source_root,
                                                                  git_head_short),
                            '--prefix', 'systemd-@0@/'.format(git_head),
                            'HEAD'])
index 34fab86..cd0f1db 100644 (file)
@@ -11,7 +11,7 @@ option('split-bin', type : 'combo', choices : ['auto', 'true', 'false'],
 option('rootlibdir', type : 'string',
        description : '''[/usr]/lib/x86_64-linux-gnu or such''')
 option('rootprefix', type : 'string',
-       description : '''override the root prefix''')
+       description : '''override the root prefix [default '/' if split-usr and '/usr' otherwise]''')
 option('link-udev-shared', type : 'boolean',
        description : 'link systemd-udev and its helpers to libsystemd-shared.so')
 option('link-systemctl-shared', type: 'boolean',
@@ -213,7 +213,7 @@ option('dns-over-tls', type : 'combo', choices : ['auto', 'gnutls', 'openssl', '
        description : 'DNS-over-TLS support')
 option('dns-servers', type : 'string',
        description : 'space-separated list of default DNS servers',
-       value : '8.8.8.8 8.8.4.4 2001:4860:4860::8888 2001:4860:4860::8844')
+       value : '1.1.1.1 8.8.8.8 1.0.0.1 8.8.4.4 2606:4700:4700::1111 2001:4860:4860::8888 2606:4700:4700::1001 2001:4860:4860::8844')
 option('ntp-servers', type : 'string',
        description : 'space-separated list of default NTP servers',
        value : 'time1.google.com time2.google.com time3.google.com time4.google.com')
index 3f09fb2..c9d086f 100755 (executable)
@@ -95,3 +95,7 @@ EOF
 mkdir -p "$DESTDIR"/boot/efi/EFI/systemd "$DESTDIR"/boot/efi/EFI/BOOT
 cp "$DESTDIR"/usr/lib/systemd/boot/efi/systemd-bootx64.efi "$DESTDIR"/boot/efi/EFI/systemd/systemd-bootx64.efi
 cp "$DESTDIR"/usr/lib/systemd/boot/efi/systemd-bootx64.efi "$DESTDIR"/boot/efi/EFI/BOOT/bootx64.efi
+
+mkdir -p "$DESTDIR"/efi/EFI/systemd "$DESTDIR"/efi/EFI/BOOT
+cp "$DESTDIR"/usr/lib/systemd/boot/efi/systemd-bootx64.efi "$DESTDIR"/efi/EFI/systemd/systemd-bootx64.efi
+cp "$DESTDIR"/usr/lib/systemd/boot/efi/systemd-bootx64.efi "$DESTDIR"/efi/EFI/BOOT/bootx64.efi
index 12b2381..a7d334b 100644 (file)
@@ -48,7 +48,7 @@
                DESTDIR=%{buildroot} %{__ninja} install %{__ninja_common_opts}
 
 Name:           systemd
-Version:        241
+Version:        242
 Release:        0%{?release_flags}
 # For a breakdown of the licensing, see README
 License:        LGPL-2.1+ and GPL-2.0+
@@ -462,6 +462,7 @@ fi
 %{_bindir}/systemd-run
 %dir %{_prefix}/lib/kernel
 %dir %{_prefix}/lib/kernel/install.d
+%{_prefix}/lib/kernel/install.d/00-entry-directory.install
 %{_prefix}/lib/kernel/install.d/50-depmod.install
 %{_prefix}/lib/kernel/install.d/90-loaderentry.install
 %if %{?WITH_HOSTNAMED}
index ca35901..3f09978 100644 (file)
--- a/po/fr.po
+++ b/po/fr.po
@@ -7,8 +7,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2018-11-02 14:28+0100\n"
-"PO-Revision-Date: 2018-11-02 14:32+0100\n"
+"POT-Creation-Date: 2019-03-07 22:43+0100\n"
+"PO-Revision-Date: 2019-03-07 23:09+0100\n"
 "Last-Translator: Sylvain Plantefève <sylvain.plantefeve@gmail.com>\n"
 "Language-Team: French\n"
 "Language: fr\n"
@@ -489,10 +489,9 @@ msgstr ""
 "actives."
 
 #: src/login/org.freedesktop.login1.policy:341
-msgid "Allow indication to the firmware to boot to setup interface"
+msgid "Indicate to the firmware to boot to setup interface"
 msgstr ""
-"Permet d'indiquer au micrologiciel de démarrer sur l'interface de "
-"configuration"
+"Indiquer au micrologiciel de démarrer sur l'interface de configuration"
 
 #: src/login/org.freedesktop.login1.policy:342
 msgid ""
@@ -502,11 +501,35 @@ msgstr ""
 "Authentification requise pour indiquer au micrologiciel de démarrer sur "
 "l'interface de configuration."
 
-#: src/login/org.freedesktop.login1.policy:351
+#: src/login/org.freedesktop.login1.policy:352
+msgid "Indicate to the boot loader to boot to the boot loader menu"
+msgstr "Indiquer au programme d'amorçage d'afficher le menu au démarrage"
+
+#: src/login/org.freedesktop.login1.policy:353
+msgid ""
+"Authentication is required to indicate to the boot loader to boot to the "
+"boot loader menu."
+msgstr ""
+"Authentification requise pour indiquer au programme d'amorçage d'afficher "
+"le menu au démarrage."
+
+#: src/login/org.freedesktop.login1.policy:363
+msgid "Indicate to the boot loader to boot a specific entry"
+msgstr "Indiquer au programme d'amorçage de démarrer une entrée spécifique"
+
+#: src/login/org.freedesktop.login1.policy:364
+msgid ""
+"Authentication is required to indicate to the boot loader to boot into a "
+"specific boot loader entry."
+msgstr ""
+"Authentification requise pour indiquer au programme d'amorçage de démarrer "
+"une entrée spécifique."
+
+#: src/login/org.freedesktop.login1.policy:374
 msgid "Set a wall message"
 msgstr "Définir un message wall"
 
-#: src/login/org.freedesktop.login1.policy:352
+#: src/login/org.freedesktop.login1.policy:375
 msgid "Authentication is required to set a wall message"
 msgstr "Authentification requise pour définir un message wall."
 
index 731657d..e11bbad 100644 (file)
--- a/po/ja.po
+++ b/po/ja.po
@@ -5,8 +5,8 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
-"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2018-10-27 07:32+0900\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2019-04-01 11:27+0900\n"
 "PO-Revision-Date: 2018-10-27 07:41+0900\n"
 "Last-Translator: Yu Watanabe <watanabe.yu+github@gmail.com>\n"
 "Language-Team: \n"
@@ -38,7 +38,9 @@ msgstr "システムサービスファイルやその他のユニットファイ
 
 #: src/core/org.freedesktop.systemd1.policy.in:44
 msgid "Authentication is required to manage system service or unit files."
-msgstr "システムサービスファイルやその他のユニットファイルを管理するには認証が必要です。"
+msgstr ""
+"システムサービスファイルやその他のユニットファイルを管理するには認証が必要で"
+"す。"
 
 #: src/core/org.freedesktop.systemd1.policy.in:54
 msgid "Set or unset system and service manager environment variables"
@@ -114,7 +116,8 @@ msgstr "仮想マシンもしくはコンテナイメージのダウンロード
 
 #: src/import/org.freedesktop.import1.policy:43
 msgid "Authentication is required to download a VM or container image"
-msgstr "仮想マシンもしくはコンテナイメージをダウンロードするには認証が必要です。"
+msgstr ""
+"仮想マシンもしくはコンテナイメージをダウンロードするには認証が必要です。"
 
 #: src/locale/org.freedesktop.locale1.policy:22
 msgid "Set system locale"
@@ -139,7 +142,8 @@ msgstr "アプリケーションがシステムのシャットダウンを阻害
 #: src/login/org.freedesktop.login1.policy:23
 msgid ""
 "Authentication is required for an application to inhibit system shutdown."
-msgstr "アプリケーションがシステムのシャットダウンを阻害するには認証が必要です。"
+msgstr ""
+"アプリケーションがシステムのシャットダウンを阻害するには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:33
 msgid "Allow applications to delay system shutdown"
@@ -147,7 +151,8 @@ msgstr "アプリケーションがシステムのシャットダウンを遅延
 
 #: src/login/org.freedesktop.login1.policy:34
 msgid "Authentication is required for an application to delay system shutdown."
-msgstr "アプリケーションがシステムのシャットダウンを遅延させるには認証が必要です。"
+msgstr ""
+"アプリケーションがシステムのシャットダウンを遅延させるには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:44
 msgid "Allow applications to inhibit system sleep"
@@ -173,7 +178,8 @@ msgstr "アプリケーションがシステムの自動的なサスペンドを
 msgid ""
 "Authentication is required for an application to inhibit automatic system "
 "suspend."
-msgstr "アプリケーションがシステムの自動的なサスペンドを阻害するには認証が必要です。"
+msgstr ""
+"アプリケーションがシステムの自動的なサスペンドを阻害するには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:75
 msgid "Allow applications to inhibit system handling of the power key"
@@ -193,7 +199,8 @@ msgstr "アプリケーションがサスペンドキーによる動作を阻害
 msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the suspend key."
-msgstr "アプリケーションがサスペンドキーによる動作を阻害するには認証が必要です。"
+msgstr ""
+"アプリケーションがサスペンドキーによる動作を阻害するには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:97
 msgid "Allow applications to inhibit system handling of the hibernate key"
@@ -203,7 +210,8 @@ msgstr "アプリケーションがハイバネートキーによる動作を阻
 msgid ""
 "Authentication is required for an application to inhibit system handling of "
 "the hibernate key."
-msgstr "アプリケーションがハイバネートキーによる動作を阻害するには認証が必要です。"
+msgstr ""
+"アプリケーションがハイバネートキーによる動作を阻害するには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:107
 msgid "Allow applications to inhibit system handling of the lid switch"
@@ -221,7 +229,8 @@ msgstr "ログインしていないユーザがプログラムを実行するこ
 
 #: src/login/org.freedesktop.login1.policy:118
 msgid "Explicit request is required to run programs as a non-logged-in user."
-msgstr "ログインしていないユーザがプログラムを実行するには明示的な要求が必要です。"
+msgstr ""
+"ログインしていないユーザがプログラムを実行するには明示的な要求が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:127
 msgid "Allow non-logged-in users to run programs"
@@ -264,7 +273,8 @@ msgstr "他のユーザがログインしている状態でシステムの電源
 msgid ""
 "Authentication is required for powering off the system while other users are "
 "logged in."
-msgstr "他のユーザがログインしている状態でシステムの電源を切るには認証が必要です。"
+msgstr ""
+"他のユーザがログインしている状態でシステムの電源を切るには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:180
 msgid "Power off the system while an application asked to inhibit it"
@@ -274,7 +284,9 @@ msgstr "アプリケーションが使用されている状態でシステムの
 msgid ""
 "Authentication is required for powering off the system while an application "
 "asked to inhibit it."
-msgstr "アプリケーションが使用されている状態でシステムの電源を切るには認証が必要です。"
+msgstr ""
+"アプリケーションが使用されている状態でシステムの電源を切るには認証が必要で"
+"す。"
 
 #: src/login/org.freedesktop.login1.policy:191
 msgid "Reboot the system"
@@ -292,7 +304,8 @@ msgstr "他のユーザがログインしている状態でシステムを再起
 msgid ""
 "Authentication is required for rebooting the system while other users are "
 "logged in."
-msgstr "他のユーザがログインしている状態でシステムを再起動するには認証が必要です。"
+msgstr ""
+"他のユーザがログインしている状態でシステムを再起動するには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:213
 msgid "Reboot the system while an application asked to inhibit it"
@@ -302,7 +315,9 @@ msgstr "アプリケーションが使用されている状態でシステムを
 msgid ""
 "Authentication is required for rebooting the system while an application "
 "asked to inhibit it."
-msgstr "アプリケーションが使用されている状態でシステムを再起動するには認証が必要です。"
+msgstr ""
+"アプリケーションが使用されている状態でシステムを再起動するには認証が必要で"
+"す。"
 
 #: src/login/org.freedesktop.login1.policy:224
 msgid "Halt the system"
@@ -320,7 +335,8 @@ msgstr "他のユーザがログインしている状態でシステムを停止
 msgid ""
 "Authentication is required for halting the system while other users are "
 "logged in."
-msgstr "他のユーザがログインしている状態でシステムを停止するには認証が必要です。"
+msgstr ""
+"他のユーザがログインしている状態でシステムを停止するには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:246
 msgid "Halt the system while an application asked to inhibit it"
@@ -330,7 +346,8 @@ msgstr "アプリケーションが使用されている状態でシステムを
 msgid ""
 "Authentication is required for halting the system while an application asked "
 "to inhibit it."
-msgstr "アプリケーションが使用されている状態でシステムを停止するには認証が必要です。"
+msgstr ""
+"アプリケーションが使用されている状態でシステムを停止するには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:257
 msgid "Suspend the system"
@@ -348,7 +365,9 @@ msgstr "他のユーザがログインしている状態でシステムをサス
 msgid ""
 "Authentication is required for suspending the system while other users are "
 "logged in."
-msgstr "他のユーザがログインしている状態でシステムをサスペンドするには認証が必要です。"
+msgstr ""
+"他のユーザがログインしている状態でシステムをサスペンドするには認証が必要で"
+"す。"
 
 #: src/login/org.freedesktop.login1.policy:278
 msgid "Suspend the system while an application asked to inhibit it"
@@ -358,7 +377,9 @@ msgstr "アプリケーションが使用されている状態でシステムを
 msgid ""
 "Authentication is required for suspending the system while an application "
 "asked to inhibit it."
-msgstr "アプリケーションが使用されている状態でシステムをサスペンドするには認証が必要です。"
+msgstr ""
+"アプリケーションが使用されている状態でシステムをサスペンドするには認証が必要"
+"です。"
 
 #: src/login/org.freedesktop.login1.policy:289
 msgid "Hibernate the system"
@@ -376,7 +397,9 @@ msgstr "他のユーザがログインしている状態でシステムをハイ
 msgid ""
 "Authentication is required for hibernating the system while other users are "
 "logged in."
-msgstr "他のユーザがログインしている状態でシステムをハイバネートするには認証が必要です。"
+msgstr ""
+"他のユーザがログインしている状態でシステムをハイバネートするには認証が必要で"
+"す。"
 
 #: src/login/org.freedesktop.login1.policy:310
 msgid "Hibernate the system while an application asked to inhibit it"
@@ -386,7 +409,9 @@ msgstr "アプリケーションが使用されている状態でシステムを
 msgid ""
 "Authentication is required for hibernating the system while an application "
 "asked to inhibit it."
-msgstr "アプリケーションが使用されている状態でシステムをハイバネートするには認証が必要です。"
+msgstr ""
+"アプリケーションが使用されている状態でシステムをハイバネートするには認証が必"
+"要です。"
 
 #: src/login/org.freedesktop.login1.policy:321
 msgid "Manage active sessions, users and seats"
@@ -403,23 +428,56 @@ msgstr "アクティブなセッションのロックもしくはアンロック
 
 #: src/login/org.freedesktop.login1.policy:332
 msgid "Authentication is required to lock or unlock active sessions."
-msgstr "アクティブなセッションをロックもしくはアンロックするには認証が必要です。"
+msgstr ""
+"アクティブなセッションをロックもしくはアンロックするには認証が必要です。"
 
 #: src/login/org.freedesktop.login1.policy:341
-msgid "Allow indication to the firmware to boot to setup interface"
-msgstr "ファームウェアに「インターフェースの設定を起動」を表示する"
+msgid "Set the reboot \"reason\" in the kernel"
+msgstr "再起動の理由を設定する"
 
 #: src/login/org.freedesktop.login1.policy:342
+msgid "Authentication is required to set the reboot \"reason\" in the kernel."
+msgstr "再起動の理由を設定するには認証が必要です。"
+
+#: src/login/org.freedesktop.login1.policy:352
+msgid "Indicate to the firmware to boot to setup interface"
+msgstr "ファームウェアに「インターフェースの設定を起動」を表示させる"
+
+#: src/login/org.freedesktop.login1.policy:353
 msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
-msgstr "ファームウェアに「インターフェースの設定を起動」を表示するには認証が必要です。"
+msgstr ""
+"ファームウェアに「インターフェースの設定を起動」を表示させるには認証が必要で"
+"す。"
+
+#: src/login/org.freedesktop.login1.policy:363
+msgid "Indicate to the boot loader to boot to the boot loader menu"
+msgstr "ブートローダにブートローダメニューを起動するための項目を表示させる。"
 
-#: src/login/org.freedesktop.login1.policy:351
+#: src/login/org.freedesktop.login1.policy:364
+msgid ""
+"Authentication is required to indicate to the boot loader to boot to the "
+"boot loader menu."
+msgstr ""
+"ブートローダにブートローダメニューを起動するための項目を表示させるには認証が"
+"必要です。"
+
+#: src/login/org.freedesktop.login1.policy:374
+msgid "Indicate to the boot loader to boot a specific entry"
+msgstr "ブートローダに特定の項目を表示させる"
+
+#: src/login/org.freedesktop.login1.policy:375
+msgid ""
+"Authentication is required to indicate to the boot loader to boot into a "
+"specific boot loader entry."
+msgstr "ブートローダに特定の項目を表示させるには認証が必要です。"
+
+#: src/login/org.freedesktop.login1.policy:385
 msgid "Set a wall message"
 msgstr "全ユーザへのメッセージの設定"
 
-#: src/login/org.freedesktop.login1.policy:352
+#: src/login/org.freedesktop.login1.policy:386
 msgid "Authentication is required to set a wall message"
 msgstr "全ユーザへのメッセージを設定するには認証が必要です。"
 
@@ -557,7 +615,9 @@ msgstr "ハードウェア時刻をローカルタイムゾーンもしくはUTC
 msgid ""
 "Authentication is required to control whether the RTC stores the local or "
 "UTC time."
-msgstr "ハードウェア時刻をローカルタイムゾーンもしくはUTCに設定するには認証が必要です。"
+msgstr ""
+"ハードウェア時刻をローカルタイムゾーンもしくはUTCに設定するには認証が必要で"
+"す。"
 
 #: src/timedate/org.freedesktop.timedate1.policy:53
 msgid "Turn network time synchronization on or off"
@@ -569,32 +629,32 @@ msgid ""
 "shall be enabled."
 msgstr "ネットワーク経由の時刻同期を有効もしくは無効にするには認証が必要です。"
 
-#: src/core/dbus-unit.c:326
+#: src/core/dbus-unit.c:316
 msgid "Authentication is required to start '$(unit)'."
 msgstr "'$(unit)'を開始するには認証が必要です。"
 
-#: src/core/dbus-unit.c:327
+#: src/core/dbus-unit.c:317
 msgid "Authentication is required to stop '$(unit)'."
 msgstr "'$(unit)'を停止するには認証が必要です。"
 
-#: src/core/dbus-unit.c:328
+#: src/core/dbus-unit.c:318
 msgid "Authentication is required to reload '$(unit)'."
 msgstr "'$(unit)'を再読込するには認証が必要です。"
 
-#: src/core/dbus-unit.c:329 src/core/dbus-unit.c:330
+#: src/core/dbus-unit.c:319 src/core/dbus-unit.c:320
 msgid "Authentication is required to restart '$(unit)'."
 msgstr "'$(unit)'を再起動するには認証が必要です。"
 
-#: src/core/dbus-unit.c:437
+#: src/core/dbus-unit.c:492
 msgid ""
 "Authentication is required to send a UNIX signal to the processes of "
 "'$(unit)'."
 msgstr "'$(unit)'のプロセスにUNIXシグナルを送るには認証が必要です。"
 
-#: src/core/dbus-unit.c:468
+#: src/core/dbus-unit.c:523
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr "'$(unit)'の「失敗」状態をリセットするには認証が必要です。"
 
-#: src/core/dbus-unit.c:501
+#: src/core/dbus-unit.c:556
 msgid "Authentication is required to set properties on '$(unit)'."
 msgstr "'$(unit)'のプロパティを設定するには認証が必要です。"
index 13e8f3e..3790f9c 100644 (file)
--- a/po/lt.po
+++ b/po/lt.po
@@ -3,15 +3,15 @@ msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2018-10-31 03:25+0000\n"
-"PO-Revision-Date: 2018-10-31 14:50+0200\n"
+"POT-Creation-Date: 2019-04-08 15:29+0000\n"
+"PO-Revision-Date: 2019-04-08 22:01+0300\n"
 "Last-Translator: Moo\n"
 "Language-Team: Lithuanian\n"
 "Language: lt\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 2.2\n"
+"X-Generator: Poedit 2.2.1\n"
 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n"
 "%100<10 || n%100>=20) ? 1 : 2);\n"
 
@@ -468,11 +468,20 @@ msgstr ""
 "Norint užrakinti ar atrakinti aktyvius seansus, reikia nustatyti tapatybę."
 
 #: src/login/org.freedesktop.login1.policy:341
-msgid "Allow indication to the firmware to boot to setup interface"
-msgstr ""
-"Leisti nurodymą programinei aparatinei įrangai pasileisti į sąrankos sąsają"
+msgid "Set the reboot \"reason\" in the kernel"
+msgstr "Nustatyti paleidimo iš naujo \"priežastį\" branduolyje"
 
 #: src/login/org.freedesktop.login1.policy:342
+msgid "Authentication is required to set the reboot \"reason\" in the kernel."
+msgstr ""
+"Norint nustatyti paleidimo iš naujo \"priežastį\" branduolyje, reikia "
+"nustatyti tapatybę."
+
+#: src/login/org.freedesktop.login1.policy:352
+msgid "Indicate to the firmware to boot to setup interface"
+msgstr "Nurodyti programinei aparatinei įrangai pasileisti į sąrankos sąsają"
+
+#: src/login/org.freedesktop.login1.policy:353
 msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
@@ -480,11 +489,35 @@ msgstr ""
 "Norint nurodyti programinei aparatinei įrangai pasileisti į sąrankos sąsają, "
 "reikia nustatyti tapatybę."
 
-#: src/login/org.freedesktop.login1.policy:351
+#: src/login/org.freedesktop.login1.policy:363
+msgid "Indicate to the boot loader to boot to the boot loader menu"
+msgstr "Nurodyti pradiniam įkėlikliui paleisti pradinio įkėliklio meniu"
+
+#: src/login/org.freedesktop.login1.policy:364
+msgid ""
+"Authentication is required to indicate to the boot loader to boot to the "
+"boot loader menu."
+msgstr ""
+"Norint nurodyti pradiniam įkėlikliui paleisti pradinio įkėliklio meniu, "
+"reikia nustatyti tapatybę."
+
+#: src/login/org.freedesktop.login1.policy:374
+msgid "Indicate to the boot loader to boot a specific entry"
+msgstr "Nurodyti pradiniam įkėlikliui paleisti tam tikrą įrašą"
+
+#: src/login/org.freedesktop.login1.policy:375
+msgid ""
+"Authentication is required to indicate to the boot loader to boot into a "
+"specific boot loader entry."
+msgstr ""
+"Norint nurodyti pradiniam įkėlikliui paleisti tam tikrą pradinio įkėliklio "
+"įrašą, reikia nustatyti tapatybę."
+
+#: src/login/org.freedesktop.login1.policy:385
 msgid "Set a wall message"
 msgstr "Nustatyti sienos pranešimą"
 
-#: src/login/org.freedesktop.login1.policy:352
+#: src/login/org.freedesktop.login1.policy:386
 msgid "Authentication is required to set a wall message"
 msgstr "Norint nustatyti sienos pranešimą, reikia nustatyti tapatybę"
 
@@ -654,36 +687,36 @@ msgstr ""
 "Norint valdyti ar tinklo laiko sinchronizavimas turėtų būti įjungtas, reikia "
 "nustatyti tapatybę."
 
-#: src/core/dbus-unit.c:326
+#: src/core/dbus-unit.c:316
 msgid "Authentication is required to start '$(unit)'."
 msgstr "Norint paleisti \"$(unit)\", reikia nustatyti tapatybę."
 
-#: src/core/dbus-unit.c:327
+#: src/core/dbus-unit.c:317
 msgid "Authentication is required to stop '$(unit)'."
 msgstr "Norint stabdyti \"$(unit)\", reikia nustatyti tapatybę."
 
-#: src/core/dbus-unit.c:328
+#: src/core/dbus-unit.c:318
 msgid "Authentication is required to reload '$(unit)'."
 msgstr "Norint įkelti \"$(unit)\" iš naujo, reikia nustatyti tapatybę."
 
-#: src/core/dbus-unit.c:329 src/core/dbus-unit.c:330
+#: src/core/dbus-unit.c:319 src/core/dbus-unit.c:320
 msgid "Authentication is required to restart '$(unit)'."
 msgstr "Norint paleisti \"$(unit)\" iš naujo, reikia nustatyti tapatybę."
 
-#: src/core/dbus-unit.c:437
+#: src/core/dbus-unit.c:492
 msgid ""
 "Authentication is required to send a UNIX signal to the processes of "
 "'$(unit)'."
 msgstr ""
 "Norint siųsti UNIX signalą į \"$(unit)\" procesus, reikia nustatyti tapatybę."
 
-#: src/core/dbus-unit.c:468
+#: src/core/dbus-unit.c:523
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr ""
 "Norint atstatyti \"$(unit)\" įtaiso \"failed\" būseną, reikia nustatyti "
 "tapatybę."
 
-#: src/core/dbus-unit.c:501
+#: src/core/dbus-unit.c:556
 msgid "Authentication is required to set properties on '$(unit)'."
 msgstr "Norint nustatyti \"$(unit)\" savybes, reikia nustatyti tapatybę."
 
index 80c9c97..4850bda 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -6,8 +6,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: systemd\n"
 "Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n"
-"POT-Creation-Date: 2018-10-26 19:14+0000\n"
-"PO-Revision-Date: 2018-10-26 21:15+0200\n"
+"POT-Creation-Date: 2019-03-26 15:29+0000\n"
+"PO-Revision-Date: 2019-03-26 17:28+0100\n"
 "Last-Translator: Piotr Drąg <piotrdrag@gmail.com>\n"
 "Language-Team: Polish <trans-pl@lists.fedoraproject.org>\n"
 "Language: pl\n"
@@ -469,10 +469,20 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby zablokować lub odblokować aktywne sesje."
 
 #: src/login/org.freedesktop.login1.policy:341
-msgid "Allow indication to the firmware to boot to setup interface"
-msgstr "Wskazanie oprogramowaniu sprzętowemu, aby uruchomić interfejs ustawień"
+msgid "Set the reboot \"reason\" in the kernel"
+msgstr "Ustawienie przyczyny ponownego uruchomienia w jądrze"
 
 #: src/login/org.freedesktop.login1.policy:342
+msgid "Authentication is required to set the reboot \"reason\" in the kernel."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby ustawić przyczynę ponownego uruchomienia "
+"w jądrze."
+
+#: src/login/org.freedesktop.login1.policy:352
+msgid "Indicate to the firmware to boot to setup interface"
+msgstr "Wskazanie oprogramowaniu sprzętowemu, aby uruchomić interfejs ustawień"
+
+#: src/login/org.freedesktop.login1.policy:353
 msgid ""
 "Authentication is required to indicate to the firmware to boot to setup "
 "interface."
@@ -480,11 +490,35 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wskazać oprogramowaniu sprzętowemu, że "
 "należy uruchomić interfejs ustawień."
 
-#: src/login/org.freedesktop.login1.policy:351
+#: src/login/org.freedesktop.login1.policy:363
+msgid "Indicate to the boot loader to boot to the boot loader menu"
+msgstr "Wskazanie programowi startowemu, aby uruchomić jego menu"
+
+#: src/login/org.freedesktop.login1.policy:364
+msgid ""
+"Authentication is required to indicate to the boot loader to boot to the "
+"boot loader menu."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby wskazać programowi startowemu, że należy "
+"uruchomić jego menu."
+
+#: src/login/org.freedesktop.login1.policy:374
+msgid "Indicate to the boot loader to boot a specific entry"
+msgstr "Wskazanie programowi startowemu, aby uruchomić podany wpis"
+
+#: src/login/org.freedesktop.login1.policy:375
+msgid ""
+"Authentication is required to indicate to the boot loader to boot into a "
+"specific boot loader entry."
+msgstr ""
+"Wymagane jest uwierzytelnienie, aby wskazać programowi startowemu, że należy "
+"uruchomić podany wpis."
+
+#: src/login/org.freedesktop.login1.policy:385
 msgid "Set a wall message"
 msgstr "Ustawienie komunikatu wall"
 
-#: src/login/org.freedesktop.login1.policy:352
+#: src/login/org.freedesktop.login1.policy:386
 msgid "Authentication is required to set a wall message"
 msgstr "Wymagane jest uwierzytelnienie, aby ustawić komunikat wall"
 
@@ -653,25 +687,25 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby kontrolować, czy włączyć synchronizację "
 "czasu przez sieć."
 
-#: src/core/dbus-unit.c:326
+#: src/core/dbus-unit.c:325
 msgid "Authentication is required to start '$(unit)'."
 msgstr "Wymagane jest uwierzytelnienie, aby uruchomić jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:327
+#: src/core/dbus-unit.c:326
 msgid "Authentication is required to stop '$(unit)'."
 msgstr "Wymagane jest uwierzytelnienie, aby zatrzymać jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:328
+#: src/core/dbus-unit.c:327
 msgid "Authentication is required to reload '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie wczytać jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:329 src/core/dbus-unit.c:330
+#: src/core/dbus-unit.c:328 src/core/dbus-unit.c:329
 msgid "Authentication is required to restart '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ponownie uruchomić jednostkę „$(unit)”."
 
-#: src/core/dbus-unit.c:437
+#: src/core/dbus-unit.c:434
 msgid ""
 "Authentication is required to send a UNIX signal to the processes of "
 "'$(unit)'."
@@ -679,13 +713,13 @@ msgstr ""
 "Wymagane jest uwierzytelnienie, aby wysłać sygnał uniksowy do procesów "
 "jednostki „$(unit)”."
 
-#: src/core/dbus-unit.c:468
+#: src/core/dbus-unit.c:465
 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby przywrócić stan „failed” (niepowodzenia) "
 "jednostki „$(unit)”."
 
-#: src/core/dbus-unit.c:501
+#: src/core/dbus-unit.c:498
 msgid "Authentication is required to set properties on '$(unit)'."
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby ustawić właściwości jednostki „$(unit)”."
index a1458e9..491081f 100644 (file)
@@ -8,4 +8,4 @@ ACTION=="add", SUBSYSTEM=="module", KERNEL=="block", ATTR{parameters/events_dfl_
 ACTION=="change", SUBSYSTEM=="scsi", ENV{DEVTYPE}=="scsi_device", TEST=="block", ATTR{block/*/uevent}="change"
 
 # watch metadata changes, caused by tools closing the device node which was opened for writing
-ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*|nvme*|sd*|vd*|xvd*|pmem*|mmcblk*|dasd*", OPTIONS+="watch"
+ACTION!="remove", SUBSYSTEM=="block", KERNEL=="loop*|nvme*|sd*|vd*|xvd*|pmem*|mmcblk*|dasd*|nbd*", OPTIONS+="watch"
index bf36fd4..e2af7f0 100644 (file)
@@ -56,6 +56,8 @@ SUBSYSTEM=="printer", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target"
 SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target"
 SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target"
 
+SUBSYSTEM=="udc", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="usb-gadget.target"
+
 # Apply sysctl variables to network devices (and only to those) as they appear.
 ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/net/ipv4/conf/$name --prefix=/net/ipv4/neigh/$name --prefix=/net/ipv6/conf/$name --prefix=/net/ipv6/neigh/$name"
 
index 0e0c837..8755b85 100755 (executable)
@@ -2,7 +2,42 @@
 
 set -ex
 
-meson build -Dtests=unsafe -Dsplit-usr=true -Dslow-tests=true
-ninja -C build
-ninja -C build test
-DESTDIR=/var/tmp/inst1 ninja -C build install
+# keep this in sync with setup.sh
+CONTAINER=${RELEASE:-buster}-${ARCH:-amd64}
+AUTOPKGTESTDIR=${SEMAPHORE_CACHE_DIR:-/tmp}/autopkgtest
+# semaphore cannot expose these, but useful for interactive/local runs
+ARTIFACTS_DIR=/tmp/artifacts
+
+# add current debian/ packaging
+git fetch --depth=1 https://salsa.debian.org/systemd-team/systemd.git master
+git checkout FETCH_HEAD debian
+
+# craft changelog
+UPSTREAM_VER=$(git describe | sed 's/^v//')
+cat << EOF > debian/changelog.new
+systemd (${UPSTREAM_VER}-0) UNRELEASED; urgency=low
+
+  * Automatic build for upstream test
+
+ -- systemd test <pkg-systemd-maintainers@lists.alioth.debian.org>  $(date -R)
+
+EOF
+cat debian/changelog >> debian/changelog.new
+mv debian/changelog.new debian/changelog
+
+# clean out patches
+rm -rf debian/patches
+# disable autopkgtests which are not for upstream
+sed -i '/# NOUPSTREAM/ q' debian/tests/control
+# enable more unit tests
+sed -i '/^CONFFLAGS =/ s/=/= -Dtests=unsafe -Dsplit-usr=true -Dslow-tests=true /' debian/rules
+# no orig tarball
+echo '1.0' > debian/source/format
+
+# build source package
+dpkg-buildpackage -S -I -I$(basename "$SEMAPHORE_CACHE_DIR") -d -us -uc -nc
+
+# now build the package and run the tests
+rm -rf "$ARTIFACTS_DIR"
+# autopkgtest exits with 2 for "some tests skipped", accept that
+$AUTOPKGTESTDIR/runner/autopkgtest --apt-upgrade --env DEB_BUILD_OPTIONS=noudeb --env TEST_UPSTREAM=1 ../systemd_*.dsc -o "$ARTIFACTS_DIR" -- lxc -s $CONTAINER || [ $? -eq 2 ]
index d9a7b50..c904a30 100755 (executable)
@@ -2,26 +2,57 @@
 
 set -ex
 
-sudo add-apt-repository ppa:upstream-systemd-ci/systemd-ci -y
-sudo rm -rf /etc/apt/sources.list.d/beineri* /etc/apt/sources.list.d/google-chrome* /etc/apt/sources.list.d/heroku* /etc/apt/sources.list.d/mongodb* /etc/apt/sources.list.d/webupd8team* /etc/apt/sources.list.d/rwky* /etc/apt/sources.list.d/rethinkdb* /etc/apt/sources.list.d/cassandra* /etc/apt/sources.list.d/cwchien* /etc/apt/sources.list.d/rabbitmq* /etc/apt/sources.list.d/docker* /home/runner/{.npm,.phpbrew,.phpunit,.kerl,.kiex,.lein,.nvm,.npm,.phpbrew,.rbenv}
-sudo bash -c "echo 'deb-src http://de.archive.ubuntu.com/ubuntu/ xenial main restricted universe multiverse' >>/etc/apt/sources.list"
-sudo apt-get update -qq
-sudo apt-get build-dep systemd -y
-sudo apt-get install --force-yes -y util-linux libmount-dev libblkid-dev liblzma-dev libqrencode-dev libmicrohttpd-dev iptables-dev liblz4-dev libcurl4-gnutls-dev unifont clang-3.6 libasan0 itstool kbd cryptsetup-bin net-tools isc-dhcp-client iputils-ping strace qemu-system-x86 linux-image-virtual mount libgpg-error-dev libxkbcommon-dev python-lxml python3-lxml python3-pip libcap-dev
-# curl -s https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
-# sudo add-apt-repository -y 'deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty main'
-# sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
-sudo apt-get update
-sudo apt-get install --force-yes -y gettext python3-evdev python3-pyparsing libmount-dev
-# sudo apt-get install -y clang-6.0
-sudo sh -c 'echo 01010101010101010101010101010101 >/etc/machine-id'
-sudo mount -t tmpfs none /tmp
-test -d /run/mount || sudo mkdir /run/mount
-sudo adduser --system --no-create-home nfsnobody
-sudo rm -f /etc/mtab
-git clone https://github.com/ninja-build/ninja
-cd ninja
-./configure.py --bootstrap
-sudo cp ninja /usr/bin/
-cd ..
-pip3 install --user 'meson == 0.46.1'
+# default to Debian testing
+DISTRO=${DISTRO:-debian}
+RELEASE=${RELEASE:-buster}
+ARCH=${ARCH:-amd64}
+CONTAINER=${RELEASE}-${ARCH}
+MAX_CACHE_AGE=604800  # one week
+CACHE=${SEMAPHORE_CACHE_DIR:=/tmp}/${CONTAINER}.img.tar.gz
+
+create_container() {
+    # create autopkgtest LXC image; this sometimes fails with "Unable to fetch
+    # GPG key from keyserver", so retry a few times
+    for retry in $(seq 5); do
+        sudo lxc-create -n $CONTAINER -t download -- -d $DISTRO -r $RELEASE -a $ARCH && break
+        sleep $((retry*retry))
+    done
+
+    # unconfine the container, otherwise some tests fail
+    echo 'lxc.apparmor.profile = unconfined' | sudo tee -a /var/lib/lxc/$CONTAINER/config
+
+    sudo lxc-start -n $CONTAINER
+
+    # enable source repositories so that apt-get build-dep works
+    sudo lxc-attach -n $CONTAINER -- sh -ex <<EOF
+sed 's/^deb/deb-src/' /etc/apt/sources.list >> /etc/apt/sources.list.d/sources.list
+# wait until online
+while [ -z "\$(ip route list 0/0)" ]; do sleep 1; done
+apt-get -q update
+apt-get -y dist-upgrade
+apt-get install -y eatmydata
+EOF
+    sudo lxc-stop -n $CONTAINER
+
+    # cache it
+    sudo tar cpzf "$CACHE" /var/lib/lxc/$CONTAINER
+}
+
+# remove semaphore repos, some of them don't work and cause error messages
+sudo rm -f /etc/apt/sources.list.d/*
+
+# enable backports for latest LXC
+echo 'deb http://archive.ubuntu.com/ubuntu xenial-backports main restricted universe multiverse' | sudo tee -a /etc/apt/sources.list.d/backports.list
+sudo apt-get -q update
+sudo apt-get install -y -t xenial-backports lxc
+sudo apt-get install -y python3-debian git dpkg-dev fakeroot
+
+AUTOPKGTESTDIR=$SEMAPHORE_CACHE_DIR/autopkgtest
+[ -d $AUTOPKGTESTDIR ] || git clone --quiet --depth=1 https://salsa.debian.org/ci-team/autopkgtest.git "$AUTOPKGTESTDIR"
+
+# use cached container image, unless older than a week
+if [ -e "$CACHE" ] && [ $(( $(date +%s) - $(stat -c %Y "$CACHE") )) -le $MAX_CACHE_AGE ]; then
+    sudo tar -C / -xpzf "$CACHE"
+else
+    create_container
+fi
index 476101c..63a7644 100644 (file)
@@ -86,7 +86,8 @@ _busctl() {
                              -q --quiet --verbose --expect-reply=no --auto-start=no
                              --allow-interactive-authorization=no --augment-creds=no
                              --watch-bind=yes -j'
-                      [ARG]='--address -H --host -M --machine --match --timeout --size --json'
+                      [ARG]='--address -H --host -M --machine --match --timeout --size --json
+                             --destination'
         )
 
         if __contains_word "--user" ${COMP_WORDS[*]}; then
@@ -106,6 +107,9 @@ _busctl() {
                         --json)
                                 comps=$( busctl --json=help 2>/dev/null )
                         ;;
+                        --destination)
+                                comps=$( __get_busnames $mode )
+                        ;;
                 esac
                 COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
                 return 0
@@ -121,6 +125,7 @@ _busctl() {
                 [BUSNAME]='status monitor capture tree'
                 [OBJECT]='introspect'
                 [METHOD]='call'
+                [EMIT]='emit'
                 [PROPERTY_GET]='get-property'
                 [PROPERTY_SET]='set-property'
         )
@@ -165,6 +170,8 @@ _busctl() {
                 else
                         comps=''
                 fi
+        elif __contains_word "$verb" ${VERBS[EMIT]}; then
+                comps=''
         elif __contains_word "$verb" ${VERBS[PROPERTY_GET]}; then
                 if [[ $n -eq 1 ]] ; then
                         comps=$( __get_busnames $mode)
index bcd4533..3beb347 100644 (file)
@@ -28,7 +28,7 @@ __contains_word () {
 __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;
+                { while read a b; do echo " $a"; done; } | sort -u;
 }
 
 __syslog_priorities=(emerg alert crit err warning notice info debug)
@@ -48,10 +48,17 @@ _journalctl() {
                               -M --machine -o --output -u --unit --user-unit -p --priority
                               --root --case-sensitive'
                 [ARGUNKNOWN]='-c --cursor --interval -n --lines -S --since -U --until
-                              --after-cursor --verify-key -g --grep
+                              --after-cursor --cursor-file --verify-key -g --grep
                               --vacuum-size --vacuum-time --vacuum-files --output-fields'
         )
 
+        # Use the default completion for shell redirect operators
+        if __contains_word "$prev" '>' '>>' '&>'; then
+                compopt -o filenames
+                COMPREPLY=( $(compgen -f -- "$cur") )
+                return 0;
+        fi
+
         if __contains_word "$prev" ${OPTS[ARG]} ${OPTS[ARGUNKNOWN]}; then
                 case $prev in
                         --boot|-b)
@@ -70,7 +77,7 @@ _journalctl() {
                         ;;
                         --field|-F)
                                 comps=$(journalctl --fields | sort 2>/dev/null)
-                       ;;
+                        ;;
                         --machine|-M)
                                 comps=$( __get_machines )
                         ;;
index 0e58e2b..d73f956 100644 (file)
@@ -84,10 +84,13 @@ __get_restartable_units () {
 
 __get_stoppable_units () {
         # filter out masked and not-found
-        __filter_units_by_properties $1 ActiveState=active,CanStop=yes $(
+        local units=$(
                 { __get_not_masked_unit_files $1 $2
                   __get_active_units $1 $2
                 } | sort -u )
+        __filter_units_by_properties $1 ActiveState=active,CanStop=yes $units
+        __filter_units_by_properties $1 ActiveState=reloading,CanStop=yes $units
+        __filter_units_by_properties $1 ActiveState=activating,CanStop=yes $units
 }
 
 __get_reloadable_units () {
diff --git a/shell-completion/bash/systemd-id128 b/shell-completion/bash/systemd-id128
new file mode 100644 (file)
index 0000000..cfd5438
--- /dev/null
@@ -0,0 +1,74 @@
+# networkctl(1) completion                               -*- shell-script -*-
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+__contains_word () {
+        local w word=$1; shift
+        for w in "$@"; do
+                [[ $w = "$word" ]] && return
+        done
+        return 1
+}
+
+_systemd_id128() {
+        local i verb comps
+        local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+        local -A OPTS=(
+               [STANDALONE]='-h --help --version -p --pretty'
+                      [ARG]='-a --app-specific'
+        )
+
+        local -A VERBS=(
+                [STANDALONE]='new machine-id boot-id invocation-id help'
+        )
+
+        _init_completion || return
+
+        if __contains_word "$prev" ${OPTS[ARG]}; then
+                case $prev in
+                        --app-specific|-a)
+                                comps=""
+                                ;;
+                esac
+                COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
+                return 0
+        fi
+
+        if [[ "$cur" = -* ]]; then
+                COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") )
+                return 0
+        fi
+
+        for ((i=0; i < COMP_CWORD; i++)); do
+                if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
+                 ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG]}; then
+                        verb=${COMP_WORDS[i]}
+                        break
+                fi
+        done
+
+        if [[ -z $verb ]]; then
+                comps=${VERBS[*]}
+        elif __contains_word "$verb" ${VERBS[STANDALONE]}; then
+                comps=''
+        fi
+
+        COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
+        return 0
+}
+
+complete -F _systemd_id128 systemd-id128
index aa6ace0..0520e02 100644 (file)
@@ -85,6 +85,7 @@ _arguments -s \
     {-h,--help}'[Show this help]' \
     '--version[Show package version]' \
     '--no-pager[Do not pipe output into a pager]' \
+    --no-hostname"[Don't show the hostname of local log messages]" \
     {-l,--full}'[Show long fields in full]' \
     {-a,--all}'[Show all fields, including long and unprintable]' \
     {-f,--follow}'[Follow journal]' \
@@ -104,6 +105,7 @@ _arguments -s \
     {-p+,--priority=}'[Show only messages within the specified priority range]:priority:_journalctl_field_values PRIORITY' \
     {-t+,--identifier=}'[Show only messages with the specified syslog identifier]:identifier:_journalctl_field_values SYSLOG_IDENTIFIER' \
     {-c+,--cursor=}'[Start showing entries from the specified cursor]:cursors:_journalctl_field_values __CURSORS' \
+    '--cursor-file=[Show entries using cursor store in file]:file:_files' \
     '--after-cursor=[Start showing entries from after the specified cursor]:cursors:_journalctl_field_values __CURSORS' \
     '--since=[Start showing entries on or newer than the specified date]:YYYY-MM-DD HH\:MM\:SS' \
     '--until=[Stop showing entries on or older than the specified date]:YYYY-MM-DD HH\:MM\:SS' \
index 9a83bc7..473366f 100644 (file)
@@ -10,6 +10,7 @@
 #include "sd-daemon.h"
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "log.h"
@@ -21,6 +22,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "util.h"
 
 static char** arg_listen = NULL;
 static bool arg_accept = false;
@@ -73,7 +75,9 @@ static int open_sockets(int *epoll_fd, bool accept) {
                         except[fd] = fd;
 
                 log_close();
-                close_all_fds(except, 3 + n);
+                r = close_all_fds(except, 3 + n);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to close all file descriptors: %m");
         }
 
         /** Note: we leak some fd's on error here. I doesn't matter
@@ -267,11 +271,15 @@ static int do_accept(const char* name, char **argv, char **envp, int fd) {
         _cleanup_close_ int fd_accepted = -1;
 
         fd_accepted = accept4(fd, NULL, NULL, 0);
-        if (fd_accepted < 0)
+        if (fd_accepted < 0) {
+                if (ERRNO_IS_ACCEPT_AGAIN(errno))
+                        return 0;
+
                 return log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
+        }
 
-        getsockname_pretty(fd_accepted, &local);
-        getpeername_pretty(fd_accepted, true, &peer);
+        (void) getsockname_pretty(fd_accepted, &local);
+        (void) getpeername_pretty(fd_accepted, true, &peer);
         log_info("Connection from %s to %s", strna(peer), strna(local));
 
         return fork_and_exec_process(name, argv, envp, fd_accepted);
index a007ed1..a9a93d0 100644 (file)
@@ -13,6 +13,7 @@
 #include "locale-util.h"
 #include "macro.h"
 #include "missing.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "pretty-print.h"
@@ -49,6 +50,7 @@ struct security_info {
         bool memory_deny_write_execute;
         bool no_new_privileges;
         char *notify_access;
+        bool protect_hostname;
 
         bool private_devices;
         bool private_mounts;
@@ -73,6 +75,7 @@ struct security_info {
 
         uint64_t restrict_namespaces;
         bool restrict_realtime;
+        bool restrict_suid_sgid;
 
         char *root_directory;
         char *root_image;
@@ -294,10 +297,8 @@ static int assess_root_directory(
         assert(ret_description);
 
         *ret_badness =
-                (isempty(info->root_directory) ||
-                 path_equal(info->root_directory, "/")) &&
-                (isempty(info->root_image) ||
-                 path_equal(info->root_image, "/"));
+                empty_or_root(info->root_directory) ||
+                empty_or_root(info->root_image);
         *ret_description = NULL;
 
         return 0;
@@ -769,6 +770,16 @@ static const struct security_assessor security_assessor_table[] = {
                 .default_dependencies_only = true,
         },
         {
+                .id = "ProtectHostname=",
+                .description_good = "Service cannot change system host/domainname",
+                .description_bad = "Service may change system host/domainname",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectHostname=",
+                .weight = 50,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, protect_hostname),
+        },
+        {
                 .id = "ProtectSystem=",
                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectSystem=",
                 .weight = 1000,
@@ -1137,6 +1148,16 @@ static const struct security_assessor security_assessor_table[] = {
                 .offset = offsetof(struct security_info, restrict_realtime),
         },
         {
+                .id = "RestrictSUIDSGID=",
+                .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictSUIDSGID=",
+                .description_good = "SUID/SGID file creation by service is restricted",
+                .description_bad = "Service may create SUID/SGID files",
+                .weight = 1000,
+                .range = 1,
+                .assess = assess_bool,
+                .offset = offsetof(struct security_info, restrict_suid_sgid),
+        },
+        {
                 .id = "RestrictNamespaces=~CLONE_NEWUSER",
                 .url = "https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RestrictNamespaces=",
                 .description_good = "Service cannot create user namespaces",
@@ -1861,6 +1882,7 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
                 { "PrivateUsers",            "b",       NULL,                                    offsetof(struct security_info, private_users)             },
                 { "ProtectControlGroups",    "b",       NULL,                                    offsetof(struct security_info, protect_control_groups)    },
                 { "ProtectHome",             "s",       NULL,                                    offsetof(struct security_info, protect_home)              },
+                { "ProtectHostname",         "b",       NULL,                                    offsetof(struct security_info, protect_hostname)          },
                 { "ProtectKernelModules",    "b",       NULL,                                    offsetof(struct security_info, protect_kernel_modules)    },
                 { "ProtectKernelTunables",   "b",       NULL,                                    offsetof(struct security_info, protect_kernel_tunables)   },
                 { "ProtectSystem",           "s",       NULL,                                    offsetof(struct security_info, protect_system)            },
@@ -1868,6 +1890,7 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
                 { "RestrictAddressFamilies", "(bas)",   property_read_restrict_address_families, 0                                                         },
                 { "RestrictNamespaces",      "t",       NULL,                                    offsetof(struct security_info, restrict_namespaces)       },
                 { "RestrictRealtime",        "b",       NULL,                                    offsetof(struct security_info, restrict_realtime)         },
+                { "RestrictSUIDSGID",        "b",       NULL,                                    offsetof(struct security_info, restrict_suid_sgid)        },
                 { "RootDirectory",           "s",       NULL,                                    offsetof(struct security_info, root_directory)            },
                 { "RootImage",               "s",       NULL,                                    offsetof(struct security_info, root_image)                },
                 { "SupplementaryGroups",     "as",      NULL,                                    offsetof(struct security_info, supplementary_groups)      },
index 1d8a1ed..16b07cc 100644 (file)
@@ -202,7 +202,7 @@ static int verify_unit(Unit *u, bool check_man) {
                 unit_dump(u, stdout, "\t");
 
         log_unit_debug(u, "Creating %s/start job", u->id);
-        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, &err, NULL);
+        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL, &err, NULL);
         if (r < 0)
                 log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
 
index 3915b66..ac7cb0d 100644 (file)
@@ -8,6 +8,7 @@
 #include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 #include "sd-bus.h"
 
@@ -29,6 +30,7 @@
 #include "locale-util.h"
 #include "log.h"
 #include "main-func.h"
+#include "nulstr-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-util.h"
 #if HAVE_SECCOMP
 #  include "seccomp-util.h"
 #endif
+#include "sort-util.h"
 #include "special.h"
 #include "strv.h"
 #include "strxcpyx.h"
-#include "time-util.h"
 #include "terminal-util.h"
+#include "time-util.h"
 #include "unit-name.h"
 #include "util.h"
 #include "verbs.h"
@@ -78,6 +81,7 @@ static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
 static bool arg_man = true;
 static bool arg_generators = false;
 static const char *arg_root = NULL;
+static unsigned arg_iterations = 1;
 
 STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep);
@@ -270,14 +274,13 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
         if (r < 0)
                 return log_error_errno(r, "Failed to get timestamp properties: %s", bus_error_message(&error, r));
 
-        if (times.finish_time <= 0) {
-                log_error("Bootup is not yet finished (org.freedesktop.systemd1.Manager.FinishTimestampMonotonic=%"PRIu64").\n"
-                          "Please try again later.\n"
-                          "Hint: Use 'systemctl%s list-jobs' to see active jobs",
-                          times.finish_time,
-                          arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
-                return -EINPROGRESS;
-        }
+        if (times.finish_time <= 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINPROGRESS),
+                                       "Bootup is not yet finished (org.freedesktop.systemd1.Manager.FinishTimestampMonotonic=%"PRIu64").\n"
+                                       "Please try again later.\n"
+                                       "Hint: Use 'systemctl%s list-jobs' to see active jobs",
+                                       times.finish_time,
+                                       arg_scope == UNIT_FILE_SYSTEM ? "" : " --user");
 
         if (arg_scope == UNIT_FILE_SYSTEM && times.security_start_time > 0) {
                 /* security_start_time is set when systemd is not running under container environment. */
@@ -312,7 +315,6 @@ finish:
 }
 
 static void free_host_info(struct host_info *hi) {
-
         if (!hi)
                 return;
 
@@ -385,7 +387,8 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
                                 NULL,
                                 t);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to get timestamp properties of unit %s: %s", u.id, bus_error_message(&error, r));
+                        return log_error_errno(r, "Failed to get timestamp properties of unit %s: %s",
+                                               u.id, bus_error_message(&error, r));
 
                 subtract_timestamp(&t->activating, boot_times->reverse_offset);
                 subtract_timestamp(&t->activated, boot_times->reverse_offset);
@@ -458,7 +461,8 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
                                    NULL,
                                    host);
         if (r < 0) {
-                log_debug_errno(r, "Failed to get host information from systemd-hostnamed, ignoring: %s", bus_error_message(&error, r));
+                log_debug_errno(r, "Failed to get host information from systemd-hostnamed, ignoring: %s",
+                                bus_error_message(&error, r));
                 sd_bus_error_free(&error);
         }
 
@@ -472,10 +476,10 @@ manager:
                                    NULL,
                                    host);
         if (r < 0)
-                return log_error_errno(r, "Failed to get host information from systemd: %s", bus_error_message(&error, r));
+                return log_error_errno(r, "Failed to get host information from systemd: %s",
+                                       bus_error_message(&error, r));
 
         *hi = TAKE_PTR(host);
-
         return 0;
 }
 
@@ -1033,8 +1037,8 @@ static int analyze_critical_chain(int argc, char *argv[], void *userdata) {
 
         (void) pager_open(arg_pager_flags);
 
-        puts("The time after the unit is active or started is printed after the \"@\" character.\n"
-             "The time the unit takes to start is printed after the \"+\" character.\n");
+        puts("The time when unit became active or started is printed after the \"@\" character.\n"
+             "The time the unit took to start is printed after the \"+\" character.\n");
 
         if (argc > 1) {
                 char **name;
@@ -1328,7 +1332,8 @@ static int dump(int argc, char *argv[], void *userdata) {
         if (r < 0) {
                 /* fall back to Dump if DumpByFileDescriptor is not supported */
                 if (!IN_SET(r, -EACCES, -EBADR))
-                        return log_error_errno(r, "Failed to issue method call DumpByFileDescriptor: %s", bus_error_message(&error, r));
+                        return log_error_errno(r, "Failed to issue method call DumpByFileDescriptor: %s",
+                                               bus_error_message(&error, r));
 
                 return dump_fallback(bus);
         }
@@ -1365,8 +1370,7 @@ static int cat_config(int argc, char *argv[], void *userdata) {
 
                         if (!t)
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                                       "Path %s does not start with any known prefix.",
-                                                       *arg);
+                                                       "Path %s does not start with any known prefix.", *arg);
                 } else
                         t = *arg;
 
@@ -1515,9 +1519,15 @@ static int load_kernel_syscalls(Set **ret) {
         /* Let's read the available system calls from the list of available tracing events. Slightly dirty, but good
          * enough for analysis purposes. */
 
-        f = fopen("/sys/kernel/debug/tracing/available_events", "re");
-        if (!f)
-                return log_full_errno(IN_SET(errno, EPERM, EACCES, ENOENT) ? LOG_DEBUG : LOG_WARNING, errno, "Can't read open /sys/kernel/debug/tracing/available_events: %m");
+        f = fopen("/sys/kernel/tracing/available_events", "re");
+        if (!f) {
+                /* We tried the non-debugfs mount point and that didn't work. If it wasn't mounted, maybe the
+                 * old debugfs mount point works? */
+                f = fopen("/sys/kernel/debug/tracing/available_events", "re");
+                if (!f)
+                        return log_full_errno(IN_SET(errno, EPERM, EACCES, ENOENT) ? LOG_DEBUG : LOG_WARNING, errno,
+                                              "Can't read open tracefs' available_events file: %m");
+        }
 
         for (;;) {
                 _cleanup_free_ char *line = NULL;
@@ -1628,8 +1638,8 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
                                 /* make sure the error appears below normal output */
                                 fflush(stdout);
 
-                                log_error("Filter set \"%s\" not found.", *name);
-                                return -ENOENT;
+                                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+                                                       "Filter set \"%s\" not found.", *name);
                         }
 
                         dump_syscall_filter(set);
@@ -1670,57 +1680,80 @@ static int dump_timespan(int argc, char *argv[], void *userdata) {
         return EXIT_SUCCESS;
 }
 
-static int test_calendar(int argc, char *argv[], void *userdata) {
-        int ret = 0, r;
-        char **p;
-        usec_t n;
+static int test_calendar_one(usec_t n, const char *p) {
+        _cleanup_(calendar_spec_freep) CalendarSpec *spec = NULL;
+        _cleanup_free_ char *t = NULL;
+        int r;
+
+        r = calendar_spec_from_string(p, &spec);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse calendar specification '%s': %m", p);
 
-        n = now(CLOCK_REALTIME);
+        r = calendar_spec_normalize(spec);
+        if (r < 0)
+                return log_error_errno(r, "Failed to normalize calendar specification '%s': %m", p);
 
-        STRV_FOREACH(p, strv_skip(argv, 1)) {
-                _cleanup_(calendar_spec_freep) CalendarSpec *spec = NULL;
-                _cleanup_free_ char *t = NULL;
+        r = calendar_spec_to_string(spec, &t);
+        if (r < 0)
+                return log_error_errno(r, "Failed to format calendar specification '%s': %m", p);
+
+        if (!streq(t, p))
+                printf("  Original form: %s\n", p);
+
+        printf("Normalized form: %s\n", t);
+
+        for (unsigned i = 0; i < arg_iterations; i++) {
+                char buffer[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESTAMP_RELATIVE_MAX)];
                 usec_t next;
 
-                r = calendar_spec_from_string(*p, &spec);
-                if (r < 0) {
-                        ret = log_error_errno(r, "Failed to parse calendar specification '%s': %m", *p);
-                        continue;
+                r = calendar_spec_next_usec(spec, n, &next);
+                if (r == -ENOENT) {
+                        if (i == 0)
+                                printf("    Next elapse: %snever%s\n",
+                                       ansi_highlight_yellow(), ansi_normal());
+                        return 0;
                 }
-
-                r = calendar_spec_normalize(spec);
-                if (r < 0) {
-                        ret = log_error_errno(r, "Failed to normalize calendar specification '%s': %m", *p);
-                        continue;
+                if (r < 0)
+                        return log_error_errno(r, "Failed to determine next elapse for '%s': %m", p);
+
+                if (i == 0)
+                        printf("    Next elapse: %s%s%s\n",
+                               ansi_highlight_blue(), format_timestamp(buffer, sizeof(buffer), next), ansi_normal());
+                else {
+                        int k = DECIMAL_STR_WIDTH(i+1);
+
+                        if (k < 8)
+                                k = 8 - k;
+                        else
+                                k = 0;
+
+                        printf("%*sIter. #%u: %s%s%s\n",
+                               k, "", i+1,
+                               ansi_highlight_blue(), format_timestamp(buffer, sizeof(buffer), next), ansi_normal());
                 }
 
-                r = calendar_spec_to_string(spec, &t);
-                if (r < 0) {
-                        ret = log_error_errno(r, "Failed to format calendar specification '%s': %m", *p);
-                        continue;
-                }
+                if (!in_utc_timezone())
+                        printf("       (in UTC): %s\n", format_timestamp_utc(buffer, sizeof(buffer), next));
 
-                if (!streq(t, *p))
-                        printf("  Original form: %s\n", *p);
+                printf("       From now: %s\n", format_timestamp_relative(buffer, sizeof(buffer), next));
 
-                printf("Normalized form: %s\n", t);
+                n = next;
+        }
 
-                r = calendar_spec_next_usec(spec, n, &next);
-                if (r == -ENOENT)
-                        printf("    Next elapse: never\n");
-                else if (r < 0) {
-                        ret = log_error_errno(r, "Failed to determine next elapse for '%s': %m", *p);
-                        continue;
-                } else {
-                        char buffer[CONST_MAX(FORMAT_TIMESTAMP_MAX, FORMAT_TIMESTAMP_RELATIVE_MAX)];
+        return 0;
+}
 
-                        printf("    Next elapse: %s\n", format_timestamp(buffer, sizeof(buffer), next));
+static int test_calendar(int argc, char *argv[], void *userdata) {
+        int ret = 0, r;
+        char **p;
+        usec_t n;
 
-                        if (!in_utc_timezone())
-                                printf("       (in UTC): %s\n", format_timestamp_utc(buffer, sizeof(buffer), next));
+        n = now(CLOCK_REALTIME); /* We want to use the same "base" for all expressions */
 
-                        printf("       From now: %s\n", format_timestamp_relative(buffer, sizeof(buffer), next));
-                }
+        STRV_FOREACH(p, strv_skip(argv, 1)) {
+                r = test_calendar_one(n, *p);
+                if (ret == 0 && r < 0)
+                        ret = r;
 
                 if (*(p+1))
                         putchar('\n');
@@ -1827,6 +1860,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "                           earlier than the latest in the branch\n"
                "     --man[=BOOL]          Do [not] check for existence of man pages\n"
                "     --generators[=BOOL]   Do [not] run unit generators (requires privileges)\n"
+               "     --iterations=N        Show the specified number of iterations\n"
                "\nCommands:\n"
                "  time                     Print time spent in the kernel\n"
                "  blame                    Print list of running units ordered by time to init\n"
@@ -1870,6 +1904,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_NO_PAGER,
                 ARG_MAN,
                 ARG_GENERATORS,
+                ARG_ITERATIONS,
         };
 
         static const struct option options[] = {
@@ -1889,6 +1924,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "generators",   optional_argument, NULL, ARG_GENERATORS       },
                 { "host",         required_argument, NULL, 'H'                  },
                 { "machine",      required_argument, NULL, 'M'                  },
+                { "iterations",   required_argument, NULL, ARG_ITERATIONS       },
                 {}
         };
 
@@ -1988,6 +2024,13 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case ARG_ITERATIONS:
+                        r = safe_atou(optarg, &arg_iterations);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse iterations: %s", optarg);
+
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -2000,6 +2043,10 @@ static int parse_argv(int argc, char *argv[]) {
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Option --global only makes sense with verbs dot, unit-paths, verify.");
 
+        if (streq_ptr(argv[optind], "cat-config") && arg_scope == UNIT_FILE_USER)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Option --user is not supported for cat-config right now.");
+
         if (arg_root && !streq_ptr(argv[optind], "cat-config"))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Option --root is only supported for cat-config right now.");
index 780ad56..dfd6805 100644 (file)
@@ -1,5 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "sd-device.h"
 
 #include "alloc-util.h"
@@ -379,7 +383,7 @@ static int run(int argc, char *argv[]) {
                 clamp = shall_clamp(device);
 
                 r = read_one_line_file(saved, &value);
-                if (r == -ENOENT) {
+                if (IN_SET(r, -ENOENT, 0)) {
                         const char *curval;
 
                         /* Fallback to clamping current brightness or exit early if
@@ -408,7 +412,7 @@ static int run(int argc, char *argv[]) {
                 const char *value;
 
                 if (validate_device(device) == 0) {
-                        unlink(saved);
+                        (void) unlink(saved);
                         return 0;
                 }
 
index ab7a42c..1e4ee72 100644 (file)
@@ -1,11 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <malloc.h>
 #include <stdint.h>
 #include <string.h>
 
 #include "alloc-util.h"
 #include "macro.h"
-#include "util.h"
+#include "memory-util.h"
 
 void* memdup(const void *p, size_t l) {
         void *ret;
@@ -27,6 +28,9 @@ void* memdup_suffix0(const void *p, size_t l) {
 
         /* The same as memdup() but place a safety NUL byte after the allocated memory */
 
+        if (_unlikely_(l == SIZE_MAX)) /* prevent overflow */
+                return NULL;
+
         ret = malloc(l + 1);
         if (!ret)
                 return NULL;
@@ -45,19 +49,23 @@ void* greedy_realloc(void **p, size_t *allocated, size_t need, size_t size) {
         if (*allocated >= need)
                 return *p;
 
-        newalloc = MAX(need * 2, 64u / size);
-        a = newalloc * size;
+        if (_unlikely_(need > SIZE_MAX/2)) /* Overflow check */
+                return NULL;
 
-        /* check for overflows */
-        if (a < size * need)
+        newalloc = need * 2;
+        if (size_multiply_overflow(newalloc, size))
                 return NULL;
 
+        a = newalloc * size;
+        if (a < 64) /* Allocate at least 64 bytes */
+                a = 64;
+
         q = realloc(*p, a);
         if (!q)
                 return NULL;
 
         *p = q;
-        *allocated = newalloc;
+        *allocated = _unlikely_(size == 0) ? newalloc : malloc_usable_size(q) / size;
         return q;
 }
 
index 893a123..9b20be4 100644 (file)
@@ -8,6 +8,10 @@
 
 #include "macro.h"
 
+#if HAS_FEATURE_MEMORY_SANITIZER
+#  include <sanitizer/msan_interface.h>
+#endif
+
 typedef void (*free_func_t)(void *p);
 
 /* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than
@@ -152,11 +156,17 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size);
                 (void*)memset(_new_, 0, _xsize_);                       \
         })
 
-/* Takes inspiration from Rusts's Option::take() method: reads and returns a pointer, but at the same time resets it to
- * NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
+/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time
+ * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */
 #define TAKE_PTR(ptr)                           \
         ({                                      \
                 typeof(ptr) _ptr_ = (ptr);      \
                 (ptr) = NULL;                   \
                 _ptr_;                          \
         })
+
+#if HAS_FEATURE_MEMORY_SANITIZER
+#  define msan_unpoison(r, s) __msan_unpoison(r, s)
+#else
+#  define msan_unpoison(r, s)
+#endif
index c45ca01..daa95cd 100644 (file)
@@ -6,6 +6,7 @@
 #include <unistd.h>
 
 #include "async.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "log.h"
 #include "macro.h"
index 872fc3a..db6c0c3 100644 (file)
@@ -1629,7 +1629,7 @@ int btrfs_subvol_snapshot_fd_full(
                 } else if (r < 0)
                         return r;
 
-                r = copy_directory_fd_full(old_fd, new_path, COPY_MERGE|COPY_REFLINK, progress_path, progress_bytes, userdata);
+                r = copy_directory_fd_full(old_fd, new_path, COPY_MERGE|COPY_REFLINK|COPY_SAME_MOUNT, progress_path, progress_bytes, userdata);
                 if (r < 0)
                         goto fallback_fail;
 
index b944ee6..0035352 100644 (file)
@@ -28,8 +28,8 @@ int have_effective_cap(int value) {
 
         if (cap_get_flag(cap, value, CAP_EFFECTIVE, &fv) < 0)
                 return -errno;
-        else
-                return fv == CAP_SET;
+
+        return fv == CAP_SET;
 }
 
 unsigned long cap_last_cap(void) {
@@ -47,6 +47,13 @@ unsigned long cap_last_cap(void) {
         if (r >= 0) {
                 r = safe_atolu(content, &p);
                 if (r >= 0) {
+
+                        if (p > 63) /* Safety for the future: if one day the kernel learns more than 64 caps,
+                                     * then we are in trouble (since we, as much userspace and kernel space
+                                     * store capability masks in uint64_t types). Let's hence protect
+                                     * ourselves against that and always cap at 63 for now. */
+                                p = 63;
+
                         saved = p;
                         valid = true;
                         return p;
@@ -54,21 +61,19 @@ unsigned long cap_last_cap(void) {
         }
 
         /* fall back to syscall-probing for pre linux-3.2 */
-        p = (unsigned long) CAP_LAST_CAP;
+        p = MIN((unsigned long) CAP_LAST_CAP, 63U);
 
         if (prctl(PR_CAPBSET_READ, p) < 0) {
 
-                /* Hmm, look downwards, until we find one that
-                 * works */
+                /* Hmm, look downwards, until we find one that works */
                 for (p--; p > 0; p --)
                         if (prctl(PR_CAPBSET_READ, p) >= 0)
                                 break;
 
         } else {
 
-                /* Hmm, look upwards, until we find one that doesn't
-                 * work */
-                for (;; p++)
+                /* Hmm, look upwards, until we find one that doesn't work */
+                for (; p < 63; p++)
                         if (prctl(PR_CAPBSET_READ, p+1) < 0)
                                 break;
         }
@@ -102,13 +107,13 @@ int capability_update_inherited_set(cap_t caps, uint64_t set) {
 }
 
 int capability_ambient_set_apply(uint64_t set, bool also_inherit) {
-        unsigned long i;
         _cleanup_cap_free_ cap_t caps = NULL;
+        unsigned long i;
+        int r;
 
         /* Add the capabilities to the ambient set. */
 
         if (also_inherit) {
-                int r;
                 caps = cap_get_proc();
                 if (!caps)
                         return -errno;
@@ -267,16 +272,12 @@ int capability_bounding_set_drop_usermode(uint64_t keep) {
 }
 
 int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
-        _cleanup_cap_free_ cap_t d = NULL;
-        unsigned i, j = 0;
         int r;
 
-        /* Unfortunately we cannot leave privilege dropping to PID 1
-         * here, since we want to run as user but want to keep some
-         * capabilities. Since file capabilities have been introduced
-         * this cannot be done across exec() anymore, unless our
-         * binary has the capability configured in the file system,
-         * which we want to avoid. */
+        /* Unfortunately we cannot leave privilege dropping to PID 1 here, since we want to run as user but
+         * want to keep some capabilities. Since file capabilities have been introduced this cannot be done
+         * across exec() anymore, unless our binary has the capability configured in the file system, which
+         * we want to avoid. */
 
         if (setresgid(gid, gid, gid) < 0)
                 return log_error_errno(errno, "Failed to change group ID: %m");
@@ -285,7 +286,9 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
         if (r < 0)
                 return log_error_errno(r, "Failed to drop auxiliary groups list: %m");
 
-        /* Ensure we keep the permitted caps across the setresuid() */
+        /* Ensure we keep the permitted caps across the setresuid(). Note that we do this even if we actually
+         * don't want to keep any capabilities, since we want to be able to drop them from the bounding set
+         * too, and we can only do that if we have capabilities. */
         if (prctl(PR_SET_KEEPCAPS, 1) < 0)
                 return log_error_errno(errno, "Failed to enable keep capabilities flag: %m");
 
@@ -295,18 +298,21 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
         if (prctl(PR_SET_KEEPCAPS, 0) < 0)
                 return log_error_errno(errno, "Failed to disable keep capabilities flag: %m");
 
-        /* Drop all caps from the bounding set, except the ones we want */
+        /* Drop all caps from the bounding set (as well as the inheritable/permitted/effective sets), except
+         * the ones we want to keep */
         r = capability_bounding_set_drop(keep_capabilities, true);
         if (r < 0)
                 return log_error_errno(r, "Failed to drop capabilities: %m");
 
         /* Now upgrade the permitted caps we still kept to effective caps */
-        d = cap_init();
-        if (!d)
-                return log_oom();
-
-        if (keep_capabilities) {
+        if (keep_capabilities != 0) {
                 cap_value_t bits[u64log2(keep_capabilities) + 1];
+                _cleanup_cap_free_ cap_t d = NULL;
+                unsigned i, j = 0;
+
+                d = cap_init();
+                if (!d)
+                        return log_oom();
 
                 for (i = 0; i < ELEMENTSOF(bits); i++)
                         if (keep_capabilities & (1ULL << i))
@@ -315,7 +321,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities) {
                 /* use enough bits */
                 assert(i == 64 || (keep_capabilities >> i) == 0);
                 /* don't use too many bits */
-                assert(keep_capabilities & (1ULL << (i - 1)));
+                assert(keep_capabilities & (UINT64_C(1) << (i - 1)));
 
                 if (cap_set_flag(d, CAP_EFFECTIVE, j, bits, CAP_SET) < 0 ||
                     cap_set_flag(d, CAP_PERMITTED, j, bits, CAP_SET) < 0)
@@ -362,7 +368,7 @@ bool ambient_capabilities_supported(void) {
 }
 
 int capability_quintet_enforce(const CapabilityQuintet *q) {
-        _cleanup_cap_free_ cap_t c = NULL;
+        _cleanup_cap_free_ cap_t c = NULL, modified = NULL;
         int r;
 
         if (q->ambient != (uint64_t) -1) {
@@ -393,7 +399,6 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
 
                         if (cap_set_flag(c, CAP_INHERITABLE, 1, &cv, CAP_SET) < 0)
                                 return -errno;
-
                         if (cap_set_flag(c, CAP_PERMITTED, 1, &cv, CAP_SET) < 0)
                                 return -errno;
 
@@ -426,8 +431,15 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                         if (q->inheritable != (uint64_t) -1) {
                                 cap_flag_value_t old_value, new_value;
 
-                                if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value) < 0)
+                                if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value) < 0) {
+                                        if (errno == EINVAL) /* If the kernel knows more caps than this
+                                                              * version of libcap, then this will return
+                                                              * EINVAL. In that case, simply ignore it,
+                                                              * pretend it doesn't exist. */
+                                                continue;
+
                                         return -errno;
+                                }
 
                                 new_value = (q->inheritable & m) ? CAP_SET : CAP_CLEAR;
 
@@ -442,8 +454,12 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                         if (q->permitted != (uint64_t) -1) {
                                 cap_flag_value_t old_value, new_value;
 
-                                if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value) < 0)
+                                if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value) < 0) {
+                                        if (errno == EINVAL)
+                                                continue;
+
                                         return -errno;
+                                }
 
                                 new_value = (q->permitted & m) ? CAP_SET : CAP_CLEAR;
 
@@ -458,8 +474,12 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                         if (q->effective != (uint64_t) -1) {
                                 cap_flag_value_t old_value, new_value;
 
-                                if (cap_get_flag(c, cv, CAP_EFFECTIVE, &old_value) < 0)
+                                if (cap_get_flag(c, cv, CAP_EFFECTIVE, &old_value) < 0) {
+                                        if (errno == EINVAL)
+                                                continue;
+
                                         return -errno;
+                                }
 
                                 new_value = (q->effective & m) ? CAP_SET : CAP_CLEAR;
 
@@ -472,9 +492,35 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                         }
                 }
 
-                if (changed)
-                        if (cap_set_proc(c) < 0)
+                if (changed) {
+                        /* In order to change the bounding caps, we need to keep CAP_SETPCAP for a bit
+                         * longer. Let's add it to our list hence for now. */
+                        if (q->bounding != (uint64_t) -1) {
+                                cap_value_t cv = CAP_SETPCAP;
+
+                                modified = cap_dup(c);
+                                if (!modified)
+                                        return -ENOMEM;
+
+                                if (cap_set_flag(modified, CAP_PERMITTED, 1, &cv, CAP_SET) < 0)
+                                        return -errno;
+                                if (cap_set_flag(modified, CAP_EFFECTIVE, 1, &cv, CAP_SET) < 0)
+                                        return -errno;
+
+                                if (cap_compare(modified, c) == 0) {
+                                        /* No change? then drop this nonsense again */
+                                        cap_free(modified);
+                                        modified = NULL;
+                                }
+                        }
+
+                        /* Now, let's enforce the caps for the first time. Note that this is where we acquire
+                         * caps in any of the sets we currently don't have. We have to do this before
+                         * dropping the bounding caps below, since at that point we can never acquire new
+                         * caps in inherited/permitted/effective anymore, but only lose them. */
+                        if (cap_set_proc(modified ?: c) < 0)
                                 return -errno;
+                }
         }
 
         if (q->bounding != (uint64_t) -1) {
@@ -483,5 +529,13 @@ int capability_quintet_enforce(const CapabilityQuintet *q) {
                         return r;
         }
 
+        /* If needed, let's now set the caps again, this time in the final version, which differs from what
+         * we have already set only in the CAP_SETPCAP bit, which we needed for dropping the bounding
+         * bits. This call only undoes bits and doesn't acquire any which means the bounding caps don't
+         * matter. */
+        if (modified)
+                if (cap_set_proc(c) < 0)
+                        return -errno;
+
         return 0;
 }
index 02c7d5c..e69b2fb 100644 (file)
@@ -33,10 +33,12 @@ static inline void cap_free_charpp(char **p) {
 }
 #define _cleanup_cap_free_charp_ _cleanup_(cap_free_charpp)
 
+static inline uint64_t all_capabilities(void) {
+        return UINT64_MAX >> (63 - cap_last_cap());
+}
+
 static inline bool cap_test_all(uint64_t caps) {
-        uint64_t m;
-        m = (UINT64_C(1) << (cap_last_cap() + 1)) - 1;
-        return FLAGS_SET(caps, m);
+        return FLAGS_SET(caps, all_capabilities());
 }
 
 bool ambient_capabilities_supported(void);
index 27c5327..4a56874 100644 (file)
@@ -223,7 +223,7 @@ int cg_kill(
 
         _cleanup_set_free_ Set *allocated_set = NULL;
         bool done = false;
-        int r, ret = 0;
+        int r, ret = 0, ret_log_kill = 0;
         pid_t my_pid;
 
         assert(sig >= 0);
@@ -267,7 +267,7 @@ int cg_kill(
                                 continue;
 
                         if (log_kill)
-                                log_kill(pid, sig, userdata);
+                                ret_log_kill = log_kill(pid, sig, userdata);
 
                         /* If we haven't killed this process yet, kill
                          * it */
@@ -278,8 +278,12 @@ int cg_kill(
                                 if (flags & CGROUP_SIGCONT)
                                         (void) kill(pid, SIGCONT);
 
-                                if (ret == 0)
-                                        ret = 1;
+                                if (ret == 0) {
+                                        if (log_kill)
+                                                ret = ret_log_kill;
+                                        else
+                                                ret = 1;
+                                }
                         }
 
                         done = false;
@@ -2870,7 +2874,7 @@ bool fd_is_cgroup_fs(int fd) {
         return is_cgroup_fs(&s);
 }
 
-static const char *cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
+static const char *const cgroup_controller_table[_CGROUP_CONTROLLER_MAX] = {
         [CGROUP_CONTROLLER_CPU] = "cpu",
         [CGROUP_CONTROLLER_CPUACCT] = "cpuacct",
         [CGROUP_CONTROLLER_IO] = "io",
index 119b493..a39ab45 100644 (file)
@@ -167,7 +167,7 @@ typedef enum CGroupFlags {
         CGROUP_REMOVE      = 1 << 2,
 } CGroupFlags;
 
-typedef void (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata);
+typedef int (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata);
 
 int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
 int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
index 7570bba..29070c8 100644 (file)
@@ -1,6 +1,37 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <linux/fs.h>
+
+#include "missing_fs.h"
+
+/* The chattr() flags to apply when creating a new file *before* writing to it. In particular, flags such as
+ * FS_NOCOW_FL don't work if applied a-posteriori. All other flags are fine (or even necessary, think
+ * FS_IMMUTABLE_FL!) to apply after writing to the files. */
+#define CHATTR_EARLY_FL                         \
+        (FS_NOATIME_FL |                        \
+         FS_COMPR_FL   |                        \
+         FS_NOCOW_FL   |                        \
+         FS_NOCOMP_FL  |                        \
+         FS_PROJINHERIT_FL)
+
+#define CHATTR_ALL_FL                           \
+        (FS_NOATIME_FL      |                   \
+         FS_SYNC_FL         |                   \
+         FS_DIRSYNC_FL      |                   \
+         FS_APPEND_FL       |                   \
+         FS_COMPR_FL        |                   \
+         FS_NODUMP_FL       |                   \
+         FS_EXTENT_FL       |                   \
+         FS_IMMUTABLE_FL    |                   \
+         FS_JOURNAL_DATA_FL |                   \
+         FS_SECRM_FL        |                   \
+         FS_UNRM_FL         |                   \
+         FS_NOTAIL_FL       |                   \
+         FS_TOPDIR_FL       |                   \
+         FS_NOCOW_FL        |                   \
+         FS_PROJINHERIT_FL)
+
 int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous);
 int chattr_path(const char *p, unsigned value, unsigned mask, unsigned *previous);
 
index b70c6e5..d010fbb 100644 (file)
 #include "missing.h"
 #include "path-util.h"
 #include "set.h"
+#include "sort-util.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
-#include "util.h"
 
 static int files_add(
                 Hashmap *h,
index 46e02a3..eed9cfd 100644 (file)
@@ -743,7 +743,7 @@ int copy_file_fd_full(
 
         r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress_bytes, userdata);
 
-        (void) copy_times(fdf, fdt);
+        (void) copy_times(fdf, fdt, copy_flags);
         (void) copy_xattr(fdf, fdt);
 
         return r;
@@ -755,6 +755,7 @@ int copy_file_full(
                 int flags,
                 mode_t mode,
                 unsigned chattr_flags,
+                unsigned chattr_mask,
                 CopyFlags copy_flags,
                 copy_progress_bytes_t progress_bytes,
                 void *userdata) {
@@ -770,8 +771,8 @@ int copy_file_full(
                         return -errno;
         }
 
-        if (chattr_flags != 0)
-                (void) chattr_fd(fdt, chattr_flags, (unsigned) -1, NULL);
+        if (chattr_mask != 0)
+                (void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL);
 
         r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata);
         if (r < 0) {
@@ -780,6 +781,9 @@ int copy_file_full(
                 return r;
         }
 
+        if (chattr_mask != 0)
+                (void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
+
         if (close(fdt) < 0) {
                 unlink_noerrno(to);
                 return -errno;
@@ -793,6 +797,7 @@ int copy_file_atomic_full(
                 const char *to,
                 mode_t mode,
                 unsigned chattr_flags,
+                unsigned chattr_mask,
                 CopyFlags copy_flags,
                 copy_progress_bytes_t progress_bytes,
                 void *userdata) {
@@ -826,8 +831,8 @@ int copy_file_atomic_full(
                         return fdt;
         }
 
-        if (chattr_flags != 0)
-                (void) chattr_fd(fdt, chattr_flags, (unsigned) -1, NULL);
+        if (chattr_mask != 0)
+                (void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL);
 
         r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata);
         if (r < 0)
@@ -845,14 +850,16 @@ int copy_file_atomic_full(
                         return r;
         }
 
+        if (chattr_mask != 0)
+                (void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL);
+
         t = mfree(t);
         return 0;
 }
 
-int copy_times(int fdf, int fdt) {
+int copy_times(int fdf, int fdt, CopyFlags flags) {
         struct timespec ut[2];
         struct stat st;
-        usec_t crtime = 0;
 
         assert(fdf >= 0);
         assert(fdt >= 0);
@@ -866,8 +873,12 @@ int copy_times(int fdf, int fdt) {
         if (futimens(fdt, ut) < 0)
                 return -errno;
 
-        if (fd_getcrtime(fdf, &crtime) >= 0)
-                (void) fd_setcrtime(fdt, crtime);
+        if (FLAGS_SET(flags, COPY_CRTIME)) {
+                usec_t crtime;
+
+                if (fd_getcrtime(fdf, &crtime) >= 0)
+                        (void) fd_setcrtime(fdt, crtime);
+        }
 
         return 0;
 }
index f677021..51ea4d5 100644 (file)
@@ -14,6 +14,7 @@ typedef enum CopyFlags {
         COPY_REPLACE     = 1 << 2, /* Replace an existing file if there's one */
         COPY_SAME_MOUNT  = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */
         COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */
+        COPY_CRTIME      = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */
 } CopyFlags;
 
 typedef int (*copy_progress_bytes_t)(uint64_t n_bytes, void *userdata);
@@ -24,14 +25,14 @@ static inline int copy_file_fd(const char *from, int to, CopyFlags copy_flags) {
         return copy_file_fd_full(from, to, copy_flags, NULL, NULL);
 }
 
-int copy_file_full(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags, copy_progress_bytes_t progress, void *userdata);
-static inline int copy_file(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
-        return copy_file_full(from, to, open_flags, mode, chattr_flags, copy_flags, NULL, NULL);
+int copy_file_full(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, unsigned chattr_mask, CopyFlags copy_flags, copy_progress_bytes_t progress, void *userdata);
+static inline int copy_file(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, unsigned chattr_mask, CopyFlags copy_flags) {
+        return copy_file_full(from, to, open_flags, mode, chattr_flags, chattr_mask, copy_flags, NULL, NULL);
 }
 
-int copy_file_atomic_full(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags, copy_progress_bytes_t progress, void *userdata);
-static inline int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
-        return copy_file_atomic_full(from, to, mode, chattr_flags, copy_flags, NULL, NULL);
+int copy_file_atomic_full(const char *from, const char *to, mode_t mode, unsigned chattr_flags, unsigned chattr_mask, CopyFlags copy_flags, copy_progress_bytes_t progress, void *userdata);
+static inline int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, unsigned chattr_mask, CopyFlags copy_flags) {
+        return copy_file_atomic_full(from, to, mode, chattr_flags, chattr_mask, copy_flags, NULL, NULL);
 }
 
 int copy_tree_at_full(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags, copy_progress_path_t progress_path, copy_progress_bytes_t progress_bytes, void *userdata);
@@ -57,5 +58,5 @@ static inline int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags cop
         return copy_bytes_full(fdf, fdt, max_bytes, copy_flags, NULL, NULL, NULL, NULL);
 }
 
-int copy_times(int fdf, int fdt);
+int copy_times(int fdf, int fdt, CopyFlags flags);
 int copy_xattr(int fdf, int fdt);
index 16d7792..2af0b76 100644 (file)
@@ -1,8 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include "util.h"
-
 #define DEFAULT_TIMEOUT_USEC (90*USEC_PER_SEC)
 #define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
 #define DEFAULT_CONFIRM_USEC (30*USEC_PER_SEC)
 #define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
 #define SIGNALS_IGNORE SIGPIPE
 
-#if HAVE_SPLIT_USR
-#define KBD_KEYMAP_DIRS                         \
-        "/usr/share/keymaps/\0"                 \
-        "/usr/share/kbd/keymaps/\0"             \
-        "/usr/lib/kbd/keymaps/\0"               \
-        "/lib/kbd/keymaps/\0"
-#else
-#define KBD_KEYMAP_DIRS                         \
-        "/usr/share/keymaps/\0"                 \
-        "/usr/share/kbd/keymaps/\0"             \
-        "/usr/lib/kbd/keymaps/\0"
-#endif
-
-/* Note that we use the new /run prefix here (instead of /var/run) since we require them to be aliases and that way we
- * become independent of /var being mounted */
-#define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/run/dbus/system_bus_socket"
-#define KERNEL_SYSTEM_BUS_ADDRESS "kernel:path=/sys/fs/kdbus/0-system/bus"
-#define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS
-#define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus"
-#define KERNEL_USER_BUS_ADDRESS_FMT "kernel:path=/sys/fs/kdbus/"UID_FMT"-user/bus"
-#define DEFAULT_USER_BUS_ADDRESS_FMT KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT
-
-#define PLYMOUTH_SOCKET {                                       \
-                .un.sun_family = AF_UNIX,                       \
-                .un.sun_path = "\0/org/freedesktop/plymouthd",  \
-        }
-
 #define NOTIFY_FD_MAX 768
 #define NOTIFY_BUFFER_MAX PIPE_BUF
 
         "/usr/lib/" n "\0"                      \
         _CONF_PATHS_SPLIT_USR_NULSTR(n)
 
+#define CONF_PATHS_USR(n)                       \
+        "/etc/" n,                              \
+        "/run/" n,                              \
+        "/usr/local/lib/" n,                    \
+        "/usr/lib/" n
+
+#define CONF_PATHS(n)                           \
+        CONF_PATHS_USR(n)                       \
+        _CONF_PATHS_SPLIT_USR(n)
+
+#define CONF_PATHS_USR_STRV(n)                  \
+        STRV_MAKE(CONF_PATHS_USR(n))
+
 #define CONF_PATHS_STRV(n)                      \
-        STRV_MAKE(                              \
-                "/etc/" n,                      \
-                "/run/" n,                      \
-                "/usr/local/lib/" n,            \
-                "/usr/lib/" n                   \
-                _CONF_PATHS_SPLIT_USR(n))
+        STRV_MAKE(CONF_PATHS(n))
 
 #define HIGH_RLIMIT_MEMLOCK (1024ULL*1024ULL*64ULL)
index 5fcdf24..5ebe5b2 100644 (file)
@@ -28,7 +28,7 @@ int encode_devnode_name(const char *str, char *str_enc, size_t len) {
         for (i = 0, j = 0; str[i] != '\0'; i++) {
                 int seqlen;
 
-                seqlen = utf8_encoded_valid_unichar(&str[i]);
+                seqlen = utf8_encoded_valid_unichar(str + i, (size_t) -1);
                 if (seqlen > 1) {
 
                         if (len-j < (size_t)seqlen)
index 7f10f9a..a1f1308 100644 (file)
@@ -559,6 +559,6 @@ int write_env_file(const char *fname, char **l) {
                 r = -errno;
         }
 
-        unlink(p);
+        (void) unlink(p);
         return r;
 }
diff --git a/src/basic/errno-util.h b/src/basic/errno-util.h
new file mode 100644 (file)
index 0000000..d7a5ea7
--- /dev/null
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "macro.h"
+
+static inline void _reset_errno_(int *saved_errno) {
+        if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
+                return;
+
+        errno = *saved_errno;
+}
+
+#define PROTECT_ERRNO                                                   \
+        _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
+
+#define UNPROTECT_ERRNO                         \
+        do {                                    \
+                errno = _saved_errno_;          \
+                _saved_errno_ = -1;             \
+        } while (false)
+
+static inline int negative_errno(void) {
+        /* This helper should be used to shut up gcc if you know 'errno' is
+         * negative. Instead of "return -errno;", use "return negative_errno();"
+         * It will suppress bogus gcc warnings in case it assumes 'errno' might
+         * be 0 and thus the caller's error-handling might not be triggered. */
+        assert_return(errno > 0, -EINVAL);
+        return -errno;
+}
+
+/* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5.
+ *
+ * Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases.  See the
+ *          icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */
+static inline bool ERRNO_IS_DISCONNECT(int r) {
+        return IN_SET(abs(r),
+                      ECONNABORTED,
+                      ECONNREFUSED,
+                      ECONNRESET,
+                      EHOSTDOWN,
+                      EHOSTUNREACH,
+                      ENETDOWN,
+                      ENETRESET,
+                      ENETUNREACH,
+                      ENONET,
+                      ENOPROTOOPT,
+                      ENOTCONN,
+                      EPIPE,
+                      EPROTO,
+                      ESHUTDOWN);
+}
+
+/* Transient errors we might get on accept() that we should ignore. As per error handling comment in
+ * the accept(2) man page. */
+static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) {
+        return ERRNO_IS_DISCONNECT(r) ||
+                IN_SET(abs(r),
+                       EAGAIN,
+                       EINTR,
+                       EOPNOTSUPP);
+}
+
+/* Resource exhaustion, could be our fault or general system trouble */
+static inline bool ERRNO_IS_RESOURCE(int r) {
+        return IN_SET(abs(r),
+                      EMFILE,
+                      ENFILE,
+                      ENOMEM);
+}
index 3e6ef5a..b3b8401 100644 (file)
 #include "util.h"
 #include "tmpfile-util.h"
 
+/* The maximum number of iterations in the loop to close descriptors in the fallback case
+ * when /proc/self/fd/ is inaccessible. */
+#define MAX_FD_LOOP_LIMIT (1024*1024)
+
 int close_nointr(int fd) {
         assert(fd >= 0);
 
@@ -228,6 +232,13 @@ int close_all_fds(const int except[], size_t n_except) {
                 if (max_fd < 0)
                         return max_fd;
 
+                /* Refuse to do the loop over more too many elements. It's better to fail immediately than to
+                 * spin the CPU for a long time. */
+                if (max_fd > MAX_FD_LOOP_LIMIT)
+                        return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
+                                               "/proc/self/fd is inaccessible. Refusing to loop over %d potential fds.",
+                                               max_fd);
+
                 for (fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -1) {
                         int q;
 
index 4085a24..e490753 100644 (file)
@@ -77,18 +77,6 @@ int acquire_data_fd(const void *data, size_t size, unsigned flags);
 
 int fd_duplicate_data_fd(int fd);
 
-/* Hint: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5 */
-/* The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases.
- * See the icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */
-#define ERRNO_IS_DISCONNECT(r)                                          \
-        IN_SET(r,                                                       \
-               ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \
-               ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, ENONET)
-
-/* Resource exhaustion, could be our fault or general system trouble */
-#define ERRNO_IS_RESOURCE(r) \
-        IN_SET(r, ENOMEM, EMFILE, ENFILE)
-
 int fd_move_above_stdio(int fd);
 
 int rearrange_stdio(int original_input_fd, int original_output_fd, int original_error_fd);
index e18b842..9ab2f50 100644 (file)
@@ -17,6 +17,7 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
+#include "hexdecoct.h"
 #include "log.h"
 #include "macro.h"
 #include "missing.h"
@@ -212,7 +213,6 @@ int write_string_filef(
 
 int read_one_line_file(const char *fn, char **line) {
         _cleanup_fclose_ FILE *f = NULL;
-        int r;
 
         assert(fn);
         assert(line);
@@ -223,8 +223,7 @@ int read_one_line_file(const char *fn, char **line) {
 
         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
 
-        r = read_line(f, LONG_LINE_MAX, line);
-        return r < 0 ? r : 0;
+        return read_line(f, LONG_LINE_MAX, line);
 }
 
 int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
@@ -266,26 +265,29 @@ int verify_file(const char *fn, const char *blob, bool accept_extra_nl) {
         return 1;
 }
 
-int read_full_stream(
+int read_full_stream_full(
                 FILE *f,
+                const char *filename,
+                ReadFullFileFlags flags,
                 char **ret_contents,
                 size_t *ret_size) {
 
         _cleanup_free_ char *buf = NULL;
         struct stat st;
-        size_t n, l;
-        int fd;
+        size_t n, n_next, l;
+        int fd, r;
 
         assert(f);
         assert(ret_contents);
+        assert(!(flags & READ_FULL_FILE_UNBASE64) || ret_size);
 
-        n = LINE_MAX; /* Start size */
+        n_next = LINE_MAX; /* Start size */
 
         fd = fileno(f);
         if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen(), let's
                         * optimize our buffering) */
 
-                if (fstat(fileno(f), &st) < 0)
+                if (fstat(fd, &st) < 0)
                         return -errno;
 
                 if (S_ISREG(st.st_mode)) {
@@ -298,27 +300,44 @@ int read_full_stream(
                          * size of 0. Note that we increase the size to read here by one, so that the first read attempt
                          * already makes us notice the EOF. */
                         if (st.st_size > 0)
-                                n = st.st_size + 1;
+                                n_next = st.st_size + 1;
+
+                        if (flags & READ_FULL_FILE_SECURE)
+                                (void) warn_file_is_world_accessible(filename, &st, NULL, 0);
                 }
         }
 
-        l = 0;
+        n = l = 0;
         for (;;) {
                 char *t;
                 size_t k;
 
-                t = realloc(buf, n + 1);
-                if (!t)
-                        return -ENOMEM;
+                if (flags & READ_FULL_FILE_SECURE) {
+                        t = malloc(n_next + 1);
+                        if (!t) {
+                                r = -ENOMEM;
+                                goto finalize;
+                        }
+                        memcpy_safe(t, buf, n);
+                        explicit_bzero_safe(buf, n);
+                } else {
+                        t = realloc(buf, n_next + 1);
+                        if (!t)
+                                return -ENOMEM;
+                }
 
                 buf = t;
+                n = n_next;
+
                 errno = 0;
                 k = fread(buf + l, 1, n - l, f);
                 if (k > 0)
                         l += k;
 
-                if (ferror(f))
-                        return errno > 0 ? -errno : -EIO;
+                if (ferror(f)) {
+                        r = errno > 0 ? -errno : -EIO;
+                        goto finalize;
+                }
 
                 if (feof(f))
                         break;
@@ -329,10 +348,18 @@ int read_full_stream(
                 assert(l == n);
 
                 /* Safety check */
-                if (n >= READ_FULL_BYTES_MAX)
-                        return -E2BIG;
+                if (n >= READ_FULL_BYTES_MAX) {
+                        r = -E2BIG;
+                        goto finalize;
+                }
+
+                n_next = MIN(n * 2, READ_FULL_BYTES_MAX);
+        }
 
-                n = MIN(n * 2, READ_FULL_BYTES_MAX);
+        if (flags & READ_FULL_FILE_UNBASE64) {
+                buf[l++] = 0;
+                r = unbase64mem_full(buf, l, flags & READ_FULL_FILE_SECURE, (void **) ret_contents, ret_size);
+                goto finalize;
         }
 
         if (!ret_size) {
@@ -340,8 +367,10 @@ int read_full_stream(
                  * trailing NUL byte. But if there's an embedded NUL byte, then we should refuse operation as otherwise
                  * there'd be ambiguity about what we just read. */
 
-                if (memchr(buf, 0, l))
-                        return -EBADMSG;
+                if (memchr(buf, 0, l)) {
+                        r = -EBADMSG;
+                        goto finalize;
+                }
         }
 
         buf[l] = 0;
@@ -351,21 +380,27 @@ int read_full_stream(
                 *ret_size = l;
 
         return 0;
+
+finalize:
+        if (flags & READ_FULL_FILE_SECURE)
+                explicit_bzero_safe(buf, n);
+
+        return r;
 }
 
-int read_full_file(const char *fn, char **contents, size_t *size) {
+int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size) {
         _cleanup_fclose_ FILE *f = NULL;
 
-        assert(fn);
+        assert(filename);
         assert(contents);
 
-        f = fopen(fn, "re");
+        f = fopen(filename, "re");
         if (!f)
                 return -errno;
 
         (void) __fsetlocking(f, FSETLOCKING_BYCALLER);
 
-        return read_full_stream(f, contents, size);
+        return read_full_stream_full(f, filename, flags, contents, size);
 }
 
 int executable_is_script(const char *path, char **interpreter) {
@@ -820,3 +855,28 @@ int safe_fgetc(FILE *f, char *ret) {
 
         return 1;
 }
+
+int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line) {
+        struct stat _st;
+
+        if (!filename)
+                return 0;
+
+        if (!st) {
+                if (stat(filename, &_st) < 0)
+                        return -errno;
+                st = &_st;
+        }
+
+        if ((st->st_mode & S_IRWXO) == 0)
+                return 0;
+
+        if (unit)
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "%s has %04o mode that is too permissive, please adjust the access mode.",
+                           filename, st->st_mode & 07777);
+        else
+                log_warning("%s has %04o mode that is too permissive, please adjust the access mode.",
+                            filename, st->st_mode & 07777);
+        return 0;
+}
index 53e3f4e..760e738 100644 (file)
@@ -5,6 +5,7 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdio.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 
 #include "macro.h"
@@ -27,6 +28,11 @@ typedef enum {
 
 } WriteStringFileFlags;
 
+typedef enum {
+        READ_FULL_FILE_SECURE   = 1 << 0,
+        READ_FULL_FILE_UNBASE64 = 1 << 1,
+} ReadFullFileFlags;
+
 int write_string_stream_ts(FILE *f, const char *line, WriteStringFileFlags flags, struct timespec *ts);
 static inline int write_string_stream(FILE *f, const char *line, WriteStringFileFlags flags) {
         return write_string_stream_ts(f, line, flags, NULL);
@@ -38,9 +44,15 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin
 
 int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4);
 
-int read_one_line_file(const char *fn, char **line);
-int read_full_file(const char *fn, char **contents, size_t *size);
-int read_full_stream(FILE *f, char **contents, size_t *size);
+int read_one_line_file(const char *filename, char **line);
+int read_full_file_full(const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
+static inline int read_full_file(const char *filename, char **contents, size_t *size) {
+        return read_full_file_full(filename, 0, contents, size);
+}
+int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size);
+static inline int read_full_stream(FILE *f, char **contents, size_t *size) {
+        return read_full_stream_full(f, NULL, 0, contents, size);
+}
 
 int verify_file(const char *fn, const char *blob, bool accept_extra_nl);
 
@@ -76,3 +88,5 @@ static inline int read_nul_string(FILE *f, size_t limit, char **ret) {
 }
 
 int safe_fgetc(FILE *f, char *ret);
+
+int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line);
index 82ba35b..2316afb 100644 (file)
@@ -6,6 +6,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <linux/falloc.h>
 #include <linux/magic.h>
 #include <time.h>
 #include <unistd.h>
@@ -214,64 +215,109 @@ int readlink_and_make_absolute(const char *p, char **r) {
 int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid) {
         char fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
         _cleanup_close_ int fd = -1;
+        bool st_valid = false;
+        struct stat st;
+        int r;
+
         assert(path);
 
-        /* Under the assumption that we are running privileged we first change the access mode and only then hand out
-         * ownership to avoid a window where access is too open. */
+        /* Under the assumption that we are running privileged we first change the access mode and only then
+         * hand out ownership to avoid a window where access is too open. */
 
-        fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change mode/owner
-                                                       * on the same file */
+        fd = open(path, O_PATH|O_CLOEXEC|O_NOFOLLOW); /* Let's acquire an O_PATH fd, as precaution to change
+                                                       * mode/owner on the same file */
         if (fd < 0)
                 return -errno;
 
         xsprintf(fd_path, "/proc/self/fd/%i", fd);
 
         if (mode != MODE_INVALID) {
-
                 if ((mode & S_IFMT) != 0) {
-                        struct stat st;
 
                         if (stat(fd_path, &st) < 0)
                                 return -errno;
 
                         if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
                                 return -EINVAL;
+
+                        st_valid = true;
                 }
 
-                if (chmod(fd_path, mode & 07777) < 0)
-                        return -errno;
+                if (chmod(fd_path, mode & 07777) < 0) {
+                        r = -errno;
+
+                        if (!st_valid && stat(fd_path, &st) < 0)
+                                return -errno;
+
+                        if ((mode & 07777) != (st.st_mode & 07777))
+                                return r;
+
+                        st_valid = true;
+                }
         }
 
-        if (uid != UID_INVALID || gid != GID_INVALID)
-                if (chown(fd_path, uid, gid) < 0)
-                        return -errno;
+        if (uid != UID_INVALID || gid != GID_INVALID) {
+                if (chown(fd_path, uid, gid) < 0) {
+                        r = -errno;
+
+                        if (!st_valid && stat(fd_path, &st) < 0)
+                                return -errno;
+
+                        if (uid != UID_INVALID && st.st_uid != uid)
+                                return r;
+                        if (gid != GID_INVALID && st.st_gid != gid)
+                                return r;
+                }
+        }
 
         return 0;
 }
 
 int fchmod_and_chown(int fd, mode_t mode, uid_t uid, gid_t gid) {
+        bool st_valid = false;
+        struct stat st;
+        int r;
+
         /* Under the assumption that we are running privileged we first change the access mode and only then hand out
          * ownership to avoid a window where access is too open. */
 
         if (mode != MODE_INVALID) {
-
                 if ((mode & S_IFMT) != 0) {
-                        struct stat st;
 
                         if (fstat(fd, &st) < 0)
                                 return -errno;
 
                         if ((mode & S_IFMT) != (st.st_mode & S_IFMT))
                                 return -EINVAL;
+
+                        st_valid = true;
                 }
 
-                if (fchmod(fd, mode & 0777) < 0)
-                        return -errno;
+                if (fchmod(fd, mode & 07777) < 0) {
+                        r = -errno;
+
+                        if (!st_valid && fstat(fd, &st) < 0)
+                                return -errno;
+
+                        if ((mode & 07777) != (st.st_mode & 07777))
+                                return r;
+
+                        st_valid = true;
+                }
         }
 
         if (uid != UID_INVALID || gid != GID_INVALID)
-                if (fchown(fd, uid, gid) < 0)
-                        return -errno;
+                if (fchown(fd, uid, gid) < 0) {
+                        r = -errno;
+
+                        if (!st_valid && fstat(fd, &st) < 0)
+                                return -errno;
+
+                        if (uid != UID_INVALID && st.st_uid != uid)
+                                return r;
+                        if (gid != GID_INVALID && st.st_gid != gid)
+                                return r;
+                }
 
         return 0;
 }
@@ -307,6 +353,10 @@ int fd_warn_permissions(const char *path, int fd) {
         if (fstat(fd, &st) < 0)
                 return -errno;
 
+        /* Don't complain if we are reading something that is not a file, for example /dev/null */
+        if (!S_ISREG(st.st_mode))
+                return 0;
+
         if (st.st_mode & 0111)
                 log_warning("Configuration file %s is marked executable. Please remove executable permission bits. Proceeding anyway.", path);
 
@@ -931,6 +981,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags,
                 if (fstat(child, &st) < 0)
                         return -errno;
                 if ((flags & CHASE_SAFE) &&
+                    (empty_or_root(root) || (size_t)(todo - buffer) > strlen(root)) &&
                     unsafe_transition(&previous_stat, &st))
                         return log_unsafe_transition(fd, child, path, flags);
 
@@ -1335,6 +1386,21 @@ int fsync_path_at(int at_fd, const char *path) {
         return 0;
 }
 
+int syncfs_path(int atfd, const char *path) {
+        _cleanup_close_ int fd = -1;
+
+        assert(path);
+
+        fd = openat(atfd, path, O_CLOEXEC|O_RDONLY|O_NONBLOCK);
+        if (fd < 0)
+                return -errno;
+
+        if (syncfs(fd) < 0)
+                return -errno;
+
+        return 0;
+}
+
 int open_parent(const char *path, int flags, mode_t mode) {
         _cleanup_free_ char *parent = NULL;
         int fd;
@@ -1351,9 +1417,9 @@ int open_parent(const char *path, int flags, mode_t mode) {
         /* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an
          * O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */
 
-        if ((flags & O_PATH) == O_PATH)
+        if (FLAGS_SET(flags, O_PATH))
                 flags |= O_DIRECTORY;
-        else if ((flags & O_TMPFILE) != O_TMPFILE)
+        else if (!FLAGS_SET(flags, O_TMPFILE))
                 flags |= O_DIRECTORY|O_RDONLY;
 
         fd = open(parent, flags, mode);
index 7ad030b..b965120 100644 (file)
@@ -10,8 +10,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "errno-util.h"
 #include "time-util.h"
-#include "util.h"
 
 int unlink_noerrno(const char *path);
 
@@ -108,4 +108,6 @@ int unlinkat_deallocate(int fd, const char *name, int flags);
 int fsync_directory_of_file(int fd);
 int fsync_path_at(int at_fd, const char *path);
 
+int syncfs_path(int atfd, const char *path);
+
 int open_parent(const char *path, int flags, mode_t mode);
index f304a2b..9bab47d 100644 (file)
@@ -7,12 +7,10 @@
 #include "hexdecoct.h"
 
 void initialize_libgcrypt(bool secmem) {
-        const char *p;
         if (gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P))
                 return;
 
-        p = gcry_check_version("1.4.5");
-        assert(p);
+        assert_se(gcry_check_version("1.4.5"));
 
         /* Turn off "secmem". Clients which wish to make use of this
          * feature should initialize the library manually */
index 9fac676..32c53f8 100644 (file)
@@ -4,6 +4,8 @@
 #include <errno.h>
 #include <glob.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include "dirent-util.h"
 #include "glob-util.h"
index 66e9e00..c7bd732 100644 (file)
@@ -9,6 +9,7 @@
 #include "fileio.h"
 #include "hashmap.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "mempool.h"
 #include "process-util.h"
 #include "random-util.h"
@@ -16,7 +17,6 @@
 #include "siphash24.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 #if ENABLE_DEBUG_HASHMAP
 #include <pthread.h>
@@ -1536,7 +1536,6 @@ void *internal_hashmap_first_key_and_value(HashmapBase *h, bool remove, void **r
 }
 
 unsigned internal_hashmap_size(HashmapBase *h) {
-
         if (!h)
                 return 0;
 
@@ -1544,7 +1543,6 @@ unsigned internal_hashmap_size(HashmapBase *h) {
 }
 
 unsigned internal_hashmap_buckets(HashmapBase *h) {
-
         if (!h)
                 return 0;
 
@@ -1904,8 +1902,7 @@ IteratedCache *iterated_cache_free(IteratedCache *cache) {
         if (cache) {
                 free(cache->keys.ptr);
                 free(cache->values.ptr);
-                free(cache);
         }
 
-        return NULL;
+        return mfree(cache);
 }
index e16a9f9..41c8adb 100644 (file)
@@ -412,9 +412,11 @@ static inline char **ordered_hashmap_get_strv(OrderedHashmap *h) {
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_key);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, hashmap_free_free_free);
 DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free);
 DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free);
+DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_key);
 DEFINE_TRIVIAL_CLEANUP_FUNC(OrderedHashmap*, ordered_hashmap_free_free_free);
 
 #define _cleanup_hashmap_free_ _cleanup_(hashmap_freep)
index c0f9640..132439f 100644 (file)
@@ -8,8 +8,8 @@
 #include "alloc-util.h"
 #include "hexdecoct.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "string-util.h"
-#include "util.h"
 
 char octchar(int x) {
         return '0' + (x & 7);
@@ -601,10 +601,11 @@ static int base64_append_width(
         lines = DIV_ROUND_UP(len, width);
 
         slen = strlen_ptr(sep);
-        if (lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
+        if (plen >= SSIZE_MAX - 1 - slen ||
+            lines > (SSIZE_MAX - plen - 1 - slen) / (indent + width + 1))
                 return -ENOMEM;
 
-        t = realloc(*prefix, plen + 1 + slen + (indent + width + 1) * lines);
+        t = realloc(*prefix, (ssize_t) plen + 1 + slen + (indent + width + 1) * lines);
         if (!t)
                 return -ENOMEM;
 
@@ -639,7 +640,7 @@ int base64_append(
                 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);
+                return base64_append_width(prefix, plen, " ", plen, p, l, width - plen - 1);
 }
 
 static int unbase64_next(const char **p, size_t *l) {
@@ -684,11 +685,12 @@ static int unbase64_next(const char **p, size_t *l) {
         return ret;
 }
 
-int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
+int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_size) {
         _cleanup_free_ uint8_t *buf = NULL;
         const char *x;
         uint8_t *z;
         size_t len;
+        int r;
 
         assert(p || l == 0);
         assert(ret);
@@ -711,36 +713,54 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
                 a = unbase64_next(&x, &l);
                 if (a == -EPIPE) /* End of string */
                         break;
-                if (a < 0)
-                        return a;
-                if (a == INT_MAX) /* Padding is not allowed at the beginning of a 4ch block */
-                        return -EINVAL;
+                if (a < 0) {
+                        r = a;
+                        goto on_failure;
+                }
+                if (a == INT_MAX) { /* Padding is not allowed at the beginning of a 4ch block */
+                        r = -EINVAL;
+                        goto on_failure;
+                }
 
                 b = unbase64_next(&x, &l);
-                if (b < 0)
-                        return b;
-                if (b == INT_MAX) /* Padding is not allowed at the second character of a 4ch block either */
-                        return -EINVAL;
+                if (b < 0) {
+                        r = b;
+                        goto on_failure;
+                }
+                if (b == INT_MAX) { /* Padding is not allowed at the second character of a 4ch block either */
+                        r = -EINVAL;
+                        goto on_failure;
+                }
 
                 c = unbase64_next(&x, &l);
-                if (c < 0)
-                        return c;
+                if (c < 0) {
+                        r = c;
+                        goto on_failure;
+                }
 
                 d = unbase64_next(&x, &l);
-                if (d < 0)
-                        return d;
+                if (d < 0) {
+                        r = d;
+                        goto on_failure;
+                }
 
                 if (c == INT_MAX) { /* Padding at the third character */
 
-                        if (d != INT_MAX) /* If the third character is padding, the fourth must be too */
-                                return -EINVAL;
+                        if (d != INT_MAX) { /* If the third character is padding, the fourth must be too */
+                                r = -EINVAL;
+                                goto on_failure;
+                        }
 
                         /* b == 00YY0000 */
-                        if (b & 15)
-                                return -EINVAL;
+                        if (b & 15) {
+                                r = -EINVAL;
+                                goto on_failure;
+                        }
 
-                        if (l > 0) /* Trailing rubbish? */
-                                return -ENAMETOOLONG;
+                        if (l > 0) { /* Trailing rubbish? */
+                                r = -ENAMETOOLONG;
+                                goto on_failure;
+                        }
 
                         *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */
                         break;
@@ -748,11 +768,15 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
 
                 if (d == INT_MAX) {
                         /* c == 00ZZZZ00 */
-                        if (c & 3)
-                                return -EINVAL;
+                        if (c & 3) {
+                                r = -EINVAL;
+                                goto on_failure;
+                        }
 
-                        if (l > 0) /* Trailing rubbish? */
-                                return -ENAMETOOLONG;
+                        if (l > 0) { /* Trailing rubbish? */
+                                r = -ENAMETOOLONG;
+                                goto on_failure;
+                        }
 
                         *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */
                         *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */
@@ -770,6 +794,12 @@ int unbase64mem(const char *p, size_t l, void **ret, size_t *ret_size) {
         *ret = TAKE_PTR(buf);
 
         return 0;
+
+on_failure:
+        if (secure)
+                explicit_bzero_safe(buf, len);
+
+        return r;
 }
 
 void hexdump(FILE *f, const void *p, size_t s) {
index 9477d16..fa6013e 100644 (file)
@@ -33,6 +33,9 @@ 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);
+int unbase64mem_full(const char *p, size_t l, bool secure, void **mem, size_t *len);
+static inline int unbase64mem(const char *p, size_t l, void **mem, size_t *len) {
+        return unbase64mem_full(p, l, false, mem, len);
+}
 
 void hexdump(FILE *f, const void *p, size_t s);
index 2bffe47..1d5c641 100644 (file)
@@ -5,12 +5,15 @@
 #include <errno.h>
 #include <net/if.h>
 #include <stdint.h>
+#include <stdio.h>
 #include <stdlib.h>
 
 #include "alloc-util.h"
 #include "in-addr-util.h"
 #include "macro.h"
 #include "parse-util.h"
+#include "random-util.h"
+#include "strxcpyx.h"
 #include "util.h"
 
 bool in4_addr_is_null(const struct in_addr *a) {
@@ -68,6 +71,14 @@ bool in4_addr_is_localhost(const struct in_addr *a) {
         return (be32toh(a->s_addr) & UINT32_C(0xFF000000)) == UINT32_C(127) << 24;
 }
 
+bool in4_addr_is_non_local(const struct in_addr *a) {
+        /* Whether the address is not null and not localhost.
+         *
+         * As such, it is suitable to configure as DNS/NTP server from DHCP. */
+        return !in4_addr_is_null(a) &&
+               !in4_addr_is_localhost(a);
+}
+
 int in_addr_is_localhost(int family, const union in_addr_union *u) {
         assert(u);
 
@@ -207,8 +218,85 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen)
         return -EAFNOSUPPORT;
 }
 
+int in_addr_random_prefix(
+                int family,
+                union in_addr_union *u,
+                unsigned prefixlen_fixed_part,
+                unsigned prefixlen) {
+
+        assert(u);
+
+        /* Random network part of an address by one. */
+
+        if (prefixlen <= 0)
+                return 0;
+
+        if (family == AF_INET) {
+                uint32_t c, n;
+
+                if (prefixlen_fixed_part > 32)
+                        prefixlen_fixed_part = 32;
+                if (prefixlen > 32)
+                        prefixlen = 32;
+                if (prefixlen_fixed_part >= prefixlen)
+                        return -EINVAL;
+
+                c = be32toh(u->in.s_addr);
+                c &= ((UINT32_C(1) << prefixlen_fixed_part) - 1) << (32 - prefixlen_fixed_part);
+
+                random_bytes(&n, sizeof(n));
+                n &= ((UINT32_C(1) << (prefixlen - prefixlen_fixed_part)) - 1) << (32 - prefixlen);
+
+                u->in.s_addr = htobe32(n | c);
+                return 1;
+        }
+
+        if (family == AF_INET6) {
+                struct in6_addr n;
+                unsigned i, j;
+
+                if (prefixlen_fixed_part > 128)
+                        prefixlen_fixed_part = 128;
+                if (prefixlen > 128)
+                        prefixlen = 128;
+                if (prefixlen_fixed_part >= prefixlen)
+                        return -EINVAL;
+
+                random_bytes(&n, sizeof(n));
+
+                for (i = 0; i < 16; i++) {
+                        uint8_t mask_fixed_part = 0, mask = 0;
+
+                        if (i < (prefixlen_fixed_part + 7) / 8) {
+                                if (i < prefixlen_fixed_part / 8)
+                                        mask_fixed_part = 0xffu;
+                                else {
+                                        j = prefixlen_fixed_part % 8;
+                                        mask_fixed_part = ((UINT8_C(1) << (j + 1)) - 1) << (8 - j);
+                                }
+                        }
+
+                        if (i < (prefixlen + 7) / 8) {
+                                if (i < prefixlen / 8)
+                                        mask = 0xffu ^ mask_fixed_part;
+                                else {
+                                        j = prefixlen % 8;
+                                        mask = (((UINT8_C(1) << (j + 1)) - 1) << (8 - j)) ^ mask_fixed_part;
+                                }
+                        }
+
+                        u->in6.s6_addr[i] &= mask_fixed_part;
+                        u->in6.s6_addr[i] |= n.s6_addr[i] & mask;
+                }
+
+                return 1;
+        }
+
+        return -EAFNOSUPPORT;
+}
+
 int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
-        char *x;
+        _cleanup_free_ char *x = NULL;
         size_t l;
 
         assert(u);
@@ -226,18 +314,50 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) {
                 return -ENOMEM;
 
         errno = 0;
-        if (!inet_ntop(family, u, x, l)) {
-                free(x);
+        if (!inet_ntop(family, u, x, l))
                 return errno > 0 ? -errno : -EINVAL;
-        }
 
-        *ret = x;
+        *ret = TAKE_PTR(x);
+        return 0;
+}
+
+int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) {
+        _cleanup_free_ char *x = NULL;
+        char *p;
+        size_t l;
+
+        assert(u);
+        assert(ret);
+
+        if (family == AF_INET)
+                l = INET_ADDRSTRLEN + 3;
+        else if (family == AF_INET6)
+                l = INET6_ADDRSTRLEN + 4;
+        else
+                return -EAFNOSUPPORT;
+
+        if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
+                return -EINVAL;
+
+        x = new(char, l);
+        if (!x)
+                return -ENOMEM;
+
+        errno = 0;
+        if (!inet_ntop(family, u, x, l))
+                return errno > 0 ? -errno : -EINVAL;
+
+        p = x + strlen(x);
+        l -= strlen(x);
+        (void) strpcpyf(&p, l, "/%u", prefixlen);
+
+        *ret = TAKE_PTR(x);
         return 0;
 }
 
 int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) {
+        _cleanup_free_ char *x = NULL;
         size_t l;
-        char *x;
         int r;
 
         assert(u);
@@ -263,14 +383,12 @@ int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifin
                 return -ENOMEM;
 
         errno = 0;
-        if (!inet_ntop(family, u, x, l)) {
-                free(x);
+        if (!inet_ntop(family, u, x, l))
                 return errno > 0 ? -errno : -EINVAL;
-        }
 
         sprintf(strchr(x, 0), "%%%i", ifindex);
-        *ret = x;
 
+        *ret = TAKE_PTR(x);
         return 0;
 
 fallback:
index 3069790..a6a685b 100644 (file)
@@ -30,10 +30,14 @@ int in_addr_is_link_local(int family, const union in_addr_union *u);
 bool in4_addr_is_localhost(const struct in_addr *a);
 int in_addr_is_localhost(int family, const union in_addr_union *u);
 
+bool in4_addr_is_non_local(const struct in_addr *a);
+
 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);
+int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen);
 int in_addr_to_string(int family, const union in_addr_union *u, char **ret);
+int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret);
 int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret);
 int in_addr_from_string(int family, const char *s, union in_addr_union *ret);
 int in_addr_from_string_auto(const char *s, int *ret_family, union in_addr_union *ret);
diff --git a/src/basic/kbd-util.c b/src/basic/kbd-util.c
new file mode 100644 (file)
index 0000000..17d4022
--- /dev/null
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <ftw.h>
+
+#include "kbd-util.h"
+#include "log.h"
+#include "nulstr-util.h"
+#include "path-util.h"
+#include "set.h"
+#include "string-util.h"
+#include "strv.h"
+#include "utf8.h"
+
+static thread_local Set *keymaps = NULL;
+
+static int nftw_cb(
+                const char *fpath,
+                const struct stat *sb,
+                int tflag,
+                struct FTW *ftwbuf) {
+
+        _cleanup_free_ char *p = NULL;
+        char *e;
+        int r;
+
+        if (tflag != FTW_F)
+                return 0;
+
+        if (!endswith(fpath, ".map") &&
+            !endswith(fpath, ".map.gz"))
+                return 0;
+
+        p = strdup(basename(fpath));
+        if (!p)
+                return FTW_STOP;
+
+        e = endswith(p, ".map");
+        if (e)
+                *e = 0;
+
+        e = endswith(p, ".map.gz");
+        if (e)
+                *e = 0;
+
+        if (!keymap_is_valid(p))
+                return 0;
+
+        r = set_consume(keymaps, TAKE_PTR(p));
+        if (r < 0 && r != -EEXIST)
+                return r;
+
+        return 0;
+}
+
+int get_keymaps(char ***ret) {
+        _cleanup_strv_free_ char **l = NULL;
+        const char *dir;
+        int r;
+
+        keymaps = set_new(&string_hash_ops);
+        if (!keymaps)
+                return -ENOMEM;
+
+        NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
+                r = nftw(dir, nftw_cb, 20, FTW_PHYS|FTW_ACTIONRETVAL);
+
+                if (r == FTW_STOP)
+                        log_debug("Directory not found %s", dir);
+                else if (r < 0)
+                        log_debug_errno(r, "Can't add keymap: %m");
+        }
+
+        l = set_get_strv(keymaps);
+        if (!l) {
+                set_free_free(keymaps);
+                return -ENOMEM;
+        }
+
+        set_free(keymaps);
+
+        if (strv_isempty(l))
+                return -ENOENT;
+
+        strv_sort(l);
+
+        *ret = TAKE_PTR(l);
+
+        return 0;
+}
+
+bool keymap_is_valid(const char *name) {
+
+        if (isempty(name))
+                return false;
+
+        if (strlen(name) >= 128)
+                return false;
+
+        if (!utf8_is_valid(name))
+                return false;
+
+        if (!filename_is_valid(name))
+                return false;
+
+        if (!string_is_safe(name))
+                return false;
+
+        return true;
+}
diff --git a/src/basic/kbd-util.h b/src/basic/kbd-util.h
new file mode 100644 (file)
index 0000000..9efd2c7
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+#if HAVE_SPLIT_USR
+#define KBD_KEYMAP_DIRS                         \
+        "/usr/share/keymaps/\0"                 \
+        "/usr/share/kbd/keymaps/\0"             \
+        "/usr/lib/kbd/keymaps/\0"               \
+        "/lib/kbd/keymaps/\0"
+#else
+#define KBD_KEYMAP_DIRS                         \
+        "/usr/share/keymaps/\0"                 \
+        "/usr/share/kbd/keymaps/\0"             \
+        "/usr/lib/kbd/keymaps/\0"
+#endif
+
+int get_keymaps(char ***l);
+bool keymap_is_valid(const char *name);
diff --git a/src/basic/limits-util.c b/src/basic/limits-util.c
new file mode 100644 (file)
index 0000000..fbf52e5
--- /dev/null
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "cgroup-util.h"
+#include "limits-util.h"
+#include "memory-util.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "procfs-util.h"
+#include "string-util.h"
+
+uint64_t physical_memory(void) {
+        _cleanup_free_ char *root = NULL, *value = NULL;
+        uint64_t mem, lim;
+        size_t ps;
+        long sc;
+        int r;
+
+        /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
+         * memory.
+         *
+         * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
+         * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
+
+        sc = sysconf(_SC_PHYS_PAGES);
+        assert(sc > 0);
+
+        ps = page_size();
+        mem = (uint64_t) sc * (uint64_t) ps;
+
+        r = cg_get_root_path(&root);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m");
+                return mem;
+        }
+
+        r = cg_all_unified();
+        if (r < 0) {
+                log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m");
+                return mem;
+        }
+        if (r > 0) {
+                r = cg_get_attribute("memory", root, "memory.max", &value);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
+                        return mem;
+                }
+
+                if (streq(value, "max"))
+                        return mem;
+        } else {
+                r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m");
+                        return mem;
+                }
+        }
+
+        r = safe_atou64(value, &lim);
+        if (r < 0) {
+                log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value);
+                return mem;
+        }
+        if (lim == UINT64_MAX)
+                return mem;
+
+        /* Make sure the limit is a multiple of our own page size */
+        lim /= ps;
+        lim *= ps;
+
+        return MIN(mem, lim);
+}
+
+uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
+        uint64_t p, m, ps, r;
+
+        assert(max > 0);
+
+        /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
+         * the result is a multiple of the page size (rounds down). */
+
+        ps = page_size();
+        assert(ps > 0);
+
+        p = physical_memory() / ps;
+        assert(p > 0);
+
+        m = p * v;
+        if (m / p != v)
+                return UINT64_MAX;
+
+        m /= max;
+
+        r = m * ps;
+        if (r / ps != m)
+                return UINT64_MAX;
+
+        return r;
+}
+
+uint64_t system_tasks_max(void) {
+
+        uint64_t a = TASKS_MAX, b = TASKS_MAX;
+        _cleanup_free_ char *root = NULL;
+        int r;
+
+        /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
+         * limit:
+         *
+         * a) the maximum tasks value the kernel allows on this architecture
+         * b) the cgroups pids_max attribute for the system
+         * c) the kernel's configured maximum PID value
+         *
+         * And then pick the smallest of the three */
+
+        r = procfs_tasks_get_limit(&a);
+        if (r < 0)
+                log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m");
+
+        r = cg_get_root_path(&root);
+        if (r < 0)
+                log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m");
+        else {
+                _cleanup_free_ char *value = NULL;
+
+                r = cg_get_attribute("pids", root, "pids.max", &value);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m");
+                else if (!streq(value, "max")) {
+                        r = safe_atou64(value, &b);
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m");
+                }
+        }
+
+        return MIN3(TASKS_MAX,
+                    a <= 0 ? TASKS_MAX : a,
+                    b <= 0 ? TASKS_MAX : b);
+}
+
+uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
+        uint64_t t, m;
+
+        assert(max > 0);
+
+        /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
+         * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
+
+        t = system_tasks_max();
+        assert(t > 0);
+
+        m = t * v;
+        if (m / t != v) /* overflow? */
+                return UINT64_MAX;
+
+        return m / max;
+}
diff --git a/src/basic/limits-util.h b/src/basic/limits-util.h
new file mode 100644 (file)
index 0000000..77895cb
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <inttypes.h>
+
+uint64_t physical_memory(void);
+uint64_t physical_memory_scale(uint64_t v, uint64_t max);
+
+uint64_t system_tasks_max(void);
+uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
index fc1577a..6f41f50 100644 (file)
@@ -255,99 +255,6 @@ out:
         return (bool) cached_answer;
 }
 
-static thread_local Set *keymaps = NULL;
-
-static int nftw_cb(
-                const char *fpath,
-                const struct stat *sb,
-                int tflag,
-                struct FTW *ftwbuf) {
-
-        char *p, *e;
-        int r;
-
-        if (tflag != FTW_F)
-                return 0;
-
-        if (!endswith(fpath, ".map") &&
-            !endswith(fpath, ".map.gz"))
-                return 0;
-
-        p = strdup(basename(fpath));
-        if (!p)
-                return FTW_STOP;
-
-        e = endswith(p, ".map");
-        if (e)
-                *e = 0;
-
-        e = endswith(p, ".map.gz");
-        if (e)
-                *e = 0;
-
-        r = set_consume(keymaps, p);
-        if (r < 0 && r != -EEXIST)
-                return r;
-
-        return 0;
-}
-
-int get_keymaps(char ***ret) {
-        _cleanup_strv_free_ char **l = NULL;
-        const char *dir;
-        int r;
-
-        keymaps = set_new(&string_hash_ops);
-        if (!keymaps)
-                return -ENOMEM;
-
-        NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) {
-                r = nftw(dir, nftw_cb, 20, FTW_PHYS|FTW_ACTIONRETVAL);
-
-                if (r == FTW_STOP)
-                        log_debug("Directory not found %s", dir);
-                else if (r < 0)
-                        log_debug_errno(r, "Can't add keymap: %m");
-        }
-
-        l = set_get_strv(keymaps);
-        if (!l) {
-                set_free_free(keymaps);
-                return -ENOMEM;
-        }
-
-        set_free(keymaps);
-
-        if (strv_isempty(l))
-                return -ENOENT;
-
-        strv_sort(l);
-
-        *ret = TAKE_PTR(l);
-
-        return 0;
-}
-
-bool keymap_is_valid(const char *name) {
-
-        if (isempty(name))
-                return false;
-
-        if (strlen(name) >= 128)
-                return false;
-
-        if (!utf8_is_valid(name))
-                return false;
-
-        if (!filename_is_valid(name))
-                return false;
-
-        if (!string_is_safe(name))
-                return false;
-
-        return true;
-}
-
 static bool emoji_enabled(void) {
         static int cached_emoji_enabled = -1;
 
index e64f0ce..78abbaf 100644 (file)
@@ -68,9 +68,6 @@ const char *special_glyph(SpecialGlyph code) _const_;
 const char* locale_variable_to_string(LocaleVariable i) _const_;
 LocaleVariable locale_variable_from_string(const char *s) _pure_;
 
-int get_keymaps(char ***l);
-bool keymap_is_valid(const char *name);
-
 static inline void freelocalep(locale_t *p) {
         if (*p == (locale_t) 0)
                 return;
index 0486027..ea252c4 100644 (file)
@@ -19,6 +19,7 @@
 #include "sd-messages.h"
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "io-util.h"
@@ -37,7 +38,6 @@
 #include "terminal-util.h"
 #include "time-util.h"
 #include "utf8.h"
-#include "util.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
 
@@ -699,8 +699,7 @@ int log_internal_realm(
         return r;
 }
 
-_printf_(10,0)
-static int log_object_internalv(
+int log_object_internalv(
                 int level,
                 int error,
                 const char *file,
@@ -1223,7 +1222,7 @@ int log_syntax_internal(
             log_target == LOG_TARGET_NULL)
                 return -ERRNO_VALUE(error);
 
-        errno = error;
+        errno = ERRNO_VALUE(error);
 
         va_start(ap, format);
         (void) vsnprintf(buffer, sizeof buffer, format, ap);
@@ -1232,16 +1231,34 @@ int log_syntax_internal(
         if (unit)
                 unit_fmt = getpid_cached() == 1 ? "UNIT=%s" : "USER_UNIT=%s";
 
-        return log_struct_internal(
-                        LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
-                        error,
-                        file, line, func,
-                        "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
-                        "CONFIG_FILE=%s", config_file,
-                        "CONFIG_LINE=%u", config_line,
-                        LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
-                        unit_fmt, unit,
-                        NULL);
+        if (config_file)
+                return log_struct_internal(
+                                LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
+                                error,
+                                file, line, func,
+                                "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
+                                "CONFIG_FILE=%s", config_file,
+                                "CONFIG_LINE=%u", config_line,
+                                LOG_MESSAGE("%s:%u: %s", config_file, config_line, buffer),
+                                unit_fmt, unit,
+                                NULL);
+        else if (unit)
+                return log_struct_internal(
+                                LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
+                                error,
+                                file, line, func,
+                                "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
+                                LOG_MESSAGE("%s: %s", unit, buffer),
+                                unit_fmt, unit,
+                                NULL);
+        else
+                return log_struct_internal(
+                                LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level),
+                                error,
+                                file, line, func,
+                                "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR,
+                                LOG_MESSAGE("%s", buffer),
+                                NULL);
 }
 
 int log_syntax_invalid_utf8_internal(
index 17438d7..aa3d5b7 100644 (file)
@@ -115,6 +115,19 @@ int log_internalv_realm(
         log_internalv_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__)
 
 /* Realm is fixed to LOG_REALM_SYSTEMD for those */
+int log_object_internalv(
+                int level,
+                int error,
+                const char *file,
+                int line,
+                const char *func,
+                const char *object_field,
+                const char *object,
+                const char *extra_field,
+                const char *extra,
+                const char *format,
+                va_list ap) _printf_(10,0);
+
 int log_object_internal(
                 int level,
                 int error,
@@ -308,7 +321,7 @@ int log_syntax_invalid_utf8_internal(
                 int _level = (level), _e = (error);                     \
                 (log_get_max_level() >= LOG_PRI(_level))                \
                         ? log_syntax_internal(unit, _level, config_file, config_line, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
-                        : -abs(_e);                                     \
+                        : -ERRNO_VALUE(_e);                             \
         })
 
 #define log_syntax_invalid_utf8(unit, level, config_file, config_line, rvalue) \
diff --git a/src/basic/memory-util.c b/src/basic/memory-util.c
new file mode 100644 (file)
index 0000000..5f327ef
--- /dev/null
@@ -0,0 +1,57 @@
+#include <unistd.h>
+
+#include "memory-util.h"
+
+size_t page_size(void) {
+        static thread_local size_t pgsz = 0;
+        long r;
+
+        if (_likely_(pgsz > 0))
+                return pgsz;
+
+        r = sysconf(_SC_PAGESIZE);
+        assert(r > 0);
+
+        pgsz = (size_t) r;
+        return pgsz;
+}
+
+bool memeqzero(const void *data, size_t length) {
+        /* Does the buffer consist entirely of NULs?
+         * Copied from https://github.com/systemd/casync/, copied in turn from
+         * https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
+         * which is licensed CC-0.
+         */
+
+        const uint8_t *p = data;
+        size_t i;
+
+        /* Check first 16 bytes manually */
+        for (i = 0; i < 16; i++, length--) {
+                if (length == 0)
+                        return true;
+                if (p[i])
+                        return false;
+        }
+
+        /* Now we know first 16 bytes are NUL, memcmp with self.  */
+        return memcmp(data, p + i, length) == 0;
+}
+
+#if !HAVE_EXPLICIT_BZERO
+/*
+ * The pointer to memset() is volatile so that compiler must de-reference the pointer and can't assume that
+ * it points to any function in particular (such as memset(), which it then might further "optimize"). This
+ * approach is inspired by openssl's crypto/mem_clr.c.
+ */
+typedef void *(*memset_t)(void *,int,size_t);
+
+static volatile memset_t memset_func = memset;
+
+void* explicit_bzero_safe(void *p, size_t l) {
+        if (l > 0)
+                memset_func(p, '\0', l);
+
+        return p;
+}
+#endif
diff --git a/src/basic/memory-util.h b/src/basic/memory-util.h
new file mode 100644 (file)
index 0000000..915c24a
--- /dev/null
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <inttypes.h>
+#include <stdbool.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "macro.h"
+
+size_t page_size(void) _pure_;
+#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
+
+/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
+static inline void memcpy_safe(void *dst, const void *src, size_t n) {
+        if (n == 0)
+                return;
+        assert(src);
+        memcpy(dst, src, n);
+}
+
+/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */
+static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
+        if (n == 0)
+                return 0;
+        assert(s1);
+        assert(s2);
+        return memcmp(s1, s2, n);
+}
+
+/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
+static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
+        return memcmp_safe(s1, s2, MIN(n1, n2))
+            ?: CMP(n1, n2);
+}
+
+#define memzero(x,l)                                            \
+        ({                                                      \
+                size_t _l_ = (l);                               \
+                void *_x_ = (x);                                \
+                _l_ == 0 ? _x_ : memset(_x_, 0, _l_);           \
+        })
+
+#define zero(x) (memzero(&(x), sizeof(x)))
+
+bool memeqzero(const void *data, size_t length);
+
+#define eqzero(x) memeqzero(x, sizeof(x))
+
+static inline void *mempset(void *s, int c, size_t n) {
+        memset(s, c, n);
+        return (uint8_t*)s + n;
+}
+
+/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
+static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
+
+        if (needlelen <= 0)
+                return (void*) haystack;
+
+        if (haystacklen < needlelen)
+                return NULL;
+
+        assert(haystack);
+        assert(needle);
+
+        return memmem(haystack, haystacklen, needle, needlelen);
+}
+
+#if HAVE_EXPLICIT_BZERO
+static inline void* explicit_bzero_safe(void *p, size_t l) {
+        if (l > 0)
+                explicit_bzero(p, l);
+
+        return p;
+}
+#else
+void *explicit_bzero_safe(void *p, size_t l);
+#endif
+
+/* Use with _cleanup_ to erase a single 'char' when leaving scope */
+static inline void erase_char(char *p) {
+        explicit_bzero_safe(p, sizeof(char));
+}
index 159c963..22df421 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "env-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "mempool.h"
 #include "process-util.h"
 #include "util.h"
index 0fff47c..f22d6f6 100644 (file)
@@ -45,6 +45,7 @@ basic_sources = files('''
         env-util.h
         errno-list.c
         errno-list.h
+        errno-util.h
         escape.c
         escape.h
         ether-addr-util.c
@@ -75,10 +76,14 @@ basic_sources = files('''
         io-util.c
         io-util.h
         ioprio.h
+        kbd-util.c
+        kbd-util.h
         khash.c
         khash.h
         label.c
         label.h
+        limits-util.c
+        limits-util.h
         linux/btrfs.h
         linux/btrfs_tree.h
         linux/can/vxcan.h
@@ -108,6 +113,8 @@ basic_sources = files('''
         macro.h
         memfd-util.c
         memfd-util.h
+        memory-util.c
+        memory-util.h
         mempool.c
         mempool.h
         missing.h
@@ -137,13 +144,19 @@ basic_sources = files('''
         mkdir.h
         mountpoint-util.c
         mountpoint-util.h
+        namespace-util.c
+        namespace-util.h
         nss-util.h
+        nulstr-util.c
+        nulstr-util.h
         ordered-set.c
         ordered-set.h
         parse-util.c
         parse-util.h
         path-util.c
         path-util.h
+        plymouth-util.c
+        plymouth-util.h
         prioq.c
         prioq.h
         proc-cmdline.c
@@ -158,7 +171,6 @@ basic_sources = files('''
         ratelimit.h
         raw-clone.h
         raw-reboot.h
-        refcnt.h
         replace-var.c
         replace-var.h
         rlimit-util.c
@@ -179,6 +191,8 @@ basic_sources = files('''
         socket-label.c
         socket-util.c
         socket-util.h
+        sort-util.c
+        sort-util.h
         sparse-endian.h
         special.h
         stat-util.c
index 48c1af0..c262a91 100644 (file)
@@ -61,3 +61,7 @@
 #ifndef NS_GET_NSTYPE /* d95fa3c76a66b6d76b1e109ea505c55e66360f3c (4.11) */
 #define NS_GET_NSTYPE _IO(0xb7, 0x3)
 #endif
+
+#ifndef FS_PROJINHERIT_FL
+#define FS_PROJINHERIT_FL 0x20000000
+#endif
index a5fd457..276be36 100644 (file)
@@ -32,6 +32,10 @@ struct sockaddr_vm {
 #define SO_PEERGROUPS 59
 #endif
 
+#ifndef SO_BINDTOIFINDEX
+#define SO_BINDTOIFINDEX 62
+#endif
+
 #ifndef SOL_NETLINK
 #define SOL_NETLINK 270
 #endif
index 4bb65d5..6b82eab 100644 (file)
@@ -6,6 +6,7 @@
 #include <sys/stat.h>
 
 #include "alloc-util.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "macro.h"
 #include "mkdir.h"
diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c
new file mode 100644 (file)
index 0000000..67bdaa1
--- /dev/null
@@ -0,0 +1,172 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <fcntl.h>
+#include <linux/magic.h>
+
+#include "fd-util.h"
+#include "missing.h"
+#include "namespace-util.h"
+#include "process-util.h"
+#include "stat-util.h"
+#include "user-util.h"
+
+int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
+        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
+        int rfd = -1;
+
+        assert(pid >= 0);
+
+        if (mntns_fd) {
+                const char *mntns;
+
+                mntns = procfs_file_alloca(pid, "ns/mnt");
+                mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (mntnsfd < 0)
+                        return -errno;
+        }
+
+        if (pidns_fd) {
+                const char *pidns;
+
+                pidns = procfs_file_alloca(pid, "ns/pid");
+                pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (pidnsfd < 0)
+                        return -errno;
+        }
+
+        if (netns_fd) {
+                const char *netns;
+
+                netns = procfs_file_alloca(pid, "ns/net");
+                netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (netnsfd < 0)
+                        return -errno;
+        }
+
+        if (userns_fd) {
+                const char *userns;
+
+                userns = procfs_file_alloca(pid, "ns/user");
+                usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (usernsfd < 0 && errno != ENOENT)
+                        return -errno;
+        }
+
+        if (root_fd) {
+                const char *root;
+
+                root = procfs_file_alloca(pid, "root");
+                rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
+                if (rfd < 0)
+                        return -errno;
+        }
+
+        if (pidns_fd)
+                *pidns_fd = pidnsfd;
+
+        if (mntns_fd)
+                *mntns_fd = mntnsfd;
+
+        if (netns_fd)
+                *netns_fd = netnsfd;
+
+        if (userns_fd)
+                *userns_fd = usernsfd;
+
+        if (root_fd)
+                *root_fd = rfd;
+
+        pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
+
+        return 0;
+}
+
+int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
+        if (userns_fd >= 0) {
+                /* Can't setns to your own userns, since then you could
+                 * escalate from non-root to root in your own namespace, so
+                 * check if namespaces equal before attempting to enter. */
+                _cleanup_free_ char *userns_fd_path = NULL;
+                int r;
+                if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
+                        return -ENOMEM;
+
+                r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
+                if (r < 0)
+                        return r;
+                if (r)
+                        userns_fd = -1;
+        }
+
+        if (pidns_fd >= 0)
+                if (setns(pidns_fd, CLONE_NEWPID) < 0)
+                        return -errno;
+
+        if (mntns_fd >= 0)
+                if (setns(mntns_fd, CLONE_NEWNS) < 0)
+                        return -errno;
+
+        if (netns_fd >= 0)
+                if (setns(netns_fd, CLONE_NEWNET) < 0)
+                        return -errno;
+
+        if (userns_fd >= 0)
+                if (setns(userns_fd, CLONE_NEWUSER) < 0)
+                        return -errno;
+
+        if (root_fd >= 0) {
+                if (fchdir(root_fd) < 0)
+                        return -errno;
+
+                if (chroot(".") < 0)
+                        return -errno;
+        }
+
+        return reset_uid_gid();
+}
+
+int fd_is_network_ns(int fd) {
+        struct statfs s;
+        int r;
+
+        /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
+         * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
+         * this somewhat nicely.
+         *
+         * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
+         * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
+
+        if (fstatfs(fd, &s) < 0)
+                return -errno;
+
+        if (!is_fs_type(&s, NSFS_MAGIC)) {
+                /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
+                 * instead. Handle that in a somewhat smart way. */
+
+                if (is_fs_type(&s, PROC_SUPER_MAGIC)) {
+                        struct statfs t;
+
+                        /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
+                         * passed fd might refer to a network namespace, but we can't know for sure. In that case,
+                         * return a recognizable error. */
+
+                        if (statfs("/proc/self/ns/net", &t) < 0)
+                                return -errno;
+
+                        if (s.f_type == t.f_type)
+                                return -EUCLEAN; /* It's possible, we simply don't know */
+                }
+
+                return 0; /* No! */
+        }
+
+        r = ioctl(fd, NS_GET_NSTYPE);
+        if (r < 0) {
+                if (errno == ENOTTY) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
+                        return -EUCLEAN;
+
+                return -errno;
+        }
+
+        return r == CLONE_NEWNET;
+}
diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h
new file mode 100644 (file)
index 0000000..8c17ce9
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <sys/types.h>
+
+int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
+int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
+
+int fd_is_network_ns(int fd);
diff --git a/src/basic/nulstr-util.c b/src/basic/nulstr-util.c
new file mode 100644 (file)
index 0000000..b12d020
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "nulstr-util.h"
+#include "string-util.h"
+
+bool nulstr_contains(const char *nulstr, const char *needle) {
+        const char *i;
+
+        if (!nulstr)
+                return false;
+
+        NULSTR_FOREACH(i, nulstr)
+                if (streq(i, needle))
+                        return true;
+
+        return false;
+}
diff --git a/src/basic/nulstr-util.h b/src/basic/nulstr-util.h
new file mode 100644 (file)
index 0000000..436b271
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+#include <string.h>
+
+#define NULSTR_FOREACH(i, l)                                    \
+        for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
+
+#define NULSTR_FOREACH_PAIR(i, j, l)                             \
+        for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
+
+bool nulstr_contains(const char *nulstr, const char *needle);
index ed9ba77..7fdb47e 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include "fileio.h"
 #include "ordered-set.h"
 #include "strv.h"
 
@@ -45,3 +46,37 @@ int ordered_set_put_strdupv(OrderedSet *s, char **l) {
 
         return n;
 }
+
+int ordered_set_put_string_set(OrderedSet *s, OrderedSet *l) {
+        int n = 0, r;
+        Iterator i;
+        char *p;
+
+        /* Like ordered_set_put_strv, but for an OrderedSet of strings */
+
+        ORDERED_SET_FOREACH(p, l, i) {
+                r = ordered_set_put_strdup(s, p);
+                if (r < 0)
+                        return r;
+
+                n += r;
+        }
+
+        return n;
+}
+
+void ordered_set_print(FILE *f, const char *field, OrderedSet *s) {
+        bool space = false;
+        Iterator i;
+        char *p;
+
+        if (ordered_set_isempty(s))
+                return;
+
+        fputs(field, f);
+
+        ORDERED_SET_FOREACH(p, s, i)
+                fputs_with_space(f, p, NULL, &space);
+
+        fputc('\n', f);
+}
index 7cbb718..61107eb 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <stdio.h>
+
 #include "hashmap.h"
 
 typedef struct OrderedSet OrderedSet;
@@ -48,9 +50,15 @@ static inline void* ordered_set_steal_first(OrderedSet *s) {
         return ordered_hashmap_steal_first((OrderedHashmap*) s);
 }
 
+static inline char **ordered_set_get_strv(OrderedSet *s) {
+        return internal_hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s));
+}
+
 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);
+int ordered_set_put_string_set(OrderedSet *s, OrderedSet *l);
+void ordered_set_print(FILE *f, const char *field, OrderedSet *s);
 
 #define ORDERED_SET_FOREACH(e, s, i)                                    \
         for ((i) = ITERATOR_FIRST; ordered_set_iterate((s), &(i), (void**)&(e)); )
index 2215173..55cb140 100644 (file)
@@ -21,6 +21,7 @@
 #include "log.h"
 #include "macro.h"
 #include "missing.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "stat-util.h"
@@ -1103,48 +1104,40 @@ int path_simplify_and_warn(
                 unsigned line,
                 const char *lvalue) {
 
-        bool absolute, fatal = flag & PATH_CHECK_FATAL;
+        bool fatal = flag & PATH_CHECK_FATAL;
 
         assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
 
-        if (!utf8_is_valid(path)) {
-                log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
-                return -EINVAL;
-        }
+        if (!utf8_is_valid(path))
+                return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
 
         if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
+                bool absolute;
+
                 absolute = path_is_absolute(path);
 
-                if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0,
-                                   "%s= path is not absolute%s: %s",
-                                   lvalue, fatal ? "" : ", ignoring", path);
-                        return -EINVAL;
-                }
+                if (!absolute && (flag & PATH_CHECK_ABSOLUTE))
+                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "%s= path is not absolute%s: %s",
+                                          lvalue, fatal ? "" : ", ignoring", path);
 
-                if (absolute && (flag & PATH_CHECK_RELATIVE)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0,
-                                   "%s= path is absolute%s: %s",
-                                   lvalue, fatal ? "" : ", ignoring", path);
-                        return -EINVAL;
-                }
+                if (absolute && (flag & PATH_CHECK_RELATIVE))
+                        return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+                                          "%s= path is absolute%s: %s",
+                                          lvalue, fatal ? "" : ", ignoring", path);
         }
 
         path_simplify(path, true);
 
-        if (!path_is_normalized(path)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0,
-                           "%s= path is not normalized%s: %s",
-                           lvalue, fatal ? "" : ", ignoring", path);
-                return -EINVAL;
-        }
+        if (!path_is_valid(path))
+                return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+                                  "%s= path has invalid length (%zu bytes)%s.",
+                                  lvalue, strlen(path), fatal ? "" : ", ignoring");
 
-        if (!path_is_valid(path)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0,
-                           "%s= path has invalid length (%zu bytes)%s.",
-                           lvalue, strlen(path), fatal ? "" : ", ignoring");
-                return -EINVAL;
-        }
+        if (!path_is_normalized(path))
+                return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
+                                  "%s= path is not normalized%s: %s",
+                                  lvalue, fatal ? "" : ", ignoring", path);
 
         return 0;
 }
diff --git a/src/basic/plymouth-util.c b/src/basic/plymouth-util.c
new file mode 100644 (file)
index 0000000..2023ec3
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <unistd.h>
+
+#include "plymouth-util.h"
+
+bool plymouth_running(void) {
+        return access("/run/plymouth/pid", F_OK) >= 0;
+}
diff --git a/src/basic/plymouth-util.h b/src/basic/plymouth-util.h
new file mode 100644 (file)
index 0000000..e053991
--- /dev/null
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+#define PLYMOUTH_SOCKET {                                       \
+                .un.sun_family = AF_UNIX,                       \
+                .un.sun_path = "\0/org/freedesktop/plymouthd",  \
+        }
+
+bool plymouth_running(void);
index 78ce43b..f773eea 100644 (file)
@@ -32,7 +32,9 @@
 #include "ioprio.h"
 #include "log.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "missing.h"
+#include "namespace-util.h"
 #include "process-util.h"
 #include "raw-clone.h"
 #include "rlimit-util.h"
@@ -42,7 +44,6 @@
 #include "string-util.h"
 #include "terminal-util.h"
 #include "user-util.h"
-#include "util.h"
 
 int get_process_state(pid_t pid) {
         const char *p;
@@ -933,6 +934,20 @@ int getenv_for_pid(pid_t pid, const char *field, char **ret) {
         return 0;
 }
 
+int pid_is_my_child(pid_t pid) {
+        pid_t ppid;
+        int r;
+
+        if (pid <= 1)
+                return false;
+
+        r = get_process_ppid(pid, &ppid);
+        if (r < 0)
+                return r;
+
+        return ppid == getpid_cached();
+}
+
 bool pid_is_unwaited(pid_t pid) {
         /* Checks whether a PID is still valid at all, including a zombie */
 
@@ -1000,7 +1015,7 @@ _noreturn_ void freeze(void) {
         log_close();
 
         /* Make sure nobody waits for us on a socket anymore */
-        close_all_fds(NULL, 0);
+        (void) close_all_fds(NULL, 0);
 
         sync();
 
@@ -1534,6 +1549,40 @@ int set_oom_score_adjust(int value) {
                                  WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_DISABLE_BUFFER);
 }
 
+int cpus_in_affinity_mask(void) {
+        size_t n = 16;
+        int r;
+
+        for (;;) {
+                cpu_set_t *c;
+
+                c = CPU_ALLOC(n);
+                if (!c)
+                        return -ENOMEM;
+
+                if (sched_getaffinity(0, CPU_ALLOC_SIZE(n), c) >= 0) {
+                        int k;
+
+                        k = CPU_COUNT_S(CPU_ALLOC_SIZE(n), c);
+                        CPU_FREE(c);
+
+                        if (k <= 0)
+                                return -EINVAL;
+
+                        return k;
+                }
+
+                r = -errno;
+                CPU_FREE(c);
+
+                if (r != -EINVAL)
+                        return r;
+                if (n > SIZE_MAX/2)
+                        return -ENOMEM;
+                n *= 2;
+        }
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
index c85ea30..7e1d65a 100644 (file)
@@ -12,6 +12,7 @@
 #include <sys/resource.h>
 #include <sys/types.h>
 
+#include "alloc-util.h"
 #include "format-util.h"
 #include "ioprio.h"
 #include "macro.h"
@@ -68,6 +69,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_is_my_child(pid_t pid);
 int pid_from_same_root_fs(pid_t pid);
 
 bool is_main_thread(void);
@@ -192,3 +194,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX)
                 (pid) = 0;                      \
                 _pid_;                          \
         })
+
+int cpus_in_affinity_mask(void);
index f7decf6..ca25fd2 100644 (file)
 #  include <linux/random.h>
 #endif
 
+#include "alloc-util.h"
 #include "fd-util.h"
 #include "io-util.h"
 #include "missing.h"
 #include "random-util.h"
 #include "time-util.h"
 
-#if HAS_FEATURE_MEMORY_SANITIZER
-#include <sanitizer/msan_interface.h>
-#endif
-
 int rdrand(unsigned long *ret) {
 
 #if defined(__i386__) || defined(__x86_64__)
@@ -58,11 +55,7 @@ int rdrand(unsigned long *ret) {
                      "setc %1"
                      : "=r" (*ret),
                        "=qm" (err));
-
-#if HAS_FEATURE_MEMORY_SANITIZER
-        __msan_unpoison(&err, sizeof(err));
-#endif
-
+        msan_unpoison(&err, sizeof(err));
         if (!err)
                 return -EAGAIN;
 
diff --git a/src/basic/refcnt.h b/src/basic/refcnt.h
deleted file mode 100644 (file)
index 40f9a84..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1+ */
-#pragma once
-
-/* A type-safe atomic refcounter.
- *
- * DO NOT USE THIS UNLESS YOU ACTUALLY CARE ABOUT THREAD SAFETY! */
-
-typedef struct {
-        volatile unsigned _value;
-} RefCount;
-
-#define REFCNT_GET(r) ((r)._value)
-#define REFCNT_INC(r) (__sync_add_and_fetch(&(r)._value, 1))
-#define REFCNT_DEC(r) (__sync_sub_and_fetch(&(r)._value, 1))
-
-#define REFCNT_INIT ((RefCount) { ._value = 1 })
-
-#define _DEFINE_ATOMIC_REF_FUNC(type, name, scope)                    \
-        scope type *name##_ref(type *p) {                               \
-                if (!p)                                                 \
-                        return NULL;                                    \
-                                                                        \
-                assert_se(REFCNT_INC(p->n_ref) >= 2);                   \
-                return p;                                               \
-        }
-
-#define _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, scope)       \
-        scope type *name##_unref(type *p) {                             \
-                if (!p)                                                 \
-                        return NULL;                                    \
-                                                                        \
-                if (REFCNT_DEC(p->n_ref) > 0)                           \
-                        return NULL;                                    \
-                                                                        \
-                return free_func(p);                                    \
-        }
-
-#define DEFINE_ATOMIC_REF_FUNC(type, name)    \
-        _DEFINE_ATOMIC_REF_FUNC(type, name,)
-#define DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name)     \
-        _DEFINE_ATOMIC_REF_FUNC(type, name, _public_)
-
-#define DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func)       \
-        _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func,)
-#define DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func)        \
-        _DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func, _public_)
-
-#define DEFINE_ATOMIC_REF_UNREF_FUNC(type, name, free_func)   \
-        DEFINE_ATOMIC_REF_FUNC(type, name);                   \
-        DEFINE_ATOMIC_UNREF_FUNC(type, name, free_func);
-
-#define DEFINE_PUBLIC_ATOMIC_REF_UNREF_FUNC(type, name, free_func)   \
-        DEFINE_PUBLIC_ATOMIC_REF_FUNC(type, name);                   \
-        DEFINE_PUBLIC_ATOMIC_UNREF_FUNC(type, name, free_func);
index 0c957c9..acc0f88 100644 (file)
@@ -165,6 +165,11 @@ int rm_rf(const char *path, RemoveFlags flags) {
 
         assert(path);
 
+        /* For now, don't support dropping subvols when also only dropping directories, since we can't do
+         * this race-freely. */
+        if (FLAGS_SET(flags, REMOVE_ONLY_DIRECTORIES|REMOVE_SUBVOLUME))
+                return -EINVAL;
+
         /* We refuse to clean the root file system with this
          * call. This is extra paranoia to never cause a really
          * seriously broken system. */
index 3ee2b97..d42ebef 100644 (file)
@@ -3,7 +3,7 @@
 
 #include <sys/stat.h>
 
-#include "util.h"
+#include "errno-util.h"
 
 typedef enum RemoveFlags {
         REMOVE_ONLY_DIRECTORIES = 1 << 0,
index dc06f3d..f35e760 100644 (file)
@@ -1,11 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
+#include <fcntl.h>
 #include <malloc.h>
 #include <stddef.h>
 #include <string.h>
 #include <sys/stat.h>
 #include <sys/time.h>
+#include <sys/types.h>
 #include <sys/un.h>
 #include <syslog.h>
 
@@ -16,6 +18,7 @@
 #endif
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "log.h"
 #include "macro.h"
@@ -23,7 +26,6 @@
 #include "selinux-util.h"
 #include "stdio-util.h"
 #include "time-util.h"
-#include "util.h"
 
 #if HAVE_SELINUX
 DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon);
index d5254ea..a065a45 100644 (file)
@@ -6,8 +6,8 @@
 #include <sys/mman.h>
 
 #include "macro.h"
+#include "memory-util.h"
 #include "sigbus.h"
-#include "util.h"
 
 #define SIGBUS_QUEUE_MAX 64
 
index 4ed19cd..b5e9b37 100644 (file)
@@ -68,9 +68,11 @@ int socket_address_listen(
         }
 
         if (IN_SET(socket_address_family(a), AF_INET, AF_INET6)) {
-                if (bind_to_device)
-                        if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, bind_to_device, strlen(bind_to_device)+1) < 0)
-                                return -errno;
+                if (bind_to_device) {
+                        r = socket_bind_to_ifname(fd, bind_to_device);
+                        if (r < 0)
+                                return r;
+                }
 
                 if (reuse_port) {
                         r = setsockopt_int(fd, SOL_SOCKET, SO_REUSEPORT, true);
index 91bf801..904bafb 100644 (file)
 #include <unistd.h>
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
 #include "log.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "parse-util.h"
 #include "path-util.h"
@@ -31,7 +33,6 @@
 #include "strv.h"
 #include "user-util.h"
 #include "utf8.h"
-#include "util.h"
 
 #if ENABLE_IDN
 #  define IDN_FLAGS NI_IDN
@@ -235,23 +236,32 @@ int socket_address_parse_and_warn(SocketAddress *a, const char *s) {
 }
 
 int socket_address_parse_netlink(SocketAddress *a, const char *s) {
-        int family;
+        _cleanup_free_ char *word = NULL;
         unsigned group = 0;
-        _cleanup_free_ char *sfamily = NULL;
+        int family, r;
+
         assert(a);
         assert(s);
 
         zero(*a);
         a->type = SOCK_RAW;
 
-        errno = 0;
-        if (sscanf(s, "%ms %u", &sfamily, &group) < 1)
-                return errno > 0 ? -errno : -EINVAL;
+        r = extract_first_word(&s, &word, NULL, 0);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return -EINVAL;
 
-        family = netlink_family_from_string(sfamily);
+        family = netlink_family_from_string(word);
         if (family < 0)
                 return -EINVAL;
 
+        if (!isempty(s)) {
+                r = safe_atou(s, &group);
+                if (r < 0)
+                        return r;
+        }
+
         a->sockaddr.nl.nl_family = AF_NETLINK;
         a->sockaddr.nl.nl_groups = group;
 
@@ -1228,22 +1238,22 @@ int flush_accept(int fd) {
                                 continue;
 
                         return -errno;
-
-                } else if (r == 0)
+                }
+                if (r == 0)
                         return 0;
 
                 cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
                 if (cfd < 0) {
-                        if (errno == EINTR)
-                                continue;
-
                         if (errno == EAGAIN)
                                 return 0;
 
+                        if (ERRNO_IS_ACCEPT_AGAIN(errno))
+                                continue;
+
                         return -errno;
                 }
 
-                close(cfd);
+                safe_close(cfd);
         }
 }
 
@@ -1345,3 +1355,39 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) {
                 return (int) (offsetof(struct sockaddr_un, sun_path) + l + 1); /* include trailing NUL in size */
         }
 }
+
+int socket_bind_to_ifname(int fd, const char *ifname) {
+        assert(fd >= 0);
+
+        /* Call with NULL to drop binding */
+
+        if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen_ptr(ifname)) < 0)
+                return -errno;
+
+        return 0;
+}
+
+int socket_bind_to_ifindex(int fd, int ifindex) {
+        char ifname[IFNAMSIZ] = "";
+
+        assert(fd >= 0);
+
+        if (ifindex <= 0) {
+                /* Drop binding */
+                if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, NULL, 0) < 0)
+                        return -errno;
+
+                return 0;
+        }
+
+        if (setsockopt(fd, SOL_SOCKET, SO_BINDTOIFINDEX, &ifindex, sizeof(ifindex)) >= 0)
+                return 0;
+        if (errno != ENOPROTOOPT)
+                return -errno;
+
+        /* Fall back to SO_BINDTODEVICE on kernels < 5.0 which didn't have SO_BINDTOIFINDEX */
+        if (!if_indextoname(ifindex, ifname))
+                return -errno;
+
+        return socket_bind_to_ifname(fd, ifname);
+}
index 574d2b7..6920fd9 100644 (file)
@@ -198,3 +198,6 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) {
 
         return 0;
 }
+
+int socket_bind_to_ifname(int fd, const char *ifname);
+int socket_bind_to_ifindex(int fd, int ifindex);
diff --git a/src/basic/sort-util.c b/src/basic/sort-util.c
new file mode 100644 (file)
index 0000000..5cf0d1d
--- /dev/null
@@ -0,0 +1,27 @@
+#include "sort-util.h"
+#include "alloc-util.h"
+
+/* hey glibc, APIs with callbacks without a user pointer are so useless */
+void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
+                 __compar_d_fn_t compar, void *arg) {
+        size_t l, u, idx;
+        const void *p;
+        int comparison;
+
+        assert(!size_multiply_overflow(nmemb, size));
+
+        l = 0;
+        u = nmemb;
+        while (l < u) {
+                idx = (l + u) / 2;
+                p = (const uint8_t*) base + idx * size;
+                comparison = compar(key, p, arg);
+                if (comparison < 0)
+                        u = idx;
+                else if (comparison > 0)
+                        l = idx + 1;
+                else
+                        return (void *)p;
+        }
+        return NULL;
+}
diff --git a/src/basic/sort-util.h b/src/basic/sort-util.h
new file mode 100644 (file)
index 0000000..e029f86
--- /dev/null
@@ -0,0 +1,70 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdlib.h>
+
+#include "macro.h"
+
+void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
+                 __compar_d_fn_t compar, void *arg);
+
+#define typesafe_bsearch_r(k, b, n, func, userdata)                     \
+        ({                                                              \
+                const typeof(b[0]) *_k = k;                             \
+                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
+                xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
+        })
+
+/**
+ * Normal bsearch requires base to be nonnull. Here were require
+ * that only if nmemb > 0.
+ */
+static inline void* bsearch_safe(const void *key, const void *base,
+                                 size_t nmemb, size_t size, __compar_fn_t compar) {
+        if (nmemb <= 0)
+                return NULL;
+
+        assert(base);
+        return bsearch(key, base, nmemb, size, compar);
+}
+
+#define typesafe_bsearch(k, b, n, func)                                 \
+        ({                                                              \
+                const typeof(b[0]) *_k = k;                             \
+                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
+                bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
+        })
+
+/**
+ * Normal qsort requires base to be nonnull. Here were require
+ * that only if nmemb > 0.
+ */
+static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
+        if (nmemb <= 1)
+                return;
+
+        assert(base);
+        qsort(base, nmemb, size, compar);
+}
+
+/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so
+ * is the prototype for the comparison function */
+#define typesafe_qsort(p, n, func)                                      \
+        ({                                                              \
+                int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
+                qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
+        })
+
+static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
+        if (nmemb <= 1)
+                return;
+
+        assert(base);
+        qsort_r(base, nmemb, size, compar, userdata);
+}
+
+#define typesafe_qsort_r(p, n, func, userdata)                          \
+        ({                                                              \
+                int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
+                qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
+        })
index 6e4cc7f..c13286d 100644 (file)
 
 /* Magic early boot services */
 #define SPECIAL_FSCK_SERVICE "systemd-fsck@.service"
+#define SPECIAL_FSCK_ROOT_SERVICE "systemd-fsck-root.service"
 #define SPECIAL_QUOTACHECK_SERVICE "systemd-quotacheck.service"
 #define SPECIAL_QUOTAON_SERVICE "quotaon.service"
 #define SPECIAL_REMOUNT_FS_SERVICE "systemd-remount-fs.service"
+#define SPECIAL_VOLATILE_ROOT_SERVICE "systemd-volatile-root.service"
 
 /* Services systemd relies on */
 #define SPECIAL_DBUS_SERVICE "dbus.service"
index ea2bbc3..2cd722c 100644 (file)
@@ -223,52 +223,6 @@ int fd_is_network_fs(int fd) {
         return is_network_fs(&s);
 }
 
-int fd_is_network_ns(int fd) {
-        struct statfs s;
-        int r;
-
-        /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice
-         * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle
-         * this somewhat nicely.
-         *
-         * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not
-         * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */
-
-        if (fstatfs(fd, &s) < 0)
-                return -errno;
-
-        if (!is_fs_type(&s, NSFS_MAGIC)) {
-                /* On really old kernels, there was no "nsfs", and network namespace sockets belonged to procfs
-                 * instead. Handle that in a somewhat smart way. */
-
-                if (is_fs_type(&s, PROC_SUPER_MAGIC)) {
-                        struct statfs t;
-
-                        /* OK, so it is procfs. Let's see if our own network namespace is procfs, too. If so, then the
-                         * passed fd might refer to a network namespace, but we can't know for sure. In that case,
-                         * return a recognizable error. */
-
-                        if (statfs("/proc/self/ns/net", &t) < 0)
-                                return -errno;
-
-                        if (s.f_type == t.f_type)
-                                return -EUCLEAN; /* It's possible, we simply don't know */
-                }
-
-                return 0; /* No! */
-        }
-
-        r = ioctl(fd, NS_GET_NSTYPE);
-        if (r < 0) {
-                if (errno == ENOTTY) /* Old kernels didn't know this ioctl, let's also return a recognizable error in that case */
-                        return -EUCLEAN;
-
-                return -errno;
-        }
-
-        return r == CLONE_NEWNET;
-}
-
 int path_is_temporary_fs(const char *path) {
         _cleanup_close_ int fd = -1;
 
index 74fb725..7824af3 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <fcntl.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <sys/stat.h>
@@ -50,8 +51,6 @@ bool is_network_fs(const struct statfs *s) _pure_;
 int fd_is_temporary_fs(int fd);
 int fd_is_network_fs(int fd);
 
-int fd_is_network_ns(int fd);
-
 int path_is_temporary_fs(const char *path);
 
 /* Because statfs.t_type can be int on some architectures, we have to cast
index dc67b6e..c3b9448 100644 (file)
@@ -7,7 +7,7 @@
 #include <sys/types.h>
 
 #include "macro.h"
-#include "util.h"
+#include "memory-util.h"
 
 #define snprintf_ok(buf, len, fmt, ...) \
         ((size_t) snprintf(buf, len, fmt, __VA_ARGS__) < (len))
index 81f4f21..769b22a 100644 (file)
@@ -5,8 +5,8 @@
 #include <string.h>
 
 #include "alloc-util.h"
+#include "sort-util.h"
 #include "strbuf.h"
-#include "util.h"
 
 /*
  * Strbuf stores given strings in a single continuous allocated memory
index 228c12a..42fe4f4 100644 (file)
@@ -59,13 +59,13 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k
 
 #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(name,type,max,scope) \
         scope type name##_from_string(const char *s) {                  \
-                type i;                                                 \
                 unsigned u = 0;                                         \
+                type i;                                                 \
                 if (!s)                                                 \
                         return (type) -1;                               \
-                for (i = 0; i < (type) ELEMENTSOF(name##_table); i++)   \
-                        if (streq_ptr(name##_table[i], s))              \
-                                return i;                               \
+                i = (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \
+                if (i >= 0)                                             \
+                        return i;                                       \
                 if (safe_atou(s, &u) >= 0 && u <= max)                  \
                         return (type) u;                                \
                 return (type) -1;                                       \
index 93917bc..5001a2b 100644 (file)
 
 #include "alloc-util.h"
 #include "escape.h"
+#include "fileio.h"
 #include "gunicode.h"
 #include "locale-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "string-util.h"
 #include "terminal-util.h"
 #include "utf8.h"
 #include "util.h"
-#include "fileio.h"
 
 int strcmp_ptr(const char *a, const char *b) {
 
@@ -675,19 +676,6 @@ char *cellescape(char *buf, size_t len, const char *s) {
         return buf;
 }
 
-bool nulstr_contains(const char *nulstr, const char *needle) {
-        const char *i;
-
-        if (!nulstr)
-                return false;
-
-        NULSTR_FOREACH(i, nulstr)
-                if (streq(i, needle))
-                        return true;
-
-        return false;
-}
-
 char* strshorten(char *s, size_t l) {
         assert(s);
 
@@ -1048,25 +1036,6 @@ int free_and_strndup(char **p, const char *s, size_t l) {
         return 1;
 }
 
-#if !HAVE_EXPLICIT_BZERO
-/*
- * Pointer to memset is volatile so that compiler must de-reference
- * the pointer and can't assume that it points to any function in
- * particular (such as memset, which it then might further "optimize")
- * This approach is inspired by openssl's crypto/mem_clr.c.
- */
-typedef void *(*memset_t)(void *,int,size_t);
-
-static volatile memset_t memset_func = memset;
-
-void* explicit_bzero_safe(void *p, size_t l) {
-        if (l > 0)
-                memset_func(p, '\0', l);
-
-        return p;
-}
-#endif
-
 char* string_erase(char *x) {
         if (!x)
                 return NULL;
index 38070ab..b23f4c8 100644 (file)
@@ -57,6 +57,16 @@ static inline const char *empty_to_dash(const char *str) {
         return isempty(str) ? "-" : str;
 }
 
+static inline bool empty_or_dash(const char *str) {
+        return !str ||
+                str[0] == 0 ||
+                (str[0] == '-' && str[1] == 0);
+}
+
+static inline const char *empty_or_dash_to_null(const char *p) {
+        return empty_or_dash(p) ? NULL : p;
+}
+
 static inline char *startswith(const char *s, const char *prefix) {
         size_t l;
 
@@ -165,8 +175,6 @@ char *cellescape(char *buf, size_t len, const char *s);
 /* This limit is arbitrary, enough to give some idea what the string contains */
 #define CELLESCAPE_DEFAULT_LENGTH 64
 
-bool nulstr_contains(const char *nulstr, const char *needle);
-
 char* strshorten(char *s, size_t l);
 
 char *strreplace(const char *text, const char *old_string, const char *new_string);
@@ -182,33 +190,12 @@ char *strrep(const char *s, unsigned n);
 int split_pair(const char *s, const char *sep, char **l, char **r);
 
 int free_and_strdup(char **p, const char *s);
-int free_and_strndup(char **p, const char *s, size_t l);
-
-/* Normal memmem() requires haystack to be nonnull, which is annoying for zero-length buffers */
-static inline void *memmem_safe(const void *haystack, size_t haystacklen, const void *needle, size_t needlelen) {
-
-        if (needlelen <= 0)
-                return (void*) haystack;
-
-        if (haystacklen < needlelen)
-                return NULL;
-
-        assert(haystack);
-        assert(needle);
-
-        return memmem(haystack, haystacklen, needle, needlelen);
+static inline int free_and_strdup_warn(char **p, const char *s) {
+        if (free_and_strdup(p, s) < 0)
+                return log_oom();
+        return 0;
 }
-
-#if HAVE_EXPLICIT_BZERO
-static inline void* explicit_bzero_safe(void *p, size_t l) {
-        if (l > 0)
-                explicit_bzero(p, l);
-
-        return p;
-}
-#else
-void *explicit_bzero_safe(void *p, size_t l);
-#endif
+int free_and_strndup(char **p, const char *s, size_t l);
 
 char *string_erase(char *x);
 
index 3a62f25..21c1061 100644 (file)
 #include "escape.h"
 #include "extract-word.h"
 #include "fileio.h"
+#include "nulstr-util.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 char *strv_find(char **l, const char *name) {
         char **i;
index 392cab6..aa5f95a 100644 (file)
@@ -5,12 +5,12 @@
 #include <stdarg.h>
 #include <stdbool.h>
 #include <stddef.h>
+#include <stdio.h>
 
 #include "alloc-util.h"
 #include "extract-word.h"
 #include "macro.h"
 #include "string-util.h"
-#include "util.h"
 
 char *strv_find(char **l, const char *name) _pure_;
 char *strv_find_prefix(char **l, const char *name) _pure_;
index 0f38120..b692c52 100644 (file)
@@ -32,6 +32,7 @@
 #include "io-util.h"
 #include "log.h"
 #include "macro.h"
+#include "namespace-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
@@ -890,50 +891,39 @@ bool on_tty(void) {
 }
 
 int getttyname_malloc(int fd, char **ret) {
-        size_t l = 100;
+        char path[PATH_MAX], *c; /* PATH_MAX is counted *with* the trailing NUL byte */
         int r;
 
         assert(fd >= 0);
         assert(ret);
 
-        for (;;) {
-                char path[l];
-
-                r = ttyname_r(fd, path, sizeof(path));
-                if (r == 0) {
-                        char *c;
+        r = ttyname_r(fd, path, sizeof path); /* positive error */
+        assert(r >= 0);
+        if (r == ERANGE)
+                return -ENAMETOOLONG;
+        if (r > 0)
+                return -r;
 
-                        c = strdup(skip_dev_prefix(path));
-                        if (!c)
-                                return -ENOMEM;
-
-                        *ret = c;
-                        return 0;
-                }
-
-                if (r != ERANGE)
-                        return -r;
-
-                l *= 2;
-        }
+        c = strdup(skip_dev_prefix(path));
+        if (!c)
+                return -ENOMEM;
 
+        *ret = c;
         return 0;
 }
 
-int getttyname_harder(int fd, char **r) {
-        int k;
-        char *s = NULL;
+int getttyname_harder(int fd, char **ret) {
+        _cleanup_free_ char *s = NULL;
+        int r;
 
-        k = getttyname_malloc(fd, &s);
-        if (k < 0)
-                return k;
+        r = getttyname_malloc(fd, &s);
+        if (r < 0)
+                return r;
 
-        if (streq(s, "tty")) {
-                free(s);
-                return get_ctty(0, NULL, r);
-        }
+        if (streq(s, "tty"))
+                return get_ctty(0, NULL, ret);
 
-        *r = s;
+        *ret = TAKE_PTR(s);
         return 0;
 }
 
@@ -1051,6 +1041,10 @@ int ptsname_malloc(int fd, char **ret) {
                 }
 
                 free(c);
+
+                if (l > SIZE_MAX / 2)
+                        return -ENOMEM;
+
                 l *= 2;
         }
 }
index 62cdc30..daf952b 100644 (file)
@@ -1031,6 +1031,15 @@ int parse_sec_fix_0(const char *t, usec_t *ret) {
         return r;
 }
 
+int parse_sec_def_infinity(const char *t, usec_t *ret) {
+        t += strspn(t, WHITESPACE);
+        if (isempty(t)) {
+                *ret = USEC_INFINITY;
+                return 0;
+        }
+        return parse_sec(t, ret);
+}
+
 static const char* extract_nsec_multiplier(const char *p, nsec_t *multiplier) {
         static const struct {
                 const char *suffix;
@@ -1205,7 +1214,7 @@ int get_timezones(char ***ret) {
         n_allocated = 2;
         n_zones = 1;
 
-        f = fopen("/usr/share/zoneinfo/zone.tab", "re");
+        f = fopen("/usr/share/zoneinfo/zone1970.tab", "re");
         if (f) {
                 for (;;) {
                         _cleanup_free_ char *line = NULL;
index 5316305..a238f69 100644 (file)
@@ -112,6 +112,7 @@ int parse_timestamp(const char *t, usec_t *usec);
 
 int parse_sec(const char *t, usec_t *usec);
 int parse_sec_fix_0(const char *t, usec_t *usec);
+int parse_sec_def_infinity(const char *t, usec_t *usec);
 int parse_time(const char *t, usec_t *usec, usec_t default_unit);
 int parse_nsec(const char *t, nsec_t *nsec);
 
index 260f3d2..a479590 100644 (file)
@@ -80,7 +80,7 @@ char* getlogname_malloc(void) {
 char *getusername_malloc(void) {
         const char *e;
 
-        e = getenv("USER");
+        e = secure_getenv("USER");
         if (e)
                 return strdup(e);
 
@@ -238,14 +238,21 @@ int get_user_creds(
         }
 
         if (home) {
-                if (FLAGS_SET(flags, USER_CREDS_CLEAN) && empty_or_root(p->pw_dir))
-                        *home = NULL;
+                if (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
+                    (empty_or_root(p->pw_dir) ||
+                     !path_is_valid(p->pw_dir) ||
+                     !path_is_absolute(p->pw_dir)))
+                    *home = NULL; /* Note: we don't insist on normalized paths, since there are setups that have /./ in the path */
                 else
                         *home = p->pw_dir;
         }
 
         if (shell) {
-                if (FLAGS_SET(flags, USER_CREDS_CLEAN) && (isempty(p->pw_shell) || is_nologin_shell(p->pw_shell)))
+                if (FLAGS_SET(flags, USER_CREDS_CLEAN) &&
+                    (isempty(p->pw_shell) ||
+                     !path_is_valid(p->pw_dir) ||
+                     !path_is_absolute(p->pw_shell) ||
+                     is_nologin_shell(p->pw_shell)))
                         *shell = NULL;
                 else
                         *shell = p->pw_shell;
@@ -343,6 +350,9 @@ char* uid_to_name(uid_t uid) {
                         if (r != ERANGE)
                                 break;
 
+                        if (bufsize > LONG_MAX/2) /* overflow check */
+                                return NULL;
+
                         bufsize *= 2;
                 }
         }
@@ -384,6 +394,9 @@ char* gid_to_name(gid_t gid) {
                         if (r != ERANGE)
                                 break;
 
+                        if (bufsize > LONG_MAX/2) /* overflow check */
+                                return NULL;
+
                         bufsize *= 2;
                 }
         }
@@ -445,12 +458,12 @@ int get_home_dir(char **_h) {
 
         /* Take the user specified one */
         e = secure_getenv("HOME");
-        if (e && path_is_absolute(e)) {
+        if (e && path_is_valid(e) && path_is_absolute(e)) {
                 h = strdup(e);
                 if (!h)
                         return -ENOMEM;
 
-                *_h = h;
+                *_h = path_simplify(h, true);
                 return 0;
         }
 
@@ -480,14 +493,15 @@ int get_home_dir(char **_h) {
         if (!p)
                 return errno > 0 ? -errno : -ESRCH;
 
-        if (!path_is_absolute(p->pw_dir))
+        if (!path_is_valid(p->pw_dir) ||
+            !path_is_absolute(p->pw_dir))
                 return -EINVAL;
 
         h = strdup(p->pw_dir);
         if (!h)
                 return -ENOMEM;
 
-        *_h = h;
+        *_h = path_simplify(h, true);
         return 0;
 }
 
@@ -500,13 +514,13 @@ int get_shell(char **_s) {
         assert(_s);
 
         /* Take the user specified one */
-        e = getenv("SHELL");
-        if (e) {
+        e = secure_getenv("SHELL");
+        if (e && path_is_valid(e) && path_is_absolute(e)) {
                 s = strdup(e);
                 if (!s)
                         return -ENOMEM;
 
-                *_s = s;
+                *_s = path_simplify(s, true);
                 return 0;
         }
 
@@ -536,14 +550,15 @@ int get_shell(char **_s) {
         if (!p)
                 return errno > 0 ? -errno : -ESRCH;
 
-        if (!path_is_absolute(p->pw_shell))
+        if (!path_is_valid(p->pw_shell) ||
+            !path_is_absolute(p->pw_shell))
                 return -EINVAL;
 
         s = strdup(p->pw_shell);
         if (!s)
                 return -ENOMEM;
 
-        *_s = s;
+        *_s = path_simplify(s, true);
         return 0;
 }
 
index e0d1949..090c69d 100644 (file)
@@ -61,12 +61,7 @@ static bool unichar_is_control(char32_t ch) {
 }
 
 /* count of characters used to encode one unicode char */
-static size_t utf8_encoded_expected_len(const char *str) {
-        uint8_t c;
-
-        assert(str);
-
-        c = (uint8_t) str[0];
+static size_t utf8_encoded_expected_len(uint8_t c) {
         if (c < 0x80)
                 return 1;
         if ((c & 0xe0) == 0xc0)
@@ -90,7 +85,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) {
 
         assert(str);
 
-        len = utf8_encoded_expected_len(str);
+        len = utf8_encoded_expected_len(str[0]);
 
         switch (len) {
         case 1:
@@ -133,14 +128,14 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool newline) {
 
         assert(str);
 
-        for (p = str; length;) {
+        for (p = str; length > 0;) {
                 int encoded_len, r;
                 char32_t val;
 
-                encoded_len = utf8_encoded_valid_unichar(p);
-                if (encoded_len < 0 ||
-                    (size_t) encoded_len > length)
+                encoded_len = utf8_encoded_valid_unichar(p, length);
+                if (encoded_len < 0)
                         return false;
+                assert(encoded_len > 0 && (size_t) encoded_len <= length);
 
                 r = utf8_encoded_to_unichar(p, &val);
                 if (r < 0 ||
@@ -164,7 +159,7 @@ char *utf8_is_valid(const char *str) {
         while (*p) {
                 int len;
 
-                len = utf8_encoded_valid_unichar(p);
+                len = utf8_encoded_valid_unichar(p, (size_t) -1);
                 if (len < 0)
                         return NULL;
 
@@ -186,7 +181,7 @@ char *utf8_escape_invalid(const char *str) {
         while (*str) {
                 int len;
 
-                len = utf8_encoded_valid_unichar(str);
+                len = utf8_encoded_valid_unichar(str, (size_t) -1);
                 if (len > 0) {
                         s = mempcpy(s, str, len);
                         str += len;
@@ -213,7 +208,7 @@ char *utf8_escape_non_printable(const char *str) {
         while (*str) {
                 int len;
 
-                len = utf8_encoded_valid_unichar(str);
+                len = utf8_encoded_valid_unichar(str, (size_t) -1);
                 if (len > 0) {
                         if (utf8_is_printable(str, len)) {
                                 s = mempcpy(s, str, len);
@@ -405,7 +400,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length) {
                 char32_t unichar;
                 size_t e;
 
-                e = utf8_encoded_expected_len(s + i);
+                e = utf8_encoded_expected_len(s[i]);
                 if (e <= 1) /* Invalid and single byte characters are copied as they are */
                         goto copy;
 
@@ -457,17 +452,24 @@ static int utf8_unichar_to_encoded_len(char32_t unichar) {
 }
 
 /* validate one encoded unicode char and return its length */
-int utf8_encoded_valid_unichar(const char *str) {
+int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) {
         char32_t unichar;
         size_t len, i;
         int r;
 
         assert(str);
+        assert(length > 0);
 
-        len = utf8_encoded_expected_len(str);
+        /* We read until NUL, at most length bytes. (size_t) -1 may be used to disable the length check. */
+
+        len = utf8_encoded_expected_len(str[0]);
         if (len == 0)
                 return -EINVAL;
 
+        /* Do we have a truncated multi-byte character? */
+        if (len > length)
+                return -EINVAL;
+
         /* ascii is valid */
         if (len == 1)
                 return 1;
@@ -500,7 +502,7 @@ size_t utf8_n_codepoints(const char *str) {
         while (*str != 0) {
                 int k;
 
-                k = utf8_encoded_valid_unichar(str);
+                k = utf8_encoded_valid_unichar(str, (size_t) -1);
                 if (k < 0)
                         return (size_t) -1;
 
index 6284569..6df7092 100644 (file)
@@ -32,7 +32,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length);
 
 size_t char16_strlen(const char16_t *s); /* returns the number of 16bit words in the string (not bytes!) */
 
-int utf8_encoded_valid_unichar(const char *str);
+int utf8_encoded_valid_unichar(const char *str, size_t length);
 int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar);
 
 static inline bool utf16_is_surrogate(char16_t c) {
index e577c93..93d610b 100644 (file)
@@ -19,7 +19,6 @@
 #include "alloc-util.h"
 #include "btrfs-util.h"
 #include "build.h"
-#include "cgroup-util.h"
 #include "def.h"
 #include "device-nodes.h"
 #include "dirent-util.h"
@@ -52,33 +51,6 @@ int saved_argc = 0;
 char **saved_argv = NULL;
 static int saved_in_initrd = -1;
 
-size_t page_size(void) {
-        static thread_local size_t pgsz = 0;
-        long r;
-
-        if (_likely_(pgsz > 0))
-                return pgsz;
-
-        r = sysconf(_SC_PAGESIZE);
-        assert(r > 0);
-
-        pgsz = (size_t) r;
-        return pgsz;
-}
-
-bool plymouth_running(void) {
-        return access("/run/plymouth/pid", F_OK) >= 0;
-}
-
-bool display_is_local(const char *display) {
-        assert(display);
-
-        return
-                display[0] == ':' &&
-                display[1] >= '0' &&
-                display[1] <= '9';
-}
-
 bool kexec_loaded(void) {
        _cleanup_free_ char *s = NULL;
 
@@ -141,53 +113,6 @@ void in_initrd_force(bool value) {
         saved_in_initrd = value;
 }
 
-/* hey glibc, APIs with callbacks without a user pointer are so useless */
-void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
-                 __compar_d_fn_t compar, void *arg) {
-        size_t l, u, idx;
-        const void *p;
-        int comparison;
-
-        assert(!size_multiply_overflow(nmemb, size));
-
-        l = 0;
-        u = nmemb;
-        while (l < u) {
-                idx = (l + u) / 2;
-                p = (const uint8_t*) base + idx * size;
-                comparison = compar(key, p, arg);
-                if (comparison < 0)
-                        u = idx;
-                else if (comparison > 0)
-                        l = idx + 1;
-                else
-                        return (void *)p;
-        }
-        return NULL;
-}
-
-bool memeqzero(const void *data, size_t length) {
-        /* Does the buffer consist entirely of NULs?
-         * Copied from https://github.com/systemd/casync/, copied in turn from
-         * https://github.com/rustyrussell/ccan/blob/master/ccan/mem/mem.c#L92,
-         * which is licensed CC-0.
-         */
-
-        const uint8_t *p = data;
-        size_t i;
-
-        /* Check first 16 bytes manually */
-        for (i = 0; i < 16; i++, length--) {
-                if (length == 0)
-                        return true;
-                if (p[i])
-                        return false;
-        }
-
-        /* Now we know first 16 bytes are NUL, memcmp with self.  */
-        return memcmp(data, p + i, length) == 0;
-}
-
 int on_ac_power(void) {
         bool found_offline = false, found_online = false;
         _cleanup_closedir_ DIR *d = NULL;
@@ -294,268 +219,6 @@ int container_get_leader(const char *machine, pid_t *pid) {
         return 0;
 }
 
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) {
-        _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, netnsfd = -1, usernsfd = -1;
-        int rfd = -1;
-
-        assert(pid >= 0);
-
-        if (mntns_fd) {
-                const char *mntns;
-
-                mntns = procfs_file_alloca(pid, "ns/mnt");
-                mntnsfd = open(mntns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (mntnsfd < 0)
-                        return -errno;
-        }
-
-        if (pidns_fd) {
-                const char *pidns;
-
-                pidns = procfs_file_alloca(pid, "ns/pid");
-                pidnsfd = open(pidns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (pidnsfd < 0)
-                        return -errno;
-        }
-
-        if (netns_fd) {
-                const char *netns;
-
-                netns = procfs_file_alloca(pid, "ns/net");
-                netnsfd = open(netns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (netnsfd < 0)
-                        return -errno;
-        }
-
-        if (userns_fd) {
-                const char *userns;
-
-                userns = procfs_file_alloca(pid, "ns/user");
-                usernsfd = open(userns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
-                if (usernsfd < 0 && errno != ENOENT)
-                        return -errno;
-        }
-
-        if (root_fd) {
-                const char *root;
-
-                root = procfs_file_alloca(pid, "root");
-                rfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
-                if (rfd < 0)
-                        return -errno;
-        }
-
-        if (pidns_fd)
-                *pidns_fd = pidnsfd;
-
-        if (mntns_fd)
-                *mntns_fd = mntnsfd;
-
-        if (netns_fd)
-                *netns_fd = netnsfd;
-
-        if (userns_fd)
-                *userns_fd = usernsfd;
-
-        if (root_fd)
-                *root_fd = rfd;
-
-        pidnsfd = mntnsfd = netnsfd = usernsfd = -1;
-
-        return 0;
-}
-
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) {
-        if (userns_fd >= 0) {
-                /* Can't setns to your own userns, since then you could
-                 * escalate from non-root to root in your own namespace, so
-                 * check if namespaces equal before attempting to enter. */
-                _cleanup_free_ char *userns_fd_path = NULL;
-                int r;
-                if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0)
-                        return -ENOMEM;
-
-                r = files_same(userns_fd_path, "/proc/self/ns/user", 0);
-                if (r < 0)
-                        return r;
-                if (r)
-                        userns_fd = -1;
-        }
-
-        if (pidns_fd >= 0)
-                if (setns(pidns_fd, CLONE_NEWPID) < 0)
-                        return -errno;
-
-        if (mntns_fd >= 0)
-                if (setns(mntns_fd, CLONE_NEWNS) < 0)
-                        return -errno;
-
-        if (netns_fd >= 0)
-                if (setns(netns_fd, CLONE_NEWNET) < 0)
-                        return -errno;
-
-        if (userns_fd >= 0)
-                if (setns(userns_fd, CLONE_NEWUSER) < 0)
-                        return -errno;
-
-        if (root_fd >= 0) {
-                if (fchdir(root_fd) < 0)
-                        return -errno;
-
-                if (chroot(".") < 0)
-                        return -errno;
-        }
-
-        return reset_uid_gid();
-}
-
-uint64_t physical_memory(void) {
-        _cleanup_free_ char *root = NULL, *value = NULL;
-        uint64_t mem, lim;
-        size_t ps;
-        long sc;
-        int r;
-
-        /* We return this as uint64_t in case we are running as 32bit process on a 64bit kernel with huge amounts of
-         * memory.
-         *
-         * In order to support containers nicely that have a configured memory limit we'll take the minimum of the
-         * physically reported amount of memory and the limit configured for the root cgroup, if there is any. */
-
-        sc = sysconf(_SC_PHYS_PAGES);
-        assert(sc > 0);
-
-        ps = page_size();
-        mem = (uint64_t) sc * (uint64_t) ps;
-
-        r = cg_get_root_path(&root);
-        if (r < 0) {
-                log_debug_errno(r, "Failed to determine root cgroup, ignoring cgroup memory limit: %m");
-                return mem;
-        }
-
-        r = cg_all_unified();
-        if (r < 0) {
-                log_debug_errno(r, "Failed to determine root unified mode, ignoring cgroup memory limit: %m");
-                return mem;
-        }
-        if (r > 0) {
-                r = cg_get_attribute("memory", root, "memory.max", &value);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to read memory.max cgroup attribute, ignoring cgroup memory limit: %m");
-                        return mem;
-                }
-
-                if (streq(value, "max"))
-                        return mem;
-        } else {
-                r = cg_get_attribute("memory", root, "memory.limit_in_bytes", &value);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to read memory.limit_in_bytes cgroup attribute, ignoring cgroup memory limit: %m");
-                        return mem;
-                }
-        }
-
-        r = safe_atou64(value, &lim);
-        if (r < 0) {
-                log_debug_errno(r, "Failed to parse cgroup memory limit '%s', ignoring: %m", value);
-                return mem;
-        }
-        if (lim == UINT64_MAX)
-                return mem;
-
-        /* Make sure the limit is a multiple of our own page size */
-        lim /= ps;
-        lim *= ps;
-
-        return MIN(mem, lim);
-}
-
-uint64_t physical_memory_scale(uint64_t v, uint64_t max) {
-        uint64_t p, m, ps, r;
-
-        assert(max > 0);
-
-        /* Returns the physical memory size, multiplied by v divided by max. Returns UINT64_MAX on overflow. On success
-         * the result is a multiple of the page size (rounds down). */
-
-        ps = page_size();
-        assert(ps > 0);
-
-        p = physical_memory() / ps;
-        assert(p > 0);
-
-        m = p * v;
-        if (m / p != v)
-                return UINT64_MAX;
-
-        m /= max;
-
-        r = m * ps;
-        if (r / ps != m)
-                return UINT64_MAX;
-
-        return r;
-}
-
-uint64_t system_tasks_max(void) {
-
-        uint64_t a = TASKS_MAX, b = TASKS_MAX;
-        _cleanup_free_ char *root = NULL;
-        int r;
-
-        /* Determine the maximum number of tasks that may run on this system. We check three sources to determine this
-         * limit:
-         *
-         * a) the maximum tasks value the kernel allows on this architecture
-         * b) the cgroups pids_max attribute for the system
-         * c) the kernel's configured maximum PID value
-         *
-         * And then pick the smallest of the three */
-
-        r = procfs_tasks_get_limit(&a);
-        if (r < 0)
-                log_debug_errno(r, "Failed to read maximum number of tasks from /proc, ignoring: %m");
-
-        r = cg_get_root_path(&root);
-        if (r < 0)
-                log_debug_errno(r, "Failed to determine cgroup root path, ignoring: %m");
-        else {
-                _cleanup_free_ char *value = NULL;
-
-                r = cg_get_attribute("pids", root, "pids.max", &value);
-                if (r < 0)
-                        log_debug_errno(r, "Failed to read pids.max attribute of cgroup root, ignoring: %m");
-                else if (!streq(value, "max")) {
-                        r = safe_atou64(value, &b);
-                        if (r < 0)
-                                log_debug_errno(r, "Failed to parse pids.max attribute of cgroup root, ignoring: %m");
-                }
-        }
-
-        return MIN3(TASKS_MAX,
-                    a <= 0 ? TASKS_MAX : a,
-                    b <= 0 ? TASKS_MAX : b);
-}
-
-uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) {
-        uint64_t t, m;
-
-        assert(max > 0);
-
-        /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages
-         * relative to the system's maximum number of tasks. Returns UINT64_MAX on overflow. */
-
-        t = system_tasks_max();
-        assert(t > 0);
-
-        m = t * v;
-        if (m / t != v) /* overflow? */
-                return UINT64_MAX;
-
-        return m / max;
-}
-
 int version(void) {
         puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n"
              SYSTEMD_FEATURES);
index dc33d66..25e6ab8 100644 (file)
@@ -1,34 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include <alloca.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <locale.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stddef.h>
 #include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/inotify.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/statfs.h>
-#include <sys/sysmacros.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-
-#include "format-util.h"
-#include "macro.h"
-#include "time-util.h"
 
-size_t page_size(void) _pure_;
-#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
+#include "macro.h"
 
 static inline const char* yes_no(bool b) {
         return b ? "yes" : "no";
@@ -46,19 +21,14 @@ static inline const char* enable_disable(bool b) {
         return b ? "enable" : "disable";
 }
 
-bool plymouth_running(void);
-
-bool display_is_local(const char *display) _pure_;
-
-#define NULSTR_FOREACH(i, l)                                    \
-        for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
-
-#define NULSTR_FOREACH_PAIR(i, j, l)                             \
-        for ((i) = (l), (j) = strchr((i), 0)+1; (i) && *(i); (i) = strchr((j), 0)+1, (j) = *(i) ? strchr((i), 0)+1 : (i))
-
 extern int saved_argc;
 extern char **saved_argv;
 
+static inline void save_argc_argv(int argc, char **argv) {
+        saved_argc = argc;
+        saved_argv = argv;
+}
+
 bool kexec_loaded(void);
 
 int prot_from_flags(int flags) _const_;
@@ -66,138 +36,8 @@ int prot_from_flags(int flags) _const_;
 bool in_initrd(void);
 void in_initrd_force(bool value);
 
-void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size,
-                 __compar_d_fn_t compar, void *arg);
-
-#define typesafe_bsearch_r(k, b, n, func, userdata)                     \
-        ({                                                              \
-                const typeof(b[0]) *_k = k;                             \
-                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*, typeof(userdata)) = func; \
-                xbsearch_r((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_d_fn_t) _func_, userdata); \
-        })
-
-/**
- * Normal bsearch requires base to be nonnull. Here were require
- * that only if nmemb > 0.
- */
-static inline void* bsearch_safe(const void *key, const void *base,
-                                 size_t nmemb, size_t size, __compar_fn_t compar) {
-        if (nmemb <= 0)
-                return NULL;
-
-        assert(base);
-        return bsearch(key, base, nmemb, size, compar);
-}
-
-#define typesafe_bsearch(k, b, n, func)                                 \
-        ({                                                              \
-                const typeof(b[0]) *_k = k;                             \
-                int (*_func_)(const typeof(b[0])*, const typeof(b[0])*) = func; \
-                bsearch_safe((const void*) _k, (b), (n), sizeof((b)[0]), (__compar_fn_t) _func_); \
-        })
-
-/**
- * Normal qsort requires base to be nonnull. Here were require
- * that only if nmemb > 0.
- */
-static inline void qsort_safe(void *base, size_t nmemb, size_t size, __compar_fn_t compar) {
-        if (nmemb <= 1)
-                return;
-
-        assert(base);
-        qsort(base, nmemb, size, compar);
-}
-
-/* A wrapper around the above, but that adds typesafety: the element size is automatically derived from the type and so
- * is the prototype for the comparison function */
-#define typesafe_qsort(p, n, func)                                      \
-        ({                                                              \
-                int (*_func_)(const typeof(p[0])*, const typeof(p[0])*) = func; \
-                qsort_safe((p), (n), sizeof((p)[0]), (__compar_fn_t) _func_); \
-        })
-
-static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_d_fn_t compar, void *userdata) {
-        if (nmemb <= 1)
-                return;
-
-        assert(base);
-        qsort_r(base, nmemb, size, compar, userdata);
-}
-
-#define typesafe_qsort_r(p, n, func, userdata)                          \
-        ({                                                              \
-                int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \
-                qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \
-        })
-
-/* Normal memcpy requires src to be nonnull. We do nothing if n is 0. */
-static inline void memcpy_safe(void *dst, const void *src, size_t n) {
-        if (n == 0)
-                return;
-        assert(src);
-        memcpy(dst, src, n);
-}
-
-/* Normal memcmp requires s1 and s2 to be nonnull. We do nothing if n is 0. */
-static inline int memcmp_safe(const void *s1, const void *s2, size_t n) {
-        if (n == 0)
-                return 0;
-        assert(s1);
-        assert(s2);
-        return memcmp(s1, s2, n);
-}
-
-/* Compare s1 (length n1) with s2 (length n2) in lexicographic order. */
-static inline int memcmp_nn(const void *s1, size_t n1, const void *s2, size_t n2) {
-        return memcmp_safe(s1, s2, MIN(n1, n2))
-            ?: CMP(n1, n2);
-}
-
 int on_ac_power(void);
 
-#define memzero(x,l)                                            \
-        ({                                                      \
-                size_t _l_ = (l);                               \
-                void *_x_ = (x);                                \
-                _l_ == 0 ? _x_ : memset(_x_, 0, _l_);           \
-        })
-
-#define zero(x) (memzero(&(x), sizeof(x)))
-
-bool memeqzero(const void *data, size_t length);
-
-#define eqzero(x) memeqzero(x, sizeof(x))
-
-static inline void *mempset(void *s, int c, size_t n) {
-        memset(s, c, n);
-        return (uint8_t*)s + n;
-}
-
-static inline void _reset_errno_(int *saved_errno) {
-        if (*saved_errno < 0) /* Invalidated by UNPROTECT_ERRNO? */
-                return;
-
-        errno = *saved_errno;
-}
-
-#define PROTECT_ERRNO                                                   \
-        _cleanup_(_reset_errno_) _unused_ int _saved_errno_ = errno
-
-#define UNPROTECT_ERRNO                         \
-        do {                                    \
-                errno = _saved_errno_;          \
-                _saved_errno_ = -1;             \
-        } while (false)
-
-static inline int negative_errno(void) {
-        /* This helper should be used to shut up gcc if you know 'errno' is
-         * negative. Instead of "return -errno;", use "return negative_errno();"
-         * It will suppress bogus gcc warnings in case it assumes 'errno' might
-         * be 0 and thus the caller's error-handling might not be triggered. */
-        assert_return(errno > 0, -EINVAL);
-        return -errno;
-}
-
 static inline unsigned u64log2(uint64_t n) {
 #if __SIZEOF_LONG_LONG__ == 8
         return (n > 1) ? (unsigned) __builtin_clzll(n) ^ 63U : 0;
@@ -237,15 +77,6 @@ static inline unsigned log2u_round_up(unsigned x) {
 
 int container_get_leader(const char *machine, pid_t *pid);
 
-int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd);
-int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd);
-
-uint64_t physical_memory(void);
-uint64_t physical_memory_scale(uint64_t v, uint64_t max);
-
-uint64_t system_tasks_max(void);
-uint64_t system_tasks_max_scale(uint64_t v, uint64_t max);
-
 int version(void);
 
 int str_verscmp(const char *s1, const char *s2);
index f63f15f..5dd1bd6 100644 (file)
@@ -40,6 +40,8 @@ static int detect_vm_cpuid(void) {
                 /* https://wiki.freebsd.org/bhyve */
                 { "bhyve bhyve ", VIRTUALIZATION_BHYVE     },
                 { "QNXQVMBSQG",   VIRTUALIZATION_QNX       },
+                /* https://projectacrn.org */
+                { "ACRNACRNACRN", VIRTUALIZATION_ACRN      },
         };
 
         uint32_t eax, ebx, ecx, edx;
@@ -202,7 +204,7 @@ static int detect_vm_xen_dom0(void) {
         r = read_one_line_file(PATH_FEATURES, &domcap);
         if (r < 0 && r != -ENOENT)
                 return r;
-        if (r == 0) {
+        if (r >= 0) {
                 unsigned long features;
 
                 /* Here, we need to use sscanf() instead of safe_atoul()
@@ -436,10 +438,12 @@ int detect_container(void) {
                 { "systemd-nspawn", VIRTUALIZATION_SYSTEMD_NSPAWN },
                 { "docker",         VIRTUALIZATION_DOCKER         },
                 { "rkt",            VIRTUALIZATION_RKT            },
+                { "wsl",            VIRTUALIZATION_WSL            },
         };
 
         static thread_local int cached_found = _VIRTUALIZATION_INVALID;
         _cleanup_free_ char *m = NULL;
+        _cleanup_free_ char *o = NULL;
         const char *e = NULL;
         unsigned j;
         int r;
@@ -454,6 +458,15 @@ int detect_container(void) {
                 goto finish;
         }
 
+        /* "Official" way of detecting WSL https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364 */
+        r = read_one_line_file("/proc/sys/kernel/osrelease", &o);
+        if (r >= 0) {
+                if (strstr(o, "Microsoft") || strstr(o, "WSL")) {
+                        r = VIRTUALIZATION_WSL;
+                        goto finish;
+                }
+        }
+
         if (getpid_cached() == 1) {
                 /* If we are PID 1 we can just check our own environment variable, and that's authoritative. */
 
@@ -469,11 +482,11 @@ int detect_container(void) {
         /* Otherwise, PID 1 might have dropped this information into a file in /run. This is better than accessing
          * /proc/1/environ, since we don't need CAP_SYS_PTRACE for that. */
         r = read_one_line_file("/run/systemd/container", &m);
-        if (r >= 0) {
+        if (r > 0) {
                 e = m;
                 goto translate_name;
         }
-        if (r != -ENOENT)
+        if (!IN_SET(r, -ENOENT, 0))
                 return log_debug_errno(r, "Failed to read /run/systemd/container: %m");
 
         /* Fallback for cases where PID 1 was not systemd (for example, cases where init=/bin/sh is used. */
@@ -628,6 +641,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_PARALLELS] = "parallels",
         [VIRTUALIZATION_BHYVE] = "bhyve",
         [VIRTUALIZATION_QNX] = "qnx",
+        [VIRTUALIZATION_ACRN] = "acrn",
         [VIRTUALIZATION_VM_OTHER] = "vm-other",
 
         [VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
@@ -636,6 +650,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
         [VIRTUALIZATION_OPENVZ] = "openvz",
         [VIRTUALIZATION_DOCKER] = "docker",
         [VIRTUALIZATION_RKT] = "rkt",
+        [VIRTUALIZATION_WSL] = "wsl",
         [VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
 };
 
index c4cf4bf..c083689 100644 (file)
@@ -21,6 +21,7 @@ enum {
         VIRTUALIZATION_PARALLELS,
         VIRTUALIZATION_BHYVE,
         VIRTUALIZATION_QNX,
+        VIRTUALIZATION_ACRN,
         VIRTUALIZATION_VM_OTHER,
         VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER,
 
@@ -31,6 +32,7 @@ enum {
         VIRTUALIZATION_OPENVZ,
         VIRTUALIZATION_DOCKER,
         VIRTUALIZATION_RKT,
+        VIRTUALIZATION_WSL,
         VIRTUALIZATION_CONTAINER_OTHER,
         VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER,
 
index 0ee0979..1d045f9 100644 (file)
@@ -140,7 +140,12 @@ static int parse_crtime(le64_t le, usec_t *usec) {
 }
 
 int fd_getcrtime_at(int dirfd, const char *name, usec_t *ret, int flags) {
-        struct_statx sx;
+        struct_statx sx
+#if HAS_FEATURE_MEMORY_SANITIZER
+                = {}
+#  warning "Explicitly initializing struct statx, to work around msan limitation. Please remove as soon as msan has been updated to not require this."
+#endif
+                ;
         usec_t a, b;
         le64_t le;
         size_t n;
index af31f09..66e2f01 100644 (file)
@@ -7,6 +7,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "alloc-util.h"
 #include "conf-files.h"
@@ -20,7 +22,6 @@
 #include "pretty-print.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 static bool arg_cat_config = false;
 static PagerFlags arg_pager_flags = 0;
index 42b9618..b5d110f 100644 (file)
@@ -16,9 +16,9 @@
 #include "verbs.h"
 #include "virt.h"
 
-static char *arg_path = NULL;
+static char **arg_path = NULL;
 
-STATIC_DESTRUCTOR_REGISTER(arg_path, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_path, strv_freep);
 
 static int help(int argc, char *argv[], void *userdata) {
 
@@ -27,7 +27,7 @@ static int help(int argc, char *argv[], void *userdata) {
                "Mark the boot process as good or bad.\n\n"
                "  -h --help          Show this help\n"
                "     --version       Print version\n"
-               "     --path=PATH     Path to the EFI System Partition (ESP)\n"
+               "     --path=PATH     Path to the $BOOT partition (may be used multiple times)\n"
                "\n"
                "Commands:\n"
                "     good            Mark this boot as good\n"
@@ -67,7 +67,7 @@ static int parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case ARG_PATH:
-                        r = free_and_strdup(&arg_path, optarg);
+                        r = strv_extend(&arg_path, optarg);
                         if (r < 0)
                                 return log_oom();
                         break;
@@ -82,20 +82,42 @@ static int parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
-static int acquire_esp(void) {
-        _cleanup_free_ char *np = NULL;
+static int acquire_path(void) {
+        _cleanup_free_ char *esp_path = NULL, *xbootldr_path = NULL;
+        char **a;
         int r;
 
-        r = find_esp_and_warn(arg_path, false, &np, NULL, NULL, NULL, NULL);
-        if (r == -ENOKEY) /* find_esp_and_warn() doesn't warn in this one error case, but in all others */
-                return log_error_errno(r,
-                                       "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
-                                       "Alternatively, use --path= to specify path to mount point.");
-        if (r < 0)
+        if (!strv_isempty(arg_path))
+                return 0;
+
+        r = find_esp_and_warn(NULL, false, &esp_path, NULL, NULL, NULL, NULL);
+        if (r < 0 && r != -ENOKEY) /* ENOKEY means not found, and is the only error the function won't log about on its own */
+                return r;
+
+        r = find_xbootldr_and_warn(NULL, false, &xbootldr_path, NULL);
+        if (r < 0 && r != -ENOKEY)
                 return r;
 
-        free_and_replace(arg_path, np);
-        log_debug("Using EFI System Partition at %s.", arg_path);
+        if (!esp_path && !xbootldr_path)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+                                       "Couldn't find $BOOT partition. It is recommended to mount it to /boot.\n"
+                                       "Alternatively, use --path= to specify path to mount point.");
+
+        if (esp_path)
+                a = strv_new(esp_path, xbootldr_path);
+        else
+                a = strv_new(xbootldr_path);
+        if (!a)
+                return log_oom();
+
+        strv_free_and_replace(arg_path, a);
+
+        if (DEBUG_LOGGING) {
+                _cleanup_free_ char *j;
+
+                j = strv_join(arg_path, ":");
+                log_debug("Using %s as boot loader drop-in search path.", j);
+        }
 
         return 0;
 }
@@ -282,10 +304,9 @@ static const char *skip_slash(const char *path) {
 }
 
 static int verb_status(int argc, char *argv[], void *userdata) {
-
         _cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL;
-        _cleanup_close_ int fd = -1;
         uint64_t left, done;
+        char **p;
         int r;
 
         r = acquire_boot_count_path(&path, &prefix, &left, &done, &suffix);
@@ -296,7 +317,7 @@ static int verb_status(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = acquire_esp();
+        r = acquire_path();
         if (r < 0)
                 return r;
 
@@ -308,50 +329,61 @@ static int verb_status(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_oom();
 
-        log_debug("Booted file: %s%s\n"
-                  "The same modified for 'good': %s%s\n"
-                  "The same modified for 'bad':  %s%s\n",
-                  arg_path, path,
-                  arg_path, good,
-                  arg_path, bad);
+        log_debug("Booted file: %s\n"
+                  "The same modified for 'good': %s\n"
+                  "The same modified for 'bad':  %s\n",
+                  path,
+                  good,
+                  bad);
 
         log_debug("Tries left: %" PRIu64"\n"
                   "Tries done: %" PRIu64"\n",
                   left, done);
 
-        fd = open(arg_path, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
-        if (fd < 0)
-                return log_error_errno(errno, "Failed to open ESP '%s': %m", arg_path);
+        STRV_FOREACH(p, arg_path) {
+                _cleanup_close_ int fd = -1;
 
-        if (faccessat(fd, skip_slash(path), F_OK, 0) >= 0) {
-                puts("indeterminate");
-                return 0;
-        }
-        if (errno != ENOENT)
-                return log_error_errno(errno, "Failed to check if '%s' exists: %m", path);
+                fd = open(*p, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
+                if (fd < 0) {
+                        if (errno == ENOENT)
+                                continue;
 
-        if (faccessat(fd, skip_slash(good), F_OK, 0) >= 0) {
-                puts("good");
-                return 0;
-        }
-        if (errno != ENOENT)
-                return log_error_errno(errno, "Failed to check if '%s' exists: %m", good);
+                        return log_error_errno(errno, "Failed to open $BOOT partition '%s': %m", *p);
+                }
 
-        if (faccessat(fd, skip_slash(bad), F_OK, 0) >= 0) {
-                puts("bad");
-                return 0;
+                if (faccessat(fd, skip_slash(path), F_OK, 0) >= 0) {
+                        puts("indeterminate");
+                        return 0;
+                }
+                if (errno != ENOENT)
+                        return log_error_errno(errno, "Failed to check if '%s' exists: %m", path);
+
+                if (faccessat(fd, skip_slash(good), F_OK, 0) >= 0) {
+                        puts("good");
+                        return 0;
+                }
+
+                if (errno != ENOENT)
+                        return log_error_errno(errno, "Failed to check if '%s' exists: %m", good);
+
+                if (faccessat(fd, skip_slash(bad), F_OK, 0) >= 0) {
+                        puts("bad");
+                        return 0;
+                }
+                if (errno != ENOENT)
+                        return log_error_errno(errno, "Failed to check if '%s' exists: %m", bad);
+
+                /* We didn't find any of the three? If so, let's try the next directory, before we give up. */
         }
-        if (errno != ENOENT)
-                return log_error_errno(errno, "Failed to check if '%s' exists: %m", bad);
 
-        return log_error_errno(errno, "Couldn't determine boot state: %m");
+        return log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Couldn't determine boot state: %m");
 }
 
 static int verb_set(int argc, char *argv[], void *userdata) {
         _cleanup_free_ char *path = NULL, *prefix = NULL, *suffix = NULL, *good = NULL, *bad = NULL, *parent = NULL;
         const char *target, *source1, *source2;
-        _cleanup_close_ int fd = -1;
         uint64_t done;
+        char **p;
         int r;
 
         r = acquire_boot_count_path(&path, &prefix, NULL, &done, &suffix);
@@ -360,7 +392,7 @@ static int verb_set(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
-        r = acquire_esp();
+        r = acquire_path();
         if (r < 0)
                 return r;
 
@@ -372,10 +404,6 @@ static int verb_set(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_oom();
 
-        fd = open(arg_path, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
-        if (fd < 0)
-                return log_error_errno(errno, "Failed to open ESP '%s': %m", arg_path);
-
         /* Figure out what rename to what */
         if (streq(argv[0], "good")) {
                 target = good;
@@ -392,45 +420,58 @@ static int verb_set(int argc, char *argv[], void *userdata) {
                 source2 = bad;
         }
 
-        r = rename_noreplace(fd, skip_slash(source1), fd, skip_slash(target));
-        if (r == -EEXIST)
-                goto exists;
-        else if (r == -ENOENT) {
+        STRV_FOREACH(p, arg_path) {
+                _cleanup_close_ int fd = -1;
+
+                fd = open(*p, O_DIRECTORY|O_CLOEXEC|O_RDONLY);
+                if (fd < 0)
+                        return log_error_errno(errno, "Failed to open $BOOT partition '%s': %m", *p);
 
-                r = rename_noreplace(fd, skip_slash(source2), fd, skip_slash(target));
+                r = rename_noreplace(fd, skip_slash(source1), fd, skip_slash(target));
                 if (r == -EEXIST)
                         goto exists;
                 else if (r == -ENOENT) {
 
-                        if (access(target, F_OK) >= 0) /* Hmm, if we can't find either source file, maybe the destination already exists? */
+                        r = rename_noreplace(fd, skip_slash(source2), fd, skip_slash(target));
+                        if (r == -EEXIST)
                                 goto exists;
+                        else if (r == -ENOENT) {
+
+                                if (faccessat(fd, skip_slash(target), F_OK, 0) >= 0) /* Hmm, if we can't find either source file, maybe the destination already exists? */
+                                        goto exists;
+
+                                if (errno != ENOENT)
+                                        return log_error_errno(errno, "Failed to determine if %s already exists: %m", target);
+
+                                /* We found none of the snippets here, try the next directory */
+                                continue;
+                        } else if (r < 0)
+                                return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source2, target);
+                        else
+                                log_debug("Successfully renamed '%s' to '%s'.", source2, target);
 
-                        return log_error_errno(r, "Can't find boot counter source file for '%s': %m", target);
                 } else if (r < 0)
-                        return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source2, target);
+                        return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source1, target);
                 else
-                        log_debug("Successfully renamed '%s' to '%s'.", source2, target);
-
-        } else if (r < 0)
-                return log_error_errno(r, "Failed to rename '%s' to '%s': %m", source1, target);
-        else
-                log_debug("Successfully renamed '%s' to '%s'.", source1, target);
+                        log_debug("Successfully renamed '%s' to '%s'.", source1, target);
 
-        /* First, fsync() the directory these files are located in */
-        parent = dirname_malloc(path);
-        if (!parent)
-                return log_oom();
+                /* First, fsync() the directory these files are located in */
+                parent = dirname_malloc(target);
+                if (!parent)
+                        return log_oom();
 
-        r = fsync_path_at(fd, skip_slash(parent));
-        if (r < 0)
-                log_debug_errno(errno, "Failed to synchronize image directory, ignoring: %m");
+                r = fsync_path_at(fd, skip_slash(parent));
+                if (r < 0)
+                        log_debug_errno(errno, "Failed to synchronize image directory, ignoring: %m");
 
-        /* Secondly, syncfs() the whole file system these files are located in */
-        if (syncfs(fd) < 0)
-                log_debug_errno(errno, "Failed to synchronize ESP, ignoring: %m");
+                /* Secondly, syncfs() the whole file system these files are located in */
+                if (syncfs(fd) < 0)
+                        log_debug_errno(errno, "Failed to synchronize $BOOT partition, ignoring: %m");
 
-        log_info("Marked boot as '%s'. (Boot attempt counter is at %" PRIu64".)", argv[0], done);
+                log_info("Marked boot as '%s'. (Boot attempt counter is at %" PRIu64".)", argv[0], done);
+        }
 
+        log_error_errno(SYNTHETIC_ERRNO(EBUSY), "Can't find boot counter source file for '%s': %m", target);
         return 1;
 
 exists:
index dc2fd96..a7de380 100644 (file)
@@ -35,6 +35,7 @@
 #include "pretty-print.h"
 #include "rm-rf.h"
 #include "stat-util.h"
+#include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "verbs.h"
 #include "virt.h"
 
-static char *arg_path = NULL;
-static bool arg_print_path = false;
+static char *arg_esp_path = NULL;
+static char *arg_xbootldr_path = NULL;
+static bool arg_print_esp_path = false;
+static bool arg_print_dollar_boot_path = false;
 static bool arg_touch_variables = true;
 static PagerFlags arg_pager_flags = 0;
 
-STATIC_DESTRUCTOR_REGISTER(arg_path, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_esp_path, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_xbootldr_path, freep);
+
+static const char *arg_dollar_boot_path(void) {
+        /* $BOOT shall be the XBOOTLDR partition if it exists, and otherwise the ESP */
+        return arg_xbootldr_path ?: arg_esp_path;
+}
 
 static int acquire_esp(
                 bool unprivileged_mode,
@@ -62,24 +71,44 @@ static int acquire_esp(
         char *np;
         int r;
 
-        /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on its own,
-         * except for ENOKEY (which is good, we want to show our own message in that case, suggesting use of --path=)
-         * and EACCESS (only when we request unprivileged mode; in this case we simply eat up the error here, so that
-         * --list and --status work too, without noise about this). */
+        /* Find the ESP, and log about errors. Note that find_esp_and_warn() will log in all error cases on
+         * its own, except for ENOKEY (which is good, we want to show our own message in that case,
+         * suggesting use of --esp-path=) and EACCESS (only when we request unprivileged mode; in this case
+         * we simply eat up the error here, so that --list and --status work too, without noise about
+         * this). */
 
-        r = find_esp_and_warn(arg_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid);
+        r = find_esp_and_warn(arg_esp_path, unprivileged_mode, &np, ret_part, ret_pstart, ret_psize, ret_uuid);
         if (r == -ENOKEY)
                 return log_error_errno(r,
                                        "Couldn't find EFI system partition. It is recommended to mount it to /boot or /efi.\n"
-                                       "Alternatively, use --path= to specify path to mount point.");
+                                       "Alternatively, use --esp-path= to specify path to mount point.");
         if (r < 0)
                 return r;
 
-        free_and_replace(arg_path, np);
+        free_and_replace(arg_esp_path, np);
+        log_debug("Using EFI System Partition at %s.", arg_esp_path);
 
-        log_debug("Using EFI System Partition at %s.", arg_path);
+        return 1;
+}
 
-        return 0;
+static int acquire_xbootldr(bool unprivileged_mode, sd_id128_t *ret_uuid) {
+        char *np;
+        int r;
+
+        r = find_xbootldr_and_warn(arg_xbootldr_path, unprivileged_mode, &np, ret_uuid);
+        if (r == -ENOKEY) {
+                log_debug_errno(r, "Didn't find an XBOOTLDR partition, using the ESP as $BOOT.");
+                if (ret_uuid)
+                        *ret_uuid = SD_ID128_NULL;
+                return 0;
+        }
+        if (r < 0)
+                return r;
+
+        free_and_replace(arg_xbootldr_path, np);
+        log_debug("Using XBOOTLDR partition at %s as $BOOT.", arg_xbootldr_path);
+
+        return 1;
 }
 
 /* search for "#### LoaderInfo: systemd-boot 218 ####" string inside the binary */
@@ -96,6 +125,10 @@ static int get_file_version(int fd, char **v) {
         if (fstat(fd, &st) < 0)
                 return log_error_errno(errno, "Failed to stat EFI binary: %m");
 
+        r = stat_verify_regular(&st);
+        if (r < 0)
+                return log_error_errno(errno, "EFI binary is not a regular file: %m");
+
         if (st.st_size < 27) {
                 *v = NULL;
                 return 0;
@@ -112,8 +145,7 @@ static int get_file_version(int fd, char **v) {
 
         e = memmem(s, st.st_size - (s - buf), " ####", 5);
         if (!e || e - s < 3) {
-                log_error("Malformed version string.");
-                r = -EINVAL;
+                r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Malformed version string.");
                 goto finish;
         }
 
@@ -131,10 +163,13 @@ finish:
 }
 
 static int enumerate_binaries(const char *esp_path, const char *path, const char *prefix) {
-        char *p;
         _cleanup_closedir_ DIR *d = NULL;
         struct dirent *de;
-        int r = 0, c = 0;
+        int c = 0, r;
+        char *p;
+
+        assert(esp_path);
+        assert(path);
 
         p = strjoina(esp_path, "/", path);
         d = opendir(p);
@@ -146,8 +181,8 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char
         }
 
         FOREACH_DIRENT(de, d, break) {
-                _cleanup_close_ int fd = -1;
                 _cleanup_free_ char *v = NULL;
+                _cleanup_close_ int fd = -1;
 
                 if (!endswith_no_case(de->d_name, ".efi"))
                         continue;
@@ -166,6 +201,7 @@ static int enumerate_binaries(const char *esp_path, const char *path, const char
                         printf("         File: %s/%s/%s (%s%s%s)\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path, de->d_name, ansi_highlight(), v, ansi_normal());
                 else
                         printf("         File: %s/%s/%s\n", special_glyph(SPECIAL_GLYPH_TREE_RIGHT), path, de->d_name);
+
                 c++;
         }
 
@@ -188,20 +224,22 @@ static int status_binaries(const char *esp_path, sd_id128_t partition) {
         printf("\n");
 
         r = enumerate_binaries(esp_path, "EFI/systemd", NULL);
+        if (r < 0)
+                goto finish;
         if (r == 0)
                 log_info("systemd-boot not installed in ESP.");
-        else if (r < 0)
-                return r;
 
         r = enumerate_binaries(esp_path, "EFI/BOOT", "boot");
+        if (r < 0)
+                goto finish;
         if (r == 0)
                 log_info("No default/fallback boot loader installed in ESP.");
-        else if (r < 0)
-                return r;
 
-        printf("\n");
+        r = 0;
 
-        return 0;
+finish:
+        printf("\n");
+        return r;
 }
 
 static int print_efi_option(uint16_t id, bool in_order) {
@@ -274,13 +312,15 @@ static int status_variables(void) {
 static int boot_entry_show(const BootEntry *e, bool show_as_default) {
         assert(e);
 
-        printf("        title: %s%s%s%s%s%s\n",
+        printf("        title: %s%s%s%s%s%s\n"
+               "         type: %s\n",
                ansi_highlight(),
                boot_entry_title(e),
                ansi_normal(),
                ansi_highlight_green(),
                show_as_default ? " (default)" : "",
-               ansi_normal());
+               ansi_normal(),
+               boot_entry_type_to_string(e->type));
 
         if (e->id)
                 printf("           id: %s\n", e->id);
@@ -316,11 +356,34 @@ static int boot_entry_show(const BootEntry *e, bool show_as_default) {
         return 0;
 }
 
-static int status_entries(const char *esp_path, sd_id128_t partition) {
+static int status_entries(
+                const char *esp_path,
+                sd_id128_t esp_partition_uuid,
+                const char *xbootldr_path,
+                sd_id128_t xbootldr_partition_uuid) {
+
         _cleanup_(boot_config_free) BootConfig config = {};
+        sd_id128_t dollar_boot_partition_uuid;
+        const char *dollar_boot_path;
         int r;
 
-        r = boot_entries_load_config(esp_path, &config);
+        assert(esp_path || xbootldr_path);
+
+        if (xbootldr_path) {
+                dollar_boot_path = xbootldr_path;
+                dollar_boot_partition_uuid = xbootldr_partition_uuid;
+        } else {
+                dollar_boot_path = esp_path;
+                dollar_boot_partition_uuid = esp_partition_uuid;
+        }
+
+        printf("Boot Loader Entries:\n"
+               "        $BOOT: %s", dollar_boot_path);
+        if (!sd_id128_is_null(dollar_boot_partition_uuid))
+                printf(" (/dev/disk/by-partuuid/%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x)", SD_ID128_FORMAT_VAL(dollar_boot_partition_uuid));
+        printf("\n\n");
+
+        r = boot_entries_load_config(esp_path, xbootldr_path, &config);
         if (r < 0)
                 return r;
 
@@ -386,10 +449,8 @@ static int version_check(int fd_from, const char *from, int fd_to, const char *t
                                         "Skipping \"%s\", since it's owned by another boot loader.",
                                         to);
 
-        if (compare_version(a, b) < 0) {
-                log_warning("Skipping \"%s\", since a newer boot loader version exists already.", to);
-                return -ESTALE;
-        }
+        if (compare_version(a, b) < 0)
+                return log_warning_errno(SYNTHETIC_ERRNO(ESTALE), "Skipping \"%s\", since a newer boot loader version exists already.", to);
 
         return 0;
 }
@@ -436,7 +497,7 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f
                 return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", from, t);
         }
 
-        (void) copy_times(fd_from, fd_to);
+        (void) copy_times(fd_from, fd_to, 0);
 
         if (fsync(fd_to) < 0) {
                 (void) unlink_noerrno(t);
@@ -456,9 +517,9 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f
 }
 
 static int mkdir_one(const char *prefix, const char *suffix) {
-        char *p;
+        _cleanup_free_ char *p = NULL;
 
-        p = strjoina(prefix, "/", suffix);
+        p = path_join(prefix, suffix);
         if (mkdir(p, 0700) < 0) {
                 if (errno != EEXIST)
                         return log_error_errno(errno, "Failed to create \"%s\": %m", p);
@@ -468,20 +529,21 @@ static int mkdir_one(const char *prefix, const char *suffix) {
         return 0;
 }
 
-static const char *efi_subdirs[] = {
+static const char *const esp_subdirs[] = {
         "EFI",
         "EFI/systemd",
         "EFI/BOOT",
         "loader",
-        "loader/entries",
+        /* Note that "/loader/entries" is not listed here, since it should be placed in $BOOT, which might
+         * not necessarily be the ESP */
         NULL
 };
 
-static int create_dirs(const char *esp_path) {
-        const char **i;
+static int create_esp_subdirs(const char *esp_path) {
+        const char *const *i;
         int r;
 
-        STRV_FOREACH(i, efi_subdirs) {
+        STRV_FOREACH(i, esp_subdirs) {
                 r = mkdir_one(esp_path, *i);
                 if (r < 0)
                         return r;
@@ -520,22 +582,11 @@ static int install_binaries(const char *esp_path, bool force) {
         _cleanup_closedir_ DIR *d = NULL;
         int r = 0;
 
-        if (force) {
-                /* Don't create any of these directories when we are
-                 * just updating. When we update we'll drop-in our
-                 * files (unless there are newer ones already), but we
-                 * won't create the directories for them in the first
-                 * place. */
-                r = create_dirs(esp_path);
-                if (r < 0)
-                        return r;
-        }
-
         d = opendir(BOOTLIBDIR);
         if (!d)
                 return log_error_errno(errno, "Failed to open \""BOOTLIBDIR"\": %m");
 
-        FOREACH_DIRENT(de, d, break) {
+        FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read \""BOOTLIBDIR"\": %m")) {
                 int k;
 
                 if (!endswith_no_case(de->d_name, ".efi"))
@@ -624,7 +675,7 @@ static int insert_into_order(uint16_t slot, bool first) {
         }
 
         /* extend array */
-        t = realloc(order, (n + 1) * sizeof(uint16_t));
+        t = reallocarray(order, n + 1, sizeof(uint16_t));
         if (!t)
                 return -ENOMEM;
         order = t;
@@ -751,18 +802,36 @@ static int rmdir_one(const char *prefix, const char *suffix) {
 
         p = strjoina(prefix, "/", suffix);
         if (rmdir(p) < 0) {
-                if (!IN_SET(errno, ENOENT, ENOTEMPTY))
-                        return log_error_errno(errno, "Failed to remove \"%s\": %m", p);
+                bool ignore = IN_SET(errno, ENOENT, ENOTEMPTY);
+
+                log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, errno,
+                               "Failed to remove directory \"%s\": %m", p);
+                if (!ignore)
+                        return -errno;
         } else
                 log_info("Removed \"%s\".", p);
 
         return 0;
 }
 
+static int remove_esp_subdirs(const char *esp_path) {
+        size_t i;
+        int r = 0;
+
+        for (i = ELEMENTSOF(esp_subdirs)-1; i > 0; i--) {
+                int q;
+
+                q = rmdir_one(esp_path, esp_subdirs[i-1]);
+                if (q < 0 && r >= 0)
+                        r = q;
+        }
+
+        return r;
+}
+
 static int remove_binaries(const char *esp_path) {
         char *p;
         int r, q;
-        unsigned i;
 
         p = strjoina(esp_path, "/EFI/systemd");
         r = rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
@@ -771,15 +840,31 @@ static int remove_binaries(const char *esp_path) {
         if (q < 0 && r == 0)
                 r = q;
 
-        for (i = ELEMENTSOF(efi_subdirs)-1; i > 0; i--) {
-                q = rmdir_one(esp_path, efi_subdirs[i-1]);
-                if (q < 0 && r == 0)
-                        r = q;
-        }
-
         return r;
 }
 
+static int remove_loader_config(const char *esp_path) {
+        const char *p;
+
+        assert(esp_path);
+
+        p = strjoina(esp_path, "/loader/loader.conf");
+        if (unlink(p) < 0) {
+                log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to unlink file \"%s\": %m", p);
+                if (errno != ENOENT)
+                        return -errno;
+        } else
+                log_info("Removed \"%s\".", p);
+
+        return  0;
+}
+
+static int remove_entries_directory(const char *dollar_boot_path) {
+        assert(dollar_boot_path);
+
+        return rmdir_one(dollar_boot_path, "/loader/entries");
+}
+
 static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
         uint16_t slot;
         int r;
@@ -801,21 +886,14 @@ static int remove_variables(sd_id128_t uuid, const char *path, bool in_order) {
         return 0;
 }
 
-static int install_loader_config(const char *esp_path) {
-
+static int install_loader_config(const char *esp_path, sd_id128_t machine_id) {
         char machine_string[SD_ID128_STRING_MAX];
         _cleanup_(unlink_and_freep) char *t = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        sd_id128_t machine_id;
         const char *p;
         int r, fd;
 
-        r = sd_id128_get_machine(&machine_id);
-        if (r < 0)
-                return log_error_errno(r, "Failed to get machine id: %m");
-
         p = strjoina(esp_path, "/loader/loader.conf");
-
         if (access(p, F_OK) >= 0) /* Silently skip creation if the file already exists (early check) */
                 return 0;
 
@@ -844,10 +922,26 @@ static int install_loader_config(const char *esp_path) {
                 return log_error_errno(r, "Failed to move \"%s\" into place: %m", p);
 
         t = mfree(t);
-
         return 1;
 }
 
+static int install_entries_directories(const char *dollar_boot_path, sd_id128_t machine_id) {
+        int r;
+        char buf[SD_ID128_STRING_MAX];
+
+        assert(dollar_boot_path);
+
+        /* Both /loader/entries and the entry directories themselves should be located on the same
+         * partition. Also create the parent directory for entry directories, so that kernel-install
+         * knows where to put them. */
+
+        r = mkdir_one(dollar_boot_path, "loader/entries");
+        if (r < 0)
+                return r;
+
+        return mkdir_one(dollar_boot_path, sd_id128_to_string(machine_id, buf));
+}
+
 static int help(int argc, char *argv[], void *userdata) {
         _cleanup_free_ char *link = NULL;
         int r;
@@ -858,21 +952,23 @@ static int help(int argc, char *argv[], void *userdata) {
 
         printf("%s [COMMAND] [OPTIONS...]\n\n"
                "Install, update or remove the systemd-boot EFI boot manager.\n\n"
-               "  -h --help          Show this help\n"
-               "     --version       Print version\n"
-               "     --path=PATH     Path to the EFI System Partition (ESP)\n"
-               "  -p --print-path    Print path to the EFI partition\n"
-               "     --no-variables  Don't touch EFI variables\n"
-               "     --no-pager      Do not pipe output into a pager\n"
+               "  -h --help            Show this help\n"
+               "     --version         Print version\n"
+               "     --esp-path=PATH   Path to the EFI System Partition (ESP)\n"
+               "     --boot-path=PATH  Path to the $BOOT partition\n"
+               "  -p --print-esp-path  Print path to the EFI System Partition\n"
+               "     --print-boot-path Print path to the $BOOT partition\n"
+               "     --no-variables    Don't touch EFI variables\n"
+               "     --no-pager        Do not pipe output into a pager\n"
                "\nBoot Loader Commands:\n"
-               "     status          Show status of installed systemd-boot and EFI variables\n"
-               "     install         Install systemd-boot to the ESP and EFI variables\n"
-               "     update          Update systemd-boot in the ESP and EFI variables\n"
-               "     remove          Remove systemd-boot from the ESP and EFI variables\n"
+               "     status            Show status of installed systemd-boot and EFI variables\n"
+               "     install           Install systemd-boot to the ESP and EFI variables\n"
+               "     update            Update systemd-boot in the ESP and EFI variables\n"
+               "     remove            Remove systemd-boot from the ESP and EFI variables\n"
                "\nBoot Loader Entries Commands:\n"
-               "     list            List boot loader entries\n"
-               "     set-default ID  Set default boot loader entry\n"
-               "     set-oneshot ID  Set default boot loader entry, for next boot only\n"
+               "     list              List boot loader entries\n"
+               "     set-default ID    Set default boot loader entry\n"
+               "     set-oneshot ID    Set default boot loader entry, for next boot only\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
                , link);
@@ -882,19 +978,25 @@ static int help(int argc, char *argv[], void *userdata) {
 
 static int parse_argv(int argc, char *argv[]) {
         enum {
-                ARG_PATH = 0x100,
+                ARG_ESP_PATH = 0x100,
+                ARG_BOOT_PATH,
+                ARG_PRINT_BOOT_PATH,
                 ARG_VERSION,
                 ARG_NO_VARIABLES,
                 ARG_NO_PAGER,
         };
 
         static const struct option options[] = {
-                { "help",         no_argument,       NULL, 'h'              },
-                { "version",      no_argument,       NULL, ARG_VERSION      },
-                { "path",         required_argument, NULL, ARG_PATH         },
-                { "print-path",   no_argument,       NULL, 'p'              },
-                { "no-variables", no_argument,       NULL, ARG_NO_VARIABLES },
-                { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
+                { "help",            no_argument,       NULL, 'h'                 },
+                { "version",         no_argument,       NULL, ARG_VERSION         },
+                { "esp-path",        required_argument, NULL, ARG_ESP_PATH        },
+                { "path",            required_argument, NULL, ARG_ESP_PATH        }, /* Compatibility alias */
+                { "boot-path",       required_argument, NULL, ARG_BOOT_PATH       },
+                { "print-esp-path",  no_argument,       NULL, 'p'                 },
+                { "print-path",      no_argument,       NULL, 'p'                 }, /* Compatibility alias */
+                { "print-boot-path", no_argument,       NULL, ARG_PRINT_BOOT_PATH },
+                { "no-variables",    no_argument,       NULL, ARG_NO_VARIABLES    },
+                { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
                 {}
         };
 
@@ -913,14 +1015,24 @@ static int parse_argv(int argc, char *argv[]) {
                 case ARG_VERSION:
                         return version();
 
-                case ARG_PATH:
-                        r = free_and_strdup(&arg_path, optarg);
+                case ARG_ESP_PATH:
+                        r = free_and_strdup(&arg_esp_path, optarg);
+                        if (r < 0)
+                                return log_oom();
+                        break;
+
+                case ARG_BOOT_PATH:
+                        r = free_and_strdup(&arg_xbootldr_path, optarg);
                         if (r < 0)
                                 return log_oom();
                         break;
 
                 case 'p':
-                        arg_print_path = true;
+                        arg_print_esp_path = true;
+                        break;
+
+                case ARG_PRINT_BOOT_PATH:
+                        arg_print_dollar_boot_path = true;
                         break;
 
                 case ARG_NO_VARIABLES:
@@ -950,23 +1062,33 @@ static void read_loader_efi_var(const char *name, char **var) {
 }
 
 static int verb_status(int argc, char *argv[], void *userdata) {
-
-        sd_id128_t uuid = SD_ID128_NULL;
+        sd_id128_t esp_uuid = SD_ID128_NULL, xbootldr_uuid = SD_ID128_NULL;
         int r, k;
 
-        r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
-
-        if (arg_print_path) {
+        r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &esp_uuid);
+        if (arg_print_esp_path) {
                 if (r == -EACCES) /* If we couldn't acquire the ESP path, log about access errors (which is the only
                                    * error the find_esp_and_warn() won't log on its own) */
-                        return log_error_errno(r, "Failed to determine ESP: %m");
+                        return log_error_errno(r, "Failed to determine ESP location: %m");
                 if (r < 0)
                         return r;
 
-                puts(arg_path);
-                return 0;
+                puts(arg_esp_path);
+        }
+
+        r = acquire_xbootldr(geteuid() != 0, &xbootldr_uuid);
+        if (arg_print_dollar_boot_path) {
+                if (r == -EACCES)
+                        return log_error_errno(r, "Failed to determine XBOOTLDR location: %m");
+                if (r < 0)
+                        return r;
+
+                puts(arg_dollar_boot_path());
         }
 
+        if (arg_print_esp_path || arg_print_dollar_boot_path)
+                return 0;
+
         r = 0; /* If we couldn't determine the path, then don't consider that a problem from here on, just show what we
                 * can show */
 
@@ -1037,8 +1159,8 @@ static int verb_status(int argc, char *argv[], void *userdata) {
         } else
                 printf("System:\n    Not booted with EFI\n\n");
 
-        if (arg_path) {
-                k = status_binaries(arg_path, uuid);
+        if (arg_esp_path) {
+                k = status_binaries(arg_esp_path, esp_uuid);
                 if (k < 0)
                         r = k;
         }
@@ -1049,8 +1171,8 @@ static int verb_status(int argc, char *argv[], void *userdata) {
                         r = k;
         }
 
-        if (arg_path) {
-                k = status_entries(arg_path, uuid);
+        if (arg_esp_path || arg_xbootldr_path) {
+                k = status_entries(arg_esp_path, esp_uuid, arg_xbootldr_path, xbootldr_uuid);
                 if (k < 0)
                         r = k;
         }
@@ -1060,27 +1182,29 @@ static int verb_status(int argc, char *argv[], void *userdata) {
 
 static int verb_list(int argc, char *argv[], void *userdata) {
         _cleanup_(boot_config_free) BootConfig config = {};
-        _cleanup_free_ char **found_by_loader = NULL;
-        sd_id128_t uuid = SD_ID128_NULL;
         int r;
 
         /* If we lack privileges we invoke find_esp_and_warn() in "unprivileged mode" here, which does two things: turn
          * off logging about access errors and turn off potentially privileged device probing. Here we're interested in
          * the latter but not the former, hence request the mode, and log about EACCES. */
 
-        r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, &uuid);
+        r = acquire_esp(geteuid() != 0, NULL, NULL, NULL, NULL);
         if (r == -EACCES) /* We really need the ESP path for this call, hence also log about access errors */
                 return log_error_errno(r, "Failed to determine ESP: %m");
         if (r < 0)
                 return r;
 
-        r = boot_entries_load_config(arg_path, &config);
+        r = acquire_xbootldr(geteuid() != 0, NULL);
+        if (r == -EACCES)
+                return log_error_errno(r, "Failed to determine XBOOTLDR partition: %m");
+        if (r < 0)
+                return r;
+
+        r = boot_entries_load_config(arg_esp_path, arg_xbootldr_path, &config);
         if (r < 0)
                 return r;
 
-        r = efi_loader_get_entries(&found_by_loader);
-        if (r < 0 && !IN_SET(r, -ENOENT, -EOPNOTSUPP))
-                log_debug_errno(r, "Failed to acquire boot loader discovered entries: %m");
+        (void) boot_entries_augment_from_loader(&config, false);
 
         if (config.n_entries == 0)
                 log_info("No boot loader entries found.");
@@ -1096,45 +1220,37 @@ static int verb_list(int argc, char *argv[], void *userdata) {
                         if (r < 0)
                                 return r;
 
-                        puts("");
-
-                        strv_remove(found_by_loader, config.entries[n].id);
+                        if (n+1 < config.n_entries)
+                                putchar('\n');
                 }
         }
 
-        if (!strv_isempty(found_by_loader)) {
-                char **i;
-
-                printf("Automatic/Other Entries Found by Boot Loader:\n\n");
-
-                STRV_FOREACH(i, found_by_loader)
-                        puts(*i);
-        }
-
         return 0;
 }
 
-static int sync_esp(void) {
-        _cleanup_close_ int fd = -1;
-
-        if (!arg_path)
-                return 0;
+static int sync_everything(void) {
+        int ret = 0, k;
 
-        fd = open(arg_path, O_CLOEXEC|O_DIRECTORY|O_RDONLY);
-        if (fd < 0)
-                return log_error_errno(errno, "Couldn't open ESP '%s' for synchronization: %m", arg_path);
+        if (arg_esp_path) {
+                k = syncfs_path(AT_FDCWD, arg_esp_path);
+                if (k < 0)
+                        ret = log_error_errno(k, "Failed to synchronize the ESP '%s': %m", arg_esp_path);
+        }
 
-        if (syncfs(fd) < 0)
-                return log_error_errno(errno, "Failed to synchronize the ESP '%s': %m", arg_path);
+        if (arg_xbootldr_path) {
+                k = syncfs_path(AT_FDCWD, arg_xbootldr_path);
+                if (k < 0)
+                        ret = log_error_errno(k, "Failed to synchronize $BOOT '%s': %m", arg_xbootldr_path);
+        }
 
-        return 1;
+        return ret;
 }
 
 static int verb_install(int argc, char *argv[], void *userdata) {
-
         sd_id128_t uuid = SD_ID128_NULL;
         uint64_t pstart = 0, psize = 0;
         uint32_t part = 0;
+        sd_id128_t machine_id;
         bool install;
         int r;
 
@@ -1142,24 +1258,45 @@ static int verb_install(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
+        r = acquire_xbootldr(false, NULL);
+        if (r < 0)
+                return r;
+
+        r = sd_id128_get_machine(&machine_id);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get machine id: %m");
+
         install = streq(argv[0], "install");
 
         RUN_WITH_UMASK(0002) {
-                r = install_binaries(arg_path, install);
+                if (install) {
+                        /* Don't create any of these directories when we are just updating. When we update
+                         * we'll drop-in our files (unless there are newer ones already), but we won't create
+                         * the directories for them in the first place. */
+                        r = create_esp_subdirs(arg_esp_path);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = install_binaries(arg_esp_path, install);
                 if (r < 0)
                         return r;
 
                 if (install) {
-                        r = install_loader_config(arg_path);
+                        r = install_loader_config(arg_esp_path, machine_id);
+                        if (r < 0)
+                                return r;
+
+                        r = install_entries_directories(arg_dollar_boot_path(), machine_id);
                         if (r < 0)
                                 return r;
                 }
         }
 
-        (void) sync_esp();
+        (void) sync_everything();
 
         if (arg_touch_variables)
-                r = install_variables(arg_path,
+                r = install_variables(arg_esp_path,
                                       part, pstart, psize, uuid,
                                       "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi",
                                       install);
@@ -1169,21 +1306,35 @@ static int verb_install(int argc, char *argv[], void *userdata) {
 
 static int verb_remove(int argc, char *argv[], void *userdata) {
         sd_id128_t uuid = SD_ID128_NULL;
-        int r;
+        int r, q;
 
         r = acquire_esp(false, NULL, NULL, NULL, &uuid);
         if (r < 0)
                 return r;
 
-        r = remove_binaries(arg_path);
+        r = acquire_xbootldr(false, NULL);
+        if (r < 0)
+                return r;
 
-        (void) sync_esp();
+        r = remove_binaries(arg_esp_path);
 
-        if (arg_touch_variables) {
-                int q;
+        q = remove_loader_config(arg_esp_path);
+        if (q < 0 && r >= 0)
+                r = q;
+
+        q = remove_entries_directory(arg_dollar_boot_path());
+        if (q < 0 && r >= 0)
+                r = q;
 
+        q = remove_esp_subdirs(arg_esp_path);
+        if (q < 0 && r >= 0)
+                r = q;
+
+        (void) sync_everything();
+
+        if (arg_touch_variables) {
                 q = remove_variables(uuid, "/EFI/systemd/systemd-boot" EFI_MACHINE_TYPE_NAME ".efi", true);
-                if (q < 0 && r == 0)
+                if (q < 0 && r >= 0)
                         r = q;
         }
 
@@ -1261,7 +1412,7 @@ static int run(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
 
-        /* If we run in a container, automatically turn of EFI file system access */
+        /* If we run in a container, automatically turn off EFI file system access */
         if (detect_container() > 0)
                 arg_touch_variables = false;
 
index 9bf6895..57c423b 100644 (file)
@@ -1,9 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <efi.h>
+#include <efigpt.h>
 #include <efilib.h>
 
 #include "console.h"
+#include "crc32.h"
 #include "disk.h"
 #include "graphics.h"
 #include "linux.h"
@@ -267,10 +269,8 @@ static BOOLEAN line_edit(
 
                 case KEYPRESS(0, 0, CHAR_LINEFEED):
                 case KEYPRESS(0, 0, CHAR_CARRIAGE_RETURN):
-                        if (StrCmp(line, line_in) != 0) {
-                                *line_out = line;
-                                line = NULL;
-                        }
+                        if (StrCmp(line, line_in) != 0)
+                                *line_out = TAKE_PTR(line);
                         enter = TRUE;
                         exit = TRUE;
                         break;
@@ -1256,8 +1256,7 @@ static VOID config_entry_bump_counters(
         /* If the file we just renamed is the loader path, then let's update that. */
         if (StrCmp(entry->loader, old_path) == 0) {
                 FreePool(entry->loader);
-                entry->loader = new_path;
-                new_path = NULL;
+                entry->loader = TAKE_PTR(new_path);
         }
 }
 
@@ -1316,7 +1315,7 @@ static VOID config_entry_add_from_file(
                         entry->loader = stra_to_path(value);
 
                         /* do not add an entry for ourselves */
-                        if (StriCmp(entry->loader, loaded_image_path) == 0) {
+                        if (loaded_image_path && StriCmp(entry->loader, loaded_image_path) == 0) {
                                 entry->type = LOADER_UNDEFINED;
                                 break;
                         }
@@ -1358,10 +1357,8 @@ static VOID config_entry_add_from_file(
                                 s = PoolPrint(L"%s %s", entry->options, new);
                                 FreePool(entry->options);
                                 entry->options = s;
-                        } else {
-                                entry->options = new;
-                                new = NULL;
-                        }
+                        } else
+                                entry->options = TAKE_PTR(new);
 
                         continue;
                 }
@@ -1380,10 +1377,8 @@ static VOID config_entry_add_from_file(
                         s = PoolPrint(L"%s %s", initrd, entry->options);
                         FreePool(entry->options);
                         entry->options = s;
-                } else {
-                        entry->options = initrd;
-                        initrd = NULL;
-                }
+                } else
+                        entry->options = TAKE_PTR(initrd);
         }
 
         entry->device = device;
@@ -1836,7 +1831,7 @@ static VOID config_entry_add_osx(Config *config) {
 
 static VOID config_entry_add_linux(
                 Config *config,
-                EFI_LOADED_IMAGE *loaded_image,
+                EFI_HANDLE *device,
                 EFI_FILE *root_dir) {
 
         EFI_FILE_HANDLE linux_dir;
@@ -1926,7 +1921,7 @@ static VOID config_entry_add_linux(
                         conf = PoolPrint(L"%s-%s", os_id, os_version ? : os_build);
                         path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName);
 
-                        entry = config_entry_add_loader(config, loaded_image->DeviceHandle, LOADER_LINUX, conf, 'l', os_name, path);
+                        entry = config_entry_add_loader(config, device, LOADER_LINUX, conf, 'l', os_name, path);
 
                         FreePool(content);
                         content = NULL;
@@ -1955,6 +1950,213 @@ static VOID config_entry_add_linux(
         uefi_call_wrapper(linux_dir->Close, 1, linux_dir);
 }
 
+/* Note that this is in GUID format, i.e. the first 32bit, and the following pair of 16bit are byteswapped. */
+static const UINT8 xbootldr_guid[16] = {
+        0xff, 0xc2, 0x13, 0xbc, 0xe6, 0x59, 0x62, 0x42, 0xa3, 0x52, 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72
+};
+
+EFI_DEVICE_PATH *path_parent(EFI_DEVICE_PATH *path, EFI_DEVICE_PATH *node) {
+        EFI_DEVICE_PATH *parent;
+        UINTN len;
+
+        len = (UINT8*) NextDevicePathNode(node) - (UINT8*) path;
+        parent = (EFI_DEVICE_PATH*) AllocatePool(len + sizeof(EFI_DEVICE_PATH));
+        CopyMem(parent, path, len);
+        CopyMem((UINT8*) parent + len, EndDevicePath, sizeof(EFI_DEVICE_PATH));
+
+        return parent;
+}
+
+static VOID config_load_xbootldr(
+                Config *config,
+                EFI_HANDLE *device) {
+
+        EFI_DEVICE_PATH *partition_path, *node, *disk_path, *copy;
+        UINT32 found_partition_number = (UINT32) -1;
+        UINT64 found_partition_start = (UINT64) -1;
+        UINT64 found_partition_size = (UINT64) -1;
+        UINT8 found_partition_signature[16] = {};
+        EFI_HANDLE new_device;
+        EFI_FILE *root_dir;
+        EFI_STATUS r;
+
+        partition_path = DevicePathFromHandle(device);
+        if (!partition_path)
+                return;
+
+        for (node = partition_path; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) {
+                EFI_HANDLE disk_handle;
+                EFI_BLOCK_IO *block_io;
+                EFI_DEVICE_PATH *p;
+                UINTN nr;
+
+                /* First, Let's look for the SCSI/SATA/USB/… device path node, i.e. one above the media
+                 * devices */
+                if (DevicePathType(node) != MESSAGING_DEVICE_PATH)
+                        continue;
+
+                /* Determine the device path one level up */
+                disk_path = path_parent(partition_path, node);
+                p = disk_path;
+                r = uefi_call_wrapper(BS->LocateDevicePath, 3, &BlockIoProtocol, &p, &disk_handle);
+                if (EFI_ERROR(r))
+                        continue;
+
+                r = uefi_call_wrapper(BS->HandleProtocol, 3, disk_handle, &BlockIoProtocol, (VOID **)&block_io);
+                if (EFI_ERROR(r))
+                        continue;
+
+                /* Filter out some block devices early. (We only care about block devices that aren't
+                 * partitions themselves — we look for GPT partition tables to parse after all —, and only
+                 * those which contain a medium and have at least 2 blocks.) */
+                if (block_io->Media->LogicalPartition ||
+                    !block_io->Media->MediaPresent ||
+                    block_io->Media->LastBlock <= 1)
+                        continue;
+
+                /* Try both copies of the GPT header, in case one is corrupted */
+                for (nr = 0; nr < 2; nr++) {
+                        _cleanup_freepool_ EFI_PARTITION_ENTRY* entries = NULL;
+                        union {
+                                EFI_PARTITION_TABLE_HEADER gpt_header;
+                                uint8_t space[((sizeof(EFI_PARTITION_TABLE_HEADER) + 511) / 512) * 512];
+                        } gpt_header_buffer;
+                        const EFI_PARTITION_TABLE_HEADER *h = &gpt_header_buffer.gpt_header;
+                        UINT64 where;
+                        UINTN i, sz;
+                        UINT32 c;
+
+                        if (nr == 0)
+                                /* Read the first copy at LBA 1 */
+                                where = 1;
+                        else
+                                /* Read the second copy at the very last LBA of this block device */
+                                where = block_io->Media->LastBlock;
+
+                        /* Read the GPT header */
+                        r = uefi_call_wrapper(block_io->ReadBlocks, 5,
+                                              block_io,
+                                              block_io->Media->MediaId,
+                                              where,
+                                              sizeof(gpt_header_buffer), &gpt_header_buffer);
+                        if (EFI_ERROR(r))
+                                continue;
+
+                        /* Some superficial validation of the GPT header */
+                        c = CompareMem(&h->Header.Signature, "EFI PART", sizeof(h->Header.Signature));
+                        if (c != 0)
+                                continue;
+
+                        if (h->Header.HeaderSize < 92 ||
+                            h->Header.HeaderSize > 512)
+                                continue;
+
+                        if (h->Header.Revision != 0x00010000U)
+                                continue;
+
+                        /* Calculate CRC check */
+                        c = ~crc32_exclude_offset((UINT32) -1,
+                                                  (const UINT8*) &gpt_header_buffer,
+                                                  h->Header.HeaderSize,
+                                                  OFFSETOF(EFI_PARTITION_TABLE_HEADER, Header.CRC32),
+                                                  sizeof(h->Header.CRC32));
+                        if (c != h->Header.CRC32)
+                                continue;
+
+                        if (h->MyLBA != where)
+                                continue;
+
+                        if (h->SizeOfPartitionEntry < sizeof(EFI_PARTITION_ENTRY))
+                                continue;
+
+                        if (h->NumberOfPartitionEntries <= 0 ||
+                            h->NumberOfPartitionEntries > 1024)
+                                continue;
+
+                        if (h->SizeOfPartitionEntry > UINTN_MAX / h->NumberOfPartitionEntries) /* overflow check */
+                                continue;
+
+                        /* Now load the GPT entry table */
+                        sz = ALIGN_TO((UINTN) h->SizeOfPartitionEntry * (UINTN) h->NumberOfPartitionEntries, 512);
+                        entries = AllocatePool(sz);
+
+                        r = uefi_call_wrapper(block_io->ReadBlocks, 5,
+                                              block_io,
+                                              block_io->Media->MediaId,
+                                              h->PartitionEntryLBA,
+                                              sz, entries);
+                        if (EFI_ERROR(r))
+                                continue;
+
+                        /* Calculate CRC of entries array, too */
+                        c = ~crc32((UINT32) -1, entries, sz);
+                        if (c != h->PartitionEntryArrayCRC32)
+                                continue;
+
+                        for (i = 0; i < h->NumberOfPartitionEntries; i++) {
+                                EFI_PARTITION_ENTRY *entry;
+
+                                entry = (EFI_PARTITION_ENTRY*) ((UINT8*) entries + h->SizeOfPartitionEntry * i);
+
+                                if (CompareMem(&entry->PartitionTypeGUID, xbootldr_guid, 16) == 0) {
+                                        UINT64 end;
+
+                                        /* Let's use memcpy(), in case the structs are not aligned (they really should be though) */
+                                        CopyMem(&found_partition_start, &entry->StartingLBA, sizeof(found_partition_start));
+                                        CopyMem(&end, &entry->EndingLBA, sizeof(end));
+
+                                        if (end < found_partition_start) /* Bogus? */
+                                                continue;
+
+                                        found_partition_size = end - found_partition_start + 1;
+                                        CopyMem(found_partition_signature, &entry->UniquePartitionGUID, sizeof(found_partition_signature));
+
+                                        found_partition_number = i + 1;
+                                        goto found;
+                                }
+                        }
+
+                        break; /* This GPT was fully valid, but we didn't find what we are looking for. This
+                                * means there's no reason to check the second copy of the GPT header */
+                }
+        }
+
+        return; /* Not found */
+
+found:
+        copy = DuplicateDevicePath(partition_path);
+
+        /* Patch in the data we found */
+        for (node = copy; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) {
+                HARDDRIVE_DEVICE_PATH *hd;
+
+                if (DevicePathType(node) != MEDIA_DEVICE_PATH)
+                        continue;
+
+                if (DevicePathSubType(node) != MEDIA_HARDDRIVE_DP)
+                        continue;
+
+                hd = (HARDDRIVE_DEVICE_PATH*) node;
+                hd->PartitionNumber = found_partition_number;
+                hd->PartitionStart = found_partition_start;
+                hd->PartitionSize = found_partition_size;
+                CopyMem(hd->Signature, found_partition_signature, sizeof(hd->Signature));
+                hd->MBRType = MBR_TYPE_EFI_PARTITION_TABLE_HEADER;
+                hd->SignatureType = SIGNATURE_TYPE_GUID;
+        }
+
+        r = uefi_call_wrapper(BS->LocateDevicePath, 3, &BlockIoProtocol, &copy, &new_device);
+        if (EFI_ERROR(r))
+                return;
+
+        root_dir = LibOpenRoot(new_device);
+        if (!root_dir)
+                return;
+
+        config_entry_add_linux(config, new_device, root_dir);
+        config_load_entries(config, new_device, root_dir, NULL);
+}
+
 static EFI_STATUS image_start(
                 EFI_HANDLE parent_image,
                 const Config *config,
@@ -2121,7 +2323,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
 
         root_dir = LibOpenRoot(loaded_image->DeviceHandle);
         if (!root_dir) {
-                Print(L"Unable to open root directory: %r ", err);
+                Print(L"Unable to open root directory.");
                 uefi_call_wrapper(BS->Stall, 1, 3 * 1000 * 1000);
                 return EFI_LOAD_ERROR;
         }
@@ -2142,11 +2344,14 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         config_load_defaults(&config, root_dir);
 
         /* scan /EFI/Linux/ directory */
-        config_entry_add_linux(&config, loaded_image, root_dir);
+        config_entry_add_linux(&config, loaded_image->DeviceHandle, root_dir);
 
         /* scan /loader/entries/\*.conf files */
         config_load_entries(&config, loaded_image->DeviceHandle, root_dir, loaded_image_path);
 
+        /* Similar, but on any XBOOTLDR partition */
+        config_load_xbootldr(&config, loaded_image->DeviceHandle);
+
         /* sort entries after version number */
         config_sort_entries(&config);
 
@@ -2163,7 +2368,10 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
                 UINT64 osind = (UINT64)*b;
 
                 if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI)
-                        config_entry_add_call(&config, L"auto-reboot-to-firmware-setup", L"Reboot Into Firmware Interface", reboot_into_firmware);
+                        config_entry_add_call(&config,
+                                              L"auto-reboot-to-firmware-setup",
+                                              L"Reboot Into Firmware Interface",
+                                              reboot_into_firmware);
                 FreePool(b);
         }
 
diff --git a/src/boot/efi/crc32.c b/src/boot/efi/crc32.c
new file mode 100644 (file)
index 0000000..46b9aee
--- /dev/null
@@ -0,0 +1,142 @@
+/* This is copied from util-linux, which in turn copied in the version from Gary S. Brown */
+
+/*
+ *  COPYRIGHT (C) 1986 Gary S. Brown.  You may use this program, or
+ *  code or tables extracted from it, as desired without restriction.
+ *
+ *  First, the polynomial itself and its table of feedback terms.  The
+ *  polynomial is
+ *  X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
+ *
+ *  Note that we take it "backwards" and put the highest-order term in
+ *  the lowest-order bit.  The X^32 term is "implied"; the LSB is the
+ *  X^31 term, etc.  The X^0 term (usually shown as "+1") results in
+ *  the MSB being 1.
+ *
+ *  Note that the usual hardware shift register implementation, which
+ *  is what we're using (we're merely optimizing it by doing eight-bit
+ *  chunks at a time) shifts bits into the lowest-order term.  In our
+ *  implementation, that means shifting towards the right.  Why do we
+ *  do it this way?  Because the calculated CRC must be transmitted in
+ *  order from highest-order term to lowest-order term.  UARTs transmit
+ *  characters in order from LSB to MSB.  By storing the CRC this way,
+ *  we hand it to the UART in the order low-byte to high-byte; the UART
+ *  sends each low-bit to high-bit; and the result is transmission bit
+ *  by bit from highest- to lowest-order term without requiring any bit
+ *  shuffling on our part.  Reception works similarly.
+ *
+ *  The feedback terms table consists of 256, 32-bit entries.  Notes
+ *
+ *      The table can be generated at runtime if desired; code to do so
+ *      is shown later.  It might not be obvious, but the feedback
+ *      terms simply represent the results of eight shift/xor opera-
+ *      tions for all combinations of data and CRC register values.
+ *
+ *      The values must be right-shifted by eight bits by the "updcrc"
+ *      logic; the shift must be unsigned (bring in zeroes).  On some
+ *      hardware you could probably optimize the shift in assembler by
+ *      using byte-swap instructions.
+ *      polynomial $edb88320
+ *
+ */
+
+#include "crc32.h"
+
+static const UINT32 crc32_tab[] = {
+        0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
+        0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
+        0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
+        0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
+        0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
+        0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
+        0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
+        0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
+        0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
+        0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
+        0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
+        0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
+        0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
+        0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
+        0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
+        0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
+        0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
+        0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
+        0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
+        0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
+        0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
+        0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
+        0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
+        0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
+        0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
+        0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
+        0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
+        0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
+        0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
+        0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
+        0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
+        0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
+        0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
+        0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
+        0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
+        0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
+        0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
+        0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
+        0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
+        0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
+        0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
+        0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
+        0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
+        0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
+        0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
+        0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
+        0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
+        0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
+        0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
+        0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
+        0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
+        0x2d02ef8dL
+};
+
+static inline UINT32 crc32_add_char(UINT32 crc, UINT8 c) {
+        return crc32_tab[(crc ^ c) & 0xff] ^ (crc >> 8);
+}
+
+/*
+ * This a generic crc32() function, it takes seed as an argument,
+ * and does __not__ xor at the end. Then individual users can do
+ * whatever they need.
+ */
+UINT32 crc32(UINT32 seed, const VOID *buf, UINTN len) {
+        const UINT8 *p = buf;
+        UINT32 crc = seed;
+
+        while (len > 0) {
+                crc = crc32_add_char(crc, *p++);
+                len--;
+        }
+
+        return crc;
+}
+
+UINT32 crc32_exclude_offset(
+                UINT32 seed,
+                const VOID *buf,
+                UINTN len,
+                UINTN exclude_off,
+                UINTN exclude_len) {
+
+        const UINT8 *p = buf;
+        UINT32 crc = seed;
+        UINTN i;
+
+        for (i = 0; i < len; i++) {
+                UINT8 x = *p++;
+
+                if (i >= exclude_off && i < exclude_off + exclude_len)
+                        x = 0;
+
+                crc = crc32_add_char(crc, x);
+        }
+
+        return crc;
+}
diff --git a/src/boot/efi/crc32.h b/src/boot/efi/crc32.h
new file mode 100644 (file)
index 0000000..64150ee
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <efi.h>
+#include <efilib.h>
+
+UINT32 crc32(UINT32 seed, const VOID *buf, UINTN len);
+UINT32 crc32_exclude_offset(UINT32 seed, const VOID *buf, UINTN len, UINTN exclude_off, UINTN exclude_len);
index 5b4c085..ad26cc5 100644 (file)
 #include "linux.h"
 #include "util.h"
 
-#define SETUP_MAGIC             0x53726448      /* "HdrS" */
-struct SetupHeader {
-        UINT8 boot_sector[0x01f1];
-        UINT8 setup_secs;
-        UINT16 root_flags;
-        UINT32 sys_size;
-        UINT16 ram_size;
-        UINT16 video_mode;
-        UINT16 root_dev;
-        UINT16 signature;
-        UINT16 jump;
-        UINT32 header;
-        UINT16 version;
-        UINT16 su_switch;
-        UINT16 setup_seg;
-        UINT16 start_sys;
-        UINT16 kernel_ver;
-        UINT8 loader_id;
-        UINT8 load_flags;
-        UINT16 movesize;
-        UINT32 code32_start;
-        UINT32 ramdisk_start;
-        UINT32 ramdisk_len;
-        UINT32 bootsect_kludge;
-        UINT16 heap_end;
-        UINT8 ext_loader_ver;
-        UINT8 ext_loader_type;
-        UINT32 cmd_line_ptr;
-        UINT32 ramdisk_max;
-        UINT32 kernel_alignment;
-        UINT8 relocatable_kernel;
-        UINT8 min_alignment;
-        UINT16 xloadflags;
-        UINT32 cmdline_size;
-        UINT32 hardware_subarch;
-        UINT64 hardware_subarch_data;
-        UINT32 payload_offset;
-        UINT32 payload_length;
-        UINT64 setup_data;
-        UINT64 pref_address;
-        UINT32 init_size;
-        UINT32 handover_offset;
-} __attribute__((packed));
-
 #ifdef __x86_64__
-typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup);
-static VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) {
+typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params);
+static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
         handover_f handover;
 
         asm volatile ("cli");
-        handover = (handover_f)((UINTN)setup->code32_start + 512 + setup->handover_offset);
-        handover(image, ST, setup);
+        handover = (handover_f)((UINTN)params->hdr.code32_start + 512 + params->hdr.handover_offset);
+        handover(image, ST, params);
 }
 #else
-typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup) __attribute__((regparm(0)));
-static VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) {
+typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct boot_params *params) __attribute__((regparm(0)));
+static VOID linux_efi_handover(EFI_HANDLE image, struct boot_params *params) {
         handover_f handover;
 
-        handover = (handover_f)((UINTN)setup->code32_start + setup->handover_offset);
-        handover(image, ST, setup);
+        handover = (handover_f)((UINTN)params->hdr.code32_start + params->hdr.handover_offset);
+        handover(image, ST, params);
 }
 #endif
 
 EFI_STATUS linux_exec(EFI_HANDLE *image,
                       CHAR8 *cmdline, UINTN cmdline_len,
                       UINTN linux_addr,
-                      UINTN initrd_addr, UINTN initrd_size, BOOLEAN secure) {
-        struct SetupHeader *image_setup;
-        struct SetupHeader *boot_setup;
+                      UINTN initrd_addr, UINTN initrd_size) {
+        struct boot_params *image_params;
+        struct boot_params *boot_params;
+        UINT8 setup_sectors;
         EFI_PHYSICAL_ADDRESS addr;
         EFI_STATUS err;
 
-        image_setup = (struct SetupHeader *)(linux_addr);
-        if (image_setup->signature != 0xAA55 || image_setup->header != SETUP_MAGIC)
-                return EFI_LOAD_ERROR;
+        image_params = (struct boot_params *) linux_addr;
 
-        if (image_setup->version < 0x20b || !image_setup->relocatable_kernel)
+        if (image_params->hdr.boot_flag != 0xAA55 ||
+            image_params->hdr.header != SETUP_MAGIC ||
+            image_params->hdr.version < 0x20b ||
+            !image_params->hdr.relocatable_kernel)
                 return EFI_LOAD_ERROR;
 
-        addr = 0x3fffffff;
+        boot_params = (struct boot_params *) 0xFFFFFFFF;
         err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData,
-                                EFI_SIZE_TO_PAGES(0x4000), &addr);
+                                EFI_SIZE_TO_PAGES(0x4000), (UINTN *) &boot_params);
         if (EFI_ERROR(err))
                 return err;
-        boot_setup = (struct SetupHeader *)(UINTN)addr;
-        ZeroMem(boot_setup, 0x4000);
-        CopyMem(boot_setup, image_setup, sizeof(struct SetupHeader));
-        boot_setup->loader_id = 0xff;
-
-        if (secure) {
-                /* set secure boot flag in linux kernel zero page, see
-                   - Documentation/x86/zero-page.txt
-                   - arch/x86/include/uapi/asm/bootparam.h
-                   - drivers/firmware/efi/libstub/secureboot.c
-                   in the linux kernel source tree
-                   Possible values: 0 (unassigned), 1 (undetected), 2 (disabled), 3 (enabled)
-                */
-                boot_setup->boot_sector[0x1ec] = 3;
-        }
 
-        boot_setup->code32_start = (UINT32)linux_addr + (image_setup->setup_secs+1) * 512;
+        ZeroMem(boot_params, 0x4000);
+        CopyMem(&boot_params->hdr, &image_params->hdr, sizeof(struct setup_header));
+        boot_params->hdr.type_of_loader = 0xff;
+        setup_sectors = image_params->hdr.setup_sects > 0 ? image_params->hdr.setup_sects : 4;
+        boot_params->hdr.code32_start = (UINT32)linux_addr + (setup_sectors + 1) * 512;
 
         if (cmdline) {
                 addr = 0xA0000;
@@ -116,12 +63,12 @@ EFI_STATUS linux_exec(EFI_HANDLE *image,
                         return err;
                 CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len);
                 ((CHAR8 *)(UINTN)addr)[cmdline_len] = 0;
-                boot_setup->cmd_line_ptr = (UINT32)addr;
+                boot_params->hdr.cmd_line_ptr = (UINT32)addr;
         }
 
-        boot_setup->ramdisk_start = (UINT32)initrd_addr;
-        boot_setup->ramdisk_len = (UINT32)initrd_size;
+        boot_params->hdr.ramdisk_image = (UINT32)initrd_addr;
+        boot_params->hdr.ramdisk_size = (UINT32)initrd_size;
 
-        linux_efi_handover(image, boot_setup);
+        linux_efi_handover(image, boot_params);
         return EFI_LOAD_ERROR;
 }
index 2458a2f..ec655ce 100644 (file)
@@ -1,7 +1,87 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#define SETUP_MAGIC             0x53726448      /* "HdrS" */
+
+struct setup_header {
+        UINT8  setup_sects;
+        UINT16 root_flags;
+        UINT32 syssize;
+        UINT16 ram_size;
+        UINT16 vid_mode;
+        UINT16 root_dev;
+        UINT16 boot_flag;
+        UINT16 jump;
+        UINT32 header;
+        UINT16 version;
+        UINT32 realmode_swtch;
+        UINT16 start_sys_seg;
+        UINT16 kernel_version;
+        UINT8  type_of_loader;
+        UINT8  loadflags;
+        UINT16 setup_move_size;
+        UINT32 code32_start;
+        UINT32 ramdisk_image;
+        UINT32 ramdisk_size;
+        UINT32 bootsect_kludge;
+        UINT16 heap_end_ptr;
+        UINT8  ext_loader_ver;
+        UINT8  ext_loader_type;
+        UINT32 cmd_line_ptr;
+        UINT32 initrd_addr_max;
+        UINT32 kernel_alignment;
+        UINT8  relocatable_kernel;
+        UINT8  min_alignment;
+        UINT16 xloadflags;
+        UINT32 cmdline_size;
+        UINT32 hardware_subarch;
+        UINT64 hardware_subarch_data;
+        UINT32 payload_offset;
+        UINT32 payload_length;
+        UINT64 setup_data;
+        UINT64 pref_address;
+        UINT32 init_size;
+        UINT32 handover_offset;
+} __attribute__((packed));
+
+/* adapted from linux' bootparam.h */
+struct boot_params {
+        UINT8  screen_info[64];         // was: struct screen_info
+        UINT8  apm_bios_info[20];       // was: struct apm_bios_info
+        UINT8  _pad2[4];
+        UINT64 tboot_addr;
+        UINT8  ist_info[16];            // was: struct ist_info
+        UINT8  _pad3[16];
+        UINT8  hd0_info[16];
+        UINT8  hd1_info[16];
+        UINT8  sys_desc_table[16];      // was: struct sys_desc_table
+        UINT8  olpc_ofw_header[16];     // was: struct olpc_ofw_header
+        UINT32 ext_ramdisk_image;
+        UINT32 ext_ramdisk_size;
+        UINT32 ext_cmd_line_ptr;
+        UINT8  _pad4[116];
+        UINT8  edid_info[128];          // was: struct edid_info
+        UINT8  efi_info[32];            // was: struct efi_info
+        UINT32 alt_mem_k;
+        UINT32 scratch;
+        UINT8  e820_entries;
+        UINT8  eddbuf_entries;
+        UINT8  edd_mbr_sig_buf_entries;
+        UINT8  kbd_status;
+        UINT8  secure_boot;
+        UINT8  _pad5[2];
+        UINT8  sentinel;
+        UINT8  _pad6[1];
+        struct setup_header hdr;
+        UINT8  _pad7[0x290-0x1f1-sizeof(struct setup_header)];
+        UINT32 edd_mbr_sig_buffer[16];  // was: edd_mbr_sig_buffer[EDD_MBR_SIG_MAX]
+        UINT8  e820_table[20*128];      // was: struct boot_e820_entry e820_table[E820_MAX_ENTRIES_ZEROPAGE]
+        UINT8  _pad8[48];
+        UINT8  eddbuf[6*82];            // was: struct edd_info eddbuf[EDDMAXNR]
+        UINT8  _pad9[276];
+} __attribute__((packed));
+
 EFI_STATUS linux_exec(EFI_HANDLE *image,
                       CHAR8 *cmdline, UINTN cmdline_size,
                       UINTN linux_addr,
-                      UINTN initrd_addr, UINTN initrd_size, BOOLEAN secure);
+                      UINTN initrd_addr, UINTN initrd_size);
index 576918c..93869a5 100644 (file)
@@ -2,14 +2,15 @@
 
 efi_headers = files('''
         console.h
+        crc32.h
         disk.h
         graphics.h
         linux.h
         measure.h
         pe.h
+        shim.h
         splash.h
         util.h
-        shim.h
 '''.split())
 
 common_sources = '''
@@ -24,6 +25,7 @@ systemd_boot_sources = '''
         boot.c
         console.c
         shim.c
+        crc32.c
 '''.split()
 
 stub_sources = '''
index 6b07879..26c204f 100644 (file)
@@ -87,12 +87,13 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
 #endif
         }
 
-        /* export the device path this image is started from */
-        if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
-                efivar_set(L"LoaderDevicePartUUID", uuid, FALSE);
+        /* Export the device path this image is started from, if it's not set yet */
+        if (efivar_get_raw(&loader_guid, L"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS)
+                if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS)
+                        efivar_set(L"LoaderDevicePartUUID", uuid, FALSE);
 
         /* if LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from UEFI */
-        if (efivar_get_raw(&global_guid, L"LoaderImageIdentifier", &b, &size) != EFI_SUCCESS) {
+        if (efivar_get_raw(&loader_guid, L"LoaderImageIdentifier", NULL, NULL) != EFI_SUCCESS) {
                 _cleanup_freepool_ CHAR16 *s;
 
                 s = DevicePathToStr(loaded_image->FilePath);
@@ -100,7 +101,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         }
 
         /* if LoaderFirmwareInfo is not set, let's set it */
-        if (efivar_get_raw(&global_guid, L"LoaderFirmwareInfo", &b, &size) != EFI_SUCCESS) {
+        if (efivar_get_raw(&loader_guid, L"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) {
                 _cleanup_freepool_ CHAR16 *s;
 
                 s = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff);
@@ -108,7 +109,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         }
 
         /* ditto for LoaderFirmwareType */
-        if (efivar_get_raw(&global_guid, L"LoaderFirmwareType", &b, &size) != EFI_SUCCESS) {
+        if (efivar_get_raw(&loader_guid, L"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) {
                 _cleanup_freepool_ CHAR16 *s;
 
                 s = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff);
@@ -116,7 +117,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
         }
 
         /* add StubInfo */
-        if (efivar_get_raw(&global_guid, L"StubInfo", &b, &size) != EFI_SUCCESS)
+        if (efivar_get_raw(&loader_guid, L"StubInfo", NULL, NULL) != EFI_SUCCESS)
                 efivar_set(L"StubInfo", L"systemd-stub " GIT_VERSION, FALSE);
 
         if (szs[3] > 0)
@@ -124,7 +125,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
 
         err = linux_exec(image, cmdline, cmdline_len,
                          (UINTN)loaded_image->ImageBase + addrs[1],
-                         (UINTN)loaded_image->ImageBase + addrs[2], szs[2], secure);
+                         (UINTN)loaded_image->ImageBase + addrs[2], szs[2]);
 
         graphics_mode(FALSE);
         Print(L"Execution of embedded linux image failed: %r\n", err);
index f1f1674..4134e22 100644 (file)
@@ -117,10 +117,12 @@ EFI_STATUS efivar_get(const CHAR16 *name, CHAR16 **value) {
         if ((size % 2) != 0)
                 return EFI_INVALID_PARAMETER;
 
+        if (!value)
+                return EFI_SUCCESS;
+
         /* Return buffer directly if it happens to be NUL terminated already */
         if (size >= 2 && buf[size-2] == 0 && buf[size-1] == 0) {
-                *value = (CHAR16*) buf;
-                buf = NULL;
+                *value = (CHAR16*) TAKE_PTR(buf);
                 return EFI_SUCCESS;
         }
 
@@ -141,7 +143,7 @@ EFI_STATUS efivar_get_int(const CHAR16 *name, UINTN *i) {
         EFI_STATUS err;
 
         err = efivar_get(name, &val);
-        if (!EFI_ERROR(err))
+        if (!EFI_ERROR(err) && i)
                 *i = Atoi(val);
 
         return err;
@@ -159,8 +161,10 @@ EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **bu
 
         err = uefi_call_wrapper(RT->GetVariable, 5, (CHAR16*) name, (EFI_GUID *)vendor, NULL, &l, buf);
         if (!EFI_ERROR(err)) {
-                *buffer = buf;
-                buf = NULL;
+
+                if (buffer)
+                        *buffer = TAKE_PTR(buf);
+
                 if (size)
                         *size = l;
         }
index 4ba7050..cef127f 100644 (file)
@@ -7,6 +7,10 @@
 #define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
 #define OFFSETOF(x,y) __builtin_offsetof(x,y)
 
+static inline UINTN ALIGN_TO(UINTN l, UINTN ali) {
+        return ((l + ali - 1) & ~(ali - 1));
+}
+
 static inline const CHAR16 *yes_no(BOOLEAN b) {
         return b ? L"yes" : L"no";
 }
@@ -55,3 +59,10 @@ const EFI_GUID loader_guid;
 
 #define UINTN_MAX (~(UINTN)0)
 #define INTN_MAX ((INTN)(UINTN_MAX>>1))
+
+#define TAKE_PTR(ptr)                           \
+        ({                                      \
+                typeof(ptr) _ptr_ = (ptr);      \
+                (ptr) = NULL;                   \
+                _ptr_;                          \
+        })
index 1ac4649..8e2b33e 100644 (file)
@@ -1,12 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <getopt.h>
+#include <signal.h>
 #include <stdio_ext.h>
 
-#include <hashmap.h>
-
-#include "sd-bus.h"
-
 #include "alloc-util.h"
 #include "bus-dump.h"
 #include "bus-internal.h"
@@ -18,6 +15,7 @@
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "hashmap.h"
 #include "json.h"
 #include "locale-util.h"
 #include "log.h"
 #include "path-util.h"
 #include "pretty-print.h"
 #include "set.h"
+#include "sd-bus.h"
+#include "sort-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "user-util.h"
 #include "util.h"
-#include "signal.h"
 #include "verbs.h"
 
 static enum {
@@ -60,6 +59,7 @@ static bool arg_allow_interactive_authorization = true;
 static bool arg_augment_creds = true;
 static bool arg_watch_bind = false;
 static usec_t arg_timeout = 0;
+static const char *arg_destination = NULL;
 static int arg_sender_pid = 0;
 static int arg_receiver_pid = 0;
 static bool arg_pid = false;
@@ -804,10 +804,8 @@ static int on_interface(const char *interface, uint64_t flags, void *userdata) {
                 return log_oom();
 
         r = set_put(members, m);
-        if (r <= 0) {
-                log_error("Duplicate interface");
-                return -EINVAL;
-        }
+        if (r <= 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate interface");
 
         m = NULL;
         return 0;
@@ -845,10 +843,8 @@ static int on_method(const char *interface, const char *name, const char *signat
                 return log_oom();
 
         r = set_put(members, m);
-        if (r <= 0) {
-                log_error("Duplicate method");
-                return -EINVAL;
-        }
+        if (r <= 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate method");
 
         m = NULL;
         return 0;
@@ -882,10 +878,8 @@ static int on_signal(const char *interface, const char *name, const char *signat
                 return log_oom();
 
         r = set_put(members, m);
-        if (r <= 0) {
-                log_error("Duplicate signal");
-                return -EINVAL;
-        }
+        if (r <= 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate signal");
 
         m = NULL;
         return 0;
@@ -920,10 +914,8 @@ static int on_property(const char *interface, const char *name, const char *sign
                 return log_oom();
 
         r = set_put(members, m);
-        if (r <= 0) {
-                log_error("Duplicate property");
-                return -EINVAL;
-        }
+        if (r <= 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Duplicate property");
 
         m = NULL;
         return 0;
@@ -1200,10 +1192,9 @@ static int prepare_connection(sd_bus *bus, char *argv[])
 
         STRV_FOREACH(i, argv+1) {
                 _cleanup_free_ char *m = NULL;
-                if (!service_name_is_valid(*i)) {
-                        log_error("Invalid service name '%s'", *i);
-                        return -EINVAL;
-                }
+
+                if (!service_name_is_valid(*i))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid service name '%s'", *i);
 
                 m = strjoin("sender='", *i, "'");
                 if (!m)
@@ -2159,10 +2150,8 @@ static int call(int argc, char **argv, void *userdata) {
                 if (r < 0)
                         return r;
 
-                if (*p) {
-                        log_error("Too many parameters for signature.");
-                        return -EINVAL;
-                }
+                if (*p)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
         }
 
         if (!arg_expect_reply) {
@@ -2217,6 +2206,49 @@ static int call(int argc, char **argv, void *userdata) {
         return 0;
 }
 
+static int emit_signal(int argc, char **argv, void *userdata) {
+        _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
+        int r;
+
+        r = acquire_bus(false, &bus);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_new_signal(bus, &m, argv[1], argv[2], argv[3]);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        if (arg_destination) {
+                r = sd_bus_message_set_destination(m, arg_destination);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        r = sd_bus_message_set_auto_start(m, arg_auto_start);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        if (!isempty(argv[4])) {
+                char **p;
+
+                p = argv+5;
+
+                r = message_append_cmdline(m, argv[4], &p);
+                if (r < 0)
+                        return r;
+
+                if (*p)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
+        }
+
+        r = sd_bus_send(bus, m, NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to send signal: %m");
+
+        return 0;
+}
+
 static int get_property(int argc, char **argv, void *userdata) {
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
@@ -2313,10 +2345,8 @@ static int set_property(int argc, char **argv, void *userdata) {
         if (r < 0)
                 return bus_log_create_error(r);
 
-        if (*p) {
-                log_error("Too many parameters for signature.");
-                return -EINVAL;
-        }
+        if (*p)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Too many parameters for signature.");
 
         r = sd_bus_call(bus, m, arg_timeout, &error, NULL);
         if (r < 0)
@@ -2335,34 +2365,35 @@ static int help(void) {
 
         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
                "Introspect the bus.\n\n"
-               "  -h --help               Show this help\n"
-               "     --version            Show package version\n"
-               "     --no-pager           Do not pipe output into a pager\n"
-               "     --no-legend          Do not show the headers and footers\n"
-               "     --system             Connect to system bus\n"
-               "     --user               Connect to user bus\n"
-               "  -H --host=[USER@]HOST   Operate on remote host\n"
-               "  -M --machine=CONTAINER  Operate on local container\n"
-               "     --address=ADDRESS    Connect to bus specified by address\n"
-               "     --show-machine       Show machine ID column in list\n"
-               "     --unique             Only show unique names\n"
-               "     --acquired           Only show acquired names\n"
-               "     --activatable        Only show activatable names\n"
-               "     --match=MATCH        Only show matching messages\n"
-               "     --size=SIZE          Maximum length of captured packet\n"
-               "     --list               Don't show tree, but simple object path list\n"
-               "  -q --quiet              Don't show method call reply\n"
-               "     --verbose            Show result values in long format\n"
-               "     --json=MODE          Output as JSON\n"
-               "  -j                      Same as --json=pretty on tty, --json=short otherwise\n"
-               "     --expect-reply=BOOL  Expect a method call reply\n"
-               "     --auto-start=BOOL    Auto-start destination service\n"
+               "  -h --help                Show this help\n"
+               "     --version             Show package version\n"
+               "     --no-pager            Do not pipe output into a pager\n"
+               "     --no-legend           Do not show the headers and footers\n"
+               "     --system              Connect to system bus\n"
+               "     --user                Connect to user bus\n"
+               "  -H --host=[USER@]HOST    Operate on remote host\n"
+               "  -M --machine=CONTAINER   Operate on local container\n"
+               "     --address=ADDRESS     Connect to bus specified by address\n"
+               "     --show-machine        Show machine ID column in list\n"
+               "     --unique              Only show unique names\n"
+               "     --acquired            Only show acquired names\n"
+               "     --activatable         Only show activatable names\n"
+               "     --match=MATCH         Only show matching messages\n"
+               "     --size=SIZE           Maximum length of captured packet\n"
+               "     --list                Don't show tree, but simple object path list\n"
+               "  -q --quiet               Don't show method call reply\n"
+               "     --verbose             Show result values in long format\n"
+               "     --json=MODE           Output as JSON\n"
+               "  -j                       Same as --json=pretty on tty, --json=short otherwise\n"
+               "     --expect-reply=BOOL   Expect a method call reply\n"
+               "     --auto-start=BOOL     Auto-start destination service\n"
                "     --allow-interactive-authorization=BOOL\n"
-               "                          Allow interactive authorization for operation\n"
-               "     --timeout=SECS       Maximum time to wait for method call completion\n"
-               "     --augment-creds=BOOL Extend credential data with data read from /proc/$PID\n"
-               "     --watch-bind=BOOL    Wait for bus AF_UNIX socket to be bound in the file\n"
-               "                          system\n\n"
+               "                           Allow interactive authorization for operation\n"
+               "     --timeout=SECS        Maximum time to wait for method call completion\n"
+               "     --augment-creds=BOOL  Extend credential data with data read from /proc/$PID\n"
+               "     --watch-bind=BOOL     Wait for bus AF_UNIX socket to be bound in the file\n"
+               "                           system\n"
+               "     --destination=SERVICE Destination service of a signal\n"
                "\n"
                "     --pid=PID            Only show messages with pid equals PID\n"
                "     --sender-pid=SENDER_PID\n"
@@ -2371,21 +2402,23 @@ static int help(void) {
                "                          Only show message with receiver pid equals RECEIVER_PID\n"
                "     --well-known-names=BOOL \n"
                "                          Show well know names connected to unique names on graph\n"
-               "Commands:\n"
-               "  list                    List bus names\n"
-               "  status [SERVICE]        Show bus service, process or bus owner credentials\n"
-               "  monitor [SERVICE...]    Show bus traffic\n"
+               "\nCommands:\n"
+               "  list                     List bus names\n"
+               "  status [SERVICE]         Show bus service, process or bus owner credentials\n"
+               "  monitor [SERVICE...]     Show bus traffic\n"
                "  dot [SERVICE...]        Generate bus traffic graph\n"
-               "  capture [SERVICE...]    Capture bus traffic as pcap\n"
-               "  tree [SERVICE...]       Show object tree of service\n"
+               "  capture [SERVICE...]     Capture bus traffic as pcap\n"
+               "  tree [SERVICE...]        Show object tree of service\n"
                "  introspect SERVICE OBJECT [INTERFACE]\n"
                "  call SERVICE OBJECT INTERFACE METHOD [SIGNATURE [ARGUMENT...]]\n"
-               "                          Call a method\n"
+               "                           Call a method\n"
+               "  emit OBJECT INTERFACE SIGNAL [SIGNATURE [ARGUMENT...]]\n"
+               "                           Emit a signal\n"
                "  get-property SERVICE OBJECT INTERFACE PROPERTY...\n"
-               "                          Get property value\n"
+               "                           Get property value\n"
                "  set-property SERVICE OBJECT INTERFACE PROPERTY SIGNATURE ARGUMENT...\n"
-               "                          Set property value\n"
-               "  help                    Show this help\n"
+               "                           Set property value\n"
+               "  help                     Show this help\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
                , link
@@ -2443,6 +2476,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_AUGMENT_CREDS,
                 ARG_WATCH_BIND,
                 ARG_JSON,
+                ARG_DESTINATION,
                 ARG_PID,
                 ARG_SENDER_PID,
                 ARG_RECEIVER_PID,
@@ -2475,6 +2509,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "augment-creds",                   required_argument, NULL, ARG_AUGMENT_CREDS                   },
                 { "watch-bind",                      required_argument, NULL, ARG_WATCH_BIND                      },
                 { "json",                            required_argument, NULL, ARG_JSON                            },
+                { "destination",                     required_argument, NULL, ARG_DESTINATION                     },
                 { "pid",                             required_argument, NULL, ARG_PID},
                 { "sender-pid",                      required_argument, NULL, ARG_SENDER_PID},
                 { "receiver-pid",                    required_argument, NULL, ARG_RECEIVER_PID},
@@ -2667,6 +2702,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_well_known_names = parse_boolean(optarg);
                         break;
 
+                case ARG_DESTINATION:
+                        arg_destination = optarg;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -2688,6 +2727,7 @@ static int busctl_main(int argc, char *argv[]) {
                 { "tree",         VERB_ANY, VERB_ANY, 0,            tree           },
                 { "introspect",   3,        4,        0,            introspect     },
                 { "call",         5,        VERB_ANY, 0,            call           },
+                { "emit",         4,        VERB_ANY, 0,            emit_signal    },
                 { "get-property", 5,        VERB_ANY, 0,            get_property   },
                 { "set-property", 6,        VERB_ANY, 0,            set_property   },
                 { "help",         VERB_ANY, VERB_ANY, 0,            verb_help      },
index b6b15cf..09ee0e8 100644 (file)
@@ -53,8 +53,8 @@ static int help(void) {
                "     --version        Show package version\n"
                "     --no-pager       Do not pipe output into a pager\n"
                "  -a --all            Show all groups, including empty\n"
-               "  -u --unit           Show the subtrees of specifified system units\n"
-               "     --user-unit      Show the subtrees of specifified user units\n"
+               "  -u --unit           Show the subtrees of specified system units\n"
+               "     --user-unit      Show the subtrees of specified user units\n"
                "  -l --full           Do not ellipsize output\n"
                "  -k                  Include kernel threads in output\n"
                "  -M --machine=       Show container\n"
index b3bda30..f27c801 100644 (file)
 #include "pretty-print.h"
 #include "process-util.h"
 #include "procfs-util.h"
+#include "sort-util.h"
 #include "stdio-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "unit-name.h"
-#include "util.h"
 #include "virt.h"
 
 typedef struct Group {
@@ -223,71 +223,6 @@ static int process(
                 if (g->n_tasks > 0)
                         g->n_tasks_valid = true;
 
-        } else if (STR_IN_SET(controller, "cpu", "cpuacct") || cpu_accounting_is_cheap()) {
-                _cleanup_free_ char *p = NULL, *v = NULL;
-                uint64_t new_usage;
-                nsec_t timestamp;
-
-                if (is_root_cgroup(path)) {
-                        r = procfs_cpu_get_usage(&new_usage);
-                        if (r < 0)
-                                return r;
-                } else if (all_unified) {
-                        _cleanup_free_ char *val = NULL;
-
-                        if (!streq(controller, "cpu"))
-                                return 0;
-
-                        r = cg_get_keyed_attribute("cpu", path, "cpu.stat", STRV_MAKE("usage_usec"), &val);
-                        if (IN_SET(r, -ENOENT, -ENXIO))
-                                return 0;
-                        if (r < 0)
-                                return r;
-
-                        r = safe_atou64(val, &new_usage);
-                        if (r < 0)
-                                return r;
-
-                        new_usage *= NSEC_PER_USEC;
-                } else {
-                        if (!streq(controller, "cpuacct"))
-                                return 0;
-
-                        r = cg_get_path(controller, path, "cpuacct.usage", &p);
-                        if (r < 0)
-                                return r;
-
-                        r = read_one_line_file(p, &v);
-                        if (r == -ENOENT)
-                                return 0;
-                        if (r < 0)
-                                return r;
-
-                        r = safe_atou64(v, &new_usage);
-                        if (r < 0)
-                                return r;
-                }
-
-                timestamp = now_nsec(CLOCK_MONOTONIC);
-
-                if (g->cpu_iteration == iteration - 1 &&
-                    (nsec_t) new_usage > g->cpu_usage) {
-
-                        nsec_t x, y;
-
-                        x = timestamp - g->cpu_timestamp;
-                        if (x < 1)
-                                x = 1;
-
-                        y = (nsec_t) new_usage - g->cpu_usage;
-                        g->cpu_fraction = (double) y / (double) x;
-                        g->cpu_valid = true;
-                }
-
-                g->cpu_usage = (nsec_t) new_usage;
-                g->cpu_timestamp = timestamp;
-                g->cpu_iteration = iteration;
-
         } else if (streq(controller, "memory")) {
 
                 if (is_root_cgroup(path)) {
@@ -411,6 +346,71 @@ static int process(
                 g->io_output = wr;
                 g->io_timestamp = timestamp;
                 g->io_iteration = iteration;
+        } else if (STR_IN_SET(controller, "cpu", "cpuacct") || cpu_accounting_is_cheap()) {
+                _cleanup_free_ char *p = NULL, *v = NULL;
+                uint64_t new_usage;
+                nsec_t timestamp;
+
+                if (is_root_cgroup(path)) {
+                        r = procfs_cpu_get_usage(&new_usage);
+                        if (r < 0)
+                                return r;
+                } else if (all_unified) {
+                        _cleanup_free_ char *val = NULL;
+
+                        if (!streq(controller, "cpu"))
+                                return 0;
+
+                        r = cg_get_keyed_attribute("cpu", path, "cpu.stat", STRV_MAKE("usage_usec"), &val);
+                        if (IN_SET(r, -ENOENT, -ENXIO))
+                                return 0;
+                        if (r < 0)
+                                return r;
+
+                        r = safe_atou64(val, &new_usage);
+                        if (r < 0)
+                                return r;
+
+                        new_usage *= NSEC_PER_USEC;
+                } else {
+                        if (!streq(controller, "cpuacct"))
+                                return 0;
+
+                        r = cg_get_path(controller, path, "cpuacct.usage", &p);
+                        if (r < 0)
+                                return r;
+
+                        r = read_one_line_file(p, &v);
+                        if (r == -ENOENT)
+                                return 0;
+                        if (r < 0)
+                                return r;
+
+                        r = safe_atou64(v, &new_usage);
+                        if (r < 0)
+                                return r;
+                }
+
+                timestamp = now_nsec(CLOCK_MONOTONIC);
+
+                if (g->cpu_iteration == iteration - 1 &&
+                    (nsec_t) new_usage > g->cpu_usage) {
+
+                        nsec_t x, y;
+
+                        x = timestamp - g->cpu_timestamp;
+                        if (x < 1)
+                                x = 1;
+
+                        y = (nsec_t) new_usage - g->cpu_usage;
+                        g->cpu_fraction = (double) y / (double) x;
+                        g->cpu_valid = true;
+                }
+
+                g->cpu_usage = (nsec_t) new_usage;
+                g->cpu_timestamp = timestamp;
+                g->cpu_iteration = iteration;
+
         }
 
         if (ret)
@@ -922,10 +922,9 @@ static int run(int argc, char *argv[]) {
 
         arg_count = (mask & CGROUP_MASK_PIDS) ? COUNT_PIDS : COUNT_USERSPACE_PROCESSES;
 
-        if (arg_recursive_unset && arg_count == COUNT_PIDS) {
-                log_error("Non-recursive counting is only supported when counting processes, not tasks. Use -P or -k.");
-                return -EINVAL;
-        }
+        if (arg_recursive_unset && arg_count == COUNT_PIDS)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Non-recursive counting is only supported when counting processes, not tasks. Use -P or -k.");
 
         r = show_cgroup_get_path_and_warn(arg_machine, arg_root, &root);
         if (r < 0)
index 6a83739..bcdd7e1 100644 (file)
@@ -759,7 +759,7 @@ static void automount_enter_running(Automount *a) {
                 return;
         }
 
-        mkdir_p_label(a->where, a->directory_mode);
+        (void) mkdir_p_label(a->where, a->directory_mode);
 
         /* Before we do anything, let's see if somebody is playing games with us? */
         if (lstat(a->where, &st) < 0) {
@@ -781,7 +781,7 @@ static void automount_enter_running(Automount *a) {
                 goto fail;
         }
 
-        r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
+        r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
         if (r < 0) {
                 log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
                 goto fail;
@@ -796,7 +796,6 @@ fail:
 
 static int automount_start(Unit *u) {
         Automount *a = AUTOMOUNT(u);
-        Unit *trigger;
         int r;
 
         assert(a);
@@ -807,13 +806,11 @@ static int automount_start(Unit *u) {
                 return -EEXIST;
         }
 
-        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;
-        }
+        r = unit_test_trigger_loaded(u);
+        if (r < 0)
+                return r;
 
-        r = unit_start_limit_test(u);
+        r = unit_test_start_limit(u);
         if (r < 0) {
                 automount_enter_dead(a, AUTOMOUNT_FAILURE_START_LIMIT_HIT);
                 return r;
@@ -1038,7 +1035,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
                         goto fail;
                 }
 
-                r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, &error, NULL);
+                r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, NULL, &error, NULL);
                 if (r < 0) {
                         log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
                         goto fail;
index 18f5533..723c7b4 100644 (file)
@@ -20,6 +20,7 @@
 #include "bpf-program.h"
 #include "fd-util.h"
 #include "ip-address-access.h"
+#include "memory-util.h"
 #include "missing_syscall.h"
 #include "unit.h"
 
index 0092161..e14b3ab 100644 (file)
@@ -30,6 +30,7 @@
 #include "dbus-busname.h"
 #include "fd-util.h"
 #include "format-util.h"
+#include "memory-util.h"
 #include "parse-util.h"
 #include "process-util.h"
 #include "service.h"
@@ -366,7 +367,7 @@ static int busname_coldplug(Unit *u) {
             pid_is_unwaited(n->control_pid) &&
             IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
 
-                r = unit_watch_pid(UNIT(n), n->control_pid);
+                r = unit_watch_pid(UNIT(n), n->control_pid, false);
                 if (r < 0)
                         return r;
 
@@ -429,7 +430,7 @@ static int busname_make_starter(BusName *n, pid_t *_pid) {
                 _exit(ret);
         }
 
-        r = unit_watch_pid(UNIT(n), pid);
+        r = unit_watch_pid(UNIT(n), pid, true);
         if (r < 0)
                 goto fail;
 
@@ -595,7 +596,7 @@ static void busname_enter_running(BusName *n) {
                         goto fail;
                 }
 
-                r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, &error, NULL);
+                r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, NULL, &error, NULL);
                 if (r < 0)
                         goto fail;
         }
@@ -636,7 +637,7 @@ static int busname_start(Unit *u) {
 
         assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
 
-        r = unit_start_limit_test(u);
+        r = unit_test_start_limit(u);
         if (r < 0) {
                 busname_enter_dead(n, BUSNAME_FAILURE_START_LIMIT_HIT);
                 return r;
index 9c51edb..43aadd5 100644 (file)
@@ -5,15 +5,16 @@
 
 #include "alloc-util.h"
 #include "blockdev-util.h"
+#include "bpf-devices.h"
 #include "bpf-firewall.h"
 #include "btrfs-util.h"
-#include "bpf-devices.h"
 #include "bus-error.h"
 #include "cgroup-util.h"
 #include "cgroup.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -27,7 +28,7 @@
 #include "smack-util.h"
 #include "virt.h"
 
-#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
+#define CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
 
 /* Returns the log level to use when cgroup attribute writes fail. When an attribute is missing or we have access
  * problems we downgrade to LOG_DEBUG. This is supposed to be nice to container managers and kernels which want to mask
@@ -100,6 +101,7 @@ void cgroup_context_init(CGroupContext *c) {
                 .cpu_weight = CGROUP_WEIGHT_INVALID,
                 .startup_cpu_weight = CGROUP_WEIGHT_INVALID,
                 .cpu_quota_per_sec_usec = USEC_INFINITY,
+                .cpu_quota_period_usec = USEC_INFINITY,
 
                 .cpu_shares = CGROUP_CPU_SHARES_INVALID,
                 .startup_cpu_shares = CGROUP_CPU_SHARES_INVALID,
@@ -208,6 +210,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
         CGroupDeviceAllow *a;
         IPAddressAccessItem *iaai;
         char u[FORMAT_TIMESPAN_MAX];
+        char v[FORMAT_TIMESPAN_MAX];
 
         assert(c);
         assert(f);
@@ -226,6 +229,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 "%sCPUShares=%" PRIu64 "\n"
                 "%sStartupCPUShares=%" PRIu64 "\n"
                 "%sCPUQuotaPerSecSec=%s\n"
+                "%sCPUQuotaPeriodSec=%s\n"
                 "%sIOWeight=%" PRIu64 "\n"
                 "%sStartupIOWeight=%" PRIu64 "\n"
                 "%sBlockIOWeight=%" PRIu64 "\n"
@@ -250,6 +254,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
                 prefix, c->cpu_shares,
                 prefix, c->startup_cpu_shares,
                 prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
+                prefix, format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1),
                 prefix, c->io_weight,
                 prefix, c->startup_io_weight,
                 prefix, c->blockio_weight,
@@ -658,6 +663,40 @@ static uint64_t cgroup_context_cpu_shares(CGroupContext *c, ManagerState state)
                 return CGROUP_CPU_SHARES_DEFAULT;
 }
 
+usec_t cgroup_cpu_adjust_period(usec_t period, usec_t quota, usec_t resolution, usec_t max_period) {
+        /* kernel uses a minimum resolution of 1ms, so both period and (quota * period)
+         * need to be higher than that boundary. quota is specified in USecPerSec.
+         * Additionally, period must be at most max_period. */
+        assert(quota > 0);
+
+        return MIN(MAX3(period, resolution, resolution * USEC_PER_SEC / quota), max_period);
+}
+
+static usec_t cgroup_cpu_adjust_period_and_log(Unit *u, usec_t period, usec_t quota) {
+        usec_t new_period;
+
+        if (quota == USEC_INFINITY)
+                /* Always use default period for infinity quota. */
+                return CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC;
+
+        if (period == USEC_INFINITY)
+                /* Default period was requested. */
+                period = CGROUP_CPU_QUOTA_DEFAULT_PERIOD_USEC;
+
+        /* Clamp to interval [1ms, 1s] */
+        new_period = cgroup_cpu_adjust_period(period, quota, USEC_PER_MSEC, USEC_PER_SEC);
+
+        if (new_period != period) {
+                char v[FORMAT_TIMESPAN_MAX];
+                log_unit_full(u, u->warned_clamping_cpu_quota_period ? LOG_DEBUG : LOG_WARNING, 0,
+                              "Clamping CPU interval for cpu.max: period is now %s",
+                              format_timespan(v, sizeof(v), new_period, 1));
+                u->warned_clamping_cpu_quota_period = true;
+        }
+
+        return new_period;
+}
+
 static void cgroup_apply_unified_cpu_weight(Unit *u, uint64_t weight) {
         char buf[DECIMAL_STR_MAX(uint64_t) + 2];
 
@@ -665,14 +704,15 @@ static void cgroup_apply_unified_cpu_weight(Unit *u, uint64_t weight) {
         (void) set_attribute_and_warn(u, "cpu", "cpu.weight", buf);
 }
 
-static void cgroup_apply_unified_cpu_quota(Unit *u, usec_t quota) {
+static void cgroup_apply_unified_cpu_quota(Unit *u, usec_t quota, usec_t period) {
         char buf[(DECIMAL_STR_MAX(usec_t) + 1) * 2 + 1];
 
+        period = cgroup_cpu_adjust_period_and_log(u, period, quota);
         if (quota != USEC_INFINITY)
                 xsprintf(buf, USEC_FMT " " USEC_FMT "\n",
-                         quota * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC, CGROUP_CPU_QUOTA_PERIOD_USEC);
+                         MAX(quota * period / USEC_PER_SEC, USEC_PER_MSEC), period);
         else
-                xsprintf(buf, "max " USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
+                xsprintf(buf, "max " USEC_FMT "\n", period);
         (void) set_attribute_and_warn(u, "cpu", "cpu.max", buf);
 }
 
@@ -683,14 +723,16 @@ static void cgroup_apply_legacy_cpu_shares(Unit *u, uint64_t shares) {
         (void) set_attribute_and_warn(u, "cpu", "cpu.shares", buf);
 }
 
-static void cgroup_apply_legacy_cpu_quota(Unit *u, usec_t quota) {
+static void cgroup_apply_legacy_cpu_quota(Unit *u, usec_t quota, usec_t period) {
         char buf[DECIMAL_STR_MAX(usec_t) + 2];
 
-        xsprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
+        period = cgroup_cpu_adjust_period_and_log(u, period, quota);
+
+        xsprintf(buf, USEC_FMT "\n", period);
         (void) set_attribute_and_warn(u, "cpu", "cpu.cfs_period_us", buf);
 
         if (quota != USEC_INFINITY) {
-                xsprintf(buf, USEC_FMT "\n", quota * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC);
+                xsprintf(buf, USEC_FMT "\n", MAX(quota * period / USEC_PER_SEC, USEC_PER_MSEC));
                 (void) set_attribute_and_warn(u, "cpu", "cpu.cfs_quota_us", buf);
         } else
                 (void) set_attribute_and_warn(u, "cpu", "cpu.cfs_quota_us", "-1\n");
@@ -913,7 +955,7 @@ static void cgroup_context_apply(
                                 weight = CGROUP_WEIGHT_DEFAULT;
 
                         cgroup_apply_unified_cpu_weight(u, weight);
-                        cgroup_apply_unified_cpu_quota(u, c->cpu_quota_per_sec_usec);
+                        cgroup_apply_unified_cpu_quota(u, c->cpu_quota_per_sec_usec, c->cpu_quota_period_usec);
 
                 } else {
                         uint64_t shares;
@@ -932,7 +974,7 @@ static void cgroup_context_apply(
                                 shares = CGROUP_CPU_SHARES_DEFAULT;
 
                         cgroup_apply_legacy_cpu_shares(u, shares);
-                        cgroup_apply_legacy_cpu_quota(u, c->cpu_quota_per_sec_usec);
+                        cgroup_apply_legacy_cpu_quota(u, c->cpu_quota_per_sec_usec, c->cpu_quota_period_usec);
                 }
         }
 
@@ -2231,7 +2273,7 @@ void unit_prune_cgroup(Unit *u) {
 
 int unit_search_main_pid(Unit *u, pid_t *ret) {
         _cleanup_fclose_ FILE *f = NULL;
-        pid_t pid = 0, npid, mypid;
+        pid_t pid = 0, npid;
         int r;
 
         assert(u);
@@ -2244,15 +2286,12 @@ int unit_search_main_pid(Unit *u, pid_t *ret) {
         if (r < 0)
                 return r;
 
-        mypid = getpid_cached();
         while (cg_read_pid(f, &npid) > 0)  {
-                pid_t ppid;
 
                 if (npid == pid)
                         continue;
 
-                /* Ignore processes that aren't our kids */
-                if (get_process_ppid(npid, &ppid) >= 0 && ppid != mypid)
+                if (pid_is_my_child(npid) == 0)
                         continue;
 
                 if (pid != 0)
@@ -2284,7 +2323,7 @@ static int unit_watch_pids_in_path(Unit *u, const char *path) {
                 pid_t pid;
 
                 while ((r = cg_read_pid(f, &pid)) > 0) {
-                        r = unit_watch_pid(u, pid);
+                        r = unit_watch_pid(u, pid, false);
                         if (r < 0 && ret >= 0)
                                 ret = r;
                 }
index 266daa2..51e7c96 100644 (file)
@@ -79,10 +79,15 @@ struct CGroupContext {
         bool tasks_accounting;
         bool ip_accounting;
 
+        bool delegate;
+        CGroupMask delegate_controllers;
+        CGroupMask disable_controllers;
+
         /* For unified hierarchy */
         uint64_t cpu_weight;
         uint64_t startup_cpu_weight;
         usec_t cpu_quota_per_sec_usec;
+        usec_t cpu_quota_period_usec;
 
         uint64_t io_weight;
         uint64_t startup_io_weight;
@@ -115,11 +120,6 @@ struct CGroupContext {
 
         /* Common */
         uint64_t tasks_max;
-
-        bool delegate;
-        CGroupMask delegate_controllers;
-
-        CGroupMask disable_controllers;
 };
 
 /* Used when querying IP accounting data */
@@ -135,6 +135,8 @@ typedef enum CGroupIPAccountingMetric {
 typedef struct Unit Unit;
 typedef struct Manager Manager;
 
+usec_t cgroup_cpu_adjust_period(usec_t period, usec_t quota, usec_t resolution, usec_t max_period);
+
 void cgroup_context_init(CGroupContext *c);
 void cgroup_context_done(CGroupContext *c);
 void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix);
index 7767301..49d96b7 100644 (file)
 #include "strv.h"
 #include "user-util.h"
 
-static int chown_one(int fd, const struct stat *st, uid_t uid, gid_t gid) {
+static int chown_one(
+                int fd,
+                const struct stat *st,
+                uid_t uid,
+                gid_t gid,
+                mode_t mask) {
+
         char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
         const char *n;
 
@@ -42,13 +48,19 @@ static int chown_one(int fd, const struct stat *st, uid_t uid, gid_t gid) {
          * because on some kernels/file systems trying to change the access mode will succeed but has no effect while
          * on others it actively fails. */
         if (!S_ISLNK(st->st_mode))
-                if (chmod(procfs_path, st->st_mode & 07777) < 0)
+                if (chmod(procfs_path, st->st_mode & 07777 & mask) < 0)
                         return -errno;
 
         return 1;
 }
 
-static int chown_recursive_internal(int fd, const struct stat *st, uid_t uid, gid_t gid) {
+static int chown_recursive_internal(
+                int fd,
+                const struct stat *st,
+                uid_t uid,
+                gid_t gid,
+                mode_t mask) {
+
         _cleanup_closedir_ DIR *d = NULL;
         bool changed = false;
         struct dirent *de;
@@ -87,13 +99,13 @@ static int chown_recursive_internal(int fd, const struct stat *st, uid_t uid, gi
                         if (subdir_fd < 0)
                                 return subdir_fd;
 
-                        r = chown_recursive_internal(subdir_fd, &fst, uid, gid); /* takes possession of subdir_fd even on failure */
+                        r = chown_recursive_internal(subdir_fd, &fst, uid, gid, mask); /* takes possession of subdir_fd even on failure */
                         if (r < 0)
                                 return r;
                         if (r > 0)
                                 changed = true;
                 } else {
-                        r = chown_one(path_fd, &fst, uid, gid);
+                        r = chown_one(path_fd, &fst, uid, gid, mask);
                         if (r < 0)
                                 return r;
                         if (r > 0)
@@ -101,14 +113,19 @@ static int chown_recursive_internal(int fd, const struct stat *st, uid_t uid, gi
                 }
         }
 
-        r = chown_one(dirfd(d), st, uid, gid);
+        r = chown_one(dirfd(d), st, uid, gid, mask);
         if (r < 0)
                 return r;
 
         return r > 0 || changed;
 }
 
-int path_chown_recursive(const char *path, uid_t uid, gid_t gid) {
+int path_chown_recursive(
+                const char *path,
+                uid_t uid,
+                gid_t gid,
+                mode_t mask) {
+
         _cleanup_close_ int fd = -1;
         struct stat st;
 
@@ -129,5 +146,5 @@ int path_chown_recursive(const char *path, uid_t uid, gid_t gid) {
             (!gid_is_valid(gid) || st.st_gid == gid))
                 return 0;
 
-        return chown_recursive_internal(TAKE_FD(fd), &st, uid, gid); /* we donate the fd to the call, regardless if it succeeded or failed */
+        return chown_recursive_internal(TAKE_FD(fd), &st, uid, gid, mask); /* we donate the fd to the call, regardless if it succeeded or failed */
 }
index f3fa40a..bfee05f 100644 (file)
@@ -3,4 +3,4 @@
 
 #include <sys/types.h>
 
-int path_chown_recursive(const char *path, uid_t uid, gid_t gid);
+int path_chown_recursive(const char *path, uid_t uid, gid_t gid, mode_t mask);
index 53890bc..4615aea 100644 (file)
@@ -13,6 +13,7 @@
 #include "dbus-util.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "limits-util.h"
 #include "path-util.h"
 
 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
@@ -330,6 +331,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
         SD_BUS_PROPERTY("CPUShares", "t", NULL, offsetof(CGroupContext, cpu_shares), 0),
         SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, offsetof(CGroupContext, startup_cpu_shares), 0),
         SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
+        SD_BUS_PROPERTY("CPUQuotaPeriodUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_period_usec), 0),
         SD_BUS_PROPERTY("IOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, io_accounting), 0),
         SD_BUS_PROPERTY("IOWeight", "t", NULL, offsetof(CGroupContext, io_weight), 0),
         SD_BUS_PROPERTY("StartupIOWeight", "t", NULL, offsetof(CGroupContext, startup_io_weight), 0),
@@ -713,6 +715,7 @@ int bus_cgroup_set_property(
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         c->cpu_quota_per_sec_usec = u64;
+                        u->warned_clamping_cpu_quota_period = false;
                         unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
 
                         if (c->cpu_quota_per_sec_usec == USEC_INFINITY)
@@ -727,6 +730,29 @@ int bus_cgroup_set_property(
 
                 return 1;
 
+        } else if (streq(name, "CPUQuotaPeriodUSec")) {
+                uint64_t u64;
+
+                r = sd_bus_message_read(message, "t", &u64);
+                if (r < 0)
+                        return r;
+
+                if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
+                        c->cpu_quota_period_usec = u64;
+                        u->warned_clamping_cpu_quota_period = false;
+                        unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
+                        if (c->cpu_quota_period_usec == USEC_INFINITY)
+                                unit_write_setting(u, flags, "CPUQuotaPeriodSec", "CPUQuotaPeriodSec=");
+                        else {
+                                char v[FORMAT_TIMESPAN_MAX];
+                                unit_write_settingf(u, flags, "CPUQuotaPeriodSec",
+                                                    "CPUQuotaPeriodSec=%s",
+                                                    format_timespan(v, sizeof(v), c->cpu_quota_period_usec, 1));
+                        }
+                }
+
+                return 1;
+
         } else if ((iol_type = cgroup_io_limit_type_from_string(name)) >= 0) {
                 const char *path;
                 unsigned n = 0;
index cc98372..afd7c9b 100644 (file)
@@ -816,12 +816,15 @@ const sd_bus_vtable bus_exec_vtable[] = {
         SD_BUS_PROPERTY("ConfigurationDirectory", "as", NULL, offsetof(ExecContext, directories[EXEC_DIRECTORY_CONFIGURATION].paths), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RestrictSUIDSGID", "b", bus_property_get_bool, offsetof(ExecContext, restrict_suid_sgid), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("RestrictNamespaces", "t", bus_property_get_ulong, offsetof(ExecContext, restrict_namespaces), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("BindPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("BindReadOnlyPaths", "a(ssbt)", property_get_bind_paths, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TemporaryFileSystem", "a(ss)", property_get_temporary_filesystems, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("MountAPIVFS", "b", bus_property_get_bool, offsetof(ExecContext, mount_apivfs), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("KeyringMode", "s", property_get_exec_keyring_mode, offsetof(ExecContext, keyring_mode), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST),
 
         /* Obsolete/redundant properties: */
         SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1171,6 +1174,9 @@ int bus_exec_context_set_transient_property(
         if (streq(name, "RestrictRealtime"))
                 return bus_set_transient_bool(u, name, &c->restrict_realtime, message, flags, error);
 
+        if (streq(name, "RestrictSUIDSGID"))
+                return bus_set_transient_bool(u, name, &c->restrict_suid_sgid, message, flags, error);
+
         if (streq(name, "DynamicUser"))
                 return bus_set_transient_bool(u, name, &c->dynamic_user, message, flags, error);
 
@@ -1198,6 +1204,9 @@ int bus_exec_context_set_transient_property(
         if (streq(name, "LockPersonality"))
                 return bus_set_transient_bool(u, name, &c->lock_personality, message, flags, error);
 
+        if (streq(name, "ProtectHostname"))
+                return bus_set_transient_bool(u, name, &c->protect_hostname, message, flags, error);
+
         if (streq(name, "UtmpIdentifier"))
                 return bus_set_transient_string(u, name, &c->utmp_id, message, flags, error);
 
@@ -1258,6 +1267,9 @@ int bus_exec_context_set_transient_property(
         if (streq(name, "MountFlags"))
                 return bus_set_transient_mount_flags(u, name, &c->mount_flags, message, flags, error);
 
+        if (streq(name, "NetworkNamespacePath"))
+                return bus_set_transient_path(u, name, &c->network_namespace_path, message, flags, error);
+
         if (streq(name, "SupplementaryGroups")) {
                 _cleanup_strv_free_ char **l = NULL;
                 char **p;
@@ -1428,7 +1440,7 @@ int bus_exec_context_set_transient_property(
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *joined = NULL;
-                        bool invert = !whitelist;
+                        SeccompParseFlags invert_flag = whitelist ? 0 : SECCOMP_PARSE_INVERT;
                         char **s;
 
                         if (strv_isempty(l)) {
@@ -1447,7 +1459,12 @@ int bus_exec_context_set_transient_property(
                                 c->syscall_whitelist = whitelist;
 
                                 if (c->syscall_whitelist) {
-                                        r = seccomp_parse_syscall_filter("@default", -1, c->syscall_filter, SECCOMP_PARSE_WHITELIST | (invert ? SECCOMP_PARSE_INVERT : 0));
+                                        r = seccomp_parse_syscall_filter("@default",
+                                                                         -1,
+                                                                         c->syscall_filter,
+                                                                         SECCOMP_PARSE_WHITELIST | invert_flag,
+                                                                         u->id,
+                                                                         NULL, 0);
                                         if (r < 0)
                                                 return r;
                                 }
@@ -1461,7 +1478,12 @@ int bus_exec_context_set_transient_property(
                                 if (r < 0)
                                         return r;
 
-                                r = seccomp_parse_syscall_filter(n, e, c->syscall_filter, (invert ? SECCOMP_PARSE_INVERT : 0) | (c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0));
+                                r = seccomp_parse_syscall_filter(n,
+                                                                 e,
+                                                                 c->syscall_filter,
+                                                                 (c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0) | invert_flag,
+                                                                 u->id,
+                                                                 NULL, 0);
                                 if (r < 0)
                                         return r;
                         }
@@ -1539,7 +1561,6 @@ int bus_exec_context_set_transient_property(
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         _cleanup_free_ char *joined = NULL;
-                        bool invert = !whitelist;
                         char **s;
 
                         if (strv_isempty(l)) {
@@ -1565,7 +1586,7 @@ int bus_exec_context_set_transient_property(
                                 if (af < 0)
                                         return af;
 
-                                if (!invert == c->address_families_whitelist) {
+                                if (whitelist == c->address_families_whitelist) {
                                         r = set_put(c->address_families, INT_TO_PTR(af));
                                         if (r < 0)
                                                 return r;
@@ -2222,26 +2243,21 @@ int bus_exec_context_set_transient_property(
                 }
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                        char ***dirs = NULL;
                         ExecDirectoryType i;
+                        ExecDirectory *d;
 
-                        for (i = 0; i < _EXEC_DIRECTORY_TYPE_MAX; i++)
-                                if (streq(name, exec_directory_type_to_string(i))) {
-                                        dirs = &c->directories[i].paths;
-                                        break;
-                                }
-
-                        assert(dirs);
+                        assert_se((i = exec_directory_type_from_string(name)) >= 0);
+                        d = c->directories + i;
 
                         if (strv_isempty(l)) {
-                                *dirs = strv_free(*dirs);
+                                d->paths = strv_free(d->paths);
                                 unit_write_settingf(u, flags, name, "%s=", name);
                         } else {
                                 _cleanup_free_ char *joined = NULL;
 
-                                r = strv_extend_strv(dirs, l, true);
+                                r = strv_extend_strv(&d->paths, l, true);
                                 if (r < 0)
-                                        return -ENOMEM;
+                                        return r;
 
                                 joined = unit_concat_strv(l, UNIT_ESCAPE_SPECIFIERS);
                                 if (!joined)
index a279304..c84a23c 100644 (file)
@@ -334,8 +334,25 @@ static int bus_load_unit_by_name(Manager *m, sd_bus_message *message, const char
         return manager_load_unit(m, name, NULL, error, ret_unit);
 }
 
-static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int reply_unit_path(Unit *u, sd_bus_message *message, sd_bus_error *error) {
         _cleanup_free_ char *path = NULL;
+        int r;
+
+        assert(u);
+        assert(message);
+
+        r = mac_selinux_unit_access_check(u, message, "status", error);
+        if (r < 0)
+                return r;
+
+        path = unit_dbus_path(u);
+        if (!path)
+                return log_oom();
+
+        return sd_bus_reply_method_return(message, "o", path);
+}
+
+static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         const char *name;
         Unit *u;
@@ -354,19 +371,10 @@ static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error
         if (r < 0)
                 return r;
 
-        r = mac_selinux_unit_access_check(u, message, "status", error);
-        if (r < 0)
-                return r;
-
-        path = unit_dbus_path(u);
-        if (!path)
-                return -ENOMEM;
-
-        return sd_bus_reply_method_return(message, "o", path);
+        return reply_unit_path(u, message, error);
 }
 
 static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        _cleanup_free_ char *path = NULL;
         Manager *m = userdata;
         pid_t pid;
         Unit *u;
@@ -401,15 +409,7 @@ static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bu
         if (!u)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID "PID_FMT" does not belong to any loaded unit.", pid);
 
-        r = mac_selinux_unit_access_check(u, message, "status", error);
-        if (r < 0)
-                return r;
-
-        path = unit_dbus_path(u);
-        if (!path)
-                return -ENOMEM;
-
-        return sd_bus_reply_method_return(message, "o", path);
+        return reply_unit_path(u, message, error);
 }
 
 static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -471,7 +471,6 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd
 }
 
 static int method_get_unit_by_control_group(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        _cleanup_free_ char *path = NULL;
         Manager *m = userdata;
         const char *cgroup;
         Unit *u;
@@ -485,19 +484,10 @@ static int method_get_unit_by_control_group(sd_bus_message *message, void *userd
         if (!u)
                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Control group '%s' is not valid or not managed by this instance", cgroup);
 
-        r = mac_selinux_unit_access_check(u, message, "status", error);
-        if (r < 0)
-                return r;
-
-        path = unit_dbus_path(u);
-        if (!path)
-                return -ENOMEM;
-
-        return sd_bus_reply_method_return(message, "o", path);
+        return reply_unit_path(u, message, error);
 }
 
 static int method_load_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        _cleanup_free_ char *path = NULL;
         Manager *m = userdata;
         const char *name;
         Unit *u;
@@ -516,15 +506,7 @@ static int method_load_unit(sd_bus_message *message, void *userdata, sd_bus_erro
         if (r < 0)
                 return r;
 
-        r = mac_selinux_unit_access_check(u, message, "status", error);
-        if (r < 0)
-                return r;
-
-        path = unit_dbus_path(u);
-        if (!path)
-                return -ENOMEM;
-
-        return sd_bus_reply_method_return(message, "o", path);
+        return reply_unit_path(u, message, error);
 }
 
 static int method_start_unit_generic(sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
@@ -574,30 +556,18 @@ static int method_reload_or_try_restart_unit(sd_bus_message *message, void *user
         return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, true, error);
 }
 
-static int method_start_unit_replace(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        Manager *m = userdata;
-        const char *old_name;
-        Unit *u;
-        int r;
-
-        assert(message);
-        assert(m);
-
-        r = sd_bus_message_read(message, "s", &old_name);
-        if (r < 0)
-                return r;
-
-        r = bus_get_unit_by_name(m, message, old_name, &u, error);
-        if (r < 0)
-                return r;
-        if (!u->job || u->job->type != JOB_START)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
+typedef enum GenericUnitOperationFlags {
+        GENERIC_UNIT_LOAD            = 1 << 0, /* Load if the unit is not loaded yet */
+        GENERIC_UNIT_VALIDATE_LOADED = 1 << 1, /* Verify unit is properly loaded before forwarding call */
+} GenericUnitOperationFlags;
 
-        return method_start_unit_generic(message, m, JOB_START, false, error);
-}
+static int method_generic_unit_operation(
+                sd_bus_message *message,
+                Manager *m,
+                sd_bus_error *error,
+                sd_bus_message_handler_t handler,
+                GenericUnitOperationFlags flags) {
 
-static int method_kill_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        Manager *m = userdata;
         const char *name;
         Unit *u;
         int r;
@@ -605,107 +575,82 @@ static int method_kill_unit(sd_bus_message *message, void *userdata, sd_bus_erro
         assert(message);
         assert(m);
 
+        /* Read the first argument from the command and pass the operation to the specified per-unit
+         * method. */
+
         r = sd_bus_message_read(message, "s", &name);
         if (r < 0)
                 return r;
 
-        r = bus_get_unit_by_name(m, message, name, &u, error);
+        if (!isempty(name) && FLAGS_SET(flags, GENERIC_UNIT_LOAD))
+                r = manager_load_unit(m, name, NULL, error, &u);
+        else
+                r = bus_get_unit_by_name(m, message, name, &u, error);
         if (r < 0)
                 return r;
 
-        return bus_unit_method_kill(message, u, error);
-}
-
-static int method_reset_failed_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        Manager *m = userdata;
-        const char *name;
-        Unit *u;
-        int r;
-
-        assert(message);
-        assert(m);
-
-        r = sd_bus_message_read(message, "s", &name);
-        if (r < 0)
-                return r;
+        if (FLAGS_SET(flags, GENERIC_UNIT_VALIDATE_LOADED)) {
+                r = bus_unit_validate_load_state(u, error);
+                if (r < 0)
+                        return r;
+        }
 
-        r = bus_get_unit_by_name(m, message, name, &u, error);
-        if (r < 0)
-                return r;
+        return handler(message, u, error);
+}
 
-        return bus_unit_method_reset_failed(message, u, error);
+static int method_enqueue_unit_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        /* We don't bother with GENERIC_UNIT_VALIDATE_LOADED here, as the job logic validates that anyway */
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_enqueue_job, GENERIC_UNIT_LOAD);
 }
 
-static int method_set_unit_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+static int method_start_unit_replace(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
-        const char *name;
+        const char *old_name;
         Unit *u;
         int r;
 
         assert(message);
         assert(m);
 
-        r = sd_bus_message_read(message, "s", &name);
-        if (r < 0)
-                return r;
-
-        r = bus_load_unit_by_name(m, message, name, &u, error);
+        r = sd_bus_message_read(message, "s", &old_name);
         if (r < 0)
                 return r;
 
-        r = bus_unit_validate_load_state(u, error);
+        r = bus_get_unit_by_name(m, message, old_name, &u, error);
         if (r < 0)
                 return r;
+        if (!u->job || u->job->type != JOB_START)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
 
-        return bus_unit_method_set_properties(message, u, error);
+        return method_start_unit_generic(message, m, JOB_START, false, error);
 }
 
-static int method_ref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        Manager *m = userdata;
-        const char *name;
-        Unit *u;
-        int r;
-
-        assert(message);
-        assert(m);
-
-        r = sd_bus_message_read(message, "s", &name);
-        if (r < 0)
-                return r;
+static int method_kill_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        /* We don't bother with GENERIC_UNIT_LOAD nor GENERIC_UNIT_VALIDATE_LOADED here, as it shouldn't
+         * matter whether a unit is loaded for killing any processes possibly in the unit's cgroup. */
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_kill, 0);
+}
 
-        r = bus_load_unit_by_name(m, message, name, &u, error);
-        if (r < 0)
-                return r;
+static int method_reset_failed_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        /* Don't load the unit (because unloaded units can't be in failed state), and don't insist on the
+         * unit to be loaded properly (since a failed unit might have its unit file disappeared) */
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_reset_failed, 0);
+}
 
-        r = bus_unit_validate_load_state(u, error);
-        if (r < 0)
-                return r;
+static int method_set_unit_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        /* Only change properties on fully loaded units, and load them in order to set properties */
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_set_properties, GENERIC_UNIT_LOAD|GENERIC_UNIT_VALIDATE_LOADED);
+}
 
-        return bus_unit_method_ref(message, u, error);
+static int method_ref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        /* Only allow reffing of fully loaded units, and make sure reffing a unit loads it. */
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_ref, GENERIC_UNIT_LOAD|GENERIC_UNIT_VALIDATE_LOADED);
 }
 
 static int method_unref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        Manager *m = userdata;
-        const char *name;
-        Unit *u;
-        int r;
-
-        assert(message);
-        assert(m);
-
-        r = sd_bus_message_read(message, "s", &name);
-        if (r < 0)
-                return r;
-
-        r = bus_load_unit_by_name(m, message, name, &u, error);
-        if (r < 0)
-                return r;
-
-        r = bus_unit_validate_load_state(u, error);
-        if (r < 0)
-                return r;
-
-        return bus_unit_method_unref(message, u, error);
+        /* Dropping a ref OTOH should not require the unit to still be loaded. And since a reffed unit is a
+         * loaded unit there's no need to load the unit for unreffing it. */
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_unref, 0);
 }
 
 static int reply_unit_info(sd_bus_message *reply, Unit *u) {
@@ -783,43 +728,16 @@ static int method_list_units_by_names(sd_bus_message *message, void *userdata, s
 }
 
 static int method_get_unit_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        Manager *m = userdata;
-        const char *name;
-        Unit *u;
-        int r;
-
-        assert(message);
-        assert(m);
-
-        r = sd_bus_message_read(message, "s", &name);
-        if (r < 0)
-                return r;
-
-        r = bus_get_unit_by_name(m, message, name, &u, error);
-        if (r < 0)
-                return r;
-
-        return bus_unit_method_get_processes(message, u, error);
+        /* Don't load a unit (since it won't have any processes if it's not loaded), but don't insist on the
+         * unit being loaded (because even improperly loaded units might still have processes around */
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_get_processes, 0);
 }
 
 static int method_attach_processes_to_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        Manager *m = userdata;
-        const char *name;
-        Unit *u;
-        int r;
-
-        assert(message);
-        assert(m);
-
-        r = sd_bus_message_read(message, "s", &name);
-        if (r < 0)
-                return r;
-
-        r = bus_get_unit_by_name(m, message, name, &u, error);
-        if (r < 0)
-                return r;
-
-        return bus_unit_method_attach_processes(message, u, error);
+        /* Don't allow attaching new processes to units that aren't loaded. Don't bother with loading a unit
+         * for this purpose though, as an unloaded unit is a stopped unit, and we don't allow attaching
+         * processes to stopped units anyway. */
+        return method_generic_unit_operation(message, userdata, error, bus_unit_method_attach_processes, GENERIC_UNIT_VALIDATE_LOADED);
 }
 
 static int transient_unit_from_message(
@@ -955,7 +873,7 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
                 return r;
 
         /* Finally, start it */
-        return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
+        return bus_unit_queue_job(message, u, JOB_START, mode, 0, error);
 }
 
 static int method_get_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1490,7 +1408,7 @@ static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *e
 }
 
 static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_error *error) {
-        char *ri = NULL, *rt = NULL;
+        _cleanup_free_ char *ri = NULL, *rt = NULL;
         const char *root, *init;
         Manager *m = userdata;
         struct statvfs svfs;
@@ -1562,17 +1480,12 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er
 
         if (!isempty(init)) {
                 ri = strdup(init);
-                if (!ri) {
-                        free(rt);
+                if (!ri)
                         return -ENOMEM;
-                }
         }
 
-        free(m->switch_root);
-        m->switch_root = rt;
-
-        free(m->switch_root_init);
-        m->switch_root_init = ri;
+        free_and_replace(m->switch_root, rt);
+        free_and_replace(m->switch_root_init, ri);
 
         m->objective = MANAGER_SWITCH_ROOT;
 
@@ -2553,6 +2466,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("EnqueueUnitJob", "sss", "uososa(uosos)", method_enqueue_unit_job, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
index bb807df..8eb915e 100644 (file)
@@ -106,7 +106,7 @@ static int bus_scope_set_transient_property(
                                 return r;
 
                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
-                                r = unit_watch_pid(UNIT(s), pid);
+                                r = unit_watch_pid(UNIT(s), pid, false);
                                 if (r < 0 && r != -EEXIST)
                                         return r;
                         }
index 0904cc0..48c0fb7 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <stdio_ext.h>
+#include <fcntl.h>
 
 #include "alloc-util.h"
 #include "async.h"
@@ -55,7 +56,7 @@ static int property_get_exit_status_set(
                 return r;
 
         SET_FOREACH(id, status_set->status, i) {
-                int val = PTR_TO_INT(id);
+                int32_t val = PTR_TO_INT(id);
 
                 if (val < 0 || val > 255)
                         continue;
@@ -74,10 +75,10 @@ static int property_get_exit_status_set(
                 return r;
 
         SET_FOREACH(id, status_set->signal, i) {
-                int val = PTR_TO_INT(id);
+                int32_t val = PTR_TO_INT(id);
                 const char *str;
 
-                str = signal_to_string(val);
+                str = signal_to_string((int) val);
                 if (!str)
                         continue;
 
@@ -120,6 +121,7 @@ const sd_bus_vtable bus_service_vtable[] = {
         SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("StatusErrno", "i", bus_property_get_int, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+        SD_BUS_PROPERTY("ReloadResult", "s", property_get_result, offsetof(Service, reload_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("USBFunctionDescriptors", "s", NULL, offsetof(Service, usb_function_descriptors), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("USBFunctionStrings", "s", NULL, offsetof(Service, usb_function_strings), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Unit, ref_uid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -151,7 +153,7 @@ static int bus_set_transient_exit_status(
                 UnitWriteFlags flags,
                 sd_bus_error *error) {
 
-        const int *status, *signal;
+        const int32_t *status, *signal;
         size_t sz_status, sz_signal, i;
         int r;
 
@@ -171,6 +173,9 @@ static int bus_set_transient_exit_status(
         if (r < 0)
                 return r;
 
+        sz_status /= sizeof(int32_t);
+        sz_signal /= sizeof(int32_t);
+
         if (sz_status == 0 && sz_signal == 0 && !UNIT_WRITE_FLAGS_NOOP(flags)) {
                 exit_status_set_free(status_set);
                 unit_write_settingf(u, flags, name, "%s=", name);
@@ -179,34 +184,34 @@ static int bus_set_transient_exit_status(
 
         for (i = 0; i < sz_status; i++) {
                 if (status[i] < 0 || status[i] > 255)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid status code in %s: %i", name, status[i]);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid status code in %s: %"PRIi32, name, status[i]);
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         r = set_ensure_allocated(&status_set->status, NULL);
                         if (r < 0)
                                 return r;
 
-                        r = set_put(status_set->status, INT_TO_PTR(status[i]));
+                        r = set_put(status_set->status, INT_TO_PTR((int) status[i]));
                         if (r < 0)
                                 return r;
 
-                        unit_write_settingf(u, flags, name, "%s=%i", name, status[i]);
+                        unit_write_settingf(u, flags, name, "%s=%"PRIi32, name, status[i]);
                 }
         }
 
         for (i = 0; i < sz_signal; i++) {
                 const char *str;
 
-                str = signal_to_string(signal[i]);
+                str = signal_to_string((int) signal[i]);
                 if (!str)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal in %s: %i", name, signal[i]);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal in %s: %"PRIi32, name, signal[i]);
 
                 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                         r = set_ensure_allocated(&status_set->signal, NULL);
                         if (r < 0)
                                 return r;
 
-                        r = set_put(status_set->signal, INT_TO_PTR(signal[i]));
+                        r = set_put(status_set->signal, INT_TO_PTR((int) signal[i]));
                         if (r < 0)
                                 return r;
 
index b9d2f3d..807ca80 100644 (file)
@@ -123,6 +123,8 @@ const sd_bus_vtable bus_timer_vtable[] = {
         SD_BUS_PROPERTY("Unit", "s", bus_property_get_triggered_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("TimersMonotonic", "a(stt)", property_get_monotonic_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
         SD_BUS_PROPERTY("TimersCalendar", "a(sst)", property_get_calendar_timers, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+        SD_BUS_PROPERTY("OnClockChange", "b", bus_property_get_bool, offsetof(Timer, on_clock_change), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("OnTimezoneChange", "b", bus_property_get_bool, offsetof(Timer, on_timezone_change), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("NextElapseUSecRealtime", "t", bus_property_get_usec, offsetof(Timer, next_elapse_realtime), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", property_get_next_elapse_monotonic, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -171,6 +173,12 @@ static int bus_timer_set_transient_property(
         if (streq(name, "RemainAfterElapse"))
                 return bus_set_transient_bool(u, name, &t->remain_after_elapse, message, flags, error);
 
+        if (streq(name, "OnTimezoneChange"))
+                return bus_set_transient_bool(u, name, &t->on_timezone_change, message, flags, error);
+
+        if (streq(name, "OnClockChange"))
+                return bus_set_transient_bool(u, name, &t->on_clock_change, message, flags, error);
+
         if (streq(name, "TimersMonotonic")) {
                 const char *base_name;
                 usec_t usec = 0;
@@ -194,12 +202,14 @@ static int bus_timer_set_transient_property(
                                 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", base_name,
                                                     format_timespan(ts, sizeof(ts), usec, USEC_PER_MSEC));
 
-                                v = new0(TimerValue, 1);
+                                v = new(TimerValue, 1);
                                 if (!v)
                                         return -ENOMEM;
 
-                                v->base = b;
-                                v->value = usec;
+                                *v = (TimerValue) {
+                                        .base = b,
+                                        .value = usec,
+                                };
 
                                 LIST_PREPEND(value, t->values, v);
                         }
@@ -247,12 +257,14 @@ static int bus_timer_set_transient_property(
 
                                 unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", base_name, str);
 
-                                v = new0(TimerValue, 1);
+                                v = new(TimerValue, 1);
                                 if (!v)
                                         return -ENOMEM;
 
-                                v->base = b;
-                                v->calendar_spec = TAKE_PTR(c);
+                                *v = (TimerValue) {
+                                        .base = b,
+                                        .calendar_spec = TAKE_PTR(c),
+                                };
 
                                 LIST_PREPEND(value, t->values, v);
                         }
@@ -300,12 +312,14 @@ static int bus_timer_set_transient_property(
                         unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name,
                                             format_timespan(time, sizeof(time), usec, USEC_PER_MSEC));
 
-                        v = new0(TimerValue, 1);
+                        v = new(TimerValue, 1);
                         if (!v)
                                 return -ENOMEM;
 
-                        v->base = b;
-                        v->value = usec;
+                        *v = (TimerValue) {
+                                .base = b,
+                                .value = usec,
+                        };
 
                         LIST_PREPEND(value, t->values, v);
                 }
@@ -333,12 +347,14 @@ static int bus_timer_set_transient_property(
 
                         unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "%s=%s", name, str);
 
-                        v = new0(TimerValue, 1);
+                        v = new(TimerValue, 1);
                         if (!v)
                                 return -ENOMEM;
 
-                        v->base = TIMER_CALENDAR;
-                        v->calendar_spec = TAKE_PTR(c);
+                        *v = (TimerValue) {
+                                .base = TIMER_CALENDAR,
+                                .calendar_spec = TAKE_PTR(c),
+                        };
 
                         LIST_PREPEND(value, t->values, v);
                 }
index 17c2003..6f1a74d 100644 (file)
@@ -312,6 +312,14 @@ static int bus_verify_manage_units_async_full(
                         error);
 }
 
+static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
+        [JOB_START]       = N_("Authentication is required to start '$(unit)'."),
+        [JOB_STOP]        = N_("Authentication is required to stop '$(unit)'."),
+        [JOB_RELOAD]      = N_("Authentication is required to reload '$(unit)'."),
+        [JOB_RESTART]     = N_("Authentication is required to restart '$(unit)'."),
+        [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
+};
+
 int bus_unit_method_start_generic(
                 sd_bus_message *message,
                 Unit *u,
@@ -319,16 +327,8 @@ int bus_unit_method_start_generic(
                 bool reload_if_possible,
                 sd_bus_error *error) {
 
-        const char *smode;
+        const char *smode, *verb;
         JobMode mode;
-        _cleanup_free_ char *verb = NULL;
-        static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
-                [JOB_START]       = N_("Authentication is required to start '$(unit)'."),
-                [JOB_STOP]        = N_("Authentication is required to stop '$(unit)'."),
-                [JOB_RELOAD]      = N_("Authentication is required to reload '$(unit)'."),
-                [JOB_RESTART]     = N_("Authentication is required to restart '$(unit)'."),
-                [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
-        };
         int r;
 
         assert(message);
@@ -351,17 +351,15 @@ int bus_unit_method_start_generic(
                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
 
         if (reload_if_possible)
-                verb = strjoin("reload-or-", job_type_to_string(job_type));
+                verb = strjoina("reload-or-", job_type_to_string(job_type));
         else
-                verb = strdup(job_type_to_string(job_type));
-        if (!verb)
-                return -ENOMEM;
+                verb = job_type_to_string(job_type);
 
         r = bus_verify_manage_units_async_full(
                         u,
                         verb,
                         CAP_SYS_ADMIN,
-                        job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL,
+                        polkit_message_for_job[job_type],
                         true,
                         message,
                         error);
@@ -370,7 +368,8 @@ int bus_unit_method_start_generic(
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error);
+        return bus_unit_queue_job(message, u, job_type, mode,
+                                  reload_if_possible ? BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE : 0, error);
 }
 
 static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -401,6 +400,62 @@ static int method_reload_or_try_restart(sd_bus_message *message, void *userdata,
         return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
 }
 
+int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        BusUnitQueueFlags flags = BUS_UNIT_QUEUE_VERBOSE_REPLY;
+        const char *jtype, *smode;
+        Unit *u = userdata;
+        JobType type;
+        JobMode mode;
+        int r;
+
+        assert(message);
+        assert(u);
+
+        r = sd_bus_message_read(message, "ss", &jtype, &smode);
+        if (r < 0)
+                return r;
+
+        /* Parse the two magic reload types "reload-or-…" manually */
+        if (streq(jtype, "reload-or-restart")) {
+                type = JOB_RESTART;
+                flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
+        } else if (streq(jtype, "reload-or-try-restart")) {
+                type = JOB_TRY_RESTART;
+                flags |= BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE;
+        } else {
+                /* And the rest generically */
+                type = job_type_from_string(jtype);
+                if (type < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job type %s invalid", jtype);
+        }
+
+        mode = job_mode_from_string(smode);
+        if (mode < 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
+
+        r = mac_selinux_unit_access_check(
+                        u, message,
+                        job_type_to_access_method(type),
+                        error);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_manage_units_async_full(
+                        u,
+                        jtype,
+                        CAP_SYS_ADMIN,
+                        polkit_message_for_job[type],
+                        true,
+                        message,
+                        error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        return bus_unit_queue_job(message, u, type, mode, flags, error);
+}
+
 int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Unit *u = userdata;
         const char *swho;
@@ -686,6 +741,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
         SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("EnqueueJob", "ss", "uososa(uosos)", bus_unit_method_enqueue_job, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -1272,11 +1328,14 @@ int bus_unit_queue_job(
                 Unit *u,
                 JobType type,
                 JobMode mode,
-                bool reload_if_possible,
+                BusUnitQueueFlags flags,
                 sd_bus_error *error) {
 
-        _cleanup_free_ char *path = NULL;
-        Job *j;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        _cleanup_free_ char *job_path = NULL, *unit_path = NULL;
+        _cleanup_(set_freep) Set *affected = NULL;
+        Iterator i;
+        Job *j, *a;
         int r;
 
         assert(message);
@@ -1291,7 +1350,7 @@ int bus_unit_queue_job(
         if (r < 0)
                 return r;
 
-        if (reload_if_possible && unit_can_reload(u)) {
+        if (FLAGS_SET(flags, BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE) && unit_can_reload(u)) {
                 if (type == JOB_RESTART)
                         type = JOB_RELOAD_OR_START;
                 else if (type == JOB_TRY_RESTART)
@@ -1309,7 +1368,13 @@ int bus_unit_queue_job(
             (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
                 return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id);
 
-        r = manager_add_job(u->manager, type, u, mode, error, &j);
+        if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) {
+                affected = set_new(NULL);
+                if (!affected)
+                        return -ENOMEM;
+        }
+
+        r = manager_add_job(u->manager, type, u, mode, affected, error, &j);
         if (r < 0)
                 return r;
 
@@ -1317,14 +1382,67 @@ int bus_unit_queue_job(
         if (r < 0)
                 return r;
 
-        path = job_dbus_path(j);
-        if (!path)
-                return -ENOMEM;
-
         /* Before we send the method reply, force out the announcement JobNew for this job */
         bus_job_send_pending_change_signal(j, true);
 
-        return sd_bus_reply_method_return(message, "o", path);
+        job_path = job_dbus_path(j);
+        if (!job_path)
+                return -ENOMEM;
+
+        /* The classic response is just a job object path */
+        if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY))
+                return sd_bus_reply_method_return(message, "o", job_path);
+
+        /* In verbose mode respond with the anchor job plus everything that has been affected */
+        r = sd_bus_message_new_method_return(message, &reply);
+        if (r < 0)
+                return r;
+
+        unit_path = unit_dbus_path(j->unit);
+        if (!unit_path)
+                return -ENOMEM;
+
+        r = sd_bus_message_append(reply, "uosos",
+                                  j->id, job_path,
+                                  j->unit->id, unit_path,
+                                  job_type_to_string(j->type));
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(reply, 'a', "(uosos)");
+        if (r < 0)
+                return r;
+
+        SET_FOREACH(a, affected, i) {
+
+                if (a->id == j->id)
+                        continue;
+
+                /* Free paths from previous iteration */
+                job_path = mfree(job_path);
+                unit_path = mfree(unit_path);
+
+                job_path = job_dbus_path(a);
+                if (!job_path)
+                        return -ENOMEM;
+
+                unit_path = unit_dbus_path(a->unit);
+                if (!unit_path)
+                        return -ENOMEM;
+
+                r = sd_bus_message_append(reply, "(uosos)",
+                                          a->id, job_path,
+                                          a->unit->id, unit_path,
+                                          job_type_to_string(a->type));
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_bus_message_close_container(reply);
+        if (r < 0)
+                return r;
+
+        return sd_bus_send(NULL, reply, NULL);
 }
 
 static int bus_unit_set_live_property(
@@ -1674,9 +1792,17 @@ static int bus_unit_set_transient_property(
                         return r;
 
                 STRV_FOREACH(p, l) {
+                        path_simplify(*p, true);
+
                         if (!path_is_absolute(*p))
                                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path specified in %s is not absolute: %s", name, *p);
 
+                        if (!path_is_valid(*p))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path specified in %s has invalid length: %s", name, *p);
+
+                        if (!path_is_normalized(*p))
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path specified in %s is not normalized: %s", name, *p);
+
                         if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
                                 r = unit_require_mounts_for(u, *p, UNIT_DEPENDENCY_FILE);
                                 if (r < 0)
index 345345e..740bb1c 100644 (file)
@@ -15,6 +15,7 @@ void bus_unit_send_pending_change_signal(Unit *u, bool including_new);
 void bus_unit_send_removed_signal(Unit *u);
 
 int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
+int bus_unit_method_enqueue_job(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
@@ -25,7 +26,12 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
 int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error);
 int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error);
 
-int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
+typedef enum BusUnitQueueFlags {
+        BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE = 1 << 0,
+        BUS_UNIT_QUEUE_VERBOSE_REPLY      = 1 << 1,
+} BusUnitQueueFlags;
+
+int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, BusUnitQueueFlags flags, sd_bus_error *error);
 int bus_unit_validate_load_state(Unit *u, sd_bus_error *error);
 
 int bus_unit_track_add_name(Unit *u, const char *name);
index 81f2e51..e4cd9c8 100644 (file)
@@ -177,7 +177,7 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd
                 goto failed;
         }
 
-        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, &error, NULL);
+        r = manager_add_job(m, JOB_START, u, JOB_REPLACE, NULL, &error, NULL);
         if (r < 0)
                 goto failed;
 
@@ -622,6 +622,9 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
 
         nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
         if (nfd < 0) {
+                if (ERRNO_IS_ACCEPT_AGAIN(errno))
+                        return 0;
+
                 log_warning_errno(errno, "Failed to accept private connection, ignoring: %m");
                 return 0;
         }
index e1fef0f..499e523 100644 (file)
@@ -17,6 +17,7 @@
 #include "stat-util.h"
 #include "string-util.h"
 #include "swap.h"
+#include "udev-util.h"
 #include "unit-name.h"
 #include "unit.h"
 
@@ -432,7 +433,7 @@ static int device_add_udev_wants(Unit *u, sd_device *dev) {
                         if (strv_contains(d->wants_property, *i)) /* Was this unit already listed before? */
                                 continue;
 
-                        r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, &error, NULL);
+                        r = manager_add_job_by_name(u->manager, JOB_START, *i, JOB_FAIL, NULL, &error, NULL);
                         if (r < 0)
                                 log_unit_warning_errno(u, r, "Failed to enqueue SYSTEMD_WANTS= job, ignoring: %s", bus_error_message(&error, r));
                 }
@@ -665,9 +666,13 @@ static void device_found_changed(Device *d, DeviceFound previous, DeviceFound no
 }
 
 static void device_update_found_one(Device *d, DeviceFound found, DeviceFound mask) {
+        Manager *m;
+
         assert(d);
 
-        if (MANAGER_IS_RUNNING(UNIT(d)->manager)) {
+        m = UNIT(d)->manager;
+
+        if (MANAGER_IS_RUNNING(m) && (m->honor_device_enumeration || MANAGER_IS_USER(m))) {
                 DeviceFound n, previous;
 
                 /* When we are already running, then apply the new mask right-away, and trigger state changes
@@ -729,6 +734,9 @@ static bool device_is_ready(sd_device *dev) {
 
         assert(dev);
 
+        if (device_is_renaming(dev) > 0)
+                return false;
+
         if (sd_device_get_property_value(dev, "SYSTEMD_READY", &ready) < 0)
                 return true;
 
@@ -895,7 +903,8 @@ static void device_propagate_reload_by_sysfs(Manager *m, const char *sysfs) {
 
 static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) {
         Manager *m = userdata;
-        const char *action, *sysfs;
+        DeviceAction action;
+        const char *sysfs;
         int r;
 
         assert(m);
@@ -907,19 +916,19 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *
                 return 0;
         }
 
-        r = sd_device_get_property_value(dev, "ACTION", &action);
+        r = device_get_action(dev, &action);
         if (r < 0) {
-                log_device_error_errno(dev, r, "Failed to get udev action string: %m");
+                log_device_error_errno(dev, r, "Failed to get udev action: %m");
                 return 0;
         }
 
-        if (streq(action, "change"))
+        if (action == DEVICE_ACTION_CHANGE)
                 device_propagate_reload_by_sysfs(m, sysfs);
 
         /* A change event can signal that a device is becoming ready, in particular if
          * the device is using the SYSTEMD_READY logic in udev
          * so we need to reach the else block of the follwing if, even for change events */
-        if (streq(action, "remove"))  {
+        if (action == DEVICE_ACTION_REMOVE) {
                 r = swap_process_device_remove(m, dev);
                 if (r < 0)
                         log_device_warning_errno(dev, r, "Failed to process swap device remove event, ignoring: %m");
index 530df70..c380bee 100644 (file)
@@ -3,11 +3,14 @@
 #include <grp.h>
 #include <pwd.h>
 #include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "clean-ipc.h"
 #include "dynamic-user.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "io-util.h"
 #include "nscd-flush.h"
@@ -707,7 +710,7 @@ int dynamic_user_lookup_uid(Manager *m, uid_t uid, char **ret) {
 
         xsprintf(lock_path, "/run/systemd/dynamic-uid/" UID_FMT, uid);
         r = read_one_line_file(lock_path, &user);
-        if (r == -ENOENT)
+        if (IN_SET(r, -ENOENT, 0))
                 return -ESRCH;
         if (r < 0)
                 return r;
index 112f91e..0a55630 100644 (file)
@@ -15,8 +15,8 @@ typedef struct DynamicCreds {
  * used. This means, if you want to allocate a group and user pair, and they might have two different names, then you
  * need to allocated two of these objects. DynamicCreds below makes that easy. */
 struct DynamicUser {
-        unsigned n_ref;
         Manager *manager;
+        unsigned n_ref;
 
         /* An AF_UNIX socket pair that contains a datagram containing both the numeric ID assigned, as well as a lock
          * file fd locking the user ID we picked. */
index f98b0de..4330c0f 100644 (file)
@@ -20,7 +20,7 @@ static void log_and_status(Manager *m, bool warn, const char *message, const cha
                                       "%s: %s", message, reason);
 }
 
-int emergency_action(
+void emergency_action(
                 Manager *m,
                 EmergencyAction action,
                 EmergencyActionFlags options,
@@ -33,11 +33,11 @@ int emergency_action(
         assert(action < _EMERGENCY_ACTION_MAX);
 
         if (action == EMERGENCY_ACTION_NONE)
-                return -ECANCELED;
+                return;
 
         if (FLAGS_SET(options, EMERGENCY_ACTION_IS_WATCHDOG) && !m->service_watchdogs) {
                 log_warning("Watchdog disabled! Not acting on: %s", reason);
-                return -ECANCELED;
+                return;
         }
 
         bool warn = FLAGS_SET(options, EMERGENCY_ACTION_WARN);
@@ -47,15 +47,14 @@ int emergency_action(
         case EMERGENCY_ACTION_REBOOT:
                 log_and_status(m, warn, "Rebooting", reason);
 
-                (void) update_reboot_parameter_and_warn(reboot_arg);
-                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
-
+                (void) update_reboot_parameter_and_warn(reboot_arg, true);
+                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
                 break;
 
         case EMERGENCY_ACTION_REBOOT_FORCE:
                 log_and_status(m, warn, "Forcibly rebooting", reason);
 
-                (void) update_reboot_parameter_and_warn(reboot_arg);
+                (void) update_reboot_parameter_and_warn(reboot_arg, true);
                 m->objective = MANAGER_REBOOT;
 
                 break;
@@ -82,7 +81,7 @@ int emergency_action(
 
                 if (MANAGER_IS_USER(m) || detect_container() > 0) {
                         log_and_status(m, warn, "Exiting", reason);
-                        (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
+                        (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_EXIT_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
                         break;
                 }
 
@@ -91,7 +90,7 @@ int emergency_action(
 
         case EMERGENCY_ACTION_POWEROFF:
                 log_and_status(m, warn, "Powering off", reason);
-                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL);
+                (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE_IRREVERSIBLY, NULL, NULL);
                 break;
 
         case EMERGENCY_ACTION_EXIT_FORCE:
@@ -125,8 +124,6 @@ int emergency_action(
         default:
                 assert_not_reached("Unknown emergency action");
         }
-
-        return -ECANCELED;
 }
 
 static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
index 6e6c69d..706c38a 100644 (file)
@@ -24,9 +24,9 @@ typedef enum EmergencyActionFlags {
 #include "macro.h"
 #include "manager.h"
 
-int emergency_action(Manager *m,
-                     EmergencyAction action, EmergencyActionFlags options,
-                     const char *reboot_arg, int exit_status, const char *reason);
+void emergency_action(Manager *m,
+                      EmergencyAction action, EmergencyActionFlags options,
+                      const char *reboot_arg, int exit_status, const char *reason);
 
 const char* emergency_action_to_string(EmergencyAction i) _const_;
 EmergencyAction emergency_action_from_string(const char *s) _pure_;
index 548df02..018c2dc 100644 (file)
@@ -65,6 +65,7 @@
 #include "log.h"
 #include "macro.h"
 #include "manager.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "mkdir.h"
 #include "namespace.h"
@@ -91,7 +92,6 @@
 #include "umask-util.h"
 #include "unit.h"
 #include "user-util.h"
-#include "util.h"
 #include "utmp-wtmp.h"
 
 #define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
@@ -1425,13 +1425,15 @@ static bool context_has_no_new_privileges(const ExecContext *c) {
         return context_has_address_families(c) ||
                 c->memory_deny_write_execute ||
                 c->restrict_realtime ||
+                c->restrict_suid_sgid ||
                 exec_context_restrict_namespaces_set(c) ||
                 c->protect_kernel_tunables ||
                 c->protect_kernel_modules ||
                 c->private_devices ||
                 context_has_syscall_filters(c) ||
                 !set_isempty(c->syscall_archs) ||
-                c->lock_personality;
+                c->lock_personality ||
+                c->protect_hostname;
 }
 
 #if HAVE_SECCOMP
@@ -1529,6 +1531,19 @@ static int apply_restrict_realtime(const Unit* u, const ExecContext *c) {
         return seccomp_restrict_realtime();
 }
 
+static int apply_restrict_suid_sgid(const Unit* u, const ExecContext *c) {
+        assert(u);
+        assert(c);
+
+        if (!c->restrict_suid_sgid)
+                return 0;
+
+        if (skip_seccomp_unavailable(u, "RestrictSUIDSGID="))
+                return 0;
+
+        return seccomp_restrict_suid_sgid();
+}
+
 static int apply_protect_sysctl(const Unit *u, const ExecContext *c) {
         assert(u);
         assert(c);
@@ -1717,6 +1732,8 @@ static int build_environment(
                 x = strappend("HOME=", home);
                 if (!x)
                         return -ENOMEM;
+
+                path_simplify(x + 5, true);
                 our_env[n_env++] = x;
         }
 
@@ -1736,6 +1753,8 @@ static int build_environment(
                 x = strappend("SHELL=", shell);
                 if (!x)
                         return -ENOMEM;
+
+                path_simplify(x + 6, true);
                 our_env[n_env++] = x;
         }
 
@@ -1860,7 +1879,7 @@ static bool exec_needs_mount_namespace(
         if (context->n_temporary_filesystems > 0)
                 return true;
 
-        if (context->mount_flags != 0)
+        if (!IN_SET(context->mount_flags, 0, MS_SHARED))
                 return true;
 
         if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir))
@@ -2090,7 +2109,7 @@ static int setup_exec_directory(
         STRV_FOREACH(rt, context->directories[type].paths) {
                 _cleanup_free_ char *p = NULL, *pp = NULL;
 
-                p = strjoin(params->prefix[type], "/", *rt);
+                p = path_join(params->prefix[type], *rt);
                 if (!p) {
                         r = -ENOMEM;
                         goto fail;
@@ -2101,7 +2120,8 @@ static int setup_exec_directory(
                         goto fail;
 
                 if (context->dynamic_user &&
-                    !IN_SET(type, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION)) {
+                    (!IN_SET(type, EXEC_DIRECTORY_RUNTIME, EXEC_DIRECTORY_CONFIGURATION) ||
+                     (type == EXEC_DIRECTORY_RUNTIME && context->runtime_directory_preserve_mode != EXEC_PRESERVE_NO))) {
                         _cleanup_free_ char *private_root = NULL;
 
                         /* So, here's one extra complication when dealing with DynamicUser=1 units. In that case we
@@ -2126,7 +2146,7 @@ static int setup_exec_directory(
                          * Also, note that we don't do this for EXEC_DIRECTORY_RUNTIME as that's often used for sharing
                          * files or sockets with other services. */
 
-                        private_root = strjoin(params->prefix[type], "/private");
+                        private_root = path_join(params->prefix[type], "private");
                         if (!private_root) {
                                 r = -ENOMEM;
                                 goto fail;
@@ -2137,7 +2157,7 @@ static int setup_exec_directory(
                         if (r < 0)
                                 goto fail;
 
-                        pp = strjoin(private_root, "/", *rt);
+                        pp = path_join(private_root, *rt);
                         if (!pp) {
                                 r = -ENOMEM;
                                 goto fail;
@@ -2172,39 +2192,47 @@ static int setup_exec_directory(
                         if (r < 0)
                                 goto fail;
 
-                        /* Lock down the access mode */
-                        if (chmod(pp, context->directories[type].mode) < 0) {
-                                r = -errno;
-                                goto fail;
-                        }
                 } else {
                         r = mkdir_label(p, context->directories[type].mode);
-                        if (r < 0 && r != -EEXIST)
-                                goto fail;
-                        if (r == -EEXIST) {
-                                struct stat st;
-
-                                if (stat(p, &st) < 0) {
-                                        r = -errno;
+                        if (r < 0) {
+                                if (r != -EEXIST)
                                         goto fail;
-                                }
-                                if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0)
-                                        log_warning("%s \'%s\' already exists but the mode is different. "
-                                                    "(filesystem: %o %sMode: %o)",
-                                                    exec_directory_type_to_string(type), *rt,
-                                                    st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777);
-                                if (!context->dynamic_user)
+
+                                if (type == EXEC_DIRECTORY_CONFIGURATION) {
+                                        struct stat st;
+
+                                        /* Don't change the owner/access mode of the configuration directory,
+                                         * as in the common case it is not written to by a service, and shall
+                                         * not be writable. */
+
+                                        if (stat(p, &st) < 0) {
+                                                r = -errno;
+                                                goto fail;
+                                        }
+
+                                        /* Still complain if the access mode doesn't match */
+                                        if (((st.st_mode ^ context->directories[type].mode) & 07777) != 0)
+                                                log_warning("%s \'%s\' already exists but the mode is different. "
+                                                            "(File system: %o %sMode: %o)",
+                                                            exec_directory_type_to_string(type), *rt,
+                                                            st.st_mode & 07777, exec_directory_type_to_string(type), context->directories[type].mode & 07777);
+
                                         continue;
+                                }
                         }
                 }
 
-                /* Don't change the owner of the configuration directory, as in the common case it is not written to by
-                 * a service, and shall not be writable. */
-                if (type == EXEC_DIRECTORY_CONFIGURATION)
-                        continue;
+                /* Lock down the access mode (we use chmod_and_chown() to make this idempotent. We don't
+                 * specifiy UID/GID here, so that path_chown_recursive() can optimize things depending on the
+                 * current UID/GID ownership.) */
+                r = chmod_and_chown(pp ?: p, context->directories[type].mode, UID_INVALID, GID_INVALID);
+                if (r < 0)
+                        goto fail;
 
-                /* Then, change the ownership of the whole tree, if necessary */
-                r = path_chown_recursive(pp ?: p, uid, gid);
+                /* Then, change the ownership of the whole tree, if necessary. When dynamic users are used we
+                 * drop the suid/sgid bits, since we really don't want SUID/SGID files for dynamic UID/GID
+                 * assignments to exist.*/
+                r = path_chown_recursive(pp ?: p, uid, gid, context->dynamic_user ? 01777 : 07777);
                 if (r < 0)
                         goto fail;
         }
@@ -2374,6 +2402,7 @@ static int compile_bind_mounts(
                                 .source = s,
                                 .destination = d,
                                 .read_only = false,
+                                .nosuid = context->dynamic_user, /* don't allow suid/sgid when DynamicUser= is on */
                                 .recursive = true,
                                 .ignore_enoent = false,
                         };
@@ -2441,6 +2470,7 @@ static int apply_mount_namespace(
                         .protect_control_groups = context->protect_control_groups,
                         .protect_kernel_tunables = context->protect_kernel_tunables,
                         .protect_kernel_modules = context->protect_kernel_modules,
+                        .protect_hostname = context->protect_hostname,
                         .mount_apivfs = context->mount_apivfs,
                         .private_mounts = context->private_mounts,
                 };
@@ -2456,6 +2486,9 @@ static int apply_mount_namespace(
         else
                 ns_info = (NamespaceInfo) {};
 
+        if (context->mount_flags == MS_SHARED)
+                log_unit_debug(u, "shared mount propagation hidden by other fs namespacing unit settings: ignoring");
+
         r = setup_namespace(root_dir, root_image,
                             &ns_info, context->read_write_paths,
                             needs_sandboxing ? context->read_only_paths : NULL,
@@ -2754,12 +2787,6 @@ static int acquire_home(const ExecContext *c, uid_t uid, const char** home, char
         if (!c->working_directory_home)
                 return 0;
 
-        if (uid == 0) {
-                /* Hardcode /root as home directory for UID 0 */
-                *home = "/root";
-                return 1;
-        }
-
         r = get_home_dir(buf);
         if (r < 0)
                 return r;
@@ -2862,12 +2889,13 @@ static int exec_child(
                 int user_lookup_fd,
                 int *exit_status) {
 
-        _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL;
+        _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **replaced_argv = NULL;
         int *fds_with_exec_fd, n_fds_with_exec_fd, r, ngids = 0, exec_fd = -1;
         _cleanup_free_ gid_t *supplementary_gids = NULL;
         const char *username = NULL, *groupname = NULL;
         _cleanup_free_ char *home_buffer = NULL;
         const char *home = NULL, *shell = NULL;
+        char **final_argv = NULL;
         dev_t journal_stream_dev = 0;
         ino_t journal_stream_ino = 0;
         bool needs_sandboxing,          /* Do we need to set up full sandboxing? (i.e. all namespacing, all MAC stuff, caps, yadda yadda */
@@ -3077,6 +3105,14 @@ static int exec_child(
                 }
         }
 
+        if (context->network_namespace_path && runtime && runtime->netns_storage_socket[0] >= 0) {
+                r = open_netns_path(runtime->netns_storage_socket, context->network_namespace_path);
+                if (r < 0) {
+                        *exit_status = EXIT_NETWORK;
+                        return log_unit_error_errno(unit, r, "Failed to open network namespace path %s: %m", context->network_namespace_path);
+                }
+        }
+
         r = setup_input(context, params, socket_fd, named_iofds);
         if (r < 0) {
                 *exit_status = EXIT_STDIN;
@@ -3163,7 +3199,7 @@ static int exec_child(
                                       USER_PROCESS,
                                       username);
 
-        if (context->user) {
+        if (uid_is_valid(uid)) {
                 r = chown_terminal(STDIN_FILENO, uid);
                 if (r < 0) {
                         *exit_status = EXIT_STDIN;
@@ -3287,13 +3323,17 @@ static int exec_child(
                 }
         }
 
-        if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) {
+        if ((context->private_network || context->network_namespace_path) && runtime && runtime->netns_storage_socket[0] >= 0) {
+
                 if (ns_type_supported(NAMESPACE_NET)) {
                         r = setup_netns(runtime->netns_storage_socket);
                         if (r < 0) {
                                 *exit_status = EXIT_NETWORK;
                                 return log_unit_error_errno(unit, r, "Failed to set up network namespacing: %m");
                         }
+                } else if (context->network_namespace_path) {
+                        *exit_status = EXIT_NETWORK;
+                        return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EOPNOTSUPP), "NetworkNamespacePath= is not supported, refusing.");
                 } else
                         log_unit_warning(unit, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring.");
         }
@@ -3307,6 +3347,23 @@ static int exec_child(
                 }
         }
 
+        if (context->protect_hostname) {
+                if (ns_type_supported(NAMESPACE_UTS)) {
+                        if (unshare(CLONE_NEWUTS) < 0) {
+                                *exit_status = EXIT_NAMESPACE;
+                                return log_unit_error_errno(unit, errno, "Failed to set up UTS namespacing: %m");
+                        }
+                } else
+                        log_unit_warning(unit, "ProtectHostname=yes is configured, but the kernel does not support UTS namespaces, ignoring namespace setup.");
+#if HAVE_SECCOMP
+                r = seccomp_protect_hostname();
+                if (r < 0) {
+                        *exit_status = EXIT_SECCOMP;
+                        return log_unit_error_errno(unit, r, "Failed to apply hostname restrictions: %m");
+                }
+#endif
+        }
+
         /* Drop groups as early as possbile */
         if (needs_setuid) {
                 r = enforce_groups(gid, supplementary_gids, ngids);
@@ -3463,7 +3520,7 @@ static int exec_child(
         }
 
         if (needs_setuid) {
-                if (context->user) {
+                if (uid_is_valid(uid)) {
                         r = enforce_user(context, uid);
                         if (r < 0) {
                                 *exit_status = EXIT_USER;
@@ -3567,6 +3624,12 @@ static int exec_child(
                         return log_unit_error_errno(unit, r, "Failed to apply realtime restrictions: %m");
                 }
 
+                r = apply_restrict_suid_sgid(unit, context);
+                if (r < 0) {
+                        *exit_status = EXIT_SECCOMP;
+                        return log_unit_error_errno(unit, r, "Failed to apply SUID/SGID restrictions: %m");
+                }
+
                 r = apply_restrict_namespaces(unit, context);
                 if (r < 0) {
                         *exit_status = EXIT_SECCOMP;
@@ -3625,11 +3688,15 @@ static int exec_child(
                 strv_free_and_replace(accum_env, ee);
         }
 
-        final_argv = replace_env_argv(command->argv, accum_env);
-        if (!final_argv) {
-                *exit_status = EXIT_MEMORY;
-                return log_oom();
-        }
+        if (!FLAGS_SET(command->flags, EXEC_COMMAND_NO_ENV_EXPAND)) {
+                replaced_argv = replace_env_argv(command->argv, accum_env);
+                if (!replaced_argv) {
+                        *exit_status = EXIT_MEMORY;
+                        return log_oom();
+                }
+                final_argv = replaced_argv;
+        } else
+                final_argv = command->argv;
 
         if (DEBUG_LOGGING) {
                 _cleanup_free_ char *line;
@@ -3900,6 +3967,8 @@ void exec_context_done(ExecContext *c) {
 
         c->stdin_data = mfree(c->stdin_data);
         c->stdin_data_size = 0;
+
+        c->network_namespace_path = mfree(c->network_namespace_path);
 }
 
 int exec_context_destroy_runtime_directory(const ExecContext *c, const char *runtime_prefix) {
@@ -3913,12 +3982,12 @@ int exec_context_destroy_runtime_directory(const ExecContext *c, const char *run
         STRV_FOREACH(i, c->directories[EXEC_DIRECTORY_RUNTIME].paths) {
                 _cleanup_free_ char *p;
 
-                p = strjoin(runtime_prefix, "/", *i);
+                p = path_join(runtime_prefix, *i);
                 if (!p)
                         return -ENOMEM;
 
-                /* We execute this synchronously, since we need to be sure this is gone when we start the service
-                 * next. */
+                /* We execute this synchronously, since we need to be sure this is gone when we start the
+                 * service next. */
                 (void) rm_rf(p, REMOVE_ROOT);
         }
 
@@ -4159,17 +4228,23 @@ static bool tty_may_match_dev_console(const char *tty) {
                 return true; /* if we could not resolve, assume it may */
 
         /* "tty0" means the active VC, so it may be the same sometimes */
-        return streq(resolved, tty) || (streq(resolved, "tty0") && tty_is_vc(tty));
+        return path_equal(resolved, tty) || (streq(resolved, "tty0") && tty_is_vc(tty));
 }
 
-bool exec_context_may_touch_console(const ExecContext *ec) {
+static bool exec_context_may_touch_tty(const ExecContext *ec) {
+        assert(ec);
 
-        return (ec->tty_reset ||
+        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)) &&
+                is_terminal_output(ec->std_error);
+}
+
+bool exec_context_may_touch_console(const ExecContext *ec) {
+
+        return exec_context_may_touch_tty(ec) &&
                tty_may_match_dev_console(exec_context_tty_path(ec));
 }
 
@@ -4211,7 +4286,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                 "%sIgnoreSIGPIPE: %s\n"
                 "%sMemoryDenyWriteExecute: %s\n"
                 "%sRestrictRealtime: %s\n"
-                "%sKeyringMode: %s\n",
+                "%sRestrictSUIDSGID: %s\n"
+                "%sKeyringMode: %s\n"
+                "%sProtectHostname: %s\n",
                 prefix, c->umask,
                 prefix, c->working_directory ? c->working_directory : "/",
                 prefix, c->root_directory ? c->root_directory : "/",
@@ -4229,7 +4306,9 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                 prefix, yes_no(c->ignore_sigpipe),
                 prefix, yes_no(c->memory_deny_write_execute),
                 prefix, yes_no(c->restrict_realtime),
-                prefix, exec_keyring_mode_to_string(c->keyring_mode));
+                prefix, yes_no(c->restrict_suid_sgid),
+                prefix, exec_keyring_mode_to_string(c->keyring_mode),
+                prefix, yes_no(c->protect_hostname));
 
         if (c->root_image)
                 fprintf(f, "%sRootImage: %s\n", prefix, c->root_image);
@@ -4583,6 +4662,11 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                                 prefix, s);
         }
 
+        if (c->network_namespace_path)
+                fprintf(f,
+                        "%sNetworkNamespacePath: %s\n",
+                        prefix, c->network_namespace_path);
+
         if (c->syscall_errno > 0) {
                 const char *errno_name;
 
@@ -4594,11 +4678,6 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) {
                 else
                         fprintf(f, "%d\n", c->syscall_errno);
         }
-
-        if (c->apparmor_profile)
-                fprintf(f,
-                        "%sAppArmorProfile: %s%s\n",
-                        prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
 }
 
 bool exec_context_maintains_privileges(const ExecContext *c) {
@@ -4642,6 +4721,30 @@ void exec_context_free_log_extra_fields(ExecContext *c) {
         c->n_log_extra_fields = 0;
 }
 
+void exec_context_revert_tty(ExecContext *c) {
+        int r;
+
+        assert(c);
+
+        /* First, reset the TTY (possibly kicking everybody else from the TTY) */
+        exec_context_tty_reset(c, NULL);
+
+        /* And then undo what chown_terminal() did earlier. Note that we only do this if we have a path
+         * configured. If the TTY was passed to us as file descriptor we assume the TTY is opened and managed
+         * by whoever passed it to us and thus knows better when and how to chmod()/chown() it back. */
+
+        if (exec_context_may_touch_tty(c)) {
+                const char *path;
+
+                path = exec_context_tty_path(c);
+                if (path) {
+                        r = chmod_and_chown(path, TTY_MODE, 0, TTY_GID);
+                        if (r < 0 && r != -ENOENT)
+                                log_warning_errno(r, "Failed to reset TTY ownership/access mode of %s, ignoring: %m", path);
+                }
+        }
+}
+
 void exec_status_start(ExecStatus *s, pid_t pid) {
         assert(s);
 
@@ -4666,12 +4769,8 @@ void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int
         s->code = code;
         s->status = status;
 
-        if (context) {
-                if (context->utmp_id)
-                        (void) utmp_put_dead_process(context->utmp_id, pid, code, status);
-
-                exec_context_tty_reset(context, NULL);
-        }
+        if (context && context->utmp_id)
+                (void) utmp_put_dead_process(context->utmp_id, pid, code, status);
 }
 
 void exec_status_reset(ExecStatus *s) {
@@ -4887,18 +4986,23 @@ static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) {
 }
 
 static void exec_runtime_freep(ExecRuntime **rt) {
-        if (*rt)
-                (void) exec_runtime_free(*rt, false);
+        (void) exec_runtime_free(*rt, false);
 }
 
-static int exec_runtime_allocate(ExecRuntime **rt) {
-        assert(rt);
+static int exec_runtime_allocate(ExecRuntime **ret) {
+        ExecRuntime *n;
 
-        *rt = new0(ExecRuntime, 1);
-        if (!*rt)
+        assert(ret);
+
+        n = new(ExecRuntime, 1);
+        if (!n)
                 return -ENOMEM;
 
-        (*rt)->netns_storage_socket[0] = (*rt)->netns_storage_socket[1] = -1;
+        *n = (ExecRuntime) {
+                .netns_storage_socket = { -1, -1 },
+        };
+
+        *ret = n;
         return 0;
 }
 
@@ -4961,7 +5065,7 @@ static int exec_runtime_add(
 
 static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, ExecRuntime **ret) {
         _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL;
-        _cleanup_close_pair_ int netns_storage_socket[2] = {-1, -1};
+        _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 };
         int r;
 
         assert(m);
@@ -4969,7 +5073,7 @@ static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, E
         assert(id);
 
         /* It is not necessary to create ExecRuntime object. */
-        if (!c->private_network && !c->private_tmp)
+        if (!c->private_network && !c->private_tmp && !c->network_namespace_path)
                 return 0;
 
         if (c->private_tmp) {
@@ -4978,7 +5082,7 @@ static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, E
                         return r;
         }
 
-        if (c->private_network) {
+        if (c->private_network || c->network_namespace_path) {
                 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, netns_storage_socket) < 0)
                         return -errno;
         }
@@ -4988,8 +5092,7 @@ static int exec_runtime_make(Manager *m, const ExecContext *c, const char *id, E
                 return r;
 
         /* Avoid cleanup */
-        netns_storage_socket[0] = -1;
-        netns_storage_socket[1] = -1;
+        netns_storage_socket[0] = netns_storage_socket[1] = -1;
         return 1;
 }
 
index 7c909e5..e337b66 100644 (file)
@@ -19,6 +19,7 @@ typedef struct Manager Manager;
 #include "missing_resource.h"
 #include "namespace.h"
 #include "nsflags.h"
+#include "time-util.h"
 
 #define EXEC_STDIN_DATA_MAX (64U*1024U*1024U)
 
@@ -79,9 +80,9 @@ typedef enum ExecKeyringMode {
 
 /* Contains start and exit information about an executed command.  */
 struct ExecStatus {
-        pid_t pid;
         dual_timestamp start_timestamp;
         dual_timestamp exit_timestamp;
+        pid_t pid;
         int code;     /* as in siginfo_t::si_code */
         int status;   /* as in sigingo_t::si_status */
 };
@@ -91,6 +92,7 @@ typedef enum ExecCommandFlags {
         EXEC_COMMAND_FULLY_PRIVILEGED = 1 << 1,
         EXEC_COMMAND_NO_SETUID        = 1 << 2,
         EXEC_COMMAND_AMBIENT_MAGIC    = 1 << 3,
+        EXEC_COMMAND_NO_ENV_EXPAND    = 1 << 4,
 } ExecCommandFlags;
 
 /* Stores information about commands we execute. Covers both configuration settings as well as runtime data. */
@@ -147,8 +149,21 @@ struct ExecContext {
 
         struct rlimit *rlimit[_RLIMIT_MAX];
         char *working_directory, *root_directory, *root_image;
-        bool working_directory_missing_ok;
-        bool working_directory_home;
+        bool working_directory_missing_ok:1;
+        bool working_directory_home:1;
+
+        bool oom_score_adjust_set:1;
+        bool nice_set:1;
+        bool ioprio_set:1;
+        bool cpu_sched_set:1;
+
+        /* This is not exposed to the user but available internally. We need it to make sure that whenever we
+         * spawn /usr/bin/mount it is run in the same process group as us so that the autofs logic detects
+         * that it belongs to us and we don't enter a trigger loop. */
+        bool same_pgrp;
+
+        bool cpu_sched_reset_on_fork;
+        bool non_blocking;
 
         mode_t umask;
         int oom_score_adjust;
@@ -157,12 +172,13 @@ struct ExecContext {
         int cpu_sched_policy;
         int cpu_sched_priority;
 
-        cpu_set_t *cpuset;
         unsigned cpuset_ncpus;
+        cpu_set_t *cpuset;
 
         ExecInput std_input;
         ExecOutput std_output;
         ExecOutput std_error;
+        bool stdio_as_fds;
         char *stdio_fdname[3];
         char *stdio_file[3];
 
@@ -171,8 +187,6 @@ struct ExecContext {
 
         nsec_t timer_slack_nsec;
 
-        bool stdio_as_fds;
-
         char *tty_path;
 
         bool tty_reset;
@@ -181,6 +195,8 @@ struct ExecContext {
 
         bool ignore_sigpipe;
 
+        ExecKeyringMode keyring_mode;
+
         /* Since resolving these names might involve socket
          * connections and we don't want to deadlock ourselves these
          * names are resolved on execution only and in the child
@@ -194,16 +210,15 @@ struct ExecContext {
         char *utmp_id;
         ExecUtmpMode utmp_mode;
 
-        bool selinux_context_ignore;
-        char *selinux_context;
+        bool no_new_privileges;
 
+        bool selinux_context_ignore;
         bool apparmor_profile_ignore;
-        char *apparmor_profile;
-
         bool smack_process_label_ignore;
-        char *smack_process_label;
 
-        ExecKeyringMode keyring_mode;
+        char *selinux_context;
+        char *apparmor_profile;
+        char *smack_process_label;
 
         char **read_write_paths, **read_only_paths, **inaccessible_paths;
         unsigned long mount_flags;
@@ -219,10 +234,8 @@ struct ExecContext {
         int secure_bits;
 
         int syslog_priority;
-        char *syslog_identifier;
         bool syslog_level_prefix;
-
-        int log_level_max;
+        char *syslog_identifier;
 
         struct iovec* log_extra_fields;
         size_t n_log_extra_fields;
@@ -230,34 +243,30 @@ struct ExecContext {
         usec_t log_rate_limit_interval_usec;
         unsigned log_rate_limit_burst;
 
-        bool cpu_sched_reset_on_fork;
-        bool non_blocking;
+        int log_level_max;
+
         bool private_tmp;
         bool private_network;
         bool private_devices;
         bool private_users;
         bool private_mounts;
-        ProtectSystem protect_system;
-        ProtectHome protect_home;
         bool protect_kernel_tunables;
         bool protect_kernel_modules;
         bool protect_control_groups;
+        ProtectSystem protect_system;
+        ProtectHome protect_home;
+        bool protect_hostname;
         bool mount_apivfs;
 
-        bool no_new_privileges;
-
         bool dynamic_user;
         bool remove_ipc;
 
-        /* This is not exposed to the user but available
-         * internally. We need it to make sure that whenever we spawn
-         * /usr/bin/mount it is run in the same process group as us so
-         * that the autofs logic detects that it belongs to us and we
-         * don't enter a trigger loop. */
-        bool same_pgrp;
+        bool memory_deny_write_execute;
+        bool restrict_realtime;
+        bool restrict_suid_sgid;
 
-        unsigned long personality;
         bool lock_personality;
+        unsigned long personality;
 
         unsigned long restrict_namespaces; /* The CLONE_NEWxyz flags permitted to the unit's processes */
 
@@ -266,19 +275,13 @@ struct ExecContext {
         int syscall_errno;
         bool syscall_whitelist:1;
 
-        Set *address_families;
         bool address_families_whitelist:1;
+        Set *address_families;
 
-        ExecPreserveMode runtime_directory_preserve_mode;
-        ExecDirectory directories[_EXEC_DIRECTORY_TYPE_MAX];
-
-        bool memory_deny_write_execute;
-        bool restrict_realtime;
+        char *network_namespace_path;
 
-        bool oom_score_adjust_set:1;
-        bool nice_set:1;
-        bool ioprio_set:1;
-        bool cpu_sched_set:1;
+        ExecDirectory directories[_EXEC_DIRECTORY_TYPE_MAX];
+        ExecPreserveMode runtime_directory_preserve_mode;
 };
 
 static inline bool exec_context_restrict_namespaces_set(const ExecContext *c) {
@@ -372,6 +375,8 @@ int exec_context_get_effective_ioprio(const ExecContext *c);
 
 void exec_context_free_log_extra_fields(ExecContext *c);
 
+void exec_context_revert_tty(ExecContext *c);
+
 void exec_status_start(ExecStatus *s, pid_t pid);
 void exec_status_exit(ExecStatus *s, const ExecContext *context, pid_t pid, int code, int status);
 void exec_status_dump(const ExecStatus *s, FILE *f, const char *prefix);
index fd7c5f6..17072b0 100644 (file)
@@ -5,6 +5,9 @@
 ***/
 
 #include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
@@ -12,7 +15,6 @@
 #include "fileio.h"
 #include "ima-setup.h"
 #include "log.h"
-#include "util.h"
 
 #define IMA_SECFS_DIR "/sys/kernel/security/ima"
 #define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy"
index 59bb9d2..81f5f9c 100644 (file)
@@ -17,6 +17,7 @@
 #include "parse-util.h"
 #include "serialize.h"
 #include "set.h"
+#include "sort-util.h"
 #include "special.h"
 #include "stdio-util.h"
 #include "string-table.h"
@@ -1027,6 +1028,31 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive, bool alr
                         job_fail_dependencies(u, UNIT_CONFLICTED_BY);
         }
 
+        /* A special check to make sure we take down anything RequisiteOf if we
+         * aren't active. This is when the verify-active job merges with a
+         * satisfying job type, and then loses it's invalidation effect, as the
+         * result there is JOB_DONE for the start job we merged into, while we
+         * should be failing the depending job if the said unit isn't infact
+         * active. Oneshots are an example of this, where going directly from
+         * activating to inactive is success.
+         *
+         * This happens when you use ConditionXYZ= in a unit too, since in that
+         * case the job completes with the JOB_DONE result, but the unit never
+         * really becomes active. Note that such a case still involves merging:
+         *
+         * A start job waits for something else, and a verify-active comes in
+         * and merges in the installed job. Then, later, when it becomes
+         * runnable, it finishes with JOB_DONE result as execution on conditions
+         * not being met is skipped, breaking our dependency semantics.
+         *
+         * Also, depending on if start job waits or not, the merging may or may
+         * not happen (the verify-active job may trigger after it finishes), so
+         * you get undeterministic results without this check.
+         */
+        if (result == JOB_DONE && recursive && !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
+                if (IN_SET(t, JOB_START, JOB_RELOAD))
+                        job_fail_dependencies(u, UNIT_REQUISITE_OF);
+        }
         /* Trigger OnFailure dependencies that are not generated by
          * the unit itself. We don't treat JOB_CANCELED as failure in
          * this context. And JOB_FAILURE is already handled by the
index f3915be..43648b6 100644 (file)
@@ -22,9 +22,9 @@ struct KillContext {
         KillMode kill_mode;
         int kill_signal;
         int final_kill_signal;
+        int watchdog_signal;
         bool send_sigkill;
         bool send_sighup;
-        int watchdog_signal;
 };
 
 typedef enum KillWho {
index ef407af..e178a57 100644 (file)
@@ -74,6 +74,7 @@ $1.SystemCallErrorNumber,        config_parse_syscall_errno,         0,
 $1.MemoryDenyWriteExecute,       config_parse_bool,                  0,                             offsetof($1, exec_context.memory_deny_write_execute)
 $1.RestrictNamespaces,           config_parse_restrict_namespaces,   0,                             offsetof($1, exec_context)
 $1.RestrictRealtime,             config_parse_bool,                  0,                             offsetof($1, exec_context.restrict_realtime)
+$1.RestrictSUIDSGID,             config_parse_bool,                  0,                             offsetof($1, exec_context.restrict_suid_sgid)
 $1.RestrictAddressFamilies,      config_parse_address_families,      0,                             offsetof($1, exec_context)
 $1.LockPersonality,              config_parse_bool,                  0,                             offsetof($1, exec_context.lock_personality)',
 `$1.SystemCallFilter,            config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
@@ -82,6 +83,7 @@ $1.SystemCallErrorNumber,        config_parse_warn_compat,           DISABLED_CO
 $1.MemoryDenyWriteExecute,       config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.RestrictNamespaces,           config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.RestrictRealtime,             config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
+$1.RestrictSUIDSGID,             config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.RestrictAddressFamilies,      config_parse_warn_compat,           DISABLED_CONFIGURATION,        0
 $1.LockPersonality,              config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
 $1.LimitCPU,                     config_parse_rlimit,                RLIMIT_CPU,                    offsetof($1, exec_context.rlimit)
@@ -114,6 +116,7 @@ $1.PrivateDevices,               config_parse_bool,                  0,
 $1.ProtectKernelTunables,        config_parse_bool,                  0,                             offsetof($1, exec_context.protect_kernel_tunables)
 $1.ProtectKernelModules,         config_parse_bool,                  0,                             offsetof($1, exec_context.protect_kernel_modules)
 $1.ProtectControlGroups,         config_parse_bool,                  0,                             offsetof($1, exec_context.protect_control_groups)
+$1.NetworkNamespacePath,         config_parse_unit_path_printf,      0,                             offsetof($1, exec_context.network_namespace_path)
 $1.PrivateNetwork,               config_parse_bool,                  0,                             offsetof($1, exec_context.private_network)
 $1.PrivateUsers,                 config_parse_bool,                  0,                             offsetof($1, exec_context.private_users)
 $1.PrivateMounts,                config_parse_bool,                  0,                             offsetof($1, exec_context.private_mounts)
@@ -133,6 +136,7 @@ $1.LogsDirectoryMode,            config_parse_mode,                  0,
 $1.LogsDirectory,                config_parse_exec_directories,      0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_LOGS].paths)
 $1.ConfigurationDirectoryMode,   config_parse_mode,                  0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].mode)
 $1.ConfigurationDirectory,       config_parse_exec_directories,      0,                             offsetof($1, exec_context.directories[EXEC_DIRECTORY_CONFIGURATION].paths)
+$1.ProtectHostname,              config_parse_bool,                  0,                             offsetof($1, exec_context.protect_hostname)
 m4_ifdef(`HAVE_PAM',
 `$1.PAMName,                     config_parse_unit_string_printf,    0,                             offsetof($1, exec_context.pam_name)',
 `$1.PAMName,                     config_parse_warn_compat,           DISABLED_CONFIGURATION,        0')
@@ -165,6 +169,7 @@ $1.StartupCPUWeight,             config_parse_cg_weight,             0,
 $1.CPUShares,                    config_parse_cpu_shares,            0,                             offsetof($1, cgroup_context.cpu_shares)
 $1.StartupCPUShares,             config_parse_cpu_shares,            0,                             offsetof($1, cgroup_context.startup_cpu_shares)
 $1.CPUQuota,                     config_parse_cpu_quota,             0,                             offsetof($1, cgroup_context)
+$1.CPUQuotaPeriodSec,            config_parse_sec_def_infinity,      0,                             offsetof($1, cgroup_context.cpu_quota_period_usec)
 $1.MemoryAccounting,             config_parse_bool,                  0,                             offsetof($1, cgroup_context.memory_accounting)
 $1.MemoryMin,                    config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
 $1.MemoryLow,                    config_parse_memory_limit,          0,                             offsetof($1, cgroup_context)
@@ -433,12 +438,14 @@ EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
 CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
 KILL_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
 m4_dnl
-Timer.OnCalendar,                config_parse_timer,                 0,                             0
-Timer.OnActiveSec,               config_parse_timer,                 0,                             0
-Timer.OnBootSec,                 config_parse_timer,                 0,                             0
-Timer.OnStartupSec,              config_parse_timer,                 0,                             0
-Timer.OnUnitActiveSec,           config_parse_timer,                 0,                             0
-Timer.OnUnitInactiveSec,         config_parse_timer,                 0,                             0
+Timer.OnCalendar,                config_parse_timer,                 TIMER_CALENDAR,                0
+Timer.OnActiveSec,               config_parse_timer,                 TIMER_ACTIVE,                  0
+Timer.OnBootSec,                 config_parse_timer,                 TIMER_BOOT,                    0
+Timer.OnStartupSec,              config_parse_timer,                 TIMER_STARTUP,                 0
+Timer.OnUnitActiveSec,           config_parse_timer,                 TIMER_UNIT_ACTIVE,             0
+Timer.OnUnitInactiveSec,         config_parse_timer,                 TIMER_UNIT_INACTIVE,           0
+Timer.OnClockChange,             config_parse_bool,                  0,                             offsetof(Timer, on_clock_change)
+Timer.OnTimezoneChange,          config_parse_bool,                  0,                             offsetof(Timer, on_timezone_change)
 Timer.Persistent,                config_parse_bool,                  0,                             offsetof(Timer, persistent)
 Timer.WakeSystem,                config_parse_bool,                  0,                             offsetof(Timer, wake_system)
 Timer.RemainAfterElapse,         config_parse_bool,                  0,                             offsetof(Timer, remain_after_elapse)
index d1947fb..0fe4cb4 100644 (file)
 #include "ioprio.h"
 #include "ip-protocol-list.h"
 #include "journal-util.h"
+#include "limits-util.h"
 #include "load-fragment.h"
 #include "log.h"
 #include "missing.h"
 #include "mountpoint-util.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -54,6 +56,7 @@
 #include "unit-name.h"
 #include "unit-printf.h"
 #include "user-util.h"
+#include "time-util.h"
 #include "web-util.h"
 
 static int parse_socket_protocol(const char *s) {
@@ -309,23 +312,50 @@ int config_parse_unit_path_strv_printf(
                 if (r < 0)
                         return 0;
 
-                r = strv_push(x, k);
+                r = strv_consume(x, TAKE_PTR(k));
                 if (r < 0)
                         return log_oom();
-                k = NULL;
         }
 }
 
-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) {
+static int patch_var_run(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *lvalue,
+                char **path) {
+
+        const char *e;
+        char *z;
+
+        e = path_startswith(*path, "/var/run/");
+        if (!e)
+                return 0;
+
+        z = path_join("/run/", e);
+        if (!z)
+                return log_oom();
+
+        log_syntax(unit, LOG_NOTICE, filename, line, 0,
+                   "%s= references a path below legacy directory /var/run/, updating %s → %s; "
+                   "please update the unit file accordingly.", lvalue, *path, z);
+
+        free_and_replace(*path, z);
+
+        return 1;
+}
+
+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) {
 
         _cleanup_free_ SocketPort *p = NULL;
         SocketPort *tail;
@@ -362,6 +392,12 @@ int config_parse_socket_listen(const char *unit,
                 if (r < 0)
                         return 0;
 
+                if (ltype == SOCKET_FIFO) {
+                        r = patch_var_run(unit, filename, line, lvalue, &k);
+                        if (r < 0)
+                                return r;
+                }
+
                 free_and_replace(p->path, k);
                 p->type = ltype;
 
@@ -391,6 +427,12 @@ int config_parse_socket_listen(const char *unit,
                         return 0;
                 }
 
+                if (k[0] == '/') { /* Only for AF_UNIX file system sockets… */
+                        r = patch_var_run(unit, filename, line, lvalue, &k);
+                        if (r < 0)
+                                return r;
+                }
+
                 r = socket_address_parse_and_warn(&p->address, k);
                 if (r < 0) {
                         if (r != -EAFNOSUPPORT)
@@ -560,7 +602,8 @@ int config_parse_exec(
                 for (;;) {
                         /* We accept an absolute path as first argument.  If it's prefixed with - and the path doesn't
                          * exist, we ignore it instead of erroring out; if it's prefixed with @, we allow overriding of
-                         * argv[0]; if it's prefixed with +, it will be run with full privileges and no sandboxing; if
+                         * argv[0]; if it's prefixed with :, we will not do environment variable substitution;
+                         * if it's prefixed with +, it will be run with full privileges and no sandboxing; if
                          * it's prefixed with '!' we apply sandboxing, but do not change user/group credentials; if
                          * it's prefixed with '!!', then we apply user/group credentials if the kernel supports ambient
                          * capabilities -- if it doesn't we don't apply the credentials themselves, but do apply most
@@ -575,6 +618,8 @@ int config_parse_exec(
                                 ignore = true;
                         } else if (*f == '@' && !separate_argv0)
                                 separate_argv0 = true;
+                        else if (*f == ':' && !(flags & EXEC_COMMAND_NO_ENV_EXPAND))
+                                flags |= EXEC_COMMAND_NO_ENV_EXPAND;
                         else if (*f == '+' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
                                 flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
                         else if (*f == '!' && !(flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC)))
@@ -1485,24 +1530,24 @@ int config_parse_exec_smack_process_label(
         return 0;
 }
 
-int config_parse_timer(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_timer(
+                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_(calendar_spec_freep) CalendarSpec *c = NULL;
+        _cleanup_free_ char *k = NULL;
+        Unit *u = userdata;
         Timer *t = data;
         usec_t usec = 0;
         TimerValue *v;
-        TimerBase b;
-        _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
-        Unit *u = userdata;
-        _cleanup_free_ char *k = NULL;
         int r;
 
         assert(filename);
@@ -1516,36 +1561,35 @@ int config_parse_timer(const char *unit,
                 return 0;
         }
 
-        b = timer_base_from_string(lvalue);
-        if (b < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer base, ignoring: %s", lvalue);
-                return 0;
-        }
-
         r = unit_full_printf(u, rvalue, &k);
         if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in '%s', ignoring: %m", rvalue);
                 return 0;
         }
 
-        if (b == TIMER_CALENDAR) {
-                if (calendar_spec_from_string(k, &c) < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse calendar specification, ignoring: %s", k);
+        if (ltype == TIMER_CALENDAR) {
+                r = calendar_spec_from_string(k, &c);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse calendar specification, ignoring: %s", k);
                         return 0;
                 }
-        } else
-                if (parse_sec(k, &usec) < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse timer value, ignoring: %s", k);
+        } else {
+                r = parse_sec(k, &usec);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse timer value, ignoring: %s", k);
                         return 0;
                 }
+        }
 
-        v = new0(TimerValue, 1);
+        v = new(TimerValue, 1);
         if (!v)
                 return log_oom();
 
-        v->base = b;
-        v->value = usec;
-        v->calendar_spec = TAKE_PTR(c);
+        *v = (TimerValue) {
+                .base = ltype,
+                .value = usec,
+                .calendar_spec = TAKE_PTR(c),
+        };
 
         LIST_PREPEND(value, t->values, v);
 
@@ -2649,6 +2693,8 @@ int config_parse_unit_condition_null(
         assert(rvalue);
         assert(data);
 
+        log_syntax(unit, LOG_WARNING, filename, line, 0, "%s= is deprecated, please do not use.", lvalue);
+
         if (isempty(rvalue)) {
                 /* Empty assignment resets the list */
                 *list = condition_free_list(*list);
@@ -2828,7 +2874,11 @@ int config_parse_syscall_filter(
                         c->syscall_whitelist = true;
 
                         /* Accept default syscalls if we are on a whitelist */
-                        r = seccomp_parse_syscall_filter("@default", -1, c->syscall_filter, SECCOMP_PARSE_WHITELIST);
+                        r = seccomp_parse_syscall_filter(
+                                        "@default", -1, c->syscall_filter,
+                                        SECCOMP_PARSE_PERMISSIVE|SECCOMP_PARSE_WHITELIST,
+                                        unit,
+                                        NULL, 0);
                         if (r < 0)
                                 return r;
                 }
@@ -2855,9 +2905,12 @@ int config_parse_syscall_filter(
                         continue;
                 }
 
-                r = seccomp_parse_syscall_filter_full(name, num, c->syscall_filter,
-                                                      SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|(invert ? SECCOMP_PARSE_INVERT : 0)|(c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0),
-                                                      unit, filename, line);
+                r = seccomp_parse_syscall_filter(
+                                name, num, c->syscall_filter,
+                                SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE|
+                                (invert ? SECCOMP_PARSE_INVERT : 0)|
+                                (c->syscall_whitelist ? SECCOMP_PARSE_WHITELIST : 0),
+                                unit, filename, line);
                 if (r < 0)
                         return r;
         }
@@ -4387,7 +4440,6 @@ int config_parse_pid_file(
         _cleanup_free_ char *k = NULL, *n = NULL;
         Unit *u = userdata;
         char **s = data;
-        const char *e;
         int r;
 
         assert(filename);
@@ -4417,20 +4469,11 @@ int config_parse_pid_file(
         if (r < 0)
                 return r;
 
-        e = path_startswith(n, "/var/run/");
-        if (e) {
-                char *z;
-
-                z = strjoin("/run/", e);
-                if (!z)
-                        return log_oom();
-
-                log_syntax(unit, LOG_NOTICE, filename, line, 0, "PIDFile= references path below legacy directory /var/run/, updating %s → %s; please update the unit file accordingly.", n, z);
-
-                free_and_replace(*s, z);
-        } else
-                free_and_replace(*s, n);
+        r = patch_var_run(unit, filename, line, lvalue, &n);
+        if (r < 0)
+                return r;
 
+        free_and_replace(*s, n);
         return 0;
 }
 
index f613db8..2a2fb8b 100644 (file)
@@ -8,6 +8,7 @@
 #include "loopback-setup.h"
 #include "missing.h"
 #include "netlink-util.h"
+#include "time-util.h"
 
 #define LOOPBACK_SETUP_TIMEOUT_USEC (5 * USEC_PER_SEC)
 
index aae5480..9d3096e 100644 (file)
@@ -16,6 +16,7 @@
 #include "macro.h"
 #include "mkdir.h"
 #include "mountpoint-util.h"
+#include "namespace-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "stat-util.h"
index 441b02a..d2f27ce 100644 (file)
@@ -41,41 +41,48 @@ OrderWithRequires(preun): systemd \
 OrderWithRequires(postun): systemd \
 %{nil}
 
+%__systemd_someargs_0() %{error:This macro requires some arguments}
+%__systemd_twoargs_2() %{nil}
+
 %systemd_post() \
-if [ $1 -eq 1 ] ; then \
+%{expand:%%{?__systemd_someargs_%#}} \
+if [ $1 -eq 1 ] && [ -x @bindir@/systemctl ] ; then \
         # Initial installation \
-        systemctl --no-reload preset %{?*} >/dev/null 2>&1 || : \
+        @bindir@/systemctl --no-reload preset %{?*} || : \
 fi \
 %{nil}
 
 %systemd_user_post() %{expand:%systemd_post \\--global %%{?*}}
 
 %systemd_preun() \
-if [ $1 -eq 0 ] ; then \
+%{expand:%%{?__systemd_someargs_%#}} \
+if [ $1 -eq 0 ] && [ -x @bindir@/systemctl ] ; then \
         # Package removal, not upgrade \
-        systemctl --no-reload disable --now %{?*} >/dev/null 2>&1 || : \
+        @bindir@/systemctl --no-reload disable --now %{?*} || : \
 fi \
 %{nil}
 
 %systemd_user_preun() \
-if [ $1 -eq 0 ] ; then \
+%{expand:%%{?__systemd_someargs_%#}} \
+if [ $1 -eq 0 ] && [ -x @bindir@/systemctl ] ; then \
         # Package removal, not upgrade \
-        systemctl --global disable %{?*} >/dev/null 2>&1 || : \
+        @bindir@/systemctl --global disable %{?*} || : \
 fi \
 %{nil}
 
-%systemd_postun() %{nil}
+%systemd_postun() %{expand:%%{?__systemd_someargs_%#}}%{nil}
 
-%systemd_user_postun() %{nil}
+%systemd_user_postun() %{expand:%%{?__systemd_someargs_%#}}%{nil}
 
 %systemd_postun_with_restart() \
-if [ $1 -ge 1 ] ; then \
+%{expand:%%{?__systemd_someargs_%#}} \
+if [ $1 -ge 1 ] && [ -x @bindir@/systemctl ] ; then \
         # Package upgrade, not uninstall \
-        systemctl try-restart %{?*} >/dev/null 2>&1 || : \
+        @bindir@/systemctl try-restart %{?*} || : \
 fi \
 %{nil}
 
-%systemd_user_postun_with_restart() %{nil}
+%systemd_user_postun_with_restart() %{expand:%%{?__systemd_someargs_%#}}%{nil}
 
 %udev_hwdb_update() %{nil}
 
@@ -85,16 +92,18 @@ fi \
 
 # Deprecated. Use %tmpfiles_create_package instead
 %tmpfiles_create() \
-systemd-tmpfiles --create %{?*} >/dev/null 2>&1 || : \
+%{expand:%%{?__systemd_someargs_%#}} \
+[ -x @bindir@/systemd-tmpfiles ] && @bindir@/systemd-tmpfiles --create %{?*} || : \
 %{nil}
 
 # Deprecated. Use %sysusers_create_package instead
 %sysusers_create() \
-systemd-sysusers %{?*} >/dev/null 2>&1 || : \
+%{expand:%%{?__systemd_someargs_%#}} \
+[ -x @bindir@/systemd-sysusers ] && @bindir@/systemd-sysusers %{?*} || : \
 %{nil}
 
 %sysusers_create_inline() \
-systemd-sysusers - <<SYSTEMD_INLINE_EOF >/dev/null 2>&1 || : \
+[ -x @bindir@/systemd-sysusers ] && @bindir@/systemd-sysusers - <<SYSTEMD_INLINE_EOF || : \
 %{?*} \
 SYSTEMD_INLINE_EOF \
 %{nil}
@@ -113,6 +122,7 @@ SYSTEMD_INLINE_EOF \
 #   %files
 #   %{_sysusersdir}/%{name}.conf
 %sysusers_create_package() \
+%{expand:%%{?!__systemd_twoargs_%#:%%{error:This macro requires two arguments}}} \
 systemd-sysusers --replace=%_sysusersdir/%1.conf - <<SYSTEMD_INLINE_EOF >/dev/null 2>&1 || : \
 %(cat %2) \
 SYSTEMD_INLINE_EOF \
@@ -132,17 +142,20 @@ SYSTEMD_INLINE_EOF \
 #   %files
 #   %{_tmpfilesdir}/%{name}.conf
 %tmpfiles_create_package() \
+%{expand:%%{?!__systemd_twoargs_%#:%%{error:This macro requires two arguments}}} \
 systemd-tmpfiles --replace=%_tmpfilesdir/%1.conf --create - <<SYSTEMD_INLINE_EOF >/dev/null 2>&1 || : \
 %(cat %2) \
 SYSTEMD_INLINE_EOF \
 %{nil}
 
 %sysctl_apply() \
-@rootlibexecdir@/systemd-sysctl %{?*} >/dev/null 2>&1 || : \
+%{expand:%%{?__systemd_someargs_%#}} \
+[ -x @rootlibexecdir@/systemd-sysctl ] && @rootlibexecdir@/systemd-sysctl %{?*} || : \
 %{nil}
 
 %binfmt_apply() \
-@rootlibexecdir@/systemd-binfmt %{?*} >/dev/null 2>&1 || : \
+%{expand:%%{?__systemd_someargs_%#}} \
+[ -x @rootlibexecdir@/systemd-binfmt ] && @rootlibexecdir@/systemd-binfmt %{?*} || : \
 %{nil}
 
 
index 5e37978..a047ee2 100644 (file)
@@ -47,6 +47,7 @@
 #include "ima-setup.h"
 #include "killall.h"
 #include "kmod-setup.h"
+#include "limits-util.h"
 #include "load-fragment.h"
 #include "log.h"
 #include "loopback-setup.h"
@@ -137,11 +138,11 @@ static EmergencyAction arg_cad_burst_action = EMERGENCY_ACTION_REBOOT_FORCE;
 
 _noreturn_ static void freeze_or_exit_or_reboot(void) {
 
-        /* If we are running in a contianer, let's prefer exiting, after all we can propagate an exit code to the
-         * container manager, and thus inform it that something went wrong. */
+        /* If we are running in a container, let's prefer exiting, after all we can propagate an exit code to
+         * the container manager, and thus inform it that something went wrong. */
         if (detect_container() > 0) {
                 log_emergency("Exiting PID 1...");
-                exit(EXIT_EXCEPTION);
+                _exit(EXIT_EXCEPTION);
         }
 
         if (arg_crash_reboot) {
@@ -1382,7 +1383,7 @@ static int bump_rlimit_memlock(struct rlimit *saved_rlimit) {
 
 static void test_usr(void) {
 
-        /* Check that /usr is not a separate fs */
+        /* Check that /usr is either on the same file system as / or mounted already. */
 
         if (dir_is_empty("/usr") <= 0)
                 return;
@@ -1901,9 +1902,8 @@ static int invoke_main_loop(
                         *ret_shutdown_verb = NULL;
 
                         /* Steal the switch root parameters */
-                        *ret_switch_root_dir = m->switch_root;
-                        *ret_switch_root_init = m->switch_root_init;
-                        m->switch_root = m->switch_root_init = NULL;
+                        *ret_switch_root_dir = TAKE_PTR(m->switch_root);
+                        *ret_switch_root_init = TAKE_PTR(m->switch_root_init);
 
                         return 0;
 
@@ -2114,13 +2114,13 @@ static int do_queue_default_job(
 
         assert(target->load_state == UNIT_LOADED);
 
-        r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, &error, &default_unit_job);
+        r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, NULL, &error, &default_unit_job);
         if (r == -EPERM) {
                 log_debug_errno(r, "Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
 
                 sd_bus_error_free(&error);
 
-                r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &error, &default_unit_job);
+                r = manager_add_job(m, JOB_START, target, JOB_REPLACE, NULL, &error, &default_unit_job);
                 if (r < 0) {
                         *ret_error_message = "Failed to start default target";
                         return log_emergency_errno(r, "Failed to start default target: %s", bus_error_message(&error, r));
@@ -2373,8 +2373,7 @@ int main(int argc, char *argv[]) {
         (void) prctl(PR_SET_NAME, systemd);
 
         /* Save the original command line */
-        saved_argv = argv;
-        saved_argc = argc;
+        save_argc_argv(argc, argv);
 
         /* Make sure that if the user says "syslog" we actually log to the journal. */
         log_set_upgrade_syslog_to_journal(true);
index 1852fca..93e9b95 100644 (file)
 #include "log.h"
 #include "macro.h"
 #include "manager.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "mkdir.h"
 #include "parse-util.h"
 #include "path-lookup.h"
 #include "path-util.h"
+#include "plymouth-util.h"
 #include "process-util.h"
 #include "ratelimit.h"
 #include "rlimit-util.h"
@@ -77,7 +79,6 @@
 #include "umask-util.h"
 #include "unit-name.h"
 #include "user-util.h"
-#include "util.h"
 #include "virt.h"
 #include "watchdog.h"
 
@@ -291,10 +292,10 @@ static int manager_check_ask_password(Manager *m) {
 
                 m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
                 if (m->ask_password_inotify_fd < 0)
-                        return log_error_errno(errno, "inotify_init1() failed: %m");
+                        return log_error_errno(errno, "Failed to create inotify object: %m");
 
                 if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) {
-                        log_error_errno(errno, "Failed to add watch on /run/systemd/ask-password: %m");
+                        log_error_errno(errno, "Failed to watch \"/run/systemd/ask-password\": %m");
                         manager_close_ask_password(m);
                         return -errno;
                 }
@@ -587,6 +588,7 @@ static char** sanitize_environment(char **l) {
                         "MAINPID",
                         "MANAGERPID",
                         "NOTIFY_SOCKET",
+                        "PIDFILE",
                         "REMOTE_ADDR",
                         "REMOTE_PORT",
                         "SERVICE_RESULT",
@@ -1274,7 +1276,7 @@ static unsigned manager_dispatch_stop_when_unneeded_queue(Manager *m) {
                 }
 
                 /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
-                r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
+                r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
                 if (r < 0)
                         log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
         }
@@ -1644,6 +1646,8 @@ static void manager_ready(Manager *m) {
 
         /* Let's finally catch up with any changes that took place while we were reloading/reexecing */
         manager_catchup(m);
+
+        m->honor_device_enumeration = true;
 }
 
 static Manager* manager_reloading_start(Manager *m) {
@@ -1759,9 +1763,17 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
         return 0;
 }
 
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret) {
-        int r;
+int manager_add_job(
+                Manager *m,
+                JobType type,
+                Unit *unit,
+                JobMode mode,
+                Set *affected_jobs,
+                sd_bus_error *error,
+                Job **ret) {
+
         Transaction *tr;
+        int r;
 
         assert(m);
         assert(type < _JOB_TYPE_MAX);
@@ -1769,10 +1781,10 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
         assert(mode < _JOB_MODE_MAX);
 
         if (mode == JOB_ISOLATE && type != JOB_START)
-                return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
 
         if (mode == JOB_ISOLATE && !unit->allow_isolate)
-                return sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
+                return sd_bus_error_setf(error, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
 
         log_unit_debug(unit, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
 
@@ -1784,7 +1796,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
 
         r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false,
                                                  IN_SET(mode, JOB_IGNORE_DEPENDENCIES, JOB_IGNORE_REQUIREMENTS),
-                                                 mode == JOB_IGNORE_DEPENDENCIES, e);
+                                                 mode == JOB_IGNORE_DEPENDENCIES, error);
         if (r < 0)
                 goto tr_abort;
 
@@ -1794,7 +1806,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
                         goto tr_abort;
         }
 
-        r = transaction_activate(tr, m, mode, e);
+        r = transaction_activate(tr, m, mode, affected_jobs, error);
         if (r < 0)
                 goto tr_abort;
 
@@ -1802,8 +1814,8 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_e
                        "Enqueued job %s/%s as %u", unit->id,
                        job_type_to_string(type), (unsigned) tr->anchor_job->id);
 
-        if (_ret)
-                *_ret = tr->anchor_job;
+        if (ret)
+                *ret = tr->anchor_job;
 
         transaction_free(tr);
         return 0;
@@ -1814,7 +1826,7 @@ tr_abort:
         return r;
 }
 
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) {
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **ret) {
         Unit *unit = NULL;  /* just to appease gcc, initialization is not really necessary */
         int r;
 
@@ -1828,10 +1840,10 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode
                 return r;
         assert(unit);
 
-        return manager_add_job(m, type, unit, mode, e, ret);
+        return manager_add_job(m, type, unit, mode, affected_jobs, e, ret);
 }
 
-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) {
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, Job **ret) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         int r;
 
@@ -1840,7 +1852,7 @@ int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name,
         assert(name);
         assert(mode < _JOB_MODE_MAX);
 
-        r = manager_add_job_by_name(m, type, name, mode, &error, ret);
+        r = manager_add_job_by_name(m, type, name, mode, affected_jobs, &error, ret);
         if (r < 0)
                 return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r));
 
@@ -1868,7 +1880,7 @@ int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error
         /* Failure in adding individual dependencies is ignored, so this always succeeds. */
         transaction_add_propagate_reload_jobs(tr, unit, tr->anchor_job, mode == JOB_IGNORE_DEPENDENCIES, e);
 
-        r = transaction_activate(tr, m, mode, e);
+        r = transaction_activate(tr, m, mode, NULL, e);
         if (r < 0)
                 goto tr_abort;
 
@@ -2158,6 +2170,16 @@ void manager_clear_jobs(Manager *m) {
                 job_finish_and_invalidate(j, JOB_CANCELED, false, false);
 }
 
+void manager_unwatch_pid(Manager *m, pid_t pid) {
+        assert(m);
+
+        /* First let's drop the unit keyed as "pid". */
+        (void) hashmap_remove(m->watch_pids, PID_TO_PTR(pid));
+
+        /* Then, let's also drop the array keyed by -pid. */
+        free(hashmap_remove(m->watch_pids, PID_TO_PTR(-pid)));
+}
+
 static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
         Manager *m = userdata;
         Job *j;
@@ -2568,7 +2590,7 @@ static void manager_start_target(Manager *m, const char *name, JobMode mode) {
 
         log_debug("Activating special unit %s", name);
 
-        r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL);
+        r = manager_add_job_by_name(m, JOB_START, name, mode, NULL, &error, NULL);
         if (r < 0)
                 log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
 }
@@ -3085,7 +3107,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
         }
 
         if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) {
-                if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
+                if (!IN_SET(errno, EAGAIN, ENOENT) && !ERRNO_IS_DISCONNECT(errno))
                         log_error_errno(errno, "connect() failed: %m");
                 return;
         }
@@ -3097,7 +3119,7 @@ void manager_send_unit_plymouth(Manager *m, Unit *u) {
 
         errno = 0;
         if (write(fd, message, n + 1) != n + 1)
-                if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
+                if (!IN_SET(errno, EAGAIN, ENOENT) && !ERRNO_IS_DISCONNECT(errno))
                         log_error_errno(errno, "Failed to write Plymouth message: %m");
 }
 
@@ -3160,6 +3182,9 @@ int manager_serialize(
         (void) serialize_bool(f, "taint-logged", m->taint_logged);
         (void) serialize_bool(f, "service-watchdogs", m->service_watchdogs);
 
+        /* After switching root, udevd has not been started yet. So, enumeration results should not be emitted. */
+        (void) serialize_bool(f, "honor-device-enumeration", !switching_root);
+
         t = show_status_to_string(m->show_status);
         if (t)
                 (void) serialize_item(f, "show-status", t);
@@ -3398,6 +3423,15 @@ int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
                         else
                                 m->service_watchdogs = b;
 
+                } else if ((val = startswith(l, "honor-device-enumeration="))) {
+                        int b;
+
+                        b = parse_boolean(val);
+                        if (b < 0)
+                                log_notice("Failed to parse honor-device-enumeration flag '%s', ignoring.", val);
+                        else
+                                m->honor_device_enumeration = b;
+
                 } else if ((val = startswith(l, "show-status="))) {
                         ShowStatus s;
 
@@ -3598,6 +3632,11 @@ int manager_reload(Manager *m) {
         assert(m->n_reloading > 0);
         m->n_reloading--;
 
+        /* On manager reloading, device tag data should exists, thus, we should honor the results of device
+         * enumeration. The flag should be always set correctly by the serialized data, but it may fail. So,
+         * let's always set the flag here for safety. */
+        m->honor_device_enumeration = true;
+
         manager_ready(m);
 
         m->send_reloading_done = true;
@@ -3827,7 +3866,7 @@ static bool generator_path_any(const char* const* paths) {
         return found;
 }
 
-static const char* system_env_generator_binary_paths[] = {
+static const char *const system_env_generator_binary_paths[] = {
         "/run/systemd/system-environment-generators",
         "/etc/systemd/system-environment-generators",
         "/usr/local/lib/systemd/system-environment-generators",
@@ -3835,7 +3874,7 @@ static const char* system_env_generator_binary_paths[] = {
         NULL
 };
 
-static const char* user_env_generator_binary_paths[] = {
+static const char *const user_env_generator_binary_paths[] = {
         "/run/systemd/user-environment-generators",
         "/etc/systemd/user-environment-generators",
         "/usr/local/lib/systemd/user-environment-generators",
@@ -3845,7 +3884,7 @@ static const char* user_env_generator_binary_paths[] = {
 
 static int manager_run_environment_generators(Manager *m) {
         char **tmp = NULL; /* this is only used in the forked process, no cleanup here */
-        const char **paths;
+        const char *const *paths;
         void* args[] = {
                 [STDOUT_GENERATE] = &tmp,
                 [STDOUT_COLLECT] = &tmp,
@@ -3862,8 +3901,8 @@ static int manager_run_environment_generators(Manager *m) {
                 return 0;
 
         RUN_WITH_UMASK(0022)
-                r = execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, m->transient_environment);
-
+                r = execute_directories(paths, DEFAULT_TIMEOUT_USEC, gather_environment,
+                                        args, NULL, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
         return r;
 }
 
@@ -3897,8 +3936,8 @@ static int manager_run_generators(Manager *m) {
         argv[4] = NULL;
 
         RUN_WITH_UMASK(0022)
-                (void) execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC,
-                                           NULL, NULL, (char**) argv, m->transient_environment);
+                (void) execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, NULL, NULL,
+                                           (char**) argv, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
 
         r = 0;
 
index 48c0cbb..6005d42 100644 (file)
@@ -398,6 +398,8 @@ struct Manager {
          * multiple times on the same unit. */
         unsigned sigchldgen;
         unsigned notifygen;
+
+        bool honor_device_enumeration;
 };
 
 #define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
@@ -428,9 +430,9 @@ int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_err
 int manager_load_startable_unit_or_warn(Manager *m, const char *name, const char *path, Unit **ret);
 int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u);
 
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret);
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Set *affected_jobs,  Job **ret);
 int manager_propagate_reload(Manager *m, Unit *unit, JobMode mode, sd_bus_error *e);
 
 void manager_dump_units(Manager *s, FILE *f, const char *prefix);
@@ -440,6 +442,8 @@ int manager_get_dump_string(Manager *m, char **ret);
 
 void manager_clear_jobs(Manager *m);
 
+void manager_unwatch_pid(Manager *m, pid_t pid);
+
 unsigned manager_dispatch_load_queue(Manager *m);
 
 int manager_default_environment(Manager *m);
index 3d31d2d..9b159c4 100644 (file)
@@ -1,6 +1,17 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
-libcore_la_sources = '''
+libcore_shared_sources = '''
+        killall.c
+        killall.h
+        loopback-setup.c
+        loopback-setup.h
+        machine-id-setup.c
+        machine-id-setup.h
+        mount-setup.c
+        mount-setup.h
+'''.split()
+
+libcore_sources = '''
         audit-fd.c
         audit-fd.h
         automount.c
@@ -75,8 +86,6 @@ libcore_la_sources = '''
         job.h
         kill.c
         kill.h
-        killall.c
-        killall.h
         kmod-setup.c
         kmod-setup.h
         load-dropin.c
@@ -85,14 +94,8 @@ libcore_la_sources = '''
         load-fragment.h
         locale-setup.c
         locale-setup.h
-        loopback-setup.c
-        loopback-setup.h
-        machine-id-setup.c
-        machine-id-setup.h
         manager.c
         manager.h
-        mount-setup.c
-        mount-setup.h
         mount.c
         mount.h
         namespace.c
@@ -150,13 +153,24 @@ load_fragment_gperf_nulstr_c = custom_target(
         command : [awk, '-f', '@INPUT0@', '@INPUT1@'],
         capture : true)
 
+# A convenience library to share code with other binaries:
+# systemd-shutdown, systemd-remount-fs, systemd-machine-id-setup, …
+libcore_shared = static_library(
+        'core-shared',
+        libcore_shared_sources,
+        include_directories : includes,
+        dependencies : [versiondep,
+                        libmount])
+
 libcore = static_library(
         'core',
-        libcore_la_sources,
+        libcore_sources,
         load_fragment_gperf_c,
         load_fragment_gperf_nulstr_c,
         include_directories : includes,
-        dependencies : [threads,
+        link_whole : libcore_shared,
+        dependencies : [versiondep,
+                        threads,
                         libcap,
                         librt,
                         libseccomp,
@@ -169,16 +183,6 @@ libcore = static_library(
 
 systemd_sources = files('main.c')
 
-systemd_shutdown_sources = files('''
-        shutdown.c
-        umount.c
-        umount.h
-        mount-setup.c
-        mount-setup.h
-        killall.c
-        killall.h
-'''.split())
-
 in_files = [['macros.systemd',   rpmmacrosdir],
             ['system.conf',      pkgsysconfdir],
             ['systemd.pc',       pkgconfigdatadir],
index c4b2e32..ac72229 100644 (file)
 #include "mkdir.h"
 #include "mount-setup.h"
 #include "mountpoint-util.h"
+#include "nulstr-util.h"
 #include "path-util.h"
 #include "set.h"
 #include "smack-util.h"
 #include "strv.h"
 #include "user-util.h"
-#include "util.h"
 #include "virt.h"
 
 typedef enum MountMode {
index c31cad6..b7fd35f 100644 (file)
@@ -5,18 +5,16 @@
 #include <stdio.h>
 #include <sys/epoll.h>
 
-#include <libmount.h>
-
 #include "sd-messages.h"
 
 #include "alloc-util.h"
 #include "dbus-mount.h"
 #include "dbus-unit.h"
 #include "device.h"
-#include "escape.h"
 #include "exit-status.h"
 #include "format-util.h"
 #include "fstab-util.h"
+#include "libmount-util.h"
 #include "log.h"
 #include "manager.h"
 #include "mkdir.h"
@@ -36,9 +34,6 @@
 
 #define RETRY_UMOUNT_MAX 32
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table);
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter);
-
 static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
         [MOUNT_DEAD] = UNIT_INACTIVE,
         [MOUNT_MOUNTING] = UNIT_ACTIVATING,
@@ -101,20 +96,6 @@ static bool mount_is_bind(const MountParameters *p) {
         return false;
 }
 
-static bool mount_is_auto(const MountParameters *p) {
-        assert(p);
-
-        return !fstab_test_option(p->options, "noauto\0");
-}
-
-static bool mount_is_automount(const MountParameters *p) {
-        assert(p);
-
-        return fstab_test_option(p->options,
-                                 "comment=systemd.automount\0"
-                                 "x-systemd.automount\0");
-}
-
 static bool mount_is_bound_to_device(const Mount *m) {
         const MountParameters *p;
 
@@ -338,7 +319,6 @@ static int mount_add_mount_dependencies(Mount *m) {
 }
 
 static int mount_add_device_dependencies(Mount *m) {
-        bool device_wants_mount;
         UnitDependencyMask mask;
         MountParameters *p;
         UnitDependency dep;
@@ -368,9 +348,6 @@ static int mount_add_device_dependencies(Mount *m) {
         if (path_equal(m->where, "/"))
                 return 0;
 
-        device_wants_mount =
-                mount_is_auto(p) && !mount_is_automount(p) && MANAGER_IS_SYSTEM(UNIT(m)->manager);
-
         /* Mount units from /proc/self/mountinfo are not bound to devices
          * by default since they're subject to races when devices are
          * unplugged. But the user can still force this dep with an
@@ -381,7 +358,7 @@ static int mount_add_device_dependencies(Mount *m) {
         /* We always use 'what' from /proc/self/mountinfo if mounted */
         mask = m->from_proc_self_mountinfo ? UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT : UNIT_DEPENDENCY_FILE;
 
-        r = unit_add_node_dependency(UNIT(m), p->what, device_wants_mount, dep, mask);
+        r = unit_add_node_dependency(UNIT(m), p->what, false, dep, mask);
         if (r < 0)
                 return r;
 
@@ -722,7 +699,7 @@ static int mount_coldplug(Unit *u) {
             pid_is_unwaited(m->control_pid) &&
             MOUNT_STATE_WITH_PROCESS(new_state)) {
 
-                r = unit_watch_pid(UNIT(m), m->control_pid);
+                r = unit_watch_pid(UNIT(m), m->control_pid, false);
                 if (r < 0)
                         return r;
 
@@ -828,9 +805,8 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
         if (r < 0)
                 return r;
 
-        r = unit_watch_pid(UNIT(m), pid);
+        r = unit_watch_pid(UNIT(m), pid, true);
         if (r < 0)
-                /* FIXME: we need to do something here */
                 return r;
 
         *_pid = pid;
@@ -1122,7 +1098,7 @@ static int mount_start(Unit *u) {
 
         assert(IN_SET(m->state, MOUNT_DEAD, MOUNT_FAILED));
 
-        r = unit_start_limit_test(u);
+        r = unit_test_start_limit(u);
         if (r < 0) {
                 mount_enter_dead(m, MOUNT_FAILURE_START_LIMIT_HIT);
                 return r;
@@ -1639,7 +1615,6 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
         for (;;) {
                 struct libmnt_fs *fs;
                 const char *device, *path, *options, *fstype;
-                _cleanup_free_ char *d = NULL, *p = NULL;
                 int k;
 
                 k = mnt_table_next_fs(t, i, &fs);
@@ -1656,15 +1631,9 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
                 if (!device || !path)
                         continue;
 
-                if (cunescape(device, UNESCAPE_RELAX, &d) < 0)
-                        return log_oom();
-
-                if (cunescape(path, UNESCAPE_RELAX, &p) < 0)
-                        return log_oom();
-
-                device_found_node(m, d, DEVICE_FOUND_MOUNT, DEVICE_FOUND_MOUNT);
+                device_found_node(m, device, DEVICE_FOUND_MOUNT, DEVICE_FOUND_MOUNT);
 
-                (void) mount_setup_unit(m, d, p, options, fstype, set_flags);
+                (void) mount_setup_unit(m, device, path, options, fstype, set_flags);
         }
 
         return 0;
@@ -1938,7 +1907,7 @@ static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
 
         assert(m);
 
-        return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
+        return unit_kill_common(u, who, signo, -1, m->control_pid, error);
 }
 
 static int mount_control_pid(Unit *u) {
index 7f553a4..8475145 100644 (file)
 #include "mkdir.h"
 #include "mount-util.h"
 #include "mountpoint-util.h"
+#include "namespace-util.h"
 #include "namespace.h"
+#include "nulstr-util.h"
 #include "path-util.h"
 #include "selinux-util.h"
 #include "socket-util.h"
+#include "sort-util.h"
 #include "stat-util.h"
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
 #include "umask-util.h"
 #include "user-util.h"
-#include "util.h"
 
 #define DEV_MOUNT_OPTIONS (MS_NOSUID|MS_STRICTATIME|MS_NOEXEC)
 
@@ -49,6 +51,8 @@ typedef enum MountMode {
         READONLY,
         READWRITE,
         TMPFS,
+        READWRITE_IMPLICIT, /* Should have the lowest priority. */
+        _MOUNT_MODE_MAX,
 } MountMode;
 
 typedef struct MountEntry {
@@ -57,6 +61,7 @@ typedef struct MountEntry {
         bool ignore:1;            /* Ignore if path does not exist? */
         bool has_prefix:1;        /* Already is prefixed by the root dir? */
         bool read_only:1;         /* Shall this mount point be read-only? */
+        bool nosuid:1;            /* Shall set MS_NOSUID on the mount itself */
         bool applied:1;           /* Already applied */
         char *path_malloc;        /* Use this instead of 'path_const' if we had to allocate memory */
         const char *source_const; /* The source path, for bind mounts */
@@ -77,26 +82,26 @@ static const MountEntry apivfs_table[] = {
 
 /* ProtectKernelTunables= option and the related filesystem APIs */
 static const MountEntry protect_kernel_tunables_table[] = {
-        { "/proc/acpi",          READONLY,     true  },
-        { "/proc/apm",           READONLY,     true  }, /* Obsolete API, there's no point in permitting access to this, ever */
-        { "/proc/asound",        READONLY,     true  },
-        { "/proc/bus",           READONLY,     true  },
-        { "/proc/fs",            READONLY,     true  },
-        { "/proc/irq",           READONLY,     true  },
-        { "/proc/kallsyms",      INACCESSIBLE, true  },
-        { "/proc/kcore",         INACCESSIBLE, true  },
-        { "/proc/latency_stats", READONLY,     true  },
-        { "/proc/mtrr",          READONLY,     true  },
-        { "/proc/scsi",          READONLY,     true  },
-        { "/proc/sys",           READONLY,     false },
-        { "/proc/sysrq-trigger", READONLY,     true  },
-        { "/proc/timer_stats",   READONLY,     true  },
-        { "/sys",                READONLY,     false },
-        { "/sys/fs/bpf",         READONLY,     true  },
-        { "/sys/fs/cgroup",      READWRITE,    false }, /* READONLY is set by ProtectControlGroups= option */
-        { "/sys/fs/selinux",     READWRITE,    true  },
-        { "/sys/kernel/debug",   READONLY,     true  },
-        { "/sys/kernel/tracing", READONLY,     true  },
+        { "/proc/acpi",          READONLY,           true  },
+        { "/proc/apm",           READONLY,           true  }, /* Obsolete API, there's no point in permitting access to this, ever */
+        { "/proc/asound",        READONLY,           true  },
+        { "/proc/bus",           READONLY,           true  },
+        { "/proc/fs",            READONLY,           true  },
+        { "/proc/irq",           READONLY,           true  },
+        { "/proc/kallsyms",      INACCESSIBLE,       true  },
+        { "/proc/kcore",         INACCESSIBLE,       true  },
+        { "/proc/latency_stats", READONLY,           true  },
+        { "/proc/mtrr",          READONLY,           true  },
+        { "/proc/scsi",          READONLY,           true  },
+        { "/proc/sys",           READONLY,           false },
+        { "/proc/sysrq-trigger", READONLY,           true  },
+        { "/proc/timer_stats",   READONLY,           true  },
+        { "/sys",                READONLY,           false },
+        { "/sys/fs/bpf",         READONLY,           true  },
+        { "/sys/fs/cgroup",      READWRITE_IMPLICIT, false }, /* READONLY is set by ProtectControlGroups= option */
+        { "/sys/fs/selinux",     READWRITE_IMPLICIT, true  },
+        { "/sys/kernel/debug",   READONLY,           true  },
+        { "/sys/kernel/tracing", READONLY,           true  },
 };
 
 /* ProtectKernelModules= option */
@@ -171,15 +176,33 @@ static const MountEntry protect_system_full_table[] = {
  * shall manage those, orthogonally).
  */
 static const MountEntry protect_system_strict_table[] = {
-        { "/",                   READONLY,     false },
-        { "/proc",               READWRITE,    false },      /* ProtectKernelTunables= */
-        { "/sys",                READWRITE,    false },      /* ProtectKernelTunables= */
-        { "/dev",                READWRITE,    false },      /* PrivateDevices= */
-        { "/home",               READWRITE,    true  },      /* ProtectHome= */
-        { "/run/user",           READWRITE,    true  },      /* ProtectHome= */
-        { "/root",               READWRITE,    true  },      /* ProtectHome= */
+        { "/",                   READONLY,           false },
+        { "/proc",               READWRITE_IMPLICIT, false },      /* ProtectKernelTunables= */
+        { "/sys",                READWRITE_IMPLICIT, false },      /* ProtectKernelTunables= */
+        { "/dev",                READWRITE_IMPLICIT, false },      /* PrivateDevices= */
+        { "/home",               READWRITE_IMPLICIT, true  },      /* ProtectHome= */
+        { "/run/user",           READWRITE_IMPLICIT, true  },      /* ProtectHome= */
+        { "/root",               READWRITE_IMPLICIT, true  },      /* ProtectHome= */
 };
 
+static const char * const mount_mode_table[_MOUNT_MODE_MAX] = {
+        [INACCESSIBLE]         = "inaccessible",
+        [BIND_MOUNT]           = "bind",
+        [BIND_MOUNT_RECURSIVE] = "rbind",
+        [PRIVATE_TMP]          = "private-tmp",
+        [PRIVATE_DEV]          = "private-dev",
+        [BIND_DEV]             = "bind-dev",
+        [EMPTY_DIR]            = "empty",
+        [SYSFS]                = "sysfs",
+        [PROCFS]               = "procfs",
+        [READONLY]             = "read-only",
+        [READWRITE]            = "read-write",
+        [TMPFS]                = "tmpfs",
+        [READWRITE_IMPLICIT]   = "rw-implicit",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(mount_mode, MountMode);
+
 static const char *mount_entry_path(const MountEntry *p) {
         assert(p);
 
@@ -220,7 +243,7 @@ static int append_access_mounts(MountEntry **p, char **strv, MountMode mode, boo
 
         assert(p);
 
-        /* Adds a list of user-supplied READWRITE/READONLY/INACCESSIBLE entries */
+        /* Adds a list of user-supplied READWRITE/READWRITE_IMPLICIT/READONLY/INACCESSIBLE entries */
 
         STRV_FOREACH(i, strv) {
                 bool ignore = false, needs_prefix = false;
@@ -286,6 +309,7 @@ static int append_bind_mounts(MountEntry **p, const BindMount *binds, size_t n)
                         .path_const = b->destination,
                         .mode = b->recursive ? BIND_MOUNT_RECURSIVE : BIND_MOUNT,
                         .read_only = b->read_only,
+                        .nosuid = b->nosuid,
                         .source_const = b->source,
                         .ignore = b->ignore_enoent,
                 };
@@ -446,7 +470,7 @@ static void drop_duplicates(MountEntry *m, size_t *n) {
                 if (previous &&
                     path_equal(mount_entry_path(f), mount_entry_path(previous)) &&
                     !f->applied && !previous->applied) {
-                        log_debug("%s is duplicate.", mount_entry_path(f));
+                        log_debug("%s (%s) is duplicate.", mount_entry_path(f), mount_mode_to_string(f->mode));
                         previous->read_only = previous->read_only || mount_entry_read_only(f); /* Propagate the read-only flag to the remaining entry */
                         mount_entry_done(f);
                         continue;
@@ -500,8 +524,8 @@ static void drop_nop(MountEntry *m, size_t *n) {
 
         for (f = m, t = m; f < m + *n; f++) {
 
-                /* Only suppress such subtrees for READONLY and READWRITE entries */
-                if (IN_SET(f->mode, READONLY, READWRITE)) {
+                /* Only suppress such subtrees for READONLY, READWRITE and READWRITE_IMPLICIT entries */
+                if (IN_SET(f->mode, READONLY, READWRITE, READWRITE_IMPLICIT)) {
                         MountEntry *p;
                         bool found = false;
 
@@ -515,7 +539,9 @@ static void drop_nop(MountEntry *m, size_t *n) {
 
                         /* We found it, let's see if it's the same mode, if so, we can drop this entry */
                         if (found && p->mode == f->mode) {
-                                log_debug("%s is redundant by %s", mount_entry_path(f), mount_entry_path(p));
+                                log_debug("%s (%s) is made redundant by %s (%s)",
+                                          mount_entry_path(f), mount_mode_to_string(f->mode),
+                                          mount_entry_path(p), mount_mode_to_string(p->mode));
                                 mount_entry_done(f);
                                 continue;
                         }
@@ -736,27 +762,27 @@ static int mount_private_dev(MountEntry *m) {
                 goto fail;
         }
 
-        rmdir(dev);
-        rmdir(temporary_mount);
+        (void) rmdir(dev);
+        (void) rmdir(temporary_mount);
 
         return 0;
 
 fail:
         if (devpts)
-                umount(devpts);
+                (void) umount(devpts);
 
         if (devshm)
-                umount(devshm);
+                (void) umount(devshm);
 
         if (devhugepages)
-                umount(devhugepages);
+                (void) umount(devhugepages);
 
         if (devmqueue)
-                umount(devmqueue);
+                (void) umount(devmqueue);
 
-        umount(dev);
-        rmdir(dev);
-        rmdir(temporary_mount);
+        (void) umount(dev);
+        (void) rmdir(dev);
+        (void) rmdir(temporary_mount);
 
         return r;
 }
@@ -908,6 +934,7 @@ static int apply_mount(
 
         case READONLY:
         case READWRITE:
+        case READWRITE_IMPLICIT:
                 r = path_is_mount_point(mount_entry_path(m), root_directory, 0);
                 if (r == -ENOENT && m->ignore)
                         return 0;
@@ -1017,47 +1044,56 @@ static int apply_mount(
         return 0;
 }
 
-/* Change the per-mount readonly flag on an existing mount */
-static int remount_bind_readonly(const char *path, unsigned long orig_flags) {
-        int r;
-
-        r = mount(NULL, path, NULL, MS_REMOUNT | MS_BIND | MS_RDONLY | orig_flags, NULL);
+/* Change per-mount flags on an existing mount */
+static int bind_remount_one(const char *path, unsigned long orig_flags, unsigned long new_flags, unsigned long flags_mask) {
+        if (mount(NULL, path, NULL, (orig_flags & ~flags_mask) | MS_REMOUNT | MS_BIND | new_flags, NULL) < 0)
+                return -errno;
 
-        return r < 0 ? -errno : 0;
+        return 0;
 }
 
 static int make_read_only(const MountEntry *m, char **blacklist, FILE *proc_self_mountinfo) {
+        unsigned long new_flags = 0, flags_mask = 0;
         bool submounts = false;
         int r = 0;
 
         assert(m);
         assert(proc_self_mountinfo);
 
-        if (mount_entry_read_only(m)) {
-                if (IN_SET(m->mode, EMPTY_DIR, TMPFS)) {
-                        r = remount_bind_readonly(mount_entry_path(m), m->flags);
-                } else {
-                        submounts = true;
-                        r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), true, blacklist, proc_self_mountinfo);
-                }
-        } else if (m->mode == PRIVATE_DEV) {
-                /* Set /dev readonly, but not submounts like /dev/shm. Also, we only set the per-mount read-only flag.
-                 * We can't set it on the superblock, if we are inside a user namespace and running Linux <= 4.17. */
-                r = remount_bind_readonly(mount_entry_path(m), DEV_MOUNT_OPTIONS);
-        } else
+        if (mount_entry_read_only(m) || m->mode == PRIVATE_DEV) {
+                new_flags |= MS_RDONLY;
+                flags_mask |= MS_RDONLY;
+        }
+
+        if (m->nosuid) {
+                new_flags |= MS_NOSUID;
+                flags_mask |= MS_NOSUID;
+        }
+
+        if (flags_mask == 0) /* No Change? */
                 return 0;
 
-        /* Not that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked read-only
-         * already stays this way. This improves compatibility with container managers, where we won't attempt to undo
-         * read-only mounts already applied. */
+        /* We generally apply these changes recursively, except for /dev, and the cases we know there's
+         * nothing further down.  Set /dev readonly, but not submounts like /dev/shm. Also, we only set the
+         * per-mount read-only flag.  We can't set it on the superblock, if we are inside a user namespace
+         * and running Linux <= 4.17. */
+        submounts =
+                mount_entry_read_only(m) &&
+                !IN_SET(m->mode, EMPTY_DIR, TMPFS);
+        if (submounts)
+                r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, blacklist, proc_self_mountinfo);
+        else
+                r = bind_remount_one(mount_entry_path(m), m->flags, new_flags, flags_mask);
+
+        /* Not that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked
+         * read-only already stays this way. This improves compatibility with container managers, where we
+         * won't attempt to undo read-only mounts already applied. */
 
         if (r == -ENOENT && m->ignore)
-                r = 0;
-
+                return 0;
         if (r < 0)
-                return log_debug_errno(r, "Failed to re-mount '%s'%s read-only: %m", mount_entry_path(m),
+                return log_debug_errno(r, "Failed to re-mount '%s'%s: %m", mount_entry_path(m),
                                        submounts ? " and its submounts" : "");
-
         return 0;
 }
 
@@ -1117,6 +1153,7 @@ static size_t namespace_calculate_mounts(
                 (ns_info->protect_control_groups ? 1 : 0) +
                 (ns_info->protect_kernel_modules ? ELEMENTSOF(protect_kernel_modules_table) : 0) +
                 protect_home_cnt + protect_system_cnt +
+                (ns_info->protect_hostname ? 2 : 0) +
                 (namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0);
 }
 
@@ -1156,7 +1193,7 @@ int setup_namespace(
         _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
         _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL;
         _cleanup_free_ void *root_hash = NULL;
-        MountEntry *m, *mounts = NULL;
+        MountEntry *m = NULL, *mounts = NULL;
         size_t n_mounts, root_hash_size = 0;
         bool require_prefix = false;
         const char *root;
@@ -1220,7 +1257,10 @@ int setup_namespace(
                         protect_home, protect_system);
 
         if (n_mounts > 0) {
-                m = mounts = (MountEntry *) alloca0(n_mounts * sizeof(MountEntry));
+                m = mounts = new0(MountEntry, n_mounts);
+                if (!mounts)
+                        return -ENOMEM;
+
                 r = append_access_mounts(&m, read_write_paths, READWRITE, require_prefix);
                 if (r < 0)
                         goto finish;
@@ -1265,6 +1305,7 @@ int setup_namespace(
                         *(m++) = (MountEntry) {
                                 .path_const = "/dev",
                                 .mode = PRIVATE_DEV,
+                                .flags = DEV_MOUNT_OPTIONS,
                         };
                 }
 
@@ -1301,6 +1342,17 @@ int setup_namespace(
                                 goto finish;
                 }
 
+                if (ns_info->protect_hostname) {
+                        *(m++) = (MountEntry) {
+                                .path_const = "/proc/sys/kernel/hostname",
+                                .mode = READONLY,
+                        };
+                        *(m++) = (MountEntry) {
+                                .path_const = "/proc/sys/kernel/domainname",
+                                .mode = READONLY,
+                        };
+                }
+
                 assert(mounts + n_mounts == m);
 
                 /* Prepend the root directory where that's necessary */
@@ -1380,7 +1432,7 @@ int setup_namespace(
 
         if (n_mounts > 0) {
                 _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
-                char **blacklist;
+                _cleanup_free_ char **blacklist = NULL;
                 size_t j;
 
                 /* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of /proc.
@@ -1426,7 +1478,11 @@ int setup_namespace(
                 }
 
                 /* Create a blacklist we can pass to bind_mount_recursive() */
-                blacklist = newa(char*, n_mounts+1);
+                blacklist = new(char*, n_mounts+1);
+                if (!blacklist) {
+                        r = -ENOMEM;
+                        goto finish;
+                }
                 for (j = 0; j < n_mounts; j++)
                         blacklist[j] = (char*) mount_entry_path(mounts+j);
                 blacklist[j] = NULL;
@@ -1460,6 +1516,8 @@ finish:
         for (m = mounts; m < mounts + n_mounts; m++)
                 mount_entry_done(m);
 
+        free(mounts);
+
         return r;
 }
 
@@ -1502,6 +1560,7 @@ int bind_mount_add(BindMount **b, size_t *n, const BindMount *item) {
                 .source = TAKE_PTR(s),
                 .destination = TAKE_PTR(d),
                 .read_only = item->read_only,
+                .nosuid = item->nosuid,
                 .recursive = item->recursive,
                 .ignore_enoent = item->ignore_enoent,
         };
@@ -1615,8 +1674,8 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
                 char *t;
 
                 t = strjoina(a, "/tmp");
-                rmdir(t);
-                rmdir(a);
+                (void) rmdir(t);
+                (void) rmdir(a);
 
                 free(a);
                 return r;
@@ -1649,14 +1708,14 @@ int setup_netns(int netns_storage_socket[static 2]) {
 
         netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
         if (netns == -EAGAIN) {
-                /* Nothing stored yet, so let's create a new namespace */
+                /* Nothing stored yet, so let's create a new namespace. */
 
                 if (unshare(CLONE_NEWNET) < 0) {
                         r = -errno;
                         goto fail;
                 }
 
-                loopback_setup();
+                (void) loopback_setup();
 
                 netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
                 if (netns < 0) {
@@ -1691,6 +1750,59 @@ fail:
         return r;
 }
 
+int open_netns_path(int netns_storage_socket[static 2], const char *path) {
+        _cleanup_close_ int netns = -1;
+        int q, r;
+
+        assert(netns_storage_socket);
+        assert(netns_storage_socket[0] >= 0);
+        assert(netns_storage_socket[1] >= 0);
+        assert(path);
+
+        /* If the storage socket doesn't contain a netns fd yet, open one via the file system and store it in
+         * it. This is supposed to be called ahead of time, i.e. before setup_netns() which will allocate a
+         * new anonymous netns if needed. */
+
+        if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
+                return -errno;
+
+        netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
+        if (netns == -EAGAIN) {
+                /* Nothing stored yet. Open the file from the file system. */
+
+                netns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC);
+                if (netns < 0) {
+                        r = -errno;
+                        goto fail;
+                }
+
+                r = fd_is_network_ns(netns);
+                if (r == 0) { /* Not a netns? Refuse early. */
+                        r = -EINVAL;
+                        goto fail;
+                }
+                if (r < 0 && r != -EUCLEAN) /* EUCLEAN: we don't know */
+                        goto fail;
+
+                r = 1;
+
+        } else if (netns < 0) {
+                r = netns;
+                goto fail;
+        } else
+                r = 0; /* Already allocated */
+
+        q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
+        if (q < 0) {
+                r = q;
+                goto fail;
+        }
+
+fail:
+        (void) lockf(netns_storage_socket[0], F_ULOCK, 0);
+        return r;
+}
+
 bool ns_type_supported(NamespaceType type) {
         const char *t, *ns_proc;
 
index 5e0ec97..022bdb6 100644 (file)
@@ -52,12 +52,14 @@ struct NamespaceInfo {
         bool protect_kernel_tunables:1;
         bool protect_kernel_modules:1;
         bool mount_apivfs:1;
+        bool protect_hostname:1;
 };
 
 struct BindMount {
         char *source;
         char *destination;
         bool read_only:1;
+        bool nosuid:1;
         bool recursive:1;
         bool ignore_enoent:1;
 };
@@ -92,6 +94,7 @@ int setup_tmp_dirs(
                 char **var_tmp_dir);
 
 int setup_netns(int netns_storage_socket[static 2]);
+int open_netns_path(int netns_storage_socket[static 2], const char *path);
 
 const char* protect_home_to_string(ProtectHome p) _const_;
 ProtectHome protect_home_from_string(const char *s) _pure_;
index 831e49d..5a00150 100644 (file)
@@ -474,7 +474,7 @@ static void path_enter_running(Path *p) {
                 return;
         }
 
-        r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
+        r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
         if (r < 0)
                 goto fail;
 
@@ -555,19 +555,16 @@ static void path_mkdir(Path *p) {
 
 static int path_start(Unit *u) {
         Path *p = PATH(u);
-        Unit *trigger;
         int r;
 
         assert(p);
         assert(IN_SET(p->state, PATH_DEAD, PATH_FAILED));
 
-        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;
-        }
+        r = unit_test_trigger_loaded(u);
+        if (r < 0)
+                return r;
 
-        r = unit_start_limit_test(u);
+        r = unit_test_start_limit(u);
         if (r < 0) {
                 path_enter_dead(p, PATH_FAILURE_START_LIMIT_HIT);
                 return r;
index e478661..7f83052 100644 (file)
@@ -333,11 +333,11 @@ static int scope_start(Unit *u) {
         (void) unit_reset_cpu_accounting(u);
         (void) unit_reset_ip_accounting(u);
 
-        unit_export_state_files(UNIT(s));
+        unit_export_state_files(u);
 
-        r = unit_attach_pids_to_cgroup(u, UNIT(s)->pids, NULL);
+        r = unit_attach_pids_to_cgroup(u, u->pids, NULL);
         if (r < 0) {
-                log_unit_warning_errno(UNIT(s), r, "Failed to add PIDs to scope's control group: %m");
+                log_unit_warning_errno(u, r, "Failed to add PIDs to scope's control group: %m");
                 scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
                 return r;
         }
@@ -347,7 +347,7 @@ static int scope_start(Unit *u) {
         scope_set_state(s, SCOPE_RUNNING);
 
         /* Start watching the PIDs currently in the scope */
-        (void) unit_enqueue_rewatch_pids(UNIT(s));
+        (void) unit_enqueue_rewatch_pids(u);
         return 1;
 }
 
index 0c6d885..c8b1a85 100644 (file)
@@ -17,6 +17,7 @@
 #include "alloc-util.h"
 #include "audit-fd.h"
 #include "bus-util.h"
+#include "format-util.h"
 #include "log.h"
 #include "path-util.h"
 #include "selinux-util.h"
@@ -109,7 +110,11 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
                 va_end(ap);
 
                 if (r >= 0) {
-                        audit_log_user_avc_message(fd, AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
+                        if (type == SELINUX_AVC)
+                                audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
+                        else if (type == SELINUX_ERROR)
+                                audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_SELINUX_ERR, buf, NULL, NULL, NULL, 0);
+
                         return 0;
                 }
         }
index bac1aa3..b8a94a5 100644 (file)
@@ -13,6 +13,7 @@
 #include "selinux-setup.h"
 #include "selinux-util.h"
 #include "string-util.h"
+#include "time-util.h"
 #include "util.h"
 
 #if HAVE_SELINUX
index 8560337..a5a3079 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <errno.h>
 #include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "sd-messages.h"
@@ -144,8 +146,6 @@ static void service_unwatch_pid_file(Service *s) {
 }
 
 static int service_set_main_pid(Service *s, pid_t pid) {
-        pid_t ppid;
-
         assert(s);
 
         if (pid <= 1)
@@ -164,12 +164,10 @@ static int service_set_main_pid(Service *s, pid_t pid) {
 
         s->main_pid = pid;
         s->main_pid_known = true;
+        s->main_pid_alien = pid_is_my_child(pid) == 0;
 
-        if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid_cached()) {
+        if (s->main_pid_alien)
                 log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid);
-                s->main_pid_alien = true;
-        } else
-                s->main_pid_alien = false;
 
         return 0;
 }
@@ -1008,7 +1006,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
         if (r < 0)
                 return r;
 
-        r = unit_watch_pid(UNIT(s), pid);
+        r = unit_watch_pid(UNIT(s), pid, false);
         if (r < 0) /* FIXME: we need to do something here */
                 return log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", pid);
 
@@ -1038,7 +1036,7 @@ static void service_search_main_pid(Service *s) {
         if (service_set_main_pid(s, pid) < 0)
                 return;
 
-        r = unit_watch_pid(UNIT(s), pid);
+        r = unit_watch_pid(UNIT(s), pid, false);
         if (r < 0)
                 /* FIXME: we need to do something here */
                 log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid);
@@ -1172,7 +1170,7 @@ static int service_coldplug(Unit *u) {
                     SERVICE_RUNNING, SERVICE_RELOAD,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
                     SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
-                r = unit_watch_pid(UNIT(s), s->main_pid);
+                r = unit_watch_pid(UNIT(s), s->main_pid, false);
                 if (r < 0)
                         return r;
         }
@@ -1184,7 +1182,7 @@ static int service_coldplug(Unit *u) {
                    SERVICE_RELOAD,
                    SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
                    SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
-                r = unit_watch_pid(UNIT(s), s->control_pid);
+                r = unit_watch_pid(UNIT(s), s->control_pid, false);
                 if (r < 0)
                         return r;
         }
@@ -1472,7 +1470,7 @@ static int service_spawn(
         if (r < 0)
                 return r;
 
-        our_env = new0(char*, 9);
+        our_env = new0(char*, 10);
         if (!our_env)
                 return -ENOMEM;
 
@@ -1488,6 +1486,10 @@ static int service_spawn(
                 if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid_cached()) < 0)
                         return -ENOMEM;
 
+        if (s->pid_file)
+                if (asprintf(our_env + n_env++, "PIDFILE=%s", s->pid_file) < 0)
+                        return -ENOMEM;
+
         if (s->socket_fd >= 0) {
                 union sockaddr_union sa;
                 socklen_t salen = sizeof(sa);
@@ -1580,8 +1582,8 @@ static int service_spawn(
         s->exec_fd_event_source = TAKE_PTR(exec_fd_source);
         s->exec_fd_hot = false;
 
-        r = unit_watch_pid(UNIT(s), pid);
-        if (r < 0) /* FIXME: we need to do something here */
+        r = unit_watch_pid(UNIT(s), pid, true);
+        if (r < 0)
                 return r;
 
         *_pid = pid;
@@ -1768,6 +1770,9 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
         if (s->pid_file)
                 (void) unlink(s->pid_file);
 
+        /* Reset TTY ownership if necessary */
+        exec_context_revert_tty(&s->exec_context);
+
         return;
 
 fail:
@@ -2020,6 +2025,26 @@ static void service_kill_control_process(Service *s) {
         }
 }
 
+static int service_adverse_to_leftover_processes(Service *s) {
+        assert(s);
+
+        /* KillMode=mixed and control group are used to indicate that all process should be killed off.
+         * SendSIGKILL is used for services that require a clean shutdown. These are typically database
+         * service where a SigKilled process would result in a lengthy recovery and who's shutdown or
+         * startup time is quite variable (so Timeout settings aren't of use).
+         *
+         * Here we take these two factors and refuse to start a service if there are existing processes
+         * within a control group. Databases, while generally having some protection against multiple
+         * instances running, lets not stress the rigor of these. Also ExecStartPre parts of the service
+         * aren't as rigoriously written to protect aganst against multiple use. */
+        if (unit_warn_leftover_processes(UNIT(s)) &&
+            IN_SET(s->kill_context.kill_mode, KILL_MIXED, KILL_CONTROL_GROUP) &&
+            !s->kill_context.send_sigkill) {
+               return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(EBUSY), "Will not start SendSIGKILL=no service of type KillMode=control-group or mixed while processes exist");
+        }
+        return 0;
+}
+
 static void service_enter_start(Service *s) {
         ExecCommand *c;
         usec_t timeout;
@@ -2031,7 +2056,9 @@ static void service_enter_start(Service *s) {
         service_unwatch_control_pid(s);
         service_unwatch_main_pid(s);
 
-        unit_warn_leftover_processes(UNIT(s));
+        r = service_adverse_to_leftover_processes(s);
+        if (r < 0)
+                goto fail;
 
         if (s->type == SERVICE_FORKING) {
                 s->control_command_id = SERVICE_EXEC_START;
@@ -2124,7 +2151,9 @@ static void service_enter_start_pre(Service *s) {
         s->control_command = s->exec_command[SERVICE_EXEC_START_PRE];
         if (s->control_command) {
 
-                unit_warn_leftover_processes(UNIT(s));
+                r = service_adverse_to_leftover_processes(s);
+                if (r < 0)
+                        goto fail;
 
                 s->control_command_id = SERVICE_EXEC_START_PRE;
 
@@ -2168,7 +2197,7 @@ static void service_enter_restart(Service *s) {
          * restarted. We use JOB_RESTART (instead of the more obvious
          * JOB_START) here so that those dependency jobs will be added
          * as well. */
-        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, &error, NULL);
+        r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_REPLACE, NULL, &error, NULL);
         if (r < 0)
                 goto fail;
 
@@ -2350,7 +2379,7 @@ 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 = unit_start_limit_test(u);
+        r = unit_test_start_limit(u);
         if (r < 0) {
                 service_enter_dead(s, SERVICE_FAILURE_START_LIMIT_HIT, false);
                 return r;
@@ -3200,11 +3229,19 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         bool notify_dbus = true;
         Service *s = SERVICE(u);
         ServiceResult f;
+        ExitClean clean_mode;
 
         assert(s);
         assert(pid >= 0);
 
-        if (is_clean_exit(code, status, s->type == SERVICE_ONESHOT ? EXIT_CLEAN_COMMAND : EXIT_CLEAN_DAEMON, &s->success_status))
+        /* Oneshot services and non-SERVICE_EXEC_START commands should not be
+         * considered daemons as they are typically not long running. */
+        if (s->type == SERVICE_ONESHOT || (s->control_pid == pid && s->control_command_id != SERVICE_EXEC_START))
+                clean_mode = EXIT_CLEAN_COMMAND;
+        else
+                clean_mode = EXIT_CLEAN_DAEMON;
+
+        if (is_clean_exit(code, status, clean_mode, &s->success_status))
                 f = SERVICE_SUCCESS;
         else if (code == CLD_EXITED)
                 f = SERVICE_FAILURE_EXIT_CODE;
@@ -3453,8 +3490,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
                                 if (main_pid_good(s) <= 0)
                                         service_enter_stop_post(s, f);
 
-                                /* If there is still a service
-                                 * process around, wait until
+                                /* If there is still a service process around, wait until
                                  * that one quit, too */
                                 break;
 
@@ -3476,10 +3512,14 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
         if (notify_dbus)
                 unit_add_to_dbus_queue(u);
 
-        /* If we get a SIGCHLD event for one of the processes we were interested in, then we look for others to watch,
-         * under the assumption that we'll sooner or later get a SIGCHLD for them, as the original process we watched
-         * was probably the parent of them, and they are hence now our children. */
-        (void) unit_enqueue_rewatch_pids(u);
+        /* We watch the main/control process otherwise we can't retrieve the unit they
+         * belong to with cgroupv1. But if they are not our direct child, we won't get a
+         * SIGCHLD for them. Therefore we need to look for others to watch so we can
+         * detect when the cgroup becomes empty. Note that the control process is always
+         * our child so it's pointless to watch all other processes. */
+        if (!control_pid_good(s))
+                if (!s->main_pid_known || s->main_pid_alien)
+                        (void) unit_enqueue_rewatch_pids(u);
 }
 
 static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
@@ -3673,7 +3713,7 @@ static void service_notify_message(
                         if (r > 0) {
                                 service_set_main_pid(s, new_main_pid);
 
-                                r = unit_watch_pid(UNIT(s), new_main_pid);
+                                r = unit_watch_pid(UNIT(s), new_main_pid, false);
                                 if (r < 0)
                                         log_unit_warning_errno(UNIT(s), r, "Failed to watch new main PID "PID_FMT" for service: %m", new_main_pid);
 
@@ -3891,7 +3931,7 @@ static void service_bus_name_owner_change(
                         log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, name, pid);
 
                         service_set_main_pid(s, pid);
-                        unit_watch_pid(UNIT(s), pid);
+                        unit_watch_pid(UNIT(s), pid, false);
                 }
         }
 }
index 9c4340c..57eefbb 100644 (file)
@@ -152,6 +152,7 @@ struct Service {
         /* Keep restart intention between UNIT_FAILED and UNIT_ACTIVATING */
         bool will_auto_restart:1;
         bool start_timeout_defined:1;
+        bool exec_fd_hot:1;
 
         char *bus_name;
         char *bus_name_owner; /* unique name of the current owner */
@@ -183,7 +184,6 @@ struct Service {
 
         unsigned n_restarts;
         bool flush_n_restarts;
-        bool exec_fd_hot;
 };
 
 extern const UnitVTable service_vtable;
index f748a82..02601e5 100644 (file)
@@ -1,5 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "io-util.h"
index 49b37ae..cd7fb01 100644 (file)
@@ -12,6 +12,7 @@
 #include <stdio_ext.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "dirent-util.h"
index ce7140d..a15bfbd 100644 (file)
@@ -1473,6 +1473,25 @@ static int socket_address_listen_do(
                 log_unit_error_errno(u, error, fmt, strna(_t));  \
         })
 
+static int fork_needed(const SocketAddress *address, const ExecContext *context) {
+        int r;
+
+        assert(address);
+        assert(context);
+
+        /* Check if we need to do the cgroup or netns stuff. If not we can do things much simpler. */
+
+        if (IN_SET(address->sockaddr.sa.sa_family, AF_INET, AF_INET6)) {
+                r = bpf_firewall_supported();
+                if (r < 0)
+                        return r;
+                if (r != BPF_FIREWALL_UNSUPPORTED) /* If BPF firewalling isn't supported anyway — there's no point in this forking complexity */
+                        return true;
+        }
+
+        return context->private_network || context->network_namespace_path;
+}
+
 static int socket_address_listen_in_cgroup(
                 Socket *s,
                 const SocketAddress *address,
@@ -1485,18 +1504,34 @@ static int socket_address_listen_in_cgroup(
         assert(s);
         assert(address);
 
-        /* This is a wrapper around socket_address_listen(), that forks off a helper process inside the socket's cgroup
-         * in which the socket is actually created. This way we ensure the socket is actually properly attached to the
-         * unit's cgroup for the purpose of BPF filtering and such. */
-
-        if (!IN_SET(address->sockaddr.sa.sa_family, AF_INET, AF_INET6))
-                goto shortcut; /* BPF filtering only applies to IPv4 + IPv6, shortcut things for other protocols */
+        /* This is a wrapper around socket_address_listen(), that forks off a helper process inside the
+         * socket's cgroup and network namespace in which the socket is actually created. This way we ensure
+         * the socket is actually properly attached to the unit's cgroup for the purpose of BPF filtering and
+         * such. */
 
-        r = bpf_firewall_supported();
+        r = fork_needed(address, &s->exec_context);
         if (r < 0)
                 return r;
-        if (r == BPF_FIREWALL_UNSUPPORTED) /* If BPF firewalling isn't supported anyway — there's no point in this forking complexity */
-                goto shortcut;
+        if (r == 0) {
+                /* Shortcut things... */
+                fd = socket_address_listen_do(s, address, label);
+                if (fd < 0)
+                        return log_address_error_errno(UNIT(s), address, fd, "Failed to create listening socket (%s): %m");
+
+                return fd;
+        }
+
+        r = unit_setup_exec_runtime(UNIT(s));
+        if (r < 0)
+                return log_unit_error_errno(UNIT(s), r, "Failed acquire runtime: %m");
+
+        if (s->exec_context.network_namespace_path &&
+            s->exec_runtime &&
+            s->exec_runtime->netns_storage_socket[0] >= 0) {
+                r = open_netns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path);
+                if (r < 0)
+                        return log_unit_error_errno(UNIT(s), r, "Failed to open network namespace path %s: %m", s->exec_context.network_namespace_path);
+        }
 
         if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
                 return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
@@ -1509,6 +1544,23 @@ static int socket_address_listen_in_cgroup(
 
                 pair[0] = safe_close(pair[0]);
 
+                if ((s->exec_context.private_network || s->exec_context.network_namespace_path) &&
+                    s->exec_runtime &&
+                    s->exec_runtime->netns_storage_socket[0] >= 0) {
+
+                        if (ns_type_supported(NAMESPACE_NET)) {
+                                r = setup_netns(s->exec_runtime->netns_storage_socket);
+                                if (r < 0) {
+                                        log_unit_error_errno(UNIT(s), r, "Failed to join network namespace: %m");
+                                        _exit(EXIT_NETWORK);
+                                }
+                        } else if (s->exec_context.network_namespace_path) {
+                                log_unit_error(UNIT(s), "Network namespace path configured but network namespaces not supported.");
+                                _exit(EXIT_NETWORK);
+                        } else
+                                log_unit_warning(UNIT(s), "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring.");
+                }
+
                 fd = socket_address_listen_do(s, address, label);
                 if (fd < 0) {
                         log_address_error_errno(UNIT(s), address, fd, "Failed to create listening socket (%s): %m");
@@ -1538,13 +1590,6 @@ static int socket_address_listen_in_cgroup(
                 return log_address_error_errno(UNIT(s), address, fd, "Failed to receive listening socket (%s): %m");
 
         return fd;
-
-shortcut:
-        fd = socket_address_listen_do(s, address, label);
-        if (fd < 0)
-                return log_address_error_errno(UNIT(s), address, fd, "Failed to create listening socket (%s): %m");
-
-        return fd;
 }
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Socket *, socket_close_fds);
@@ -1807,7 +1852,7 @@ static int socket_coldplug(Unit *u) {
                    SOCKET_FINAL_SIGTERM,
                    SOCKET_FINAL_SIGKILL)) {
 
-                r = unit_watch_pid(UNIT(s), s->control_pid);
+                r = unit_watch_pid(UNIT(s), s->control_pid, false);
                 if (r < 0)
                         return r;
 
@@ -1893,9 +1938,8 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
         if (r < 0)
                 return r;
 
-        r = unit_watch_pid(UNIT(s), pid);
+        r = unit_watch_pid(UNIT(s), pid, true);
         if (r < 0)
-                /* FIXME: we need to do something here */
                 return r;
 
         *_pid = pid;
@@ -1964,7 +2008,7 @@ static int socket_chown(Socket *s, pid_t *_pid) {
                 _exit(EXIT_SUCCESS);
         }
 
-        r = unit_watch_pid(UNIT(s), pid);
+        r = unit_watch_pid(UNIT(s), pid, true);
         if (r < 0)
                 goto fail;
 
@@ -2266,7 +2310,7 @@ static void socket_enter_running(Socket *s, int cfd) {
                                 goto fail;
                         }
 
-                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, &error, NULL);
+                        r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, NULL, &error, NULL);
                         if (r < 0)
                                 goto fail;
                 }
@@ -2341,7 +2385,7 @@ static void socket_enter_running(Socket *s, int cfd) {
 
                 service->peer = TAKE_PTR(p); /* Pass ownership of the peer reference */
 
-                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
+                r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, NULL, &error, NULL);
                 if (r < 0) {
                         /* We failed to activate the new service, but it still exists. Let's make sure the service
                          * closes and forgets the connection fd again, immediately. */
@@ -2442,7 +2486,7 @@ static int socket_start(Unit *u) {
 
         assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED));
 
-        r = unit_start_limit_test(u);
+        r = unit_test_start_limit(u);
         if (r < 0) {
                 socket_enter_dead(s, SOCKET_FAILURE_START_LIMIT_HIT);
                 return r;
@@ -2844,17 +2888,10 @@ static int socket_accept_do(Socket *s, int fd) {
         assert(s);
         assert(fd >= 0);
 
-        for (;;) {
-                cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
-                if (cfd < 0) {
-                        if (errno == EINTR)
-                                continue;
-
-                        return -errno;
-                }
-
-                break;
-        }
+        cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
+        if (cfd < 0)
+                /* Convert transient network errors into clean and well-defined EAGAIN */
+                return ERRNO_IS_ACCEPT_AGAIN(errno) ? -EAGAIN : -errno;
 
         return cfd;
 }
@@ -2892,6 +2929,8 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
                 pair[0] = safe_close(pair[0]);
 
                 cfd = socket_accept_do(s, fd);
+                if (cfd == -EAGAIN) /* spurious accept() */
+                        _exit(EXIT_SUCCESS);
                 if (cfd < 0) {
                         log_unit_error_errno(UNIT(s), cfd, "Failed to accept connection socket: %m");
                         _exit(EXIT_FAILURE);
@@ -2916,6 +2955,10 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
                 return r;
         }
 
+        /* If we received no fd, we got EIO here. If this happens with a process exit code of EXIT_SUCCESS
+         * this is a spurious accept(), let's convert that back to EAGAIN here. */
+        if (cfd == -EIO)
+                return -EAGAIN;
         if (cfd < 0)
                 return log_unit_error_errno(UNIT(s), cfd, "Failed to receive connection socket: %m");
 
@@ -2923,6 +2966,8 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
 
 shortcut:
         cfd = socket_accept_do(s, fd);
+        if (cfd == -EAGAIN) /* spurious accept(), skip it silently */
+                return -EAGAIN;
         if (cfd < 0)
                 return log_unit_error_errno(UNIT(s), cfd, "Failed to accept connection socket: %m");
 
@@ -2942,7 +2987,6 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
         log_unit_debug(UNIT(p->socket), "Incoming traffic");
 
         if (revents != EPOLLIN) {
-
                 if (revents & EPOLLHUP)
                         log_unit_error(UNIT(p->socket), "Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.");
                 else
@@ -2955,6 +2999,8 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
             socket_address_can_accept(&p->address)) {
 
                 cfd = socket_accept_in_cgroup(p->socket, p, fd);
+                if (cfd == -EAGAIN) /* Spurious accept() */
+                        return 0;
                 if (cfd < 0)
                         goto fail;
 
index 2d8463b..28acef2 100644 (file)
@@ -550,7 +550,7 @@ static int swap_coldplug(Unit *u) {
             pid_is_unwaited(s->control_pid) &&
             SWAP_STATE_WITH_PROCESS(new_state)) {
 
-                r = unit_watch_pid(UNIT(s), s->control_pid);
+                r = unit_watch_pid(UNIT(s), s->control_pid, false);
                 if (r < 0)
                         return r;
 
@@ -657,9 +657,8 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
         if (r < 0)
                 goto fail;
 
-        r = unit_watch_pid(UNIT(s), pid);
+        r = unit_watch_pid(UNIT(s), pid, true);
         if (r < 0)
-                /* FIXME: we need to do something here */
                 goto fail;
 
         *_pid = pid;
@@ -871,7 +870,7 @@ static int swap_start(Unit *u) {
                 if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
                         return -EAGAIN;
 
-        r = unit_start_limit_test(u);
+        r = unit_test_start_limit(u);
         if (r < 0) {
                 swap_enter_dead(s, SWAP_FAILURE_START_LIMIT_HIT);
                 return r;
index 0dae950..5d1ddd7 100644 (file)
@@ -8,25 +8,27 @@
 #  (at your option) any later version.
 
 prefix=@prefix@
-systemdutildir=@rootlibexecdir@
-systemdsystemunitdir=@systemunitdir@
-systemdsystempresetdir=@systempresetdir@
-systemduserunitdir=@userunitdir@
-systemduserpresetdir=@userpresetdir@
-systemdsystemconfdir=@pkgsysconfdir@/system
-systemduserconfdir=@pkgsysconfdir@/user
+rootprefix=@rootprefix_noslash@
+sysconfdir=@sysconfdir@
+systemdutildir=${rootprefix}/lib/systemd
+systemdsystemunitdir=${rootprefix}/lib/systemd/system
+systemdsystempresetdir=${rootprefix}/lib/systemd/system-preset
+systemduserunitdir=${prefix}/lib/systemd/user
+systemduserpresetdir=${prefix}/lib/systemd/user-preset
+systemdsystemconfdir=${sysconfdir}/systemd/system
+systemduserconfdir=${sysconfdir}/systemd/user
 systemdsystemunitpath=${systemdsystemconfdir}:/etc/systemd/system:/run/systemd/system:/usr/local/lib/systemd/system:${systemdsystemunitdir}:/usr/lib/systemd/system:/lib/systemd/system
 systemduserunitpath=${systemduserconfdir}:/etc/systemd/user:/run/systemd/user:/usr/local/lib/systemd/user:/usr/local/share/systemd/user:${systemduserunitdir}:/usr/lib/systemd/user:/usr/share/systemd/user
-systemdsystemgeneratordir=@systemgeneratordir@
-systemdusergeneratordir=@usergeneratordir@
-systemdsleepdir=@systemsleepdir@
-systemdshutdowndir=@systemshutdowndir@
-tmpfilesdir=@tmpfilesdir@
-sysusersdir=@sysusersdir@
-sysctldir=@sysctldir@
-binfmtdir=@binfmtdir@
-modulesloaddir=@modulesloaddir@
-catalogdir=@catalogdir@
+systemdsystemgeneratordir=${rootprefix}/lib/systemd/system-generators
+systemdusergeneratordir=${prefix}/lib/systemd/user-generators
+systemdsleepdir=${rootprefix}/lib/systemd/system-sleep
+systemdshutdowndir=${rootprefix}/lib/systemd/system-shutdown
+tmpfilesdir=${prefix}/lib/tmpfiles.d
+sysusersdir=${prefix}/lib/sysusers.d
+sysctldir=${prefix}/lib/sysctl.d
+binfmtdir=${prefix}/lib/binfmt.d
+modulesloaddir=${prefix}/lib/modules-load.d
+catalogdir=${prefix}/lib/systemd/catalog
 systemuidmax=@systemuidmax@
 systemgidmax=@systemgidmax@
 dynamicuidmin=@dynamicuidmin@
index d9ba2f7..8440bb2 100644 (file)
@@ -1,5 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include <errno.h>
 
 #include "alloc-util.h"
@@ -73,7 +77,7 @@ static int timer_verify(Timer *t) {
         if (UNIT(t)->load_state != UNIT_LOADED)
                 return 0;
 
-        if (!t->values) {
+        if (!t->values && !t->on_clock_change && !t->on_timezone_change) {
                 log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing.");
                 return -ENOEXEC;
         }
@@ -211,14 +215,18 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
                 "%sPersistent: %s\n"
                 "%sWakeSystem: %s\n"
                 "%sAccuracy: %s\n"
-                "%sRemainAfterElapse: %s\n",
+                "%sRemainAfterElapse: %s\n"
+                "%sOnClockChange: %s\n"
+                "%sOnTimeZoneChange %s\n",
                 prefix, timer_state_to_string(t->state),
                 prefix, timer_result_to_string(t->result),
                 prefix, trigger ? trigger->id : "n/a",
                 prefix, yes_no(t->persistent),
                 prefix, yes_no(t->wake_system),
                 prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
-                prefix, yes_no(t->remain_after_elapse));
+                prefix, yes_no(t->remain_after_elapse),
+                prefix, yes_no(t->on_clock_change),
+                prefix, yes_no(t->on_timezone_change));
 
         LIST_FOREACH(value, v, t->values) {
 
@@ -380,6 +388,13 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
                         if (r < 0)
                                 continue;
 
+                        /* To make the delay due to RandomizedDelaySec= work even at boot,
+                         * if the scheduled time has already passed, set the time when systemd
+                         * first started as the scheduled time.
+                         * Also, we don't have to check t->persistent since the logic implicitly express true. */
+                        if (v->next_elapse < UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].realtime)
+                                v->next_elapse = UNIT(t)->manager->timestamps[MANAGER_TIMESTAMP_USERSPACE].realtime;
+
                         if (!found_realtime)
                                 t->next_elapse_realtime = v->next_elapse;
                         else
@@ -463,7 +478,7 @@ static void timer_enter_waiting(Timer *t, bool time_change) {
                 }
         }
 
-        if (!found_monotonic && !found_realtime) {
+        if (!found_monotonic && !found_realtime && !t->on_timezone_change && !t->on_clock_change) {
                 log_unit_debug(UNIT(t), "Timer is elapsed.");
                 timer_enter_elapsed(t, leave_around);
                 return;
@@ -568,7 +583,7 @@ static void timer_enter_running(Timer *t) {
                 return;
         }
 
-        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
+        r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, NULL, &error, NULL);
         if (r < 0)
                 goto fail;
 
@@ -588,19 +603,16 @@ fail:
 static int timer_start(Unit *u) {
         Timer *t = TIMER(u);
         TimerValue *v;
-        Unit *trigger;
         int r;
 
         assert(t);
         assert(IN_SET(t->state, TIMER_DEAD, TIMER_FAILED));
 
-        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;
-        }
+        r = unit_test_trigger_loaded(u);
+        if (r < 0)
+                return r;
 
-        r = unit_start_limit_test(u);
+        r = unit_test_start_limit(u);
         if (r < 0) {
                 timer_enter_dead(t, TIMER_FAILURE_START_LIMIT_HIT);
                 return r;
@@ -807,8 +819,13 @@ static void timer_time_change(Unit *u) {
         if (t->last_trigger.realtime > ts)
                 t->last_trigger.realtime = ts;
 
-        log_unit_debug(u, "Time change, recalculating next elapse.");
-        timer_enter_waiting(t, true);
+        if (t->on_clock_change) {
+                log_unit_debug(u, "Time change, triggering activation.");
+                timer_enter_running(t);
+        } else {
+                log_unit_debug(u, "Time change, recalculating next elapse.");
+                timer_enter_waiting(t, true);
+        }
 }
 
 static void timer_timezone_change(Unit *u) {
@@ -819,8 +836,13 @@ static void timer_timezone_change(Unit *u) {
         if (t->state != TIMER_WAITING)
                 return;
 
-        log_unit_debug(u, "Timezone change, recalculating next elapse.");
-        timer_enter_waiting(t, false);
+        if (t->on_timezone_change) {
+                log_unit_debug(u, "Timezone change, triggering activation.");
+                timer_enter_running(t);
+        } else {
+                log_unit_debug(u, "Timezone change, recalculating next elapse.");
+                timer_enter_waiting(t, false);
+        }
 }
 
 static const char* const timer_base_table[_TIMER_BASE_MAX] = {
index 833aadb..ab66a20 100644 (file)
@@ -57,6 +57,8 @@ struct Timer {
         bool persistent;
         bool wake_system;
         bool remain_after_elapse;
+        bool on_clock_change;
+        bool on_timezone_change;
 
         char *stamp_path;
 };
index 2418332..3b6b240 100644 (file)
@@ -279,32 +279,40 @@ static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) {
 }
 
 static void transaction_drop_redundant(Transaction *tr) {
-        Job *j;
-        Iterator i;
+        bool again;
 
-        /* Goes through the transaction and removes all jobs of the units
-         * whose jobs are all noops. If not all of a unit's jobs are
-         * redundant, they are kept. */
+        /* Goes through the transaction and removes all jobs of the units whose jobs are all noops. If not
+         * all of a unit's jobs are redundant, they are kept. */
 
         assert(tr);
 
-rescan:
-        HASHMAP_FOREACH(j, tr->jobs, i) {
-                Job *k;
+        do {
+                Iterator i;
+                Job *j;
 
-                LIST_FOREACH(transaction, k, j) {
+                again = false;
 
-                        if (tr->anchor_job == k ||
-                            !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
-                            (k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type)))
-                                goto next_unit;
-                }
+                HASHMAP_FOREACH(j, tr->jobs, i) {
+                        bool keep = false;
+                        Job *k;
 
-                log_trace("Found redundant job %s/%s, dropping from transaction.", j->unit->id, job_type_to_string(j->type));
-                transaction_delete_job(tr, j, false);
-                goto rescan;
-        next_unit:;
-        }
+                        LIST_FOREACH(transaction, k, j)
+                                if (tr->anchor_job == k ||
+                                    !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
+                                    (k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type))) {
+                                        keep = true;
+                                        break;
+                                }
+
+                        if (!keep) {
+                                log_trace("Found redundant job %s/%s, dropping from transaction.",
+                                          j->unit->id, job_type_to_string(j->type));
+                                transaction_delete_job(tr, j, false);
+                                again = true;
+                                break;
+                        }
+                }
+        } while (again);
 }
 
 _pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) {
@@ -485,29 +493,36 @@ static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bu
 }
 
 static void transaction_collect_garbage(Transaction *tr) {
-        Iterator i;
-        Job *j;
+        bool again;
 
         assert(tr);
 
         /* Drop jobs that are not required by any other job */
 
-rescan:
-        HASHMAP_FOREACH(j, tr->jobs, i) {
-                if (tr->anchor_job == j)
-                        continue;
-                if (j->object_list) {
+        do {
+                Iterator i;
+                Job *j;
+
+                again = false;
+
+                HASHMAP_FOREACH(j, tr->jobs, i) {
+                        if (tr->anchor_job == j)
+                                continue;
+
+                        if (!j->object_list) {
+                                log_trace("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type));
+                                transaction_delete_job(tr, j, true);
+                                again = true;
+                                break;
+                        }
+
                         log_trace("Keeping job %s/%s because of %s/%s",
                                   j->unit->id, job_type_to_string(j->type),
                                   j->object_list->subject ? j->object_list->subject->unit->id : "root",
                                   j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root");
-                        continue;
                 }
 
-                log_trace("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type));
-                transaction_delete_job(tr, j, true);
-                goto rescan;
-        }
+        } while (again);
 }
 
 static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_error *e) {
@@ -589,7 +604,12 @@ rescan:
         }
 }
 
-static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
+static int transaction_apply(
+                Transaction *tr,
+                Manager *m,
+                JobMode mode,
+                Set *affected_jobs) {
+
         Iterator i;
         Job *j;
         int r;
@@ -646,6 +666,11 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
                 job_add_to_dbus_queue(j);
                 job_start_timer(j, false);
                 job_shutdown_magic(j);
+
+                /* When 'affected' is specified, let's track all in it all jobs that were touched because of
+                 * this transaction. */
+                if (affected_jobs)
+                        (void) set_put(affected_jobs, j);
         }
 
         return 0;
@@ -658,7 +683,13 @@ rollback:
         return r;
 }
 
-int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
+int transaction_activate(
+                Transaction *tr,
+                Manager *m,
+                JobMode mode,
+                Set *affected_jobs,
+                sd_bus_error *e) {
+
         Iterator i;
         Job *j;
         int r;
@@ -735,7 +766,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error
                 return log_notice_errno(r, "Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
 
         /* Tenth step: apply changes */
-        r = transaction_apply(tr, m, mode);
+        r = transaction_apply(tr, m, mode, affected_jobs);
         if (r < 0)
                 return log_warning_errno(r, "Failed to apply transaction: %m");
 
index 70d74a4..4b5620f 100644 (file)
@@ -29,6 +29,6 @@ int transaction_add_job_and_dependencies(
                 bool ignore_requirements,
                 bool ignore_order,
                 sd_bus_error *e);
-int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e);
+int transaction_activate(Transaction *tr, Manager *m, JobMode mode, Set *affected, sd_bus_error *e);
 int transaction_add_isolate_jobs(Transaction *tr, Manager *m);
 void transaction_abort(Transaction *tr);
index a72a05d..5b592be 100644 (file)
@@ -1590,66 +1590,43 @@ fail:
         return log_unit_debug_errno(u, r, "Failed to load configuration: %m");
 }
 
-static bool unit_condition_test_list(Unit *u, Condition *first, const char *(*to_string)(ConditionType t)) {
-        Condition *c;
-        int triggered = -1;
-
-        assert(u);
-        assert(to_string);
-
-        /* If the condition list is empty, then it is true */
-        if (!first)
-                return true;
-
-        /* Otherwise, if all of the non-trigger conditions apply and
-         * if any of the trigger conditions apply (unless there are
-         * none) we return true */
-        LIST_FOREACH(conditions, c, first) {
-                int r;
-
-                r = condition_test(c);
-                if (r < 0)
-                        log_unit_warning(u,
-                                         "Couldn't determine result for %s=%s%s%s, assuming failed: %m",
-                                         to_string(c->type),
-                                         c->trigger ? "|" : "",
-                                         c->negate ? "!" : "",
-                                         c->parameter);
-                else
-                        log_unit_debug(u,
-                                       "%s=%s%s%s %s.",
-                                       to_string(c->type),
-                                       c->trigger ? "|" : "",
-                                       c->negate ? "!" : "",
-                                       c->parameter,
-                                       condition_result_to_string(c->result));
-
-                if (!c->trigger && r <= 0)
-                        return false;
+_printf_(7, 8)
+static int log_unit_internal(void *userdata, int level, int error, const char *file, int line, const char *func, const char *format, ...) {
+        Unit *u = userdata;
+        va_list ap;
+        int r;
 
-                if (c->trigger && triggered <= 0)
-                        triggered = r > 0;
-        }
+        va_start(ap, format);
+        if (u)
+                r = log_object_internalv(level, error, file, line, func,
+                                         u->manager->unit_log_field,
+                                         u->id,
+                                         u->manager->invocation_log_field,
+                                         u->invocation_id_string,
+                                         format, ap);
+        else
+                r = log_internalv(level, error,  file, line, func, format, ap);
+        va_end(ap);
 
-        return triggered != 0;
+        return r;
 }
 
-static bool unit_condition_test(Unit *u) {
+static bool unit_test_condition(Unit *u) {
         assert(u);
 
         dual_timestamp_get(&u->condition_timestamp);
-        u->condition_result = unit_condition_test_list(u, u->conditions, condition_type_to_string);
+        u->condition_result = condition_test_list(u->conditions, condition_type_to_string, log_unit_internal, u);
 
         unit_add_to_dbus_queue(u);
 
         return u->condition_result;
 }
 
-static bool unit_assert_test(Unit *u) {
+static bool unit_test_assert(Unit *u) {
         assert(u);
 
         dual_timestamp_get(&u->assert_timestamp);
-        u->assert_result = unit_condition_test_list(u, u->asserts, assert_type_to_string);
+        u->assert_result = condition_test_list(u->asserts, assert_type_to_string, log_unit_internal, u);
 
         unit_add_to_dbus_queue(u);
 
@@ -1668,7 +1645,7 @@ void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg
         REENABLE_WARNING;
 }
 
-int unit_start_limit_test(Unit *u) {
+int unit_test_start_limit(Unit *u) {
         const char *reason;
 
         assert(u);
@@ -1683,9 +1660,11 @@ int unit_start_limit_test(Unit *u) {
 
         reason = strjoina("unit ", u->id, " failed");
 
-        return emergency_action(u->manager, u->start_limit_action,
-                                EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN,
-                                u->reboot_arg, -1, reason);
+        emergency_action(u->manager, u->start_limit_action,
+                         EMERGENCY_ACTION_IS_WATCHDOG|EMERGENCY_ACTION_WARN,
+                         u->reboot_arg, -1, reason);
+
+        return -ECANCELED;
 }
 
 bool unit_shall_confirm_spawn(Unit *u) {
@@ -1726,27 +1705,31 @@ static bool unit_verify_deps(Unit *u) {
         return true;
 }
 
-/* Errors:
- *         -EBADR:      This unit type does not support starting.
+/* Errors that aren't really errors:
  *         -EALREADY:   Unit is already started.
+ *         -ECOMM:      Condition failed
  *         -EAGAIN:     An operation is already in progress. Retry later.
- *         -ECANCELED:  Too many requests for now.
+ *
+ * Errors that are real errors:
+ *         -EBADR:      This unit type does not support starting.
+ *         -ECANCELED:  Start limit hit, too many requests for now
  *         -EPROTO:     Assert failed
  *         -EINVAL:     Unit not loaded
  *         -EOPNOTSUPP: Unit type not supported
  *         -ENOLINK:    The necessary dependencies are not fulfilled.
  *         -ESTALE:     This unit has been started before and can't be started a second time
+ *         -ENOENT:     This is a triggering unit and unit to trigger is not loaded
  */
 int unit_start(Unit *u) {
         UnitActiveState state;
         Unit *following;
+        int r;
 
         assert(u);
 
-        /* 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
-         * wait for units and when waiting is finished. */
+        /* 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 wait for units and when
+         * waiting is finished. */
         state = unit_active_state(u);
         if (UNIT_IS_ACTIVE_OR_RELOADING(state))
                 return -EALREADY;
@@ -1759,35 +1742,45 @@ int unit_start(Unit *u) {
         if (UNIT_VTABLE(u)->once_only && dual_timestamp_is_set(&u->inactive_enter_timestamp))
                 return -ESTALE;
 
-        /* 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,
-         * but we don't want to recheck the condition in that case. */
+        /* 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, but we don't want to
+         * recheck the condition in that case. */
         if (state != UNIT_ACTIVATING &&
-            !unit_condition_test(u)) {
-                log_unit_debug(u, "Starting requested but condition failed. Not starting unit.");
-                return -ECOMM;
+            !unit_test_condition(u)) {
+
+                /* Let's also check the start limit here. Normally, the start limit is only checked by the
+                 * .start() method of the unit type after it did some additional checks verifying everything
+                 * is in order (so that those other checks can propagate errors properly). However, if a
+                 * condition check doesn't hold we don't get that far but we should still ensure we are not
+                 * called in a tight loop without a rate limit check enforced, hence do the check here. Note
+                 * that ECOMM is generally not a reason for a job to fail, unlike most other errors here,
+                 * hence the chance is big that any triggering unit for us will trigger us again. Note this
+                 * condition check is a bit different from the condition check inside the per-unit .start()
+                 * function, as this one will not change the unit's state in any way (and we shouldn't here,
+                 * after all the condition failed). */
+
+                r = unit_test_start_limit(u);
+                if (r < 0)
+                        return r;
+
+                return log_unit_debug_errno(u, SYNTHETIC_ERRNO(ECOMM), "Starting requested but condition failed. Not starting unit.");
         }
 
         /* If the asserts failed, fail the entire job */
         if (state != UNIT_ACTIVATING &&
-            !unit_assert_test(u)) {
-                log_unit_notice(u, "Starting requested but asserts failed.");
-                return -EPROTO;
-        }
+            !unit_test_assert(u))
+                return log_unit_notice_errno(u, SYNTHETIC_ERRNO(EPROTO), "Starting requested but asserts failed.");
 
-        /* Units of types that aren't supported cannot be
-         * started. Note that we do this test only after the condition
-         * checks, so that we rather return condition check errors
-         * (which are usually not considered a true failure) than "not
-         * supported" errors (which are considered a failure).
+        /* Units of types that aren't supported cannot be started. Note that we do this test only after the
+         * condition checks, so that we rather return condition check errors (which are usually not
+         * considered a true failure) than "not supported" errors (which are considered a failure).
          */
         if (!unit_supported(u))
                 return -EOPNOTSUPP;
 
-        /* Let's make sure that the deps really are in order before we start this. Normally the job engine should have
-         * taken care of this already, but let's check this here again. After all, our dependencies might not be in
-         * effect anymore, due to a reload or due to a failed condition. */
+        /* Let's make sure that the deps really are in order before we start this. Normally the job engine
+         * should have taken care of this already, but let's check this here again. After all, our
+         * dependencies might not be in effect anymore, due to a reload or due to a failed condition. */
         if (!unit_verify_deps(u))
                 return -ENOLINK;
 
@@ -1802,11 +1795,9 @@ int unit_start(Unit *u) {
         if (!UNIT_VTABLE(u)->start)
                 return -EBADR;
 
-        /* We don't suppress calls to ->start() here when we are
-         * already starting, to allow this request to be used as a
-         * "hurry up" call, for example when the unit is in some "auto
-         * restart" state where it waits for a holdoff timer to elapse
-         * before it will start again. */
+        /* We don't suppress calls to ->start() here when we are already starting, to allow this request to
+         * be used as a "hurry up" call, for example when the unit is in some "auto restart" state where it
+         * waits for a holdoff timer to elapse before it will start again. */
 
         unit_add_to_dbus_queue(u);
 
@@ -1896,7 +1887,7 @@ int unit_reload(Unit *u) {
 
         state = unit_active_state(u);
         if (state == UNIT_RELOADING)
-                return -EALREADY;
+                return -EAGAIN;
 
         if (state != UNIT_ACTIVE) {
                 log_unit_warning(u, "Unit cannot be reloaded because it is inactive.");
@@ -2045,7 +2036,7 @@ static void unit_check_binds_to(Unit *u) {
         log_unit_info(u, "Unit is bound to inactive unit %s. Stopping, too.", other->id);
 
         /* A unit we need to run is gone. Sniff. Let's stop this. */
-        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
+        r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, NULL, &error, NULL);
         if (r < 0)
                 log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
 }
@@ -2061,25 +2052,25 @@ static void retroactively_start_dependencies(Unit *u) {
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_REQUIRES], i)
                 if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);
 
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BINDS_TO], i)
                 if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL, NULL);
 
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_WANTS], i)
                 if (!hashmap_get(u->dependencies[UNIT_AFTER], other) &&
                     !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL);
+                        manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL, NULL);
 
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTS], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
 
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_CONFLICTED_BY], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
 }
 
 static void retroactively_stop_dependencies(Unit *u) {
@@ -2093,7 +2084,7 @@ static void retroactively_stop_dependencies(Unit *u) {
         /* Pull down units which are bound to us recursively if enabled */
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_BOUND_BY], i)
                 if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
-                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
+                        manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL, NULL);
 }
 
 void unit_start_on_failure(Unit *u) {
@@ -2112,7 +2103,7 @@ void unit_start_on_failure(Unit *u) {
         HASHMAP_FOREACH_KEY(v, other, u->dependencies[UNIT_ON_FAILURE], i) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
-                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, &error, NULL);
+                r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, &error, NULL);
                 if (r < 0)
                         log_unit_warning_errno(u, r, "Failed to enqueue OnFailure= job, ignoring: %s", bus_error_message(&error, r));
         }
@@ -2502,17 +2493,17 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag
 
                 if (os != UNIT_FAILED && ns == UNIT_FAILED) {
                         reason = strjoina("unit ", u->id, " failed");
-                        (void) emergency_action(m, u->failure_action, 0, u->reboot_arg, unit_failure_action_exit_status(u), reason);
+                        emergency_action(m, u->failure_action, 0, u->reboot_arg, unit_failure_action_exit_status(u), reason);
                 } else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && ns == UNIT_INACTIVE) {
                         reason = strjoina("unit ", u->id, " succeeded");
-                        (void) emergency_action(m, u->success_action, 0, u->reboot_arg, unit_success_action_exit_status(u), reason);
+                        emergency_action(m, u->success_action, 0, u->reboot_arg, unit_success_action_exit_status(u), reason);
                 }
         }
 
         unit_add_to_gc_queue(u);
 }
 
-int unit_watch_pid(Unit *u, pid_t pid) {
+int unit_watch_pid(Unit *u, pid_t pid, bool exclusive) {
         int r;
 
         assert(u);
@@ -2520,6 +2511,12 @@ int unit_watch_pid(Unit *u, pid_t pid) {
 
         /* Watch a specific PID */
 
+        /* Caller might be sure that this PID belongs to this unit only. Let's take this
+         * opportunity to remove any stalled references to this PID as they can be created
+         * easily (when watching a process which is not our direct child). */
+        if (exclusive)
+                manager_unwatch_pid(u->manager, pid);
+
         r = set_ensure_allocated(&u->pids, NULL);
         if (r < 0)
                 return r;
@@ -3199,7 +3196,7 @@ static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) {
         return serialize_item(f, key, s);
 }
 
-static const char *ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
+static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
         [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes",
         [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets",
         [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes",
@@ -4092,14 +4089,20 @@ int unit_patch_contexts(Unit *u) {
                                         return -ENOMEM;
                         }
 
-                        /* If the dynamic user option is on, let's make sure that the unit can't leave its UID/GID
-                         * around in the file system or on IPC objects. Hence enforce a strict sandbox. */
+                        /* If the dynamic user option is on, let's make sure that the unit can't leave its
+                         * UID/GID around in the file system or on IPC objects. Hence enforce a strict
+                         * sandbox. */
 
                         ec->private_tmp = true;
                         ec->remove_ipc = true;
                         ec->protect_system = PROTECT_SYSTEM_STRICT;
                         if (ec->protect_home == PROTECT_HOME_NO)
                                 ec->protect_home = PROTECT_HOME_READ_ONLY;
+
+                        /* Make sure this service can neither benefit from SUID/SGID binaries nor create
+                         * them. */
+                        ec->no_new_privileges = true;
+                        ec->restrict_suid_sgid = true;
                 }
         }
 
@@ -4429,7 +4432,7 @@ int unit_make_transient(Unit *u) {
         return 0;
 }
 
-static void log_kill(pid_t pid, int sig, void *userdata) {
+static int log_kill(pid_t pid, int sig, void *userdata) {
         _cleanup_free_ char *comm = NULL;
 
         (void) get_process_comm(pid, &comm);
@@ -4437,13 +4440,15 @@ static void log_kill(pid_t pid, int sig, void *userdata) {
         /* Don't log about processes marked with brackets, under the assumption that these are temporary processes
            only, like for example systemd's own PAM stub process. */
         if (comm && comm[0] == '(')
-                return;
+                return 0;
 
         log_unit_notice(userdata,
                         "Killing process " PID_FMT " (%s) with signal SIG%s.",
                         pid,
                         strna(comm),
                         signal_to_string(sig));
+
+        return 1;
 }
 
 static int operation_to_signal(KillContext *c, KillOperation k) {
@@ -4608,7 +4613,7 @@ int unit_require_mounts_for(Unit *u, const char *path, UnitDependencyMask mask)
         if (!p)
                 return -ENOMEM;
 
-        path = path_simplify(p, false);
+        path = path_simplify(p, true);
 
         if (!path_is_normalized(path))
                 return -EPERM;
@@ -5395,29 +5400,31 @@ int unit_prepare_exec(Unit *u) {
         return 0;
 }
 
-static void log_leftover(pid_t pid, int sig, void *userdata) {
+static int log_leftover(pid_t pid, int sig, void *userdata) {
         _cleanup_free_ char *comm = NULL;
 
         (void) get_process_comm(pid, &comm);
 
         if (comm && comm[0] == '(') /* Most likely our own helper process (PAM?), ignore */
-                return;
+                return 0;
 
         log_unit_warning(userdata,
                          "Found left-over process " PID_FMT " (%s) in control group while starting unit. Ignoring.\n"
                          "This usually indicates unclean termination of a previous run, or service implementation deficiencies.",
                          pid, strna(comm));
+
+        return 1;
 }
 
-void unit_warn_leftover_processes(Unit *u) {
+int unit_warn_leftover_processes(Unit *u) {
         assert(u);
 
         (void) unit_pick_cgroup_path(u);
 
         if (!u->cgroup_path)
-                return;
+                return 0;
 
-        (void) cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, 0, 0, NULL, log_leftover, u);
+        return cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, 0, 0, NULL, log_leftover, u);
 }
 
 bool unit_needs_console(Unit *u) {
@@ -5586,6 +5593,20 @@ int unit_success_action_exit_status(Unit *u) {
         return r;
 }
 
+int unit_test_trigger_loaded(Unit *u) {
+        Unit *trigger;
+
+        /* Tests whether the unit to trigger is loaded */
+
+        trigger = UNIT_TRIGGER(u);
+        if (!trigger)
+                return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT), "Refusing to start, unit to trigger not loaded.");
+        if (trigger->load_state != UNIT_LOADED)
+                return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT), "Refusing to start, unit %s to trigger not loaded.", u->id);
+
+        return 0;
+}
+
 static const char* const collect_mode_table[_COLLECT_MODE_MAX] = {
         [COLLECT_INACTIVE] = "inactive",
         [COLLECT_INACTIVE_OR_FAILED] = "inactive-or-failed",
index 43cf157..28878b5 100644 (file)
@@ -349,6 +349,9 @@ typedef struct Unit {
         bool exported_log_rate_limit_interval:1;
         bool exported_log_rate_limit_burst:1;
 
+        /* Whether we warned about clamping the CPU quota period */
+        bool warned_clamping_cpu_quota_period:1;
+
         /* When writing transient unit files, stores which section we stored last. If < 0, we didn't write any yet. If
          * == 0 we are in the [Unit] section, if > 0 we are in the unit type-specific section. */
         signed int last_section_private:2;
@@ -675,7 +678,7 @@ typedef enum UnitNotifyFlags {
 
 void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags);
 
-int unit_watch_pid(Unit *u, pid_t pid);
+int unit_watch_pid(Unit *u, pid_t pid, bool exclusive);
 void unit_unwatch_pid(Unit *u, pid_t pid);
 void unit_unwatch_all_pids(Unit *u);
 
@@ -775,7 +778,7 @@ static inline bool unit_supported(Unit *u) {
 void unit_warn_if_dir_nonempty(Unit *u, const char* where);
 int unit_fail_if_noncanonical(Unit *u, const char* where);
 
-int unit_start_limit_test(Unit *u);
+int unit_test_start_limit(Unit *u);
 
 void unit_unref_uid(Unit *u, bool destroy_now);
 int unit_ref_uid(Unit *u, uid_t uid, bool clean_ipc);
@@ -804,7 +807,7 @@ void unit_unlink_state_files(Unit *u);
 
 int unit_prepare_exec(Unit *u);
 
-void unit_warn_leftover_processes(Unit *u);
+int unit_warn_leftover_processes(Unit *u);
 
 bool unit_needs_console(Unit *u);
 
@@ -827,6 +830,8 @@ int unit_exit_status(Unit *u);
 int unit_success_action_exit_status(Unit *u);
 int unit_failure_action_exit_status(Unit *u);
 
+int unit_test_trigger_loaded(Unit *u);
+
 /* Macros which append UNIT= or USER_UNIT= to the message */
 
 #define log_unit_full(unit, level, error, ...)                          \
index 6ce5dfc..35885df 100644 (file)
@@ -1,6 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <sys/statvfs.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "coredump-vacuum.h"
 #include "fs-util.h"
 #include "hashmap.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "string-util.h"
 #include "time-util.h"
 #include "user-util.h"
-#include "util.h"
 
 #define DEFAULT_MAX_USE_LOWER (uint64_t) (1ULL*1024ULL*1024ULL)           /* 1 MiB */
 #define DEFAULT_MAX_USE_UPPER (uint64_t) (4ULL*1024ULL*1024ULL*1024ULL)   /* 4 GiB */
index ecbb4bf..0237016 100644 (file)
@@ -35,6 +35,7 @@
 #include "log.h"
 #include "macro.h"
 #include "main-func.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "mkdir.h"
 #include "parse-util.h"
@@ -48,7 +49,6 @@
 #include "strv.h"
 #include "tmpfile-util.h"
 #include "user-util.h"
-#include "util.h"
 
 /* The maximum size up to which we process coredumps */
 #define PROCESS_SIZE_MAX ((uint64_t) (2LLU*1024LLU*1024LLU*1024LLU))
@@ -369,7 +369,7 @@ static int save_external_coredump(
         if (r < 0)
                 return log_error_errno(r, "Failed to determine coredump file name: %m");
 
-        mkdir_p_label("/var/lib/systemd/coredump", 0755);
+        (void) mkdir_p_label("/var/lib/systemd/coredump", 0755);
 
         fd = open_tmpfile_linkable(fn, O_RDWR|O_CLOEXEC, &tmp);
         if (fd < 0)
index fbee242..b239d81 100644 (file)
@@ -859,7 +859,7 @@ static int save_core(sd_journal *j, FILE *file, char **path, bool *unlink_temp)
 
 error:
         if (temp) {
-                unlink(temp);
+                (void) unlink(temp);
                 log_debug("Removed temporary file %s", temp);
         }
         return r;
@@ -985,7 +985,7 @@ finish:
 
         if (unlink_path) {
                 log_debug("Removed temporary file %s", path);
-                unlink(path);
+                (void) unlink(path);
         }
 
         return r;
index dab4c1a..ab1ac12 100644 (file)
@@ -3,6 +3,8 @@
 #include <dwarf.h>
 #include <elfutils/libdwfl.h>
 #include <stdio_ext.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "fd-util.h"
index 8759a26..e9b2168 100644 (file)
@@ -1,7 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
+#include <fcntl.h>
 #include <stdio_ext.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "alloc-util.h"
 #include "dropin.h"
@@ -262,6 +265,7 @@ static int create_disk(
                 "RemainAfterExit=yes\n"
                 "TimeoutSec=0\n" /* the binary handles timeouts anyway */
                 "KeyringMode=shared\n" /* make sure we can share cached keys among instances */
+                "OOMScoreAdjust=500\n" /* unlocking can allocate a lot of memory if Argon2 is used */
                 "ExecStart=" SYSTEMD_CRYPTSETUP_PATH " attach '%s' '%s' '%s' '%s'\n"
                 "ExecStop=" SYSTEMD_CRYPTSETUP_PATH " detach '%s'\n",
                 name_escaped, u_escaped, strempty(password_escaped), strempty(filtered_escaped),
@@ -287,10 +291,6 @@ static int create_disk(
                 return log_error_errno(r, "Failed to write unit file %s: %m", n);
 
         if (!noauto) {
-                r = generator_add_symlink(arg_dest, d, "wants", n);
-                if (r < 0)
-                        return r;
-
                 r = generator_add_symlink(arg_dest,
                                           netdev ? "remote-cryptsetup.target" : "cryptsetup.target",
                                           nofail ? "wants" : "requires", n);
index 9cb52dd..864d6ff 100644 (file)
@@ -4,6 +4,9 @@
 #include <mntent.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "sd-device.h"
 
 #include "log.h"
 #include "main-func.h"
 #include "mount-util.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "pretty-print.h"
 #include "string-util.h"
 #include "strv.h"
-#include "pretty-print.h"
-#include "util.h"
 
 /* internal helper */
 #define ANY_LUKS "LUKS"
@@ -44,6 +47,8 @@ static unsigned arg_tries = 3;
 static bool arg_readonly = false;
 static bool arg_verify = false;
 static bool arg_discards = false;
+static bool arg_same_cpu_crypt = false;
+static bool arg_submit_from_crypt_cpus = false;
 static bool arg_tcrypt_hidden = false;
 static bool arg_tcrypt_system = false;
 #ifdef CRYPT_TCRYPT_VERA_MODES
@@ -199,6 +204,10 @@ static int parse_one_option(const char *option) {
                 arg_verify = true;
         else if (STR_IN_SET(option, "allow-discards", "discard"))
                 arg_discards = true;
+        else if (streq(option, "same-cpu-crypt"))
+                arg_same_cpu_crypt = true;
+        else if (streq(option, "submit-from-crypt-cpus"))
+                arg_submit_from_crypt_cpus = true;
         else if (streq(option, "luks"))
                 arg_type = ANY_LUKS;
         else if (streq(option, "tcrypt"))
@@ -557,6 +566,10 @@ static int attach_luks_or_plain(struct crypt_device *cd,
                         log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file);
                         return -EAGAIN; /* Log actual error, but return EAGAIN */
                 }
+                if (r == -EINVAL) {
+                        log_error_errno(r, "Failed to activate with key file '%s'. (Key file missing?)", key_file);
+                        return -EAGAIN; /* Log actual error, but return EAGAIN */
+                }
                 if (r < 0)
                         return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file);
         } else {
@@ -602,6 +615,24 @@ static int help(void) {
         return 0;
 }
 
+static uint32_t determine_flags(void) {
+        uint32_t flags = 0;
+
+        if (arg_readonly)
+                flags |= CRYPT_ACTIVATE_READONLY;
+
+        if (arg_discards)
+                flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
+
+        if (arg_same_cpu_crypt)
+                flags |= CRYPT_ACTIVATE_SAME_CPU_CRYPT;
+
+        if (arg_submit_from_crypt_cpus)
+                flags |= CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS;
+
+        return flags;
+}
+
 static int run(int argc, char *argv[]) {
         _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
         int r;
@@ -666,11 +697,7 @@ static int run(int argc, char *argv[]) {
                         return 0;
                 }
 
-                if (arg_readonly)
-                        flags |= CRYPT_ACTIVATE_READONLY;
-
-                if (arg_discards)
-                        flags |= CRYPT_ACTIVATE_ALLOW_DISCARDS;
+                flags = determine_flags();
 
                 if (arg_timeout == USEC_INFINITY)
                         until = 0;
index 1bed18c..ec2ac9b 100755 (executable)
@@ -17,6 +17,9 @@
   along with systemd; If not, see <http://www.gnu.org/licenses/>.
 ***/
 
+#include <unistd.h>
+#include <sys/types.h>
+
 #include "alloc-util.h"
 #include "bus-internal.h"
 #include "bus-util.h"
index fa4ca57..1b5fb2a 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <unistd.h>
+
 #include "alloc-util.h"
 #include "generator.h"
 #include "mkdir.h"
@@ -9,7 +11,6 @@
 #include "string-util.h"
 #include "strv.h"
 #include "unit-name.h"
-#include "util.h"
 
 static const char *arg_dest = NULL;
 static char *arg_default_unit = NULL;
index 1ffbc6c..c28a816 100644 (file)
@@ -14,6 +14,7 @@
 #include "locale-util.h"
 #include "log.h"
 #include "main-func.h"
+#include "nulstr-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-util.h"
@@ -24,7 +25,6 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
-#include "util.h"
 
 static const char prefixes[] =
         "/etc\0"
index 9d64d95..b2558f0 100644 (file)
@@ -14,7 +14,7 @@ static int environment_dirs(char ***ret) {
         _cleanup_free_ char *c = NULL;
         int r;
 
-        dirs = strv_split_nulstr(CONF_PATHS_NULSTR("environment.d"));
+        dirs = strv_new(CONF_PATHS_USR("environment.d"), NULL);
         if (!dirs)
                 return -ENOMEM;
 
index dde1157..c21cf76 100644 (file)
@@ -27,6 +27,7 @@
 #include "fileio.h"
 #include "fs-util.h"
 #include "hostname-util.h"
+#include "kbd-util.h"
 #include "locale-util.h"
 #include "main-func.h"
 #include "mkdir.h"
@@ -253,7 +254,7 @@ static int process_locale(void) {
         if (arg_copy_locale && arg_root) {
 
                 mkdir_parents(etc_localeconf, 0755);
-                r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0, COPY_REFLINK);
+                r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0, 0, COPY_REFLINK);
                 if (r != -ENOENT) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to copy %s: %m", etc_localeconf);
@@ -327,7 +328,7 @@ static int process_keymap(void) {
         if (arg_copy_keymap && arg_root) {
 
                 mkdir_parents(etc_vconsoleconf, 0755);
-                r = copy_file("/etc/vconsole.conf", etc_vconsoleconf, 0, 0644, 0, COPY_REFLINK);
+                r = copy_file("/etc/vconsole.conf", etc_vconsoleconf, 0, 0644, 0, 0, COPY_REFLINK);
                 if (r != -ENOENT) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to copy %s: %m", etc_vconsoleconf);
index 524327c..8101f9c 100644 (file)
@@ -265,6 +265,7 @@ static int fsck_progress_socket(void) {
 static int run(int argc, char *argv[]) {
         _cleanup_close_pair_ int progress_pipe[2] = { -1, -1 };
         _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+        _cleanup_free_ char *dpath = NULL;
         const char *device, *type;
         bool root_directory;
         struct stat st;
@@ -290,7 +291,11 @@ static int run(int argc, char *argv[]) {
                 return 0;
 
         if (argc > 1) {
-                device = argv[1];
+                dpath = strdup(argv[1]);
+                if (!dpath)
+                        return log_oom();
+
+                device = dpath;
 
                 if (stat(device, &st) < 0)
                         return log_error_errno(errno, "Failed to stat %s: %m", device);
index 55a8242..d35f2f9 100644 (file)
@@ -119,8 +119,7 @@ static int add_swap(
         if (r < 0)
                 return r;
 
-        fputs("# Automatically generated by systemd-fstab-generator\n\n"
-              "[Unit]\n"
+        fputs("[Unit]\n"
               "SourcePath=/etc/fstab\n"
               "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n\n"
               "[Swap]\n", f);
@@ -354,6 +353,12 @@ static int add_mount(
                 "Documentation=man:fstab(5) man:systemd-fstab-generator(8)\n",
                 source);
 
+        /* All mounts under /sysroot need to happen later, at initrd-fs.target time. IOW, it's not
+         * technically part of the basic initrd filesystem itself, and so shouldn't inherit the default
+         * Before=local-fs.target dependency. */
+        if (in_initrd() && path_startswith(where, "/sysroot"))
+                fprintf(f, "DefaultDependencies=no\n");
+
         if (STRPTR_IN_SET(fstype, "nfs", "nfs4") && !(flags & AUTOMOUNT) &&
             fstab_test_yes_no_option(opts, "bg\0" "fg\0")) {
                 /* The default retry timeout that mount.nfs uses for 'bg' mounts
@@ -518,6 +523,8 @@ static int parse_fstab(bool initrd) {
         int r = 0;
 
         fstab_path = initrd ? "/sysroot/etc/fstab" : "/etc/fstab";
+        log_debug("Parsing %s...", fstab_path);
+
         f = setmntent(fstab_path, "re");
         if (!f) {
                 if (errno == ENOENT)
@@ -571,9 +578,9 @@ static int parse_fstab(bool initrd) {
                 noauto = fstab_test_yes_no_option(me->mnt_opts, "noauto\0" "auto\0");
                 nofail = fstab_test_yes_no_option(me->mnt_opts, "nofail\0" "fail\0");
 
-                log_debug("Found entry what=%s where=%s type=%s makefs=%s nofail=%s noauto=%s",
+                log_debug("Found entry what=%s where=%s type=%s makefs=%s growfs=%s noauto=%s nofail=%s",
                           what, where, me->mnt_type,
-                          yes_no(makefs),
+                          yes_no(makefs), yes_no(growfs),
                           yes_no(noauto), yes_no(nofail));
 
                 if (streq(me->mnt_type, "swap"))
@@ -720,23 +727,15 @@ static int add_sysroot_usr_mount(void) {
 }
 
 static int add_volatile_root(void) {
-        const char *from, *to;
-
-        if (arg_volatile_mode != VOLATILE_YES)
-                return 0;
 
         /* Let's add in systemd-remount-volatile.service which will remount the root device to tmpfs if this is
-         * requested, leaving only /usr from the root mount inside. */
-
-        from = strjoina(SYSTEM_DATA_UNIT_PATH "/systemd-volatile-root.service");
-        to = strjoina(arg_dest, "/" SPECIAL_INITRD_ROOT_FS_TARGET, ".requires/systemd-volatile-root.service");
-
-        (void) mkdir_parents(to, 0755);
+         * requested (or as an overlayfs), leaving only /usr from the root mount inside. */
 
-        if (symlink(from, to) < 0)
-                return log_error_errno(errno, "Failed to hook in volatile remount service: %m");
+        if (!IN_SET(arg_volatile_mode, VOLATILE_YES, VOLATILE_OVERLAY))
+                return 0;
 
-        return 0;
+        return generator_add_symlink(arg_dest, SPECIAL_INITRD_ROOT_FS_TARGET, "requires",
+                                     SYSTEM_DATA_UNIT_PATH "/" SPECIAL_VOLATILE_ROOT_SERVICE);
 }
 
 static int add_volatile_var(void) {
@@ -868,7 +867,7 @@ static int determine_root(void) {
 }
 
 static int run(const char *dest, const char *dest_early, const char *dest_late) {
-        int r;
+        int r, r2 = 0, r3 = 0;
 
         assert_se(arg_dest = dest);
         assert_se(arg_dest_late = dest_late);
@@ -881,42 +880,27 @@ static int run(const char *dest, const char *dest_early, const char *dest_late)
 
         /* Always honour root= and usr= in the kernel command line if we are in an initrd */
         if (in_initrd()) {
-                int k;
-
                 r = add_sysroot_mount();
 
-                k = add_sysroot_usr_mount();
-                if (k < 0)
-                        r = k;
+                r2 = add_sysroot_usr_mount();
 
-                k = add_volatile_root();
-                if (k < 0)
-                        r = k;
+                r3 = add_volatile_root();
         } else
                 r = add_volatile_var();
 
         /* Honour /etc/fstab only when that's enabled */
         if (arg_fstab_enabled) {
-                int k;
-
-                log_debug("Parsing /etc/fstab");
-
                 /* Parse the local /etc/fstab, possibly from the initrd */
-                k = parse_fstab(false);
-                if (k < 0)
-                        r = k;
+                r2 = parse_fstab(false);
 
                 /* If running in the initrd also parse the /etc/fstab from the host */
-                if (in_initrd()) {
-                        log_debug("Parsing /sysroot/etc/fstab");
-
-                        k = parse_fstab(true);
-                        if (k < 0)
-                                r = k;
-                }
+                if (in_initrd())
+                        r3 = parse_fstab(true);
+                else
+                        r3 = generator_enable_remount_fs_service(arg_dest);
         }
 
-        return r;
+        return r < 0 ? r : r2 < 0 ? r2 : r3;
 }
 
 DEFINE_MAIN_GENERATOR_FUNCTION(run);
diff --git a/src/fuzz/fuzz-bus-label.c b/src/fuzz/fuzz-bus-label.c
new file mode 100644 (file)
index 0000000..46a3d23
--- /dev/null
@@ -0,0 +1,18 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+
+#include "alloc-util.h"
+#include "bus-label.h"
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_free_ char *unescaped = NULL, *escaped = NULL;
+
+        unescaped = bus_label_unescape_n((const char*)data, size);
+        assert_se(unescaped != NULL);
+        escaped = bus_label_escape(unescaped);
+        assert_se(escaped != NULL);
+
+        return 0;
+}
diff --git a/src/fuzz/fuzz-calendarspec.c b/src/fuzz/fuzz-calendarspec.c
new file mode 100644 (file)
index 0000000..8f03150
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "calendarspec.h"
+#include "fd-util.h"
+#include "fuzz.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_(calendar_spec_freep) CalendarSpec *cspec = NULL;
+        _cleanup_free_ char *str = NULL, *p = NULL;
+
+        if (!getenv("SYSTEMD_LOG_LEVEL"))
+                log_set_max_level(LOG_CRIT);
+
+        str = memdup_suffix0(data, size);
+
+        if (calendar_spec_from_string(str, &cspec) >= 0) {
+                (void) calendar_spec_valid(cspec);
+                (void) calendar_spec_normalize(cspec);
+                (void) calendar_spec_to_string(cspec, &p);
+        }
+
+        return 0;
+}
index 01fe350..71bb99a 100644 (file)
@@ -1,5 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include "fuzz.h"
 
 #include "sd-dhcp-server.c"
index c9bc2b3..6d887ea 100644 (file)
@@ -49,6 +49,9 @@ static void fuzz_client(const uint8_t *data, size_t size, bool is_information_re
 }
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        if (size > 65536)
+                return 0;
+
         /* This triggers client_receive_advertise */
         fuzz_client(data, size, false);
 
diff --git a/src/fuzz/fuzz-dhcp6-client.options b/src/fuzz/fuzz-dhcp6-client.options
new file mode 100644 (file)
index 0000000..678d526
--- /dev/null
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65536
index c150c81..9bf95b9 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "fuzz.h"
+#include "memory-util.h"
 #include "resolved-dns-packet.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
diff --git a/src/fuzz/fuzz-env-file.c b/src/fuzz/fuzz-env-file.c
new file mode 100644 (file)
index 0000000..3c8ffaa
--- /dev/null
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+
+#include "alloc-util.h"
+#include "env-file.h"
+#include "fd-util.h"
+#include "fuzz.h"
+#include "strv.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_strv_free_ char **rl = NULL, **rlp =  NULL;
+
+        if (size == 0 || size > 65535)
+                return 0;
+
+        f = fmemopen((char*) data, size, "re");
+        assert_se(f);
+
+        /* We don't want to fill the logs with messages about parse errors.
+         * Disable most logging if not running standalone */
+        if (!getenv("SYSTEMD_LOG_LEVEL"))
+                log_set_max_level(LOG_CRIT);
+
+        (void) load_env_file(f, NULL, &rl);
+        assert_se(fseek(f, 0, SEEK_SET) == 0);
+        (void) load_env_file_pairs(f, NULL, &rlp);
+
+        return 0;
+}
diff --git a/src/fuzz/fuzz-env-file.options b/src/fuzz/fuzz-env-file.options
new file mode 100644 (file)
index 0000000..0824b19
--- /dev/null
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
diff --git a/src/fuzz/fuzz-hostname-util.c b/src/fuzz/fuzz-hostname-util.c
new file mode 100644 (file)
index 0000000..deaf811
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fuzz.h"
+#include "hostname-util.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_free_ char *ret = NULL;
+
+        if (size == 0)
+                return 0;
+
+        f = fmemopen((char*) data, size, "re");
+        assert_se(f);
+
+        /* We don't want to fill the logs with messages about parse errors.
+         * Disable most logging if not running standalone */
+        if (!getenv("SYSTEMD_LOG_LEVEL"))
+                log_set_max_level(LOG_CRIT);
+
+        (void) read_etc_hostname_stream(f, &ret);
+
+        return 0;
+}
index 5d6c8eb..0991b28 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <linux/sockios.h>
 #include <sys/ioctl.h>
+#include <unistd.h>
 
 #include "fd-util.h"
 #include "fuzz.h"
@@ -15,7 +16,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         StdoutStream *stream;
         int v;
 
-        if (size == 0)
+        if (size == 0 || size > 65536)
                 return 0;
 
         if (!getenv("SYSTEMD_LOG_LEVEL"))
diff --git a/src/fuzz/fuzz-journald-stream.options b/src/fuzz/fuzz-journald-stream.options
new file mode 100644 (file)
index 0000000..678d526
--- /dev/null
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65536
index b9291d4..7f25230 100644 (file)
@@ -23,6 +23,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
         _cleanup_(sd_lldp_unrefp) sd_lldp *lldp = NULL;
 
+        if (size > 2048)
+                return 0;
+
         assert_se(sd_event_new(&e) == 0);
         assert_se(sd_lldp_new(&lldp) >= 0);
         assert_se(sd_lldp_set_ifindex(lldp, 42) >= 0);
diff --git a/src/fuzz/fuzz-lldp.options b/src/fuzz/fuzz-lldp.options
new file mode 100644 (file)
index 0000000..60bd9b0
--- /dev/null
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 2048
index 3a1e60f..d8d256d 100644 (file)
@@ -43,6 +43,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
         _cleanup_(sd_ndisc_unrefp) sd_ndisc *nd = NULL;
 
+        if (size > 2048)
+                return 0;
+
         assert_se(sd_event_new(&e) >= 0);
         assert_se(sd_ndisc_new(&nd) >= 0);
         assert_se(sd_ndisc_attach_event(nd, e, 0) >= 0);
diff --git a/src/fuzz/fuzz-ndisc-rs.options b/src/fuzz/fuzz-ndisc-rs.options
new file mode 100644 (file)
index 0000000..60bd9b0
--- /dev/null
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 2048
diff --git a/src/fuzz/fuzz-nspawn-oci.c b/src/fuzz/fuzz-nspawn-oci.c
new file mode 100644 (file)
index 0000000..f7b59f1
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fuzz.h"
+#include "nspawn-oci.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_(settings_freep) Settings *s = NULL;
+
+        if (size == 0)
+                return 0;
+
+        f = fmemopen((char*) data, size, "re");
+        assert_se(f);
+
+        /* We don't want to fill the logs with messages about parse errors.
+         * Disable most logging if not running standalone */
+        if (!getenv("SYSTEMD_LOG_LEVEL"))
+                log_set_max_level(LOG_CRIT);
+
+        (void) oci_load(f, "/dev/null", &s);
+
+        return 0;
+}
diff --git a/src/fuzz/fuzz-nspawn-settings.c b/src/fuzz/fuzz-nspawn-settings.c
new file mode 100644 (file)
index 0000000..6c81eb7
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <errno.h>
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fuzz.h"
+#include "nspawn-settings.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_(settings_freep) Settings *s = NULL;
+
+        if (size == 0)
+                return 0;
+
+        f = fmemopen((char*) data, size, "re");
+        assert_se(f);
+
+        /* We don't want to fill the logs with messages about parse errors.
+         * Disable most logging if not running standalone */
+        if (!getenv("SYSTEMD_LOG_LEVEL"))
+                log_set_max_level(LOG_CRIT);
+
+        (void) settings_load(f, "/dev/null", &s);
+
+        return 0;
+}
diff --git a/src/fuzz/fuzz-time-util.c b/src/fuzz/fuzz-time-util.c
new file mode 100644 (file)
index 0000000..22b2496
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "fuzz.h"
+#include "time-util.h"
+#include "util.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_free_ char *str = NULL;
+        usec_t usec;
+
+        if (!getenv("SYSTEMD_LOG_LEVEL"))
+                log_set_max_level(LOG_CRIT);
+
+        str = memdup_suffix0(data, size);
+
+        (void) parse_timestamp(str, &usec);
+        (void) parse_sec(str, &usec);
+        (void) parse_sec_fix_0(str, &usec);
+        (void) parse_sec_def_infinity(str, &usec);
+        (void) parse_time(str, &usec, USEC_PER_SEC);
+        (void) parse_nsec(str, &usec);
+
+        (void) timezone_is_valid(str, LOG_DEBUG);
+
+        return 0;
+}
diff --git a/src/fuzz/fuzz-udev-database.c b/src/fuzz/fuzz-udev-database.c
new file mode 100644 (file)
index 0000000..9d7c0fa
--- /dev/null
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "device-internal.h"
+#include "device-private.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "fuzz.h"
+#include "tmpfile-util.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_(sd_device_unrefp) sd_device *dev = NULL;
+        _cleanup_(unlink_tempfilep) char filename[] = "/tmp/fuzz-udev-database.XXXXXX";
+        _cleanup_fclose_ FILE *f = NULL;
+
+        if (!getenv("SYSTEMD_LOG_LEVEL"))
+                log_set_max_level(LOG_CRIT);
+
+        assert_se(fmkostemp_safe(filename, "r+", &f) == 0);
+        if (size != 0)
+                assert_se(fwrite(data, size, 1, f) == 1);
+
+        fflush(f);
+        assert_se(device_new_aux(&dev) >= 0);
+        (void) device_read_db_internal_filename(dev, filename);
+        return 0;
+}
index 93de501..84b1ea6 100644 (file)
@@ -79,6 +79,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         assert_se(g);
 
         unit_dump(u, g, "");
+        manager_dump(m, g, ">>>");
 
         return 0;
 }
index f628001..0d1ad2b 100644 (file)
@@ -97,6 +97,10 @@ fuzzers += [
           libshared],
          []],
 
+        [['src/fuzz/fuzz-udev-database.c'],
+         [libshared],
+         []],
+
         [['src/fuzz/fuzz-udev-rules.c'],
          [libudev_core,
           libudev_static,
@@ -108,4 +112,34 @@ fuzzers += [
         [['src/fuzz/fuzz-compress.c'],
          [libshared],
          []],
+
+        [['src/fuzz/fuzz-bus-label.c'],
+         [libshared],
+         []],
+
+        [['src/fuzz/fuzz-env-file.c'],
+         [libshared],
+         []],
+
+        [['src/fuzz/fuzz-hostname-util.c'],
+         [libshared],
+         []],
+
+        [['src/fuzz/fuzz-nspawn-settings.c'],
+         [libshared,
+          libnspawn_core],
+         []],
+
+        [['src/fuzz/fuzz-nspawn-oci.c'],
+         [libshared,
+          libnspawn_core],
+         []],
+
+        [['src/fuzz/fuzz-calendarspec.c'],
+         [libshared],
+         []],
+
+        [['src/fuzz/fuzz-time-util.c'],
+         [libshared],
+         []],
 ]
index d9e29c4..0f1e184 100644 (file)
@@ -18,6 +18,7 @@
 #include "efivars.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "fs-util.h"
 #include "fstab-util.h"
 #include "generator.h"
 #include "gpt.h"
@@ -322,7 +323,6 @@ static int add_swap(const char *path) {
         return generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET, "wants", name);
 }
 
-#if ENABLE_EFI
 static int add_automount(
                 const char *id,
                 const char *what,
@@ -384,8 +384,43 @@ static int add_automount(
         return generator_add_symlink(arg_dest, SPECIAL_LOCAL_FS_TARGET, "wants", unit);
 }
 
-static int add_esp(DissectedPartition *p) {
-        const char *esp;
+static int add_xbootldr(DissectedPartition *p) {
+        int r;
+
+        assert(p);
+
+        if (in_initrd()) {
+                log_debug("In initrd, ignoring the XBOOTLDR partition.");
+                return 0;
+        }
+
+        r = fstab_is_mount_point("/boot");
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse fstab: %m");
+        if (r > 0) {
+                log_debug("/boot specified in fstab, ignoring XBOOTLDR partition.");
+                return 0;
+        }
+
+        r = path_is_busy("/boot");
+        if (r < 0)
+                return r;
+        if (r > 0)
+                return 0;
+
+        return add_automount("boot",
+                             p->node,
+                             "/boot",
+                             p->fstype,
+                             true,
+                             "umask=0077",
+                             "Boot Loader Partition",
+                             120 * USEC_PER_SEC);
+}
+
+#if ENABLE_EFI
+static int add_esp(DissectedPartition *p, bool has_xbootldr) {
+        const char *esp_path = NULL, *id = NULL;
         int r;
 
         assert(p);
@@ -395,21 +430,37 @@ static int add_esp(DissectedPartition *p) {
                 return 0;
         }
 
-        /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice */
-        esp = access("/efi/", F_OK) >= 0 ? "/efi" : "/boot";
+        /* If /efi exists we'll use that. Otherwise we'll use /boot, as that's usually the better choice, but
+         * only if there's no explicit XBOOTLDR partition around. */
+        if (access("/efi", F_OK) < 0) {
+                if (errno != ENOENT)
+                        return log_error_errno(errno, "Failed to determine whether /efi exists: %m");
+
+                /* Use /boot as fallback, but only if there's no XBOOTLDR partition */
+                if (!has_xbootldr) {
+                        esp_path = "/boot";
+                        id = "boot";
+                }
+        }
+        if (!esp_path)
+                esp_path = "/efi";
+        if (!id)
+                id = "efi";
 
         /* We create an .automount which is not overridden by the .mount from the fstab generator. */
-        r = fstab_is_mount_point(esp);
+        r = fstab_is_mount_point(esp_path);
         if (r < 0)
                 return log_error_errno(r, "Failed to parse fstab: %m");
         if (r > 0) {
-                log_debug("%s specified in fstab, ignoring.", esp);
+                log_debug("%s specified in fstab, ignoring.", esp_path);
                 return 0;
         }
 
-        r = path_is_busy(esp);
-        if (r != 0)
-                return r < 0 ? r : 0;
+        r = path_is_busy(esp_path);
+        if (r < 0)
+                return r;
+        if (r > 0)
+                return 0;
 
         if (is_efi_boot()) {
                 sd_id128_t loader_uuid;
@@ -425,15 +476,15 @@ static int add_esp(DissectedPartition *p) {
                         return log_error_errno(r, "Failed to read ESP partition UUID: %m");
 
                 if (!sd_id128_equal(p->uuid, loader_uuid)) {
-                        log_debug("Partition for %s does not appear to be the partition we are booted from.", esp);
+                        log_debug("Partition for %s does not appear to be the partition we are booted from.", p->node);
                         return 0;
                 }
         } else
                 log_debug("Not an EFI boot, skipping ESP check.");
 
-        return add_automount("boot",
+        return add_automount(id,
                              p->node,
-                             esp,
+                             esp_path,
                              p->fstype,
                              true,
                              "umask=0077",
@@ -441,7 +492,7 @@ static int add_esp(DissectedPartition *p) {
                              120 * USEC_PER_SEC);
 }
 #else
-static int add_esp(DissectedPartition *p) {
+static int add_esp(DissectedPartition *p, bool has_xbootldr) {
         return 0;
 }
 #endif
@@ -467,13 +518,13 @@ static int add_root_rw(DissectedPartition *p) {
                 return 0;
         }
 
+        (void) generator_enable_remount_fs_service(arg_dest);
+
         path = strjoina(arg_dest, "/systemd-remount-fs.service.d/50-remount-rw.conf");
         (void) mkdir_parents(path, 0755);
 
         r = write_string_file(path,
                               "# Automatically generated by systemd-gpt-generator\n\n"
-                              "[Unit]\n"
-                              "ConditionPathExists=\n\n" /* We need to turn off the ConditionPathExist= in the main unit file */
                               "[Service]\n"
                               "Environment=SYSTEMD_REMOUNT_ROOT_RW=1\n",
                               WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_NOFOLLOW);
@@ -483,7 +534,7 @@ static int add_root_rw(DissectedPartition *p) {
         return 0;
 }
 
-static int open_parent(dev_t devnum, int *ret) {
+static int open_parent_devno(dev_t devnum, int *ret) {
         _cleanup_(sd_device_unrefp) sd_device *d = NULL;
         const char *name, *devtype, *node;
         sd_device *parent;
@@ -551,7 +602,7 @@ static int enumerate_partitions(dev_t devnum) {
         _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
         int r, k;
 
-        r = open_parent(devnum, &fd);
+        r = open_parent_devno(devnum, &fd);
         if (r <= 0)
                 return r;
 
@@ -569,8 +620,14 @@ static int enumerate_partitions(dev_t devnum) {
                         r = k;
         }
 
+        if (m->partitions[PARTITION_XBOOTLDR].found) {
+                k = add_xbootldr(m->partitions + PARTITION_XBOOTLDR);
+                if (k < 0)
+                        r = k;
+        }
+
         if (m->partitions[PARTITION_ESP].found) {
-                k = add_esp(m->partitions + PARTITION_ESP);
+                k = add_esp(m->partitions + PARTITION_ESP, m->partitions[PARTITION_XBOOTLDR].found);
                 if (k < 0)
                         r = k;
         }
@@ -678,6 +735,9 @@ static int add_root_mount(void) {
                         return r;
         }
 
+        /* Note that we do not need to enable systemd-remount-fs.service here. If
+         * /etc/fstab exists, systemd-fstab-generator will pull it in for us. */
+
         return add_mount(
                         "root",
                         "/dev/gpt-auto-root",
@@ -704,8 +764,25 @@ static int add_mounts(void) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to determine block device of /usr file system: %m");
                 if (r == 0) {
-                        log_debug("Neither root nor /usr file system are on a (single) block device.");
-                        return 0;
+                        _cleanup_free_ char *p = NULL;
+                        mode_t m;
+
+                        /* If the root mount has been replaced by some form of volatile file system (overlayfs), the
+                         * original root block device node is symlinked in /run/systemd/volatile-root. Let's read that
+                         * here. */
+                        r = readlink_malloc("/run/systemd/volatile-root", &p);
+                        if (r == -ENOENT) {
+                                log_debug("Neither root nor /usr file system are on a (single) block device.");
+                                return 0;
+                        }
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to read symlink /run/systemd/volatile-root: %m");
+
+                        r = device_path_parse_major_minor(p, &m, &devno);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse major/minor device node: %m");
+                        if (!S_ISBLK(m))
+                                return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Volatile root device is of wrong type.");
                 }
         }
 
index 8b127ca..02eb0c9 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <errno.h>
 #include <stdio.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "fstab-util.h"
@@ -13,7 +14,6 @@
 #include "special.h"
 #include "string-util.h"
 #include "unit-name.h"
-#include "util.h"
 
 static const char *arg_dest = "/tmp";
 static char *arg_resume_device = NULL;
index 7777450..c35ef55 100644 (file)
@@ -3,6 +3,8 @@
 #include <errno.h>
 #include <string.h>
 #include <sys/utsname.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
@@ -19,6 +21,7 @@
 #include "main-func.h"
 #include "missing_capability.h"
 #include "nscd-flush.h"
+#include "nulstr-util.h"
 #include "os-util.h"
 #include "parse-util.h"
 #include "path-util.h"
index 06049e7..60551ec 100644 (file)
@@ -70,7 +70,7 @@ static int help(void) {
         if (r < 0)
                 return log_oom();
 
-        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+        printf("%s [OPTIONS...] {COMMAND}\n\n"
                "Generate and print id128 strings.\n\n"
                "  -h --help               Show this help\n"
                "  -p --pretty             Generate samples of program code\n"
index 7db03b2..cd6822f 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
+
 #include "alloc-util.h"
 #include "build.h"
 #include "curl-util.h"
index a03e844..6a7be64 100644 (file)
@@ -7,6 +7,7 @@
 #include "sd-event.h"
 
 #include "hashmap.h"
+#include "time-util.h"
 
 typedef struct CurlGlue CurlGlue;
 
index 6a02b47..c1c946c 100644 (file)
@@ -223,7 +223,7 @@ static int raw_export_process(RawExport *e) {
 
 finish:
         if (r >= 0) {
-                (void) copy_times(e->input_fd, e->output_fd);
+                (void) copy_times(e->input_fd, e->output_fd, COPY_CRTIME);
                 (void) copy_xattr(e->input_fd, e->output_fd);
         }
 
index 4907106..77d24b8 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <getopt.h>
+#include <locale.h>
 
 #include "sd-event.h"
 #include "sd-id128.h"
@@ -77,8 +78,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
 
         if (argc >= 3)
                 path = argv[2];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+        path = empty_or_dash_to_null(path);
 
         determine_compression_from_filename(path);
 
@@ -154,8 +154,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
 
         if (argc >= 3)
                 path = argv[2];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+        path = empty_or_dash_to_null(path);
 
         determine_compression_from_filename(path);
 
index 89f0301..1f63ebb 100644 (file)
@@ -15,6 +15,7 @@
 #include "import-common.h"
 #include "os-util.h"
 #include "process-util.h"
+#include "selinux-util.h"
 #include "signal-util.h"
 #include "tmpfile-util.h"
 #include "util.h"
@@ -62,6 +63,7 @@ int import_make_read_only(const char *path) {
 
 int import_fork_tar_x(const char *path, pid_t *ret) {
         _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
+        bool use_selinux;
         pid_t pid;
         int r;
 
@@ -71,6 +73,8 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
         if (pipe2(pipefd, O_CLOEXEC) < 0)
                 return log_error_errno(errno, "Failed to create pipe for tar: %m");
 
+        use_selinux = mac_selinux_use();
+
         r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
         if (r < 0)
                 return r;
@@ -100,7 +104,8 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
                 if (r < 0)
                         log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
 
-                execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*", NULL);
+                execlp("tar", "tar", "--numeric-owner", "-C", path, "-px", "--xattrs", "--xattrs-include=*",
+                       use_selinux ? "--selinux" : "--no-selinux", NULL);
                 log_error_errno(errno, "Failed to execute tar: %m");
                 _exit(EXIT_FAILURE);
         }
@@ -112,6 +117,7 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
 
 int import_fork_tar_c(const char *path, pid_t *ret) {
         _cleanup_close_pair_ int pipefd[2] = { -1, -1 };
+        bool use_selinux;
         pid_t pid;
         int r;
 
@@ -121,6 +127,8 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
         if (pipe2(pipefd, O_CLOEXEC) < 0)
                 return log_error_errno(errno, "Failed to create pipe for tar: %m");
 
+        use_selinux = mac_selinux_use();
+
         r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
         if (r < 0)
                 return r;
@@ -144,7 +152,8 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
                 if (r < 0)
                         log_error_errno(r, "Failed to drop capabilities, ignoring: %m");
 
-                execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*", ".", NULL);
+                execlp("tar", "tar", "-C", path, "-c", "--xattrs", "--xattrs-include=*",
+                       use_selinux ? "--selinux" : "--no-selinux", ".", NULL);
                 log_error_errno(errno, "Failed to execute tar: %m");
                 _exit(EXIT_FAILURE);
         }
index 35ba6ba..0434449 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <getopt.h>
+#include <locale.h>
 
 #include "alloc-util.h"
 #include "btrfs-util.h"
@@ -116,15 +117,13 @@ static int import_fs(int argc, char *argv[], void *userdata) {
 
         if (argc >= 2)
                 path = argv[1];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+        path = empty_or_dash_to_null(path);
 
         if (argc >= 3)
                 local = argv[2];
         else if (path)
                 local = basename(path);
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+        local = empty_or_dash_to_null(local);
 
         if (local) {
                 if (!machine_name_is_valid(local)) {
index 4b11615..b905832 100644 (file)
@@ -183,7 +183,7 @@ static int raw_import_maybe_convert_qcow2(RawImport *i) {
 
         r = qcow2_convert(i->output_fd, converted_fd);
         if (r < 0) {
-                unlink(t);
+                (void) unlink(t);
                 return log_error_errno(r, "Failed to convert qcow2 image: %m");
         }
 
@@ -215,7 +215,7 @@ static int raw_import_finish(RawImport *i) {
                 return r;
 
         if (S_ISREG(i->st.st_mode)) {
-                (void) copy_times(i->input_fd, i->output_fd);
+                (void) copy_times(i->input_fd, i->output_fd, COPY_CRTIME);
                 (void) copy_xattr(i->input_fd, i->output_fd);
         }
 
index f34244a..cc28557 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <getopt.h>
+#include <locale.h>
 
 #include "sd-event.h"
 #include "sd-id128.h"
@@ -48,15 +49,13 @@ static int import_tar(int argc, char *argv[], void *userdata) {
 
         if (argc >= 2)
                 path = argv[1];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+        path = empty_or_dash_to_null(path);
 
         if (argc >= 3)
                 local = argv[2];
         else if (path)
                 local = basename(path);
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+        local = empty_or_dash_to_null(local);
 
         if (local) {
                 r = tar_strip_suffixes(local, &ll);
@@ -144,15 +143,13 @@ static int import_raw(int argc, char *argv[], void *userdata) {
 
         if (argc >= 2)
                 path = argv[1];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+        path = empty_or_dash_to_null(path);
 
         if (argc >= 3)
                 local = argv[2];
         else if (path)
                 local = basename(path);
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+        local = empty_or_dash_to_null(local);
 
         if (local) {
                 r = raw_strip_suffixes(local, &ll);
index 6881bd6..9f759a7 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
+#include <sys/stat.h>
 #include <sys/xattr.h>
 
 #include "alloc-util.h"
index 3a3e015..4f76421 100644 (file)
@@ -250,7 +250,7 @@ static int raw_pull_maybe_convert_qcow2(RawPull *i) {
 
         r = qcow2_convert(i->raw_job->disk_fd, converted_fd);
         if (r < 0) {
-                unlink(t);
+                (void) unlink(t);
                 return log_error_errno(r, "Failed to convert qcow2 image: %m");
         }
 
@@ -299,7 +299,7 @@ static int raw_pull_copy_auxiliary_file(
 
         local = strjoina(i->image_root, "/", i->local, suffix);
 
-        r = copy_file_atomic(*path, local, 0644, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
+        r = copy_file_atomic(*path, local, 0644, 0, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
         if (r == -EEXIST)
                 log_warning_errno(r, "File %s already exists, not replacing.", local);
         else if (r == -ENOENT)
@@ -364,11 +364,11 @@ static int raw_pull_make_local_copy(RawPull *i) {
 
         r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, COPY_REFLINK);
         if (r < 0) {
-                unlink(tp);
+                (void) unlink(tp);
                 return log_error_errno(r, "Failed to make writable copy of image: %m");
         }
 
-        (void) copy_times(i->raw_job->disk_fd, dfd);
+        (void) copy_times(i->raw_job->disk_fd, dfd, COPY_CRTIME);
         (void) copy_xattr(i->raw_job->disk_fd, dfd);
 
         dfd = safe_close(dfd);
@@ -376,7 +376,7 @@ static int raw_pull_make_local_copy(RawPull *i) {
         r = rename(tp, p);
         if (r < 0)  {
                 r = log_error_errno(errno, "Failed to move writable image into place: %m");
-                unlink(tp);
+                (void) unlink(tp);
                 return r;
         }
 
index e7a208e..3930578 100644 (file)
@@ -244,7 +244,7 @@ static int tar_pull_make_local_copy(TarPull *i) {
 
                 local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
 
-                r = copy_file_atomic(i->settings_path, local_settings, 0664, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
+                r = copy_file_atomic(i->settings_path, local_settings, 0664, 0, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
                 if (r == -EEXIST)
                         log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
                 else if (r == -ENOENT)
index 3376992..7e87124 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <getopt.h>
+#include <locale.h>
 
 #include "sd-event.h"
 #include "sd-id128.h"
@@ -63,8 +64,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
                 local = l;
         }
 
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+        local = empty_or_dash_to_null(local);
 
         if (local) {
                 r = tar_strip_suffixes(local, &ll);
@@ -150,8 +150,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
                 local = l;
         }
 
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+        local = empty_or_dash_to_null(local);
 
         if (local) {
                 r = raw_strip_suffixes(local, &ll);
index bd2b458..1703cfd 100644 (file)
@@ -1,9 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include "fd-util.h"
 #include "log.h"
 #include "qcow2-util.h"
-#include "util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_close_ int sfd = -1, dfd = -1;
index 260dc2e..96ea942 100644 (file)
@@ -4,6 +4,8 @@
 #include <errno.h>
 #include <stdio.h>
 #include <sys/epoll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "sd-bus.h"
@@ -18,9 +20,9 @@
 #include "initreq.h"
 #include "list.h"
 #include "log.h"
-#include "special.h"
-#include "util.h"
+#include "memory-util.h"
 #include "process-util.h"
+#include "special.h"
 
 #define SERVER_FD_MAX 16
 #define TIMEOUT_MSEC ((int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))
index af45fa5..734e8c7 100644 (file)
@@ -5,6 +5,8 @@
 #include <microhttpd.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "sd-bus.h"
index 802c3ea..2321a91 100644 (file)
@@ -265,6 +265,7 @@ static int request_handler(
         const char *header;
         int r, code, fd;
         _cleanup_free_ char *hostname = NULL;
+        bool chunked = false;
         size_t len;
 
         assert(connection);
@@ -290,21 +291,33 @@ static int request_handler(
                 return mhd_respond(connection, MHD_HTTP_UNSUPPORTED_MEDIA_TYPE,
                                    "Content-Type: application/vnd.fdo.journal is required.");
 
+        header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Transfer-Encoding");
+        if (header) {
+                if (!strcaseeq(header, "chunked"))
+                        return mhd_respondf(connection, 0, MHD_HTTP_BAD_REQUEST,
+                                            "Unsupported Transfer-Encoding type: %s", header);
+
+                chunked = true;
+        }
+
         header = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Content-Length");
-        if (!header)
-                return mhd_respond(connection, MHD_HTTP_LENGTH_REQUIRED,
-                                   "Content-Length header is required.");
-        r = safe_atozu(header, &len);
-        if (r < 0)
-                return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED,
-                                    "Content-Length: %s cannot be parsed: %m", header);
-
-        if (len > ENTRY_SIZE_MAX)
-                /* When serialized, an entry of maximum size might be slightly larger,
-                 * so this does not correspond exactly to the limit in journald. Oh well.
-                 */
-                return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE,
-                                    "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX);
+        if (header) {
+                if (chunked)
+                        return mhd_respond(connection, MHD_HTTP_BAD_REQUEST,
+                                           "Content-Length must not specified when Transfer-Encoding type is 'chuncked'");
+
+                r = safe_atozu(header, &len);
+                if (r < 0)
+                        return mhd_respondf(connection, r, MHD_HTTP_LENGTH_REQUIRED,
+                                            "Content-Length: %s cannot be parsed: %m", header);
+
+                if (len > ENTRY_SIZE_MAX)
+                        /* When serialized, an entry of maximum size might be slightly larger,
+                         * so this does not correspond exactly to the limit in journald. Oh well.
+                         */
+                        return mhd_respondf(connection, 0, MHD_HTTP_PAYLOAD_TOO_LARGE,
+                                            "Payload larger than maximum size of %u bytes", ENTRY_SIZE_MAX);
+        }
 
         {
                 const union MHD_ConnectionInfo *ci;
index 535d06a..ebcae2f 100644 (file)
@@ -68,7 +68,11 @@ int process_source(RemoteSource *source, bool compress, bool seal) {
 
         assert(source->importer.iovw.iovec);
 
-        r = writer_write(source->writer, &source->importer.iovw, &source->importer.ts, compress, seal);
+        r = writer_write(source->writer,
+                         &source->importer.iovw,
+                         &source->importer.ts,
+                         &source->importer.boot_id,
+                         compress, seal);
         if (r == -EBADMSG) {
                 log_error_errno(r, "Entry is invalid, ignoring.");
                 r = 0;
index 188ff35..ab5e03a 100644 (file)
@@ -59,6 +59,7 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(Writer, writer, writer_free);
 int writer_write(Writer *w,
                  struct iovec_wrapper *iovw,
                  dual_timestamp *ts,
+                 sd_id128_t *boot_id,
                  bool compress,
                  bool seal) {
         int r;
@@ -75,7 +76,7 @@ int writer_write(Writer *w,
                         return r;
         }
 
-        r = journal_file_append_entry(w->journal, ts, NULL,
+        r = journal_file_append_entry(w->journal, ts, boot_id,
                                       iovw->iovec, iovw->count,
                                       &w->seqnum, NULL, NULL);
         if (r >= 0) {
@@ -93,7 +94,7 @@ int writer_write(Writer *w,
                 log_debug("%s: Successfully rotated journal", w->journal->path);
 
         log_debug("Retrying write.");
-        r = journal_file_append_entry(w->journal, ts, NULL,
+        r = journal_file_append_entry(w->journal, ts, boot_id,
                                       iovw->iovec, iovw->count,
                                       &w->seqnum, NULL, NULL);
         if (r < 0)
index e445859..d42256e 100644 (file)
@@ -28,6 +28,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Writer*, writer_unref);
 int writer_write(Writer *s,
                  struct iovec_wrapper *iovw,
                  dual_timestamp *ts,
+                 sd_id128_t *boot_id,
                  bool compress,
                  bool seal);
 
index 1da32c5..04c66a2 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "alloc-util.h"
 #include "def.h"
+#include "errno-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "journal-file.h"
@@ -466,14 +467,23 @@ static int dispatch_blocking_source_event(sd_event_source *event,
         return journal_remote_handle_raw_source(event, source->importer.fd, EPOLLIN, journal_remote_server_global);
 }
 
-static int accept_connection(const char* type, int fd,
-                             SocketAddress *addr, char **hostname) {
-        int fd2, r;
+static int accept_connection(
+                const char* type,
+                int fd,
+                SocketAddress *addr,
+                char **hostname) {
+
+        _cleanup_close_ int fd2 = -1;
+        int r;
 
         log_debug("Accepting new %s connection on fd:%d", type, fd);
         fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
-        if (fd2 < 0)
+        if (fd2 < 0) {
+                if (ERRNO_IS_ACCEPT_AGAIN(errno))
+                        return -EAGAIN;
+
                 return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
+        }
 
         switch(socket_address_family(addr)) {
         case AF_INET:
@@ -482,18 +492,12 @@ static int accept_connection(const char* type, int fd,
                 char *b;
 
                 r = socket_address_print(addr, &a);
-                if (r < 0) {
-                        log_error_errno(r, "socket_address_print(): %m");
-                        close(fd2);
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "socket_address_print(): %m");
 
                 r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
-                if (r < 0) {
-                        log_error_errno(r, "Resolving hostname failed: %m");
-                        close(fd2);
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "Resolving hostname failed: %m");
 
                 log_debug("Accepted %s %s connection from %s",
                           type,
@@ -501,22 +505,22 @@ static int accept_connection(const char* type, int fd,
                           a);
 
                 *hostname = b;
+                return TAKE_FD(fd2);
+        }
 
-                return fd2;
-        };
         default:
-                log_error("Rejected %s connection with unsupported family %d",
-                          type, socket_address_family(addr));
-                close(fd2);
-
-                return -EINVAL;
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Rejected %s connection with unsupported family %d",
+                                       type, socket_address_family(addr));
         }
 }
 
-static int dispatch_raw_connection_event(sd_event_source *event,
-                                         int fd,
-                                         uint32_t revents,
-                                         void *userdata) {
+static int dispatch_raw_connection_event(
+                sd_event_source *event,
+                int fd,
+                uint32_t revents,
+                void *userdata) {
+
         RemoteServer *s = userdata;
         int fd2;
         SocketAddress addr = {
@@ -526,6 +530,8 @@ static int dispatch_raw_connection_event(sd_event_source *event,
         char *hostname = NULL;
 
         fd2 = accept_connection("raw", fd, &addr, &hostname);
+        if (fd2 == -EAGAIN)
+                return 0;
         if (fd2 < 0)
                 return fd2;
 
index ef3556f..cc96825 100644 (file)
@@ -106,7 +106,7 @@ static int check_cursor_updating(Uploader *u) {
         if (r < 0)
                 return log_error_errno(r, "Cannot save state to %s: %m",
                                        u->state_file);
-        unlink(temp_path);
+        (void) unlink(temp_path);
 
         return 0;
 }
index 4062f12..7beffc1 100644 (file)
@@ -6,6 +6,8 @@
 #include <stdio.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "sd-id128.h"
 #include "fileio.h"
 #include "hashmap.h"
 #include "log.h"
+#include "memory-util.h"
 #include "mkdir.h"
 #include "path-util.h"
 #include "siphash24.h"
+#include "sort-util.h"
 #include "sparse-endian.h"
 #include "strbuf.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tmpfile-util.h"
-#include "util.h"
 
 const char * const catalog_file_dirs[] = {
         "/usr/local/lib/systemd/catalog/",
@@ -33,7 +36,7 @@ const char * const catalog_file_dirs[] = {
         NULL
 };
 
-#define CATALOG_SIGNATURE (uint8_t[]) { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' }
+#define CATALOG_SIGNATURE { 'R', 'H', 'H', 'H', 'K', 'S', 'L', 'P' }
 
 typedef struct CatalogHeader {
         uint8_t signature[8];  /* "RHHHKSLP" */
@@ -209,34 +212,38 @@ int catalog_file_lang(const char* filename, char **lang) {
         return 1;
 }
 
-static int catalog_entry_lang(const char* filename, int line,
-                              const char* t, const char* deflang, char **lang) {
+static int catalog_entry_lang(
+                const char* filename,
+                unsigned line,
+                const char* t,
+                const char* deflang,
+                char **ret) {
+
         size_t c;
+        char *z;
 
         c = strlen(t);
         if (c < 2)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "[%s:%u] Language too short.",
-                                       filename, line);
+                                       "[%s:%u] Language too short.", filename, line);
         if (c > 31)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "[%s:%u] language too long.", filename,
-                                       line);
+                                       "[%s:%u] language too long.", filename, line);
 
         if (deflang) {
                 if (streq(t, deflang)) {
-                        log_warning("[%s:%u] language specified unnecessarily",
-                                    filename, line);
+                        log_warning("[%s:%u] language specified unnecessarily", filename, line);
                         return 0;
-                } else
-                        log_warning("[%s:%u] language differs from default for file",
-                                    filename, line);
+                }
+
+                log_warning("[%s:%u] language differs from default for file", filename, line);
         }
 
-        *lang = strdup(t);
-        if (!*lang)
-                        return -ENOMEM;
+        z = strdup(t);
+        if (!z)
+                return -ENOMEM;
 
+        *ret = z;
         return 0;
 }
 
@@ -367,32 +374,33 @@ int catalog_import_file(Hashmap *h, const char *path) {
         return 0;
 }
 
-static int64_t write_catalog(const char *database, struct strbuf *sb,
-                             CatalogItem *items, size_t n) {
-        CatalogHeader header;
+static int64_t write_catalog(
+                const char *database,
+                struct strbuf *sb,
+                CatalogItem *items,
+                size_t n) {
+
         _cleanup_fclose_ FILE *w = NULL;
-        int r;
-        _cleanup_free_ char *d, *p = NULL;
+        _cleanup_free_ char *p = NULL;
+        CatalogHeader header;
         size_t k;
+        int r;
 
-        d = dirname_malloc(database);
-        if (!d)
-                return log_oom();
-
-        r = mkdir_p(d, 0775);
+        r = mkdir_parents(database, 0755);
         if (r < 0)
-                return log_error_errno(r, "Recursive mkdir %s: %m", d);
+                return log_error_errno(r, "Failed to create parent directories of %s: %m", database);
 
         r = fopen_temporary(database, &w, &p);
         if (r < 0)
                 return log_error_errno(r, "Failed to open database for writing: %s: %m",
                                        database);
 
-        zero(header);
-        memcpy(header.signature, CATALOG_SIGNATURE, sizeof(header.signature));
-        header.header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8));
-        header.catalog_item_size = htole64(sizeof(CatalogItem));
-        header.n_items = htole64(n);
+        header = (CatalogHeader) {
+                .signature = CATALOG_SIGNATURE,
+                .header_size = htole64(ALIGN_TO(sizeof(CatalogHeader), 8)),
+                .catalog_item_size = htole64(sizeof(CatalogItem)),
+                .n_items = htole64(n),
+        };
 
         r = -EIO;
 
@@ -420,7 +428,7 @@ static int64_t write_catalog(const char *database, struct strbuf *sb,
                 goto error;
         }
 
-        fchmod(fileno(w), 0644);
+        (void) fchmod(fileno(w), 0644);
 
         if (rename(p, database) < 0) {
                 r = log_error_errno(errno, "rename (%s -> %s) failed: %m", p, database);
@@ -503,10 +511,10 @@ int catalog_update(const char* database, const char* root, const char* const* di
 }
 
 static int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p) {
+        _cleanup_close_ int fd = -1;
         const CatalogHeader *h;
-        int fd;
-        void *p;
         struct stat st;
+        void *p;
 
         assert(_fd);
         assert(_st);
@@ -516,35 +524,28 @@ static int open_mmap(const char *database, int *_fd, struct stat *_st, void **_p
         if (fd < 0)
                 return -errno;
 
-        if (fstat(fd, &st) < 0) {
-                safe_close(fd);
+        if (fstat(fd, &st) < 0)
                 return -errno;
-        }
 
-        if (st.st_size < (off_t) sizeof(CatalogHeader)) {
-                safe_close(fd);
+        if (st.st_size < (off_t) sizeof(CatalogHeader))
                 return -EINVAL;
-        }
 
         p = mmap(NULL, PAGE_ALIGN(st.st_size), PROT_READ, MAP_SHARED, fd, 0);
-        if (p == MAP_FAILED) {
-                safe_close(fd);
+        if (p == MAP_FAILED)
                 return -errno;
-        }
 
         h = p;
-        if (memcmp(h->signature, CATALOG_SIGNATURE, sizeof(h->signature)) != 0 ||
+        if (memcmp(h->signature, (const uint8_t[]) CATALOG_SIGNATURE, sizeof(h->signature)) != 0 ||
             le64toh(h->header_size) < sizeof(CatalogHeader) ||
             le64toh(h->catalog_item_size) < sizeof(CatalogItem) ||
             h->incompatible_flags != 0 ||
             le64toh(h->n_items) <= 0 ||
             st.st_size < (off_t) (le64toh(h->header_size) + le64toh(h->catalog_item_size) * le64toh(h->n_items))) {
-                safe_close(fd);
                 munmap(p, st.st_size);
                 return -EBADMSG;
         }
 
-        *_fd = fd;
+        *_fd = TAKE_FD(fd);
         *_st = st;
         *_p = p;
 
index 4e6f161..20497d1 100644 (file)
@@ -2,6 +2,7 @@
 #pragma once
 
 #include <stdbool.h>
+#include <stdio.h>
 
 #include "sd-id128.h"
 
index e95ce2b..7a79e56 100644 (file)
@@ -4,6 +4,8 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #if HAVE_XZ
index 6d062de..d60fc50 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "fsprg.h"
 #include "gcrypt-util.h"
+#include "memory-util.h"
 
 #define ISVALID_SECPAR(secpar) (((secpar) % 16 == 0) && ((secpar) >= 16) && ((secpar) <= 16384))
 #define VALIDATE_SECPAR(secpar) assert(ISVALID_SECPAR(secpar));
index 8a9ce8a..da275c2 100644 (file)
@@ -10,6 +10,8 @@
 #include "journal-authenticate.h"
 #include "journal-def.h"
 #include "journal-file.h"
+#include "memory-util.h"
+#include "time-util.h"
 
 static uint64_t journal_file_tag_seqnum(JournalFile *f) {
         uint64_t r;
index 56827f9..91d1c29 100644 (file)
 #include "journal-def.h"
 #include "journal-file.h"
 #include "lookup3.h"
+#include "memory-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "random-util.h"
 #include "set.h"
+#include "sort-util.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
@@ -237,6 +239,9 @@ int journal_file_set_offline(JournalFile *f, bool wait) {
                 int k;
 
                 assert_se(sigfillset(&ss) >= 0);
+                /* Don't block SIGBUS since the offlining thread accesses a memory mapped file.
+                 * Asynchronous SIGBUS signals can safely be handled by either thread. */
+                assert_se(sigdelset(&ss, SIGBUS) >= 0);
 
                 r = pthread_sigmask(SIG_BLOCK, &ss, &saved_ss);
                 if (r > 0)
@@ -1791,7 +1796,9 @@ static int journal_file_append_entry_internal(
         o->entry.realtime = htole64(ts->realtime);
         o->entry.monotonic = htole64(ts->monotonic);
         o->entry.xor_hash = htole64(xor_hash);
-        o->entry.boot_id = boot_id ? *boot_id : f->header->boot_id;
+        if (boot_id)
+                f->header->boot_id = *boot_id;
+        o->entry.boot_id = f->header->boot_id;
 
 #if HAVE_GCRYPT
         r = journal_file_hmac_put_object(f, OBJECT_ENTRY, o, np);
index 29e324d..e1ea368 100644 (file)
@@ -2,6 +2,7 @@
 #pragma once
 
 #include <inttypes.h>
+#include <sys/uio.h>
 
 #if HAVE_GCRYPT
 #  include <gcrypt.h>
@@ -12,9 +13,9 @@
 
 #include "hashmap.h"
 #include "journal-def.h"
-#include "macro.h"
 #include "mmap-cache.h"
 #include "sparse-endian.h"
+#include "time-util.h"
 
 typedef struct JournalMetrics {
         /* For all these: -1 means "pick automatically", and 0 means "no limit enforced" */
index 8618454..5ef11fa 100644 (file)
@@ -13,6 +13,7 @@
 #include "sd-journal.h"
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "io-util.h"
 #include "memfd-util.h"
@@ -20,7 +21,6 @@
 #include "stdio-util.h"
 #include "string-util.h"
 #include "tmpfile-util.h"
-#include "util.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
 
index 2778ce4..a932314 100644 (file)
@@ -14,9 +14,9 @@
 #include "journal-file.h"
 #include "journal-vacuum.h"
 #include "parse-util.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "time-util.h"
-#include "util.h"
 #include "xattr-util.h"
 
 struct vacuum_info {
index 5eff80a..0a06ce7 100644 (file)
@@ -65,7 +65,7 @@ static uint64_t scale_progress(uint64_t scale, uint64_t p, uint64_t m) {
          * Currently all callers use m >= 1, but we keep the check to be defensive.
          */
 
-        if (p >= m || m == 0) /* lgtm [cpp/constant-comparison] */
+        if (p >= m || m == 0) // lgtm[cpp/constant-comparison]
                 return scale;
 
         return scale * p / m;
index 14a02ed..0048909 100644 (file)
@@ -50,7 +50,9 @@
 #include "locale-util.h"
 #include "log.h"
 #include "logs-show.h"
+#include "memory-util.h"
 #include "mkdir.h"
+#include "nulstr-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-util.h"
@@ -119,6 +121,7 @@ static int arg_boot_offset = 0;
 static bool arg_dmesg = false;
 static bool arg_no_hostname = false;
 static const char *arg_cursor = NULL;
+static const char *arg_cursor_file = NULL;
 static const char *arg_after_cursor = NULL;
 static bool arg_show_cursor = false;
 static const char *arg_directory = NULL;
@@ -263,7 +266,11 @@ static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset
         sd_id128_t id = SD_ID128_NULL;
         int off = 0, r;
 
-        if (strlen(x) >= 32) {
+        if (streq(x, "all")) {
+                *boot_id = SD_ID128_NULL;
+                *offset = 0;
+                return 0;
+        } else if (strlen(x) >= 32) {
                 char *t;
 
                 t = strndupa(x, 32);
@@ -291,7 +298,7 @@ static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset
         if (offset)
                 *offset = off;
 
-        return 0;
+        return 1;
 }
 
 static int help(void) {
@@ -315,6 +322,7 @@ static int help(void) {
                "  -c --cursor=CURSOR         Show entries starting at the specified cursor\n"
                "     --after-cursor=CURSOR   Show entries after the specified cursor\n"
                "     --show-cursor           Print the cursor after all the entries\n"
+               "     --cursor-file=FILE      Show entries after cursor in FILE and update FILE\n"
                "  -b --boot[=ID]             Show current boot or the specified boot\n"
                "     --list-boots            Show terse information about recorded boots\n"
                "  -k --dmesg                 Show kernel message log from the current boot\n"
@@ -396,6 +404,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_VERIFY_KEY,
                 ARG_DISK_USAGE,
                 ARG_AFTER_CURSOR,
+                ARG_CURSOR_FILE,
                 ARG_SHOW_CURSOR,
                 ARG_USER_UNIT,
                 ARG_LIST_CATALOG,
@@ -450,6 +459,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "verify-key",     required_argument, NULL, ARG_VERIFY_KEY     },
                 { "disk-usage",     no_argument,       NULL, ARG_DISK_USAGE     },
                 { "cursor",         required_argument, NULL, 'c'                },
+                { "cursor-file",    required_argument, NULL, ARG_CURSOR_FILE    },
                 { "after-cursor",   required_argument, NULL, ARG_AFTER_CURSOR   },
                 { "show-cursor",    no_argument,       NULL, ARG_SHOW_CURSOR    },
                 { "since",          required_argument, NULL, 'S'                },
@@ -587,30 +597,34 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_THIS_BOOT:
                         arg_boot = true;
+                        arg_boot_id = SD_ID128_NULL;
+                        arg_boot_offset = 0;
                         break;
 
                 case 'b':
                         arg_boot = true;
+                        arg_boot_id = SD_ID128_NULL;
+                        arg_boot_offset = 0;
 
                         if (optarg) {
                                 r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
-                                if (r < 0) {
-                                        log_error("Failed to parse boot descriptor '%s'", optarg);
-                                        return -EINVAL;
-                                }
-                        } else {
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to parse boot descriptor '%s'", optarg);
 
-                                /* Hmm, no argument? Maybe the next
-                                 * word on the command line is
-                                 * supposed to be the argument? Let's
-                                 * see if there is one and is parsable
-                                 * as a boot descriptor... */
+                                arg_boot = r;
 
-                                if (optind < argc &&
-                                    parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset) >= 0)
+                        /* Hmm, no argument? Maybe the next
+                         * word on the command line is
+                         * supposed to be the argument? Let's
+                         * see if there is one and is parsable
+                         * as a boot descriptor... */
+                        } else if (optind < argc) {
+                                r = parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset);
+                                if (r >= 0) {
+                                        arg_boot = r;
                                         optind++;
+                                }
                         }
-
                         break;
 
                 case ARG_LIST_BOOTS:
@@ -661,6 +675,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_cursor = optarg;
                         break;
 
+                case ARG_CURSOR_FILE:
+                        arg_cursor_file = optarg;
+                        break;
+
                 case ARG_AFTER_CURSOR:
                         arg_after_cursor = optarg;
                         break;
@@ -1823,7 +1841,7 @@ finish:
         safe_close(fd);
 
         if (k) {
-                unlink(k);
+                (void) unlink(k);
                 free(k);
         }
 
@@ -1883,6 +1901,21 @@ static int verify(sd_journal *j) {
         return r;
 }
 
+static int watch_run_systemd_journal(uint32_t mask) {
+        _cleanup_close_ int watch_fd = -1;
+
+        (void) mkdir_p("/run/systemd/journal", 0755);
+
+        watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+        if (watch_fd < 0)
+                return log_error_errno(errno, "Failed to create inotify object: %m");
+
+        if (inotify_add_watch(watch_fd, "/run/systemd/journal", mask) < 0)
+                return log_error_errno(errno, "Failed to watch \"/run/systemd/journal\": %m");
+
+        return TAKE_FD(watch_fd);
+}
+
 static int flush_to_var(void) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
@@ -1916,19 +1949,13 @@ static int flush_to_var(void) {
         if (r < 0)
                 return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
 
-        mkdir_p("/run/systemd/journal", 0755);
-
-        watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+        watch_fd = watch_run_systemd_journal(IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR);
         if (watch_fd < 0)
-                return log_error_errno(errno, "Failed to create inotify watch: %m");
-
-        r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR);
-        if (r < 0)
-                return log_error_errno(errno, "Failed to watch journal directory: %m");
+                return watch_fd;
 
         for (;;) {
                 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
-                        break;
+                        return 0;
 
                 if (errno != ENOENT)
                         return log_error_errno(errno, "Failed to check for existence of /run/systemd/journal/flushed: %m");
@@ -1941,8 +1968,6 @@ static int flush_to_var(void) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to flush inotify events: %m");
         }
-
-        return 0;
 }
 
 static int send_signal_and_wait(int sig, const char *watch_path) {
@@ -1998,23 +2023,15 @@ static int send_signal_and_wait(int sig, const char *watch_path) {
 
                 /* Let's install the inotify watch, if we didn't do that yet. */
                 if (watch_fd < 0) {
-
-                        mkdir_p("/run/systemd/journal", 0755);
-
-                        watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
+                        watch_fd = watch_run_systemd_journal(IN_MOVED_TO|IN_DONT_FOLLOW|IN_ONLYDIR);
                         if (watch_fd < 0)
-                                return log_error_errno(errno, "Failed to create inotify watch: %m");
-
-                        r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_MOVED_TO|IN_DONT_FOLLOW|IN_ONLYDIR);
-                        if (r < 0)
-                                return log_error_errno(errno, "Failed to watch journal directory: %m");
+                                return watch_fd;
 
                         /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
                         continue;
                 }
 
-                /* OK, all preparatory steps done, let's wait until
-                 * inotify reports an event. */
+                /* OK, all preparatory steps done, let's wait until inotify reports an event. */
 
                 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
                 if (r < 0)
@@ -2077,6 +2094,7 @@ static int wait_for_change(sd_journal *j, int poll_fd) {
 
 int main(int argc, char *argv[]) {
         bool previous_boot_id_valid = false, first_line = true, ellipsized = false, need_seek = false;
+        bool use_cursor = false, after_cursor = false;
         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
         sd_id128_t previous_boot_id;
         int n_shown = 0, r, poll_fd = -1;
@@ -2420,19 +2438,41 @@ int main(int argc, char *argv[]) {
                 }
         }
 
-        if (arg_cursor || arg_after_cursor) {
-                r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
-                if (r < 0) {
-                        log_error_errno(r, "Failed to seek to cursor: %m");
-                        goto finish;
+        if (arg_cursor || arg_after_cursor || arg_cursor_file) {
+                _cleanup_free_ char *cursor_from_file = NULL;
+                const char *cursor = arg_cursor ?: arg_after_cursor;
+
+                if (arg_cursor_file) {
+                        r = read_one_line_file(arg_cursor_file, &cursor_from_file);
+                        if (r < 0 && r != -ENOENT) {
+                                log_error_errno(r, "Failed to read cursor file %s: %m", arg_cursor_file);
+                                goto finish;
+                        }
+
+                        if (r > 0) {
+                                cursor = cursor_from_file;
+                                after_cursor = true;
+                        }
+                } else
+                        after_cursor = !!arg_after_cursor;
+
+                if (cursor) {
+                        r = sd_journal_seek_cursor(j, cursor);
+                        if (r < 0) {
+                                log_error_errno(r, "Failed to seek to cursor: %m");
+                                goto finish;
+                        }
+                        use_cursor = true;
                 }
+        }
 
+        if (use_cursor) {
                 if (!arg_reverse)
-                        r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
+                        r = sd_journal_next_skip(j, 1 + after_cursor);
                 else
-                        r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
+                        r = sd_journal_previous_skip(j, 1 + after_cursor);
 
-                if (arg_after_cursor && r < 2) {
+                if (after_cursor && r < 2) {
                         /* We couldn't find the next entry after the cursor. */
                         if (arg_follow)
                                 need_seek = true;
@@ -2661,14 +2701,26 @@ int main(int argc, char *argv[]) {
                         if (n_shown == 0 && !arg_quiet)
                                 printf("-- No entries --\n");
 
-                        if (arg_show_cursor) {
+                        if (arg_show_cursor || arg_cursor_file) {
                                 _cleanup_free_ char *cursor = NULL;
 
                                 r = sd_journal_get_cursor(j, &cursor);
                                 if (r < 0 && r != -EADDRNOTAVAIL)
                                         log_error_errno(r, "Failed to get cursor: %m");
-                                else if (r >= 0)
-                                        printf("-- cursor: %s\n", cursor);
+                                else if (r >= 0) {
+                                        if (arg_show_cursor)
+                                                printf("-- cursor: %s\n", cursor);
+
+                                        if (arg_cursor_file) {
+                                                r = write_string_file(arg_cursor_file, cursor,
+                                                                      WRITE_STRING_FILE_CREATE |
+                                                                      WRITE_STRING_FILE_ATOMIC);
+                                                if (r < 0)
+                                                        log_error_errno(r,
+                                                                        "Failed to write new cursor to %s: %m",
+                                                                        arg_cursor_file);
+                                        }
+                                }
                         }
 
                         break;
index 5e19c71..46f79fb 100644 (file)
@@ -2,10 +2,13 @@
 #pragma once
 
 #include <inttypes.h>
+#include <sys/socket.h>
 #include <sys/types.h>
 
 #include "sd-id128.h"
 
+#include "time-util.h"
+
 typedef struct ClientContext ClientContext;
 
 #include "journald-server.h"
index 221188d..4efe34c 100644 (file)
@@ -19,6 +19,7 @@
 #include "journald-syslog.h"
 #include "journald-wall.h"
 #include "memfd-util.h"
+#include "memory-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
index 0b42d53..39e968b 100644 (file)
@@ -9,7 +9,7 @@
 #include "list.h"
 #include "random-util.h"
 #include "string-util.h"
-#include "util.h"
+#include "time-util.h"
 
 #define POOLS_MAX 5
 #define BUCKETS_MAX 127
index a299280..9dab51f 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include "util.h"
+#include "time-util.h"
 
 typedef struct JournalRateLimit JournalRateLimit;
 
index 3f6b42d..5f0b3dd 100644 (file)
@@ -16,6 +16,7 @@ typedef struct Server Server;
 #include "journald-stream.h"
 #include "list.h"
 #include "prioq.h"
+#include "time-util.h"
 
 typedef enum Storage {
         STORAGE_AUTO,
index 137c8f0..24d4ac3 100644 (file)
@@ -13,6 +13,7 @@
 #include "alloc-util.h"
 #include "dirent-util.h"
 #include "env-file.h"
+#include "errno-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -159,7 +160,7 @@ static int stdout_stream_save(StdoutStream *s) {
                         return log_oom();
         }
 
-        mkdir_p("/run/systemd/journal/streams", 0755);
+        (void) mkdir_p("/run/systemd/journal/streams", 0755);
 
         r = fopen_temporary(s->state_file, &f, &temp_path);
         if (r < 0)
@@ -605,7 +606,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
 
         fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
         if (fd < 0) {
-                if (errno == EAGAIN)
+                if (ERRNO_IS_ACCEPT_AGAIN(errno))
                         return 0;
 
                 return log_error_errno(errno, "Failed to accept stdout connection: %m");
index b73059a..026649e 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <sys/socket.h>
+
 #include "journald-server.h"
 
 void server_forward_wall(Server *s, int priority, const char *identifier, const char *message, const struct ucred *ucred);
index 0dc453e..e2f7bd7 100644 (file)
@@ -5,14 +5,15 @@
 #include <sys/mman.h>
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "hashmap.h"
 #include "list.h"
 #include "log.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "mmap-cache.h"
 #include "sigbus.h"
-#include "util.h"
 
 typedef struct Window Window;
 typedef struct Context Context;
index 0f99628..82e7d59 100644 (file)
@@ -32,6 +32,7 @@
 #include "list.h"
 #include "lookup3.h"
 #include "missing.h"
+#include "nulstr-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "replace-var.h"
index 7f13b61..1005997 100644 (file)
@@ -4,12 +4,13 @@
 #include "compress.h"
 #include "env-util.h"
 #include "macro.h"
+#include "memory-util.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "process-util.h"
 #include "random-util.h"
 #include "string-util.h"
 #include "tests.h"
-#include "util.h"
 
 typedef int (compress_t)(const void *src, uint64_t src_size, void *dst,
                          size_t dst_alloc_size, size_t *dst_size);
index 1b050b7..fac2b43 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/stat.h>
+
 #if HAVE_LZ4
 #include <lz4.h>
 #endif
 #include "fd-util.h"
 #include "fs-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "path-util.h"
 #include "random-util.h"
 #include "tests.h"
 #include "tmpfile-util.h"
-#include "util.h"
 
 #if HAVE_XZ
 # define XZ_OK 0
index 81dbc22..de9d23a 100644 (file)
@@ -1,10 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <fcntl.h>
+#include <unistd.h>
 
 #include "sd-journal.h"
 
 #include "alloc-util.h"
+#include "chattr-util.h"
 #include "journal-file.h"
 #include "journal-internal.h"
 #include "macro.h"
@@ -19,6 +21,8 @@ int main(int argc, char *argv[]) {
         int r;
 
         assert_se(mkdtemp(dn));
+        (void) chattr_path(dn, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+
         fn = strappend(dn, "/test.journal");
 
         r = journal_file_open(-1, fn, O_CREAT|O_RDWR, 0644, false, 0, false, NULL, NULL, NULL, NULL, &new_journal);
index 860baca..d10e610 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "sd-journal.h"
 
+#include "chattr-util.h"
 #include "log.h"
 #include "parse-util.h"
 #include "rm-rf.h"
@@ -11,7 +12,7 @@
 int main(int argc, char *argv[]) {
         sd_journal *j;
         int r, i, I = 100;
-        char t[] = "/tmp/journal-stream-XXXXXX";
+        char t[] = "/var/tmp/journal-stream-XXXXXX";
 
         test_setup_logging(LOG_DEBUG);
 
@@ -24,6 +25,7 @@ int main(int argc, char *argv[]) {
         log_info("Running %d loops", I);
 
         assert_se(mkdtemp(t));
+        (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
 
         for (i = 0; i < I; i++) {
                 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY);
index cf0561d..449ac8e 100644 (file)
@@ -6,6 +6,7 @@
 #include "sd-journal.h"
 
 #include "alloc-util.h"
+#include "chattr-util.h"
 #include "io-util.h"
 #include "journal-file.h"
 #include "journal-vacuum.h"
@@ -130,13 +131,21 @@ static void setup_interleaved(void) {
         test_close(two);
 }
 
+static void mkdtemp_chdir_chattr(char *path) {
+        assert_se(mkdtemp(path));
+        assert_se(chdir(path) >= 0);
+
+        /* Speed up things a bit on btrfs, ensuring that CoW is turned off for all files created in our
+         * directory during the test run */
+        (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+}
+
 static void test_skip(void (*setup)(void)) {
-        char t[] = "/tmp/journal-skip-XXXXXX";
+        char t[] = "/var/tmp/journal-skip-XXXXXX";
         sd_journal *j;
         int r;
 
-        assert_se(mkdtemp(t));
-        assert_se(chdir(t) >= 0);
+        mkdtemp_chdir_chattr(t);
 
         setup();
 
@@ -189,13 +198,12 @@ static void test_skip(void (*setup)(void)) {
 
 static void test_sequence_numbers(void) {
 
-        char t[] = "/tmp/journal-seq-XXXXXX";
+        char t[] = "/var/tmp/journal-seq-XXXXXX";
         JournalFile *one, *two;
         uint64_t seqnum = 0;
         sd_id128_t seqnum_id;
 
-        assert_se(mkdtemp(t));
-        assert_se(chdir(t) >= 0);
+        mkdtemp_chdir_chattr(t);
 
         assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0644,
                                     true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &one) == 0);
index 226c30f..6d97bc5 100644 (file)
@@ -6,6 +6,7 @@
 #include "sd-journal.h"
 
 #include "alloc-util.h"
+#include "chattr-util.h"
 #include "journal-file.h"
 #include "journal-internal.h"
 #include "log.h"
@@ -59,7 +60,7 @@ static void verify_contents(sd_journal *j, unsigned skip) {
 
 int main(int argc, char *argv[]) {
         JournalFile *one, *two, *three;
-        char t[] = "/tmp/journal-stream-XXXXXX";
+        char t[] = "/var/tmp/journal-stream-XXXXXX";
         unsigned i;
         _cleanup_(sd_journal_closep) sd_journal *j = NULL;
         char *z;
@@ -75,6 +76,7 @@ int main(int argc, char *argv[]) {
 
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
+        (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
 
         assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &one) == 0);
         assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &two) == 0);
index c4fa41e..2893a7c 100644 (file)
@@ -4,6 +4,7 @@
 #include <stdio.h>
 #include <unistd.h>
 
+#include "chattr-util.h"
 #include "fd-util.h"
 #include "io-util.h"
 #include "journal-file.h"
@@ -51,7 +52,7 @@ static int raw_verify(const char *fn, const char *verification_key) {
 }
 
 int main(int argc, char *argv[]) {
-        char t[] = "/tmp/journal-XXXXXX";
+        char t[] = "/var/tmp/journal-XXXXXX";
         unsigned n;
         JournalFile *f;
         const char *verification_key = argv[1];
@@ -70,6 +71,7 @@ int main(int argc, char *argv[]) {
 
         assert_se(mkdtemp(t));
         assert_se(chdir(t) >= 0);
+        (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
 
         log_info("Generating...");
 
index 0795e0d..7f56668 100644 (file)
@@ -3,6 +3,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 
+#include "chattr-util.h"
 #include "io-util.h"
 #include "journal-authenticate.h"
 #include "journal-file.h"
 
 static bool arg_keep = false;
 
+static void mkdtemp_chdir_chattr(char *path) {
+        assert_se(mkdtemp(path));
+        assert_se(chdir(path) >= 0);
+
+        /* Speed up things a bit on btrfs, ensuring that CoW is turned off for all files created in our
+         * directory during the test run */
+        (void) chattr_path(path, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
+}
+
 static void test_non_empty(void) {
         dual_timestamp ts;
         JournalFile *f;
@@ -21,12 +31,11 @@ static void test_non_empty(void) {
         Object *o;
         uint64_t p;
         sd_id128_t fake_boot_id;
-        char t[] = "/tmp/journal-XXXXXX";
+        char t[] = "/var/tmp/journal-XXXXXX";
 
         test_setup_logging(LOG_DEBUG);
 
-        assert_se(mkdtemp(t));
-        assert_se(chdir(t) >= 0);
+        mkdtemp_chdir_chattr(t);
 
         assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, true, NULL, NULL, NULL, NULL, &f) == 0);
 
@@ -109,12 +118,11 @@ static void test_non_empty(void) {
 
 static void test_empty(void) {
         JournalFile *f1, *f2, *f3, *f4;
-        char t[] = "/tmp/journal-XXXXXX";
+        char t[] = "/var/tmp/journal-XXXXXX";
 
         test_setup_logging(LOG_DEBUG);
 
-        assert_se(mkdtemp(t));
-        assert_se(chdir(t) >= 0);
+        mkdtemp_chdir_chattr(t);
 
         assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, false, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &f1) == 0);
 
@@ -156,7 +164,7 @@ static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
         struct iovec iovec;
         Object *o;
         uint64_t p;
-        char t[] = "/tmp/journal-XXXXXX";
+        char t[] = "/var/tmp/journal-XXXXXX";
         char data[2048] = {0};
         bool is_compressed;
         int r;
@@ -165,8 +173,7 @@ static bool check_compressed(uint64_t compress_threshold, uint64_t data_size) {
 
         test_setup_logging(LOG_DEBUG);
 
-        assert_se(mkdtemp(t));
-        assert_se(chdir(t) >= 0);
+        mkdtemp_chdir_chattr(t);
 
         assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, compress_threshold, true, NULL, NULL, NULL, NULL, &f) == 0);
 
diff --git a/src/kernel-install/00-entry-directory.install b/src/kernel-install/00-entry-directory.install
new file mode 100644 (file)
index 0000000..2aa8c58
--- /dev/null
@@ -0,0 +1,32 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+
+COMMAND="$1"
+KERNEL_VERSION="$2"
+ENTRY_DIR_ABS="$3"
+KERNEL_IMAGE="$4"
+INITRD_OPTIONS_START="5"
+
+if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then
+    exit 0
+fi
+
+if [[ $COMMAND != add ]]; then
+     exit 0
+fi
+
+# If the boot dir exists (e.g. $ESP/<machine-id>),
+# create the entry directory ($ESP/<machine-id>/<kernel-version>).
+# This is the only function of this plugin.
+MACHINE_ID_DIR="${ENTRY_DIR_ABS%/*}"
+if ! [ -d "$MACHINE_ID_DIR" ]; then
+    exit 0
+fi
+
+if [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ]; then
+    echo "+mkdir -v -p $ENTRY_DIR_ABS"
+    exec mkdir -v -p "$ENTRY_DIR_ABS"
+else
+    exec mkdir -p "$ENTRY_DIR_ABS"
+fi
index 3a19304..731fa29 100644 (file)
@@ -4,16 +4,25 @@
 
 PATH=/bin:/usr/bin:/sbin:/usr/sbin
 
-[[ $1 == "add" ]] || exit 0
-[[ $2 ]] || exit 1
+COMMAND="$1"
+KERNEL_VERSION="$2"
+ENTRY_DIR_ABS="$3"
+KERNEL_IMAGE="$4"
+INITRD_OPTIONS_START="5"
 
-case "$1" in
+[[ $KERNEL_VERSION ]] || exit 1
+
+case "$COMMAND" in
     add)
-        [[ -d /lib/modules/"$2"/kernel ]] || exit 0
-        exec depmod -a "$2"
+        [[ -d "/lib/modules/${KERNEL_VERSION}/kernel" ]] || exit 0
+        [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+            echo "Running depmod -a ${KERNEL_VERSION}"
+        exec depmod -a "${KERNEL_VERSION}"
         ;;
     remove)
-        exec rm -f /lib/modules/"$2"/modules.{alias{,.bin},builtin.bin,dep{,.bin},devname,softdep,symbols{,.bin}}
+        [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+            echo "Removing /lib/modules/${KERNEL_VERSION}/modules.dep and associated files"
+        exec rm -f /lib/modules/"${KERNEL_VERSION}"/modules.{alias{,.bin},builtin.bin,dep{,.bin},devname,softdep,symbols{,.bin}}
         ;;
     *)
         exit 0
index 9247d26..63c7306 100644 (file)
@@ -6,7 +6,7 @@ PATH=/bin:/usr/bin:/sbin:/usr/sbin
 
 COMMAND="$1"
 KERNEL_VERSION="$2"
-BOOT_DIR_ABS="$3"
+ENTRY_DIR_ABS="$3"
 KERNEL_IMAGE="$4"
 INITRD_OPTIONS_START="5"
 
@@ -14,14 +14,14 @@ if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then
     exit 0
 fi
 
-if ! [[ -d "$BOOT_DIR_ABS" ]]; then
+if ! [[ -d "$ENTRY_DIR_ABS" ]]; then
     exit 0
 fi
 
 MACHINE_ID=$KERNEL_INSTALL_MACHINE_ID
 
-BOOT_DIR="/$MACHINE_ID/$KERNEL_VERSION"
-BOOT_ROOT=${BOOT_DIR_ABS%$BOOT_DIR}
+ENTRY_DIR="/$MACHINE_ID/$KERNEL_VERSION"
+BOOT_ROOT=${ENTRY_DIR_ABS%$ENTRY_DIR}
 
 if [[ $COMMAND == remove ]]; then
     rm -f "$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf"
@@ -78,10 +78,10 @@ else
     LOADER_ENTRY="$BOOT_ROOT/loader/entries/$MACHINE_ID-$KERNEL_VERSION.conf"
 fi
 
-cp "$KERNEL_IMAGE" "$BOOT_DIR_ABS/linux" &&
-   chown root:root "$BOOT_DIR_ABS/linux" &&
-   chmod 0644 "$BOOT_DIR_ABS/linux" || {
-    echo "Could not copy '$KERNEL_IMAGE to '$BOOT_DIR_ABS/linux'." >&2
+cp "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" &&
+   chown root:root "$ENTRY_DIR_ABS/linux" &&
+   chmod 0644 "$ENTRY_DIR_ABS/linux" || {
+    echo "Could not copy '$KERNEL_IMAGE to '$ENTRY_DIR_ABS/linux'." >&2
     exit 1
 }
 
@@ -90,10 +90,12 @@ INITRD_OPTIONS=( "${@:${INITRD_OPTIONS_START}}" )
 for initrd in "${INITRD_OPTIONS[@]}"; do
     if [[ -f "${initrd}" ]]; then
         initrd_basename="$(basename ${initrd})"
-        cp "${initrd}" "$BOOT_DIR_ABS/${initrd_basename}" &&
-            chown root:root "$BOOT_DIR_ABS/${initrd_basename}" &&
-            chmod 0644 "$BOOT_DIR_ABS/${initrd_basename}" || {
-             echo "Could not copy '${initrd}' to '$BOOT_DIR_ABS/${initrd_basename}'." >&2
+        [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+            echo "Installing $ENTRY_DIR_ABS/${initrd_basename}"
+        cp "${initrd}" "$ENTRY_DIR_ABS/${initrd_basename}" &&
+            chown root:root "$ENTRY_DIR_ABS/${initrd_basename}" &&
+            chmod 0644 "$ENTRY_DIR_ABS/${initrd_basename}" || {
+             echo "Could not copy '${initrd}' to '$ENTRY_DIR_ABS/${initrd_basename}'." >&2
              exit 1
         }
     fi
@@ -108,15 +110,17 @@ mkdir -p "${LOADER_ENTRY%/*}" || {
     exit 1
 }
 
+[ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+    echo "Creating $LOADER_ENTRY"
 {
     echo "title      $PRETTY_NAME"
     echo "version    $KERNEL_VERSION"
     echo "machine-id $MACHINE_ID"
     echo "options    ${BOOT_OPTIONS[*]}"
-    echo "linux      $BOOT_DIR/linux"
+    echo "linux      $ENTRY_DIR/linux"
     for initrd in "${INITRD_OPTIONS[@]}"; do
-        [[ -f $BOOT_DIR_ABS/$(basename ${initrd}) ]] && \
-            echo "initrd     $BOOT_DIR/$(basename ${initrd})"
+        [[ -f $ENTRY_DIR_ABS/$(basename ${initrd}) ]] && \
+            echo "initrd     $ENTRY_DIR/$(basename ${initrd})"
     done
     :
 } > "$LOADER_ENTRY" || {
index af10394..b356b38 100644 (file)
@@ -5,7 +5,6 @@
 #
 # 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
@@ -64,6 +63,13 @@ for i in "$@"; do
     fi
 done
 
+KERNEL_INSTALL_VERBOSE=0
+if [ "$1" == "--verbose" -o "$1" == "-v" ]; then
+    shift
+    KERNEL_INSTALL_VERBOSE=1
+fi
+export KERNEL_INSTALL_VERBOSE
+
 if [[ "${0##*/}" == 'installkernel' ]]; then
     COMMAND='add'
     # make install doesn't pass any parameter wrt initrd handling
@@ -87,20 +93,20 @@ if [[ ! $COMMAND ]] || [[ ! $KERNEL_VERSION ]]; then
 fi
 
 if ! [[ $MACHINE_ID ]]; then
-    BOOT_DIR_ABS=$(mktemp -d /tmp/kernel-install.XXXXX) || exit 1
-    trap "rm -rf '$BOOT_DIR_ABS'" EXIT INT QUIT PIPE
+    ENTRY_DIR_ABS=$(mktemp -d /tmp/kernel-install.XXXXX) || exit 1
+    trap "rm -rf '$ENTRY_DIR_ABS'" EXIT INT QUIT PIPE
 elif [[ -d /efi/loader/entries ]] || [[ -d /efi/$MACHINE_ID ]]; then
-    BOOT_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION"
+    ENTRY_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION"
 elif [[ -d /boot/loader/entries ]] || [[ -d /boot/$MACHINE_ID ]]; then
-    BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION"
+    ENTRY_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION"
 elif [[ -d /boot/efi/loader/entries ]] || [[ -d /boot/efi/$MACHINE_ID ]]; then
-    BOOT_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION"
+    ENTRY_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION"
 elif mountpoint -q /efi; then
-    BOOT_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION"
+    ENTRY_DIR_ABS="/efi/$MACHINE_ID/$KERNEL_VERSION"
 elif mountpoint -q /boot/efi; then
-    BOOT_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION"
+    ENTRY_DIR_ABS="/boot/efi/$MACHINE_ID/$KERNEL_VERSION"
 else
-    BOOT_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION"
+    ENTRY_DIR_ABS="/boot/$MACHINE_ID/$KERNEL_VERSION"
 fi
 
 export KERNEL_INSTALL_MACHINE_ID=$MACHINE_ID
@@ -120,14 +126,16 @@ case $COMMAND in
             exit 1
         fi
 
-        mkdir -p "$BOOT_DIR_ABS" || {
-            echo "Could not create boot directory '$BOOT_DIR_ABS'." >&2
+        if [[ ! -f "$KERNEL_IMAGE" ]]; then
+            echo "Kernel image argument ${KERNEL_IMAGE} not a file" >&2
             exit 1
-        }
+        fi
 
         for f in "${PLUGINS[@]}"; do
             if [[ -x $f ]]; then
-                "$f" add "$KERNEL_VERSION" "$BOOT_DIR_ABS" "$KERNEL_IMAGE" "${INITRD_OPTIONS[@]}"
+                [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+                    echo "+$f add $KERNEL_VERSION $ENTRY_DIR_ABS $KERNEL_IMAGE ${INITRD_OPTIONS[@]}"
+                "$f" add "$KERNEL_VERSION" "$ENTRY_DIR_ABS" "$KERNEL_IMAGE" "${INITRD_OPTIONS[@]}"
                 x=$?
                 if [[ $x == $SKIP_REMAINING ]]; then
                     ret=0
@@ -137,11 +145,11 @@ case $COMMAND in
             fi
         done
 
-        if ! [[ $MACHINE_ID ]] && ! rmdir "$BOOT_DIR_ABS"; then
-            echo "Warning: In kernel-install plugins, requiring BOOT_DIR_ABS to be preset is deprecated." >&2
-            echo "         All plugins should not put anything in BOOT_DIR_ABS if the environment" >&2
+        if ! [[ $MACHINE_ID ]] && ! rmdir "$ENTRY_DIR_ABS"; then
+            echo "Warning: In kernel-install plugins, requiring ENTRY_DIR_ABS to be preset is deprecated." >&2
+            echo "         All plugins should not put anything in ENTRY_DIR_ABS if the environment" >&2
             echo "         variable KERNEL_INSTALL_MACHINE_ID is empty." >&2
-            rm -rf "$BOOT_DIR_ABS"
+            rm -rf "$ENTRY_DIR_ABS"
             ((ret+=$?))
         fi
         ;;
@@ -149,7 +157,9 @@ case $COMMAND in
     remove)
         for f in "${PLUGINS[@]}"; do
             if [[ -x $f ]]; then
-                "$f" remove "$KERNEL_VERSION" "$BOOT_DIR_ABS"
+                [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+                    echo "+$f remove $KERNEL_VERSION $ENTRY_DIR_ABS"
+                "$f" remove "$KERNEL_VERSION" "$ENTRY_DIR_ABS"
                 x=$?
                 if [[ $x == $SKIP_REMAINING ]]; then
                     ret=0
@@ -159,7 +169,10 @@ case $COMMAND in
             fi
         done
 
-        rm -rf "$BOOT_DIR_ABS"
+        [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+            echo "Removing $ENTRY_DIR_ABS"
+
+        rm -rf "$ENTRY_DIR_ABS"
         ((ret+=$?))
         ;;
 
index c6e6f81..261c3aa 100644 (file)
@@ -4,7 +4,8 @@ install_data('kernel-install',
              install_mode : 'rwxr-xr-x',
              install_dir : bindir)
 
-install_data('50-depmod.install',
+install_data('00-entry-directory.install',
+             '50-depmod.install',
              '90-loaderentry.install',
              install_mode : 'rwxr-xr-x',
              install_dir : kernelinstalldir)
index 04bf64c..0c1ff34 100644 (file)
@@ -12,6 +12,7 @@
 #include "siphash24.h"
 #include "sparse-endian.h"
 #include "stdio-util.h"
+#include "udev-util.h"
 #include "virt.h"
 
 #define SYSTEMD_PEN    43793
@@ -182,6 +183,13 @@ int dhcp_identifier_set_iaid(
                                 /* not yet ready */
                                 return -EBUSY;
 
+                        r = device_is_renaming(device);
+                        if (r < 0)
+                                return r;
+                        if (r > 0)
+                                /* device is under renaming */
+                                return -EBUSY;
+
                         name = net_get_name(device);
                 }
         }
index 9d245a9..122042a 100644 (file)
@@ -41,7 +41,6 @@ struct sd_dhcp_lease {
         /* each 0 if unset */
         be32_t address;
         be32_t server_address;
-        be32_t router;
         be32_t next_server;
 
         bool have_subnet_mask;
@@ -50,6 +49,9 @@ struct sd_dhcp_lease {
         bool have_broadcast;
         be32_t broadcast;
 
+        struct in_addr *router;
+        size_t router_size;
+
         struct in_addr *dns;
         size_t dns_size;
 
index 0e5b414..94c10ed 100644 (file)
@@ -50,12 +50,16 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
                 BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)),  /* A <- DHCP header type */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0),                   /* header type == arp_type ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
-                BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)),   /* A <- MAC address length */
-                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0),                  /* address length == dhcp_hlen ? */
-                BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)),    /* A <- client identifier */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0),                        /* client identifier == xid ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
+                BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)),   /* A <- MAC address length */
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0),                  /* address length == dhcp_hlen ? */
+                BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
+
+                /* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally
+                 * compare chaddr for ETH_ALEN bytes. */
+                BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 12),                                  /* A (the MAC address length) == ETH_ALEN ? */
                 BPF_STMT(BPF_LD + BPF_IMM, unaligned_read_be32(&eth_mac->ether_addr_octet[0])),        /* A <- 4 bytes of client's MAC */
                 BPF_STMT(BPF_MISC + BPF_TAX, 0),                                                       /* X <- A */
                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)),                 /* A <- 4 bytes of MAC from dhcp.chaddr */
@@ -68,6 +72,7 @@ static int _bind_raw_socket(int ifindex, union sockaddr_union *link,
                 BPF_STMT(BPF_ALU + BPF_XOR + BPF_X, 0),                                                /* A xor X */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0),                                          /* A == 0 ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                                          /* ignore */
+
                 BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)),  /* A <- DHCP magic cookie */
                 BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0),          /* cookie == DHCP magic cookie ? */
                 BPF_STMT(BPF_RET + BPF_K, 0),                                          /* ignore */
@@ -148,7 +153,6 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
                 .in.sin_addr.s_addr = address,
         };
         _cleanup_close_ int s = -1;
-        char ifname[IF_NAMESIZE] = "";
         int r;
 
         s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
@@ -164,12 +168,9 @@ int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port) {
                 return r;
 
         if (ifindex > 0) {
-                if (if_indextoname(ifindex, ifname) == 0)
-                        return -errno;
-
-                r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
+                r = socket_bind_to_ifindex(s, ifindex);
                 if (r < 0)
-                        return -errno;
+                        return r;
         }
 
         if (address == INADDR_ANY) {
index ad3f925..a68de4f 100644 (file)
@@ -9,10 +9,10 @@
 #include <string.h>
 
 #include "alloc-util.h"
-#include "utf8.h"
-#include "strv.h"
-
 #include "dhcp-internal.h"
+#include "memory-util.h"
+#include "strv.h"
+#include "utf8.h"
 
 static int option_append(uint8_t options[], size_t size, size_t *offset,
                          uint8_t code, size_t optlen, const void *optval) {
index 8a7c5bc..b30be7e 100644 (file)
@@ -11,7 +11,7 @@
 #include "dhcp-internal.h"
 #include "hashmap.h"
 #include "log.h"
-#include "util.h"
+#include "time-util.h"
 
 typedef struct DHCPClientId {
         size_t length;
index a2aac9a..017402c 100644 (file)
 #include "dhcp6-lease-internal.h"
 #include "dhcp6-protocol.h"
 #include "dns-domain.h"
+#include "memory-util.h"
 #include "sparse-endian.h"
 #include "strv.h"
 #include "unaligned.h"
-#include "util.h"
 
 typedef struct DHCP6StatusOption {
         struct DHCP6Option option;
index e535b12..e1f193a 100644 (file)
@@ -31,9 +31,8 @@
 
 static int icmp6_bind_router_message(const struct icmp6_filter *filter,
                                      const struct ipv6_mreq *mreq) {
-        int index = mreq->ipv6mr_interface;
+        int ifindex = mreq->ipv6mr_interface;
         _cleanup_close_ int s = -1;
-        char ifname[IF_NAMESIZE] = "";
         int r;
 
         s = socket(AF_INET6, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK, IPPROTO_ICMPV6);
@@ -52,7 +51,7 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter,
            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_int(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, index);
+        r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, ifindex);
         if (r < 0)
                 return r;
 
@@ -76,12 +75,9 @@ static int icmp6_bind_router_message(const struct icmp6_filter *filter,
         if (r < 0)
                 return r;
 
-        if (if_indextoname(index, ifname) == 0)
-                return -errno;
-
-        r = setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, ifname, strlen(ifname));
+        r = socket_bind_to_ifindex(s, ifindex);
         if (r < 0)
-                return -errno;
+                return r;
 
         return TAKE_FD(s);
 }
index f6db625..9bae4a3 100644 (file)
@@ -7,9 +7,9 @@
 #include "in-addr-util.h"
 #include "lldp-internal.h"
 #include "lldp-neighbor.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "unaligned.h"
-#include "util.h"
 
 static void lldp_neighbor_id_hash_func(const LLDPNeighborID *id, struct siphash *state) {
         siphash24_compress(id->chassis_id, id->chassis_id_size, state);
index 0c04fea..28f801c 100644 (file)
@@ -6,6 +6,7 @@
 ***/
 
 #include "log.h"
+#include "time-util.h"
 
 #include "sd-ndisc.h"
 
index 6935311..c093872 100644 (file)
@@ -10,6 +10,7 @@
 #include "alloc-util.h"
 #include "dns-domain.h"
 #include "hostname-util.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "ndisc-internal.h"
 #include "ndisc-router.h"
index 0348e7f..2154cf7 100644 (file)
@@ -10,6 +10,7 @@
 #include "alloc-util.h"
 #include "condition.h"
 #include "conf-parser.h"
+#include "device-util.h"
 #include "dhcp-lease-internal.h"
 #include "ether-addr-util.h"
 #include "hexdecoct.h"
@@ -40,31 +41,35 @@ const char *net_get_name(sd_device *device) {
 
 int net_get_unique_predictable_data(sd_device *device, uint64_t *result) {
         size_t l, sz = 0;
-        const char *name = NULL;
+        const char *name;
         int r;
         uint8_t *v;
 
         assert(device);
 
+        /* net_get_name() will return one of the device names based on stable information about the
+         * device. If this is not available, we fall back to using the device name. */
         name = net_get_name(device);
         if (!name)
-                return -ENOENT;
+                (void) sd_device_get_sysname(device, &name);
+        if (!name)
+                return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA),
+                                              "No stable identifying information found");
 
+        log_device_debug(device, "Using \"%s\" as stable identifying information", name);
         l = strlen(name);
         sz = sizeof(sd_id128_t) + l;
         v = newa(uint8_t, sz);
 
-        /* fetch some persistent data unique to this machine */
+        /* Fetch some persistent data unique to this machine */
         r = sd_id128_get_machine((sd_id128_t*) v);
         if (r < 0)
                  return r;
         memcpy(v + sizeof(sd_id128_t), name, l);
 
-        /* Let's hash the machine ID plus the device name. We
-        * use a fixed, but originally randomly created hash
-        * key here. */
+        /* Let's hash the machine ID plus the device name. We use
+         * a fixed, but originally randomly created hash key here. */
         *result = htole64(siphash24(v, sz, HASH_KEY.bytes));
-
         return 0;
 }
 
@@ -95,33 +100,12 @@ bool net_match_config(Set *match_mac,
                       char * const *match_drivers,
                       char * const *match_types,
                       char * const *match_names,
-                      Condition *match_host,
-                      Condition *match_virt,
-                      Condition *match_kernel_cmdline,
-                      Condition *match_kernel_version,
-                      Condition *match_arch,
                       const struct ether_addr *dev_mac,
                       const char *dev_path,
-                      const char *dev_parent_driver,
                       const char *dev_driver,
                       const char *dev_type,
                       const char *dev_name) {
 
-        if (match_host && condition_test(match_host) <= 0)
-                return false;
-
-        if (match_virt && condition_test(match_virt) <= 0)
-                return false;
-
-        if (match_kernel_cmdline && condition_test(match_kernel_cmdline) <= 0)
-                return false;
-
-        if (match_kernel_version && condition_test(match_kernel_version) <= 0)
-                return false;
-
-        if (match_arch && condition_test(match_arch) <= 0)
-                return false;
-
         if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
                 return false;
 
@@ -152,32 +136,31 @@ int config_parse_net_condition(const char *unit,
                                void *userdata) {
 
         ConditionType cond = ltype;
-        Condition **ret = data;
+        Condition **list = data, *c;
         bool negate;
-        Condition *c;
-        _cleanup_free_ char *s = NULL;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
         assert(data);
 
+        if (isempty(rvalue)) {
+                *list = condition_free_list_type(*list, cond);
+                return 0;
+        }
+
         negate = rvalue[0] == '!';
         if (negate)
                 rvalue++;
 
-        s = strdup(rvalue);
-        if (!s)
-                return log_oom();
-
-        c = condition_new(cond, s, false, negate);
+        c = condition_new(cond, rvalue, false, negate);
         if (!c)
                 return log_oom();
 
-        if (*ret)
-                condition_free(*ret);
+        /* Drop previous assignment. */
+        *list = condition_free_list_type(*list, cond);
 
-        *ret = c;
+        LIST_PREPEND(conditions, *list, c);
         return 0;
 }
 
@@ -409,16 +392,33 @@ int config_parse_bridge_port_priority(
         return 0;
 }
 
-void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size) {
-        unsigned i;
+size_t serialize_in_addrs(FILE *f,
+                          const struct in_addr *addresses,
+                          size_t size,
+                          bool with_leading_space,
+                          bool (*predicate)(const struct in_addr *addr)) {
+        size_t count;
+        size_t i;
 
         assert(f);
         assert(addresses);
-        assert(size);
 
-        for (i = 0; i < size; i++)
-                fprintf(f, "%s%s", inet_ntoa(addresses[i]),
-                        (i < (size - 1)) ? " ": "");
+        count = 0;
+
+        for (i = 0; i < size; i++) {
+                char sbuf[INET_ADDRSTRLEN];
+
+                if (predicate && !predicate(&addresses[i]))
+                        continue;
+                if (with_leading_space)
+                        fputc(' ', f);
+                else
+                        with_leading_space = true;
+                fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f);
+                count++;
+        }
+
+        return count;
 }
 
 int deserialize_in_addrs(struct in_addr **ret, const char *string) {
@@ -452,7 +452,7 @@ int deserialize_in_addrs(struct in_addr **ret, const char *string) {
                 size++;
         }
 
-        *ret = TAKE_PTR(addresses);
+        *ret = size > 0 ? TAKE_PTR(addresses) : NULL;
 
         return size;
 }
@@ -521,6 +521,7 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz
         fprintf(f, "%s=", key);
 
         for (i = 0; i < size; i++) {
+                char sbuf[INET_ADDRSTRLEN];
                 struct in_addr dest, gw;
                 uint8_t length;
 
@@ -528,8 +529,8 @@ void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, siz
                 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)) ? " ": "");
+                fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof(sbuf)), length);
+                fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof(sbuf)), (i < (size - 1)) ? " ": "");
         }
 
         fputs("\n", f);
index 0c8da84..62f5a4a 100644 (file)
@@ -6,9 +6,10 @@
 #include "sd-device.h"
 #include "sd-dhcp-lease.h"
 
-#include "condition.h"
 #include "conf-parser.h"
+#include "def.h"
 #include "set.h"
+#include "strv.h"
 
 #define LINK_BRIDGE_PORT_PRIORITY_INVALID 128
 #define LINK_BRIDGE_PORT_PRIORITY_MAX 63
@@ -18,14 +19,8 @@ bool net_match_config(Set *match_mac,
                       char * const *match_driver,
                       char * const *match_type,
                       char * const *match_name,
-                      Condition *match_host,
-                      Condition *match_virt,
-                      Condition *match_kernel_cmdline,
-                      Condition *match_kernel_version,
-                      Condition *match_arch,
                       const struct ether_addr *dev_mac,
                       const char *dev_path,
-                      const char *dev_parent_driver,
                       const char *dev_driver,
                       const char *dev_type,
                       const char *dev_name);
@@ -40,7 +35,11 @@ CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority);
 int net_get_unique_predictable_data(sd_device *device, uint64_t *result);
 const char *net_get_name(sd_device *device);
 
-void serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size);
+size_t serialize_in_addrs(FILE *f,
+                          const struct in_addr *addresses,
+                          size_t size,
+                          bool with_leading_space,
+                          bool (*predicate)(const struct in_addr *addr));
 int deserialize_in_addrs(struct in_addr **addresses, const char *string);
 void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses,
                          size_t size);
@@ -54,3 +53,5 @@ int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, size_t
 
 /* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */
 int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size);
+
+#define NETWORK_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/network"))
index 35fc88e..97e1dd3 100644 (file)
 #include "event-util.h"
 #include "hostname-util.h"
 #include "io-util.h"
+#include "memory-util.h"
 #include "random-util.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 #define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN)  /* Arbitrary limit */
 #define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN)
@@ -1676,8 +1676,7 @@ static int client_receive_message_udp(
 
         sd_dhcp_client *client = userdata;
         _cleanup_free_ DHCPMessage *message = NULL;
-        const struct ether_addr zero_mac = {};
-        const struct ether_addr *expected_chaddr = NULL;
+        const uint8_t *expected_chaddr = NULL;
         uint8_t expected_hlen = 0;
         ssize_t len, buflen;
 
@@ -1685,6 +1684,12 @@ static int client_receive_message_udp(
         assert(client);
 
         buflen = next_datagram_size_fd(fd);
+        if (buflen == -ENETDOWN) {
+                /* the link is down. Don't return an error or the I/O event
+                   source will be disconnected and we won't be able to receive
+                   packets again when the link comes back. */
+                return 0;
+        }
         if (buflen < 0)
                 return buflen;
 
@@ -1694,7 +1699,8 @@ static int client_receive_message_udp(
 
         len = recv(fd, message, buflen, 0);
         if (len < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
+                /* see comment above for why we shouldn't error out on ENETDOWN. */
+                if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
                         return 0;
 
                 return log_dhcp_client_errno(client, errno,
@@ -1722,11 +1728,7 @@ static int client_receive_message_udp(
 
         if (client->arp_type == ARPHRD_ETHER) {
                 expected_hlen = ETH_ALEN;
-                expected_chaddr = (const struct ether_addr *) &client->mac_addr;
-        } else {
-               /* Non-Ethernet links expect zero chaddr */
-               expected_hlen = 0;
-               expected_chaddr = &zero_mac;
+                expected_chaddr = &client->mac_addr[0];
         }
 
         if (message->hlen != expected_hlen) {
@@ -1734,7 +1736,7 @@ static int client_receive_message_udp(
                 return 0;
         }
 
-        if (memcmp(&message->chaddr[0], expected_chaddr, ETH_ALEN)) {
+        if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) {
                 log_dhcp_client(client, "Received chaddr does not match expected: ignoring");
                 return 0;
         }
@@ -1776,6 +1778,8 @@ static int client_receive_message_raw(
         assert(client);
 
         buflen = next_datagram_size_fd(fd);
+        if (buflen == -ENETDOWN)
+                return 0;
         if (buflen < 0)
                 return buflen;
 
@@ -1787,7 +1791,7 @@ static int client_receive_message_raw(
 
         len = recvmsg(fd, &msg, 0);
         if (len < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
+                if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
                         return 0;
 
                 return log_dhcp_client_errno(client, errno,
index 13badbf..a16314a 100644 (file)
@@ -9,6 +9,9 @@
 #include <stdio_ext.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "sd-dhcp-lease.h"
 
@@ -151,15 +154,15 @@ int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) {
         return 0;
 }
 
-int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr) {
+int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) {
         assert_return(lease, -EINVAL);
         assert_return(addr, -EINVAL);
 
-        if (lease->router == 0)
+        if (lease->router_size <= 0)
                 return -ENODATA;
 
-        addr->s_addr = lease->router;
-        return 0;
+        *addr = lease->router;
+        return (int) lease->router_size;
 }
 
 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) {
@@ -261,6 +264,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) {
         }
 
         free(lease->root_path);
+        free(lease->router);
         free(lease->timezone);
         free(lease->hostname);
         free(lease->domainname);
@@ -370,23 +374,6 @@ static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) {
         return 0;
 }
 
-static void filter_bogus_addresses(struct in_addr *addresses, size_t *n) {
-        size_t i, j;
-
-        /* Silently filter DNS/NTP servers supplied to us that do not make outside of the local scope. */
-
-        for (i = 0, j = 0; i < *n; i ++) {
-
-                if (in4_addr_is_null(addresses+i) ||
-                    in4_addr_is_localhost(addresses+i))
-                        continue;
-
-                addresses[j++] = addresses[i];
-        }
-
-        *n = j;
-}
-
 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);
@@ -408,8 +395,6 @@ static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_add
                 if (!addresses)
                         return -ENOMEM;
 
-                filter_bogus_addresses(addresses, &n_addresses);
-
                 free(*ret);
                 *ret = addresses;
                 *n_ret = n_addresses;
@@ -554,11 +539,9 @@ int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void
                 break;
 
         case SD_DHCP_OPTION_ROUTER:
-                if (len >= 4) {
-                        r = lease_parse_be32(option, 4, &lease->router);
-                        if (r < 0)
-                                log_debug_errno(r, "Failed to parse router address, ignoring: %m");
-                }
+                r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to parse router addresses, ignoring: %m");
                 break;
 
         case SD_DHCP_OPTION_DOMAIN_NAME_SERVER:
@@ -820,7 +803,6 @@ int dhcp_lease_new(sd_dhcp_lease **ret) {
         if (!lease)
                 return -ENOMEM;
 
-        lease->router = INADDR_ANY;
         lease->n_ref = 1;
 
         *ret = lease;
@@ -835,6 +817,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         const struct in_addr *addresses;
         const void *client_id, *data;
         size_t client_id_len, data_len;
+        char sbuf[INET_ADDRSTRLEN];
         const char *string;
         uint16_t mtu;
         _cleanup_free_ sd_dhcp_route **routes = NULL;
@@ -857,27 +840,30 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
 
         r = sd_dhcp_lease_get_address(lease, &address);
         if (r >= 0)
-                fprintf(f, "ADDRESS=%s\n", inet_ntoa(address));
+                fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
 
         r = sd_dhcp_lease_get_netmask(lease, &address);
         if (r >= 0)
-                fprintf(f, "NETMASK=%s\n", inet_ntoa(address));
+                fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
 
-        r = sd_dhcp_lease_get_router(lease, &address);
-        if (r >= 0)
-                fprintf(f, "ROUTER=%s\n", inet_ntoa(address));
+        r = sd_dhcp_lease_get_router(lease, &addresses);
+        if (r > 0) {
+                fputs("ROUTER=", f);
+                serialize_in_addrs(f, addresses, r, false, NULL);
+                fputc('\n', f);
+        }
 
         r = sd_dhcp_lease_get_server_identifier(lease, &address);
         if (r >= 0)
-                fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntoa(address));
+                fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
 
         r = sd_dhcp_lease_get_next_server(lease, &address);
         if (r >= 0)
-                fprintf(f, "NEXT_SERVER=%s\n", inet_ntoa(address));
+                fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
 
         r = sd_dhcp_lease_get_broadcast(lease, &address);
         if (r >= 0)
-                fprintf(f, "BROADCAST=%s\n", inet_ntoa(address));
+                fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf)));
 
         r = sd_dhcp_lease_get_mtu(lease, &mtu);
         if (r >= 0)
@@ -898,15 +884,15 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         r = sd_dhcp_lease_get_dns(lease, &addresses);
         if (r > 0) {
                 fputs("DNS=", f);
-                serialize_in_addrs(f, addresses, r);
-                fputs("\n", f);
+                serialize_in_addrs(f, addresses, r, false, NULL);
+                fputc('\n', f);
         }
 
         r = sd_dhcp_lease_get_ntp(lease, &addresses);
         if (r > 0) {
                 fputs("NTP=", f);
-                serialize_in_addrs(f, addresses, r);
-                fputs("\n", f);
+                serialize_in_addrs(f, addresses, r, false, NULL);
+                fputc('\n', f);
         }
 
         r = sd_dhcp_lease_get_domainname(lease, &string);
@@ -917,7 +903,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) {
         if (r > 0) {
                 fputs("DOMAIN_SEARCH_LIST=", f);
                 fputstrv(f, search_domains, NULL, NULL);
-                fputs("\n", f);
+                fputc('\n', f);
         }
 
         r = sd_dhcp_lease_get_hostname(lease, &string);
@@ -1080,9 +1066,11 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) {
         }
 
         if (router) {
-                r = inet_pton(AF_INET, router, &lease->router);
-                if (r <= 0)
-                        log_debug("Failed to parse router %s, ignoring.", router);
+                r = deserialize_in_addrs(&lease->router, router);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router);
+                else
+                        lease->router_size = r;
         }
 
         if (netmask) {
index 593ffd1..68b41df 100644 (file)
@@ -1112,6 +1112,12 @@ static int client_receive_message(
         assert(client->event);
 
         buflen = next_datagram_size_fd(fd);
+        if (buflen == -ENETDOWN) {
+                /* the link is down. Don't return an error or the I/O event
+                   source will be disconnected and we won't be able to receive
+                   packets again when the link comes back. */
+                return 0;
+        }
         if (buflen < 0)
                 return buflen;
 
@@ -1121,7 +1127,8 @@ static int client_receive_message(
 
         len = recv(fd, message, buflen, 0);
         if (len < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
+                /* see comment above for why we shouldn't error out on ENETDOWN. */
+                if (IN_SET(errno, EAGAIN, EINTR, ENETDOWN))
                         return 0;
 
                 return log_dhcp6_client_errno(client, errno, "Could not receive message from UDP socket: %m");
index 59359ae..c8e3449 100644 (file)
@@ -21,7 +21,7 @@
 #include "random-util.h"
 #include "siphash24.h"
 #include "string-util.h"
-#include "util.h"
+#include "time-util.h"
 
 /* Constants from the RFC */
 #define PROBE_WAIT_USEC (1U * USEC_PER_SEC)
index e451dff..a59a952 100644 (file)
@@ -218,28 +218,21 @@ static int ipv4ll_pick_address(sd_ipv4ll *ll) {
         return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr });
 }
 
-int sd_ipv4ll_restart(sd_ipv4ll *ll) {
-        ll->address = 0;
-
-        return sd_ipv4ll_start(ll);
-}
-
 #define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2)
 
-int sd_ipv4ll_start(sd_ipv4ll *ll) {
+static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) {
         int r;
         bool picked_address = false;
 
         assert_return(ll, -EINVAL);
         assert_return(!ether_addr_is_null(&ll->mac), -EINVAL);
-        assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
 
         /* If no random seed is set, generate some from the MAC address */
         if (!ll->seed_set)
                 ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes));
 
-        /* Restart the generation counter. */
-        ll->seed.generation = 0;
+        if (reset_generation)
+                ll->seed.generation = 0;
 
         if (ll->address == 0) {
                 r = ipv4ll_pick_address(ll);
@@ -263,6 +256,19 @@ int sd_ipv4ll_start(sd_ipv4ll *ll) {
         return 0;
 }
 
+int sd_ipv4ll_start(sd_ipv4ll *ll) {
+        assert_return(ll, -EINVAL);
+        assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY);
+
+        return ipv4ll_start_internal(ll, true);
+}
+
+int sd_ipv4ll_restart(sd_ipv4ll *ll) {
+        ll->address = 0;
+
+        return ipv4ll_start_internal(ll, false);
+}
+
 static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) {
         assert(ll);
 
@@ -298,11 +304,7 @@ void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
 
                         ll->claimed_address = 0;
                 } else {
-                        r = ipv4ll_pick_address(ll);
-                        if (r < 0)
-                                goto error;
-
-                        r = sd_ipv4acd_start(ll->acd);
+                        r = sd_ipv4ll_restart(ll);
                         if (r < 0)
                                 goto error;
                 }
index 969fc71..1f28c57 100644 (file)
@@ -13,7 +13,9 @@
 #include "lldp-internal.h"
 #include "lldp-neighbor.h"
 #include "lldp-network.h"
+#include "memory-util.h"
 #include "socket-util.h"
+#include "sort-util.h"
 #include "string-table.h"
 
 #define LLDP_DEFAULT_NEIGHBORS_MAX 128U
index 32c20b1..5e71171 100644 (file)
 #include "fd-util.h"
 #include "icmp6-util.h"
 #include "in-addr-util.h"
+#include "memory-util.h"
 #include "ndisc-internal.h"
 #include "ndisc-router.h"
 #include "random-util.h"
 #include "socket-util.h"
 #include "string-table.h"
 #include "string-util.h"
-#include "util.h"
 
 #define NDISC_TIMEOUT_NO_RA_USEC (NDISC_ROUTER_SOLICITATION_INTERVAL * NDISC_MAX_ROUTER_SOLICITATIONS)
 
index 098e01f..08433ad 100644 (file)
 #include "in-addr-util.h"
 #include "io-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "radv-internal.h"
 #include "random-util.h"
 #include "socket-util.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 _public_ int sd_radv_new(sd_radv **ret) {
         _cleanup_(sd_radv_unrefp) sd_radv *ra = NULL;
index fe6788d..0431e2c 100644 (file)
@@ -423,6 +423,7 @@ static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
         sd_event *e = userdata;
         sd_dhcp_lease *lease;
         struct in_addr addr;
+        const struct in_addr *addrs;
 
         assert_se(client);
         assert_se(event == SD_DHCP_CLIENT_EVENT_IP_ACQUIRE);
@@ -438,9 +439,9 @@ static void test_addr_acq_acquired(sd_dhcp_client *client, int event,
         assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[285],
                       sizeof(addr.s_addr)) == 0);
 
-        assert_se(sd_dhcp_lease_get_router(lease, &addr) >= 0);
-        assert_se(memcmp(&addr.s_addr, &test_addr_acq_ack[308],
-                      sizeof(addr.s_addr)) == 0);
+        assert_se(sd_dhcp_lease_get_router(lease, &addrs) == 1);
+        assert_se(memcmp(&addrs[0].s_addr, &test_addr_acq_ack[308],
+                         sizeof(addrs[0].s_addr)) == 0);
 
         if (verbose)
                 printf("  DHCP address acquired\n");
index d84859c..56bd690 100644 (file)
@@ -7,7 +7,7 @@
 #include "dhcp-internal.h"
 #include "dhcp-protocol.h"
 #include "macro.h"
-#include "util.h"
+#include "memory-util.h"
 
 struct option_desc {
         uint8_t sname[64];
index fa94b3c..00056aa 100644 (file)
 #include "dhcp6-protocol.h"
 #include "fd-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "socket-util.h"
 #include "tests.h"
-#include "util.h"
+#include "time-util.h"
 #include "virt.h"
 
 static struct ether_addr mac_addr = {
index b6c896f..7406f94 100644 (file)
@@ -15,6 +15,7 @@
 #include "lldp-network.h"
 #include "macro.h"
 #include "string-util.h"
+#include "tests.h"
 
 #define TEST_LLDP_PORT "em1"
 #define TEST_LLDP_TYPE_SYSTEM_NAME "systemd-lldp"
@@ -365,7 +366,7 @@ static void test_multiple_neighbors_sorted(sd_event *e) {
 int main(int argc, char *argv[]) {
         _cleanup_(sd_event_unrefp) sd_event *e = NULL;
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         /* LLDP reception tests */
         assert_se(sd_event_new(&e) == 0);
index c4c1c81..7dc44e5 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <netinet/icmp6.h>
 #include <arpa/inet.h>
+#include <unistd.h>
 
 #include "sd-radv.h"
 
index caf94d1..c8ee1ec 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <netinet/icmp6.h>
 #include <arpa/inet.h>
+#include <unistd.h>
 
 #include "sd-ndisc.h"
 
index f20e84e..24585ff 100644 (file)
@@ -7,6 +7,7 @@
 #include "bus-internal.h"
 #include "bus-socket.h"
 #include "fd-util.h"
+#include "namespace-util.h"
 #include "process-util.h"
 #include "util.h"
 
index 4dccbfd..95d05bd 100644 (file)
@@ -198,7 +198,7 @@ static int enqueue_kernel_reply(
         }
     }
 
-    bus->rqueue[bus->rqueue_size++] = m;
+    bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m, bus);
 
     if (ret_slot)
         *ret_slot = s;
index d6d7c14..9c3f155 100644 (file)
@@ -854,6 +854,7 @@ int bus_add_match_internal(
                         "s",
                         e);
 }
+
 int bus_add_match_internal_async(
                 sd_bus *bus,
                 sd_bus_slot **ret_slot,
index b187568..98861cd 100644 (file)
@@ -1,5 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <unistd.h>
+#include <sys/types.h>
+
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-signature.h"
index dc95237..9631964 100644 (file)
@@ -12,6 +12,7 @@
 #include "alloc-util.h"
 #include "bus-error.h"
 #include "errno-list.h"
+#include "errno-util.h"
 #include "string-util.h"
 #include "util.h"
 
index 40acae2..dff39cb 100644 (file)
@@ -43,7 +43,7 @@ bool object_path_is_valid(const char *p) {
         if (slash)
                 return false;
 
-        return true;
+        return (q - p) <= BUS_PATH_SIZE_MAX;
 }
 
 char* object_path_startswith(const char *a, const char *b) {
@@ -97,7 +97,7 @@ bool interface_name_is_valid(const char *p) {
                         dot = false;
                 }
 
-        if (q - p > 255)
+        if (q - p > SD_BUS_MAXIMUM_NAME_LENGTH)
                 return false;
 
         if (dot)
@@ -139,7 +139,7 @@ bool service_name_is_valid(const char *p) {
                         dot = false;
                 }
 
-        if (q - p > 255)
+        if (q - p > SD_BUS_MAXIMUM_NAME_LENGTH)
                 return false;
 
         if (dot)
@@ -170,7 +170,7 @@ bool member_name_is_valid(const char *p) {
                         return false;
         }
 
-        if (q - p > 255)
+        if (q - p > SD_BUS_MAXIMUM_NAME_LENGTH)
                 return false;
 
         return true;
index 10bf7fc..7dcc27c 100644 (file)
 #include "bus-kernel.h"
 #include "bus-match.h"
 #include "def.h"
+#include "format-util.h"
 #include "hashmap.h"
 #include "list.h"
 #include "prioq.h"
-#include "refcnt.h"
 #include "socket-util.h"
-#include "util.h"
+#include "time-util.h"
+
+/* Note that we use the new /run prefix here (instead of /var/run) since we require them to be aliases and
+ * that way we become independent of /var being mounted */
+#define UNIX_SYSTEM_BUS_ADDRESS "unix:path=/run/dbus/system_bus_socket"
+#define KERNEL_SYSTEM_BUS_ADDRESS "kernel:path=/sys/fs/kdbus/0-system/bus"
+#define DEFAULT_SYSTEM_BUS_ADDRESS KERNEL_SYSTEM_BUS_ADDRESS ";" UNIX_SYSTEM_BUS_ADDRESS
+#define UNIX_USER_BUS_ADDRESS_FMT "unix:path=%s/bus"
+#define KERNEL_USER_BUS_ADDRESS_FMT "kernel:path=/sys/fs/kdbus/"UID_FMT"-user/bus"
+#define DEFAULT_USER_BUS_ADDRESS_FMT KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT
 
 struct reply_callback {
         sd_bus_message_handler_t callback;
@@ -62,11 +71,11 @@ struct node {
 struct node_callback {
         struct node *node;
 
-        bool is_fallback;
-        sd_bus_message_handler_t callback;
-
+        bool is_fallback:1;
         unsigned last_iteration;
 
+        sd_bus_message_handler_t callback;
+
         LIST_FIELDS(struct node_callback, callbacks);
 };
 
@@ -89,13 +98,13 @@ struct node_object_manager {
 struct node_vtable {
         struct node *node;
 
+        bool is_fallback:1;
+        unsigned last_iteration;
+
         char *interface;
-        bool is_fallback;
         const sd_bus_vtable *vtable;
         sd_bus_object_find_t find;
 
-        unsigned last_iteration;
-
         LIST_FIELDS(struct node_vtable, vtables);
 };
 
@@ -122,9 +131,6 @@ typedef enum BusSlotType {
 
 struct sd_bus_slot {
         unsigned n_ref;
-        sd_bus *bus;
-        void *userdata;
-        sd_bus_destroy_t destroy_callback;
         BusSlotType type:5;
 
         /* Slots can be "floating" or not. If they are not floating (the usual case) then they reference the bus object
@@ -136,6 +142,11 @@ struct sd_bus_slot {
         bool floating:1;
 
         bool match_added:1;
+
+        sd_bus *bus;
+        void *userdata;
+        sd_bus_destroy_t destroy_callback;
+
         char *description;
 
         LIST_FIELDS(sd_bus_slot, slots);
@@ -174,15 +185,7 @@ enum bus_auth {
 };
 
 struct sd_bus {
-        /* We use atomic ref counting here since sd_bus_message
-           objects retain references to their originating sd_bus but
-           we want to allow them to be processed in a different
-           thread. We won't provide full thread safety, but only the
-           bare minimum that makes it possible to use sd_bus and
-           sd_bus_message objects independently and on different
-           threads as long as each object is used only once at the
-           same time. */
-        RefCount n_ref;
+        unsigned n_ref;
 
         enum bus_state state;
         int input_fd, output_fd;
@@ -219,17 +222,17 @@ struct sd_bus {
         bool connected_signal:1;
         bool close_on_exit:1;
 
-        int use_memfd;
+        signed int use_memfd:2;
 
         void *rbuffer;
         size_t rbuffer_size;
 
         sd_bus_message **rqueue;
-        unsigned rqueue_size;
+        size_t rqueue_size;
         size_t rqueue_allocated;
 
         sd_bus_message **wqueue;
-        unsigned wqueue_size;
+        size_t wqueue_size;
         size_t windex;
         size_t wqueue_allocated;
 
@@ -250,9 +253,10 @@ struct sd_bus {
         union sockaddr_union sockaddr;
         socklen_t sockaddr_size;
 
-        char *kernel;
-        char *machine;
         pid_t nspid;
+        char *machine;
+
+        char *kernel;
 
         sd_id128_t server_id;
 
@@ -262,9 +266,9 @@ struct sd_bus {
         int last_connect_error;
 
         enum bus_auth auth;
-        size_t auth_rbegin;
-        struct iovec auth_iovec[3];
         unsigned auth_index;
+        struct iovec auth_iovec[3];
+        size_t auth_rbegin;
         char *auth_buffer;
         usec_t auth_timeout;
 
@@ -281,8 +285,10 @@ struct sd_bus {
         char *exec_path;
         char **exec_argv;
 
-        unsigned iteration_counter;
-
+        /* kdbus forward-ported stuff */
+        uint64_t hello_flags;
+        uint64_t attach_flags;
+        uint64_t match_cookie;
         void *kdbus_buffer;
 
         /* We do locking around the memfd cache, since we want to
@@ -298,10 +304,7 @@ struct sd_bus {
         pid_t original_pid;
         pid_t busexec_pid;
 
-        /* kdbus forward-ported stuff */
-        uint64_t hello_flags;
-        uint64_t attach_flags;
-        uint64_t match_cookie;
+        unsigned iteration_counter;
 
         sd_event_source *input_io_event_source;
         sd_event_source *output_io_event_source;
@@ -311,13 +314,14 @@ struct sd_bus {
         sd_event *event;
         int event_priority;
 
+        pid_t tid;
+
         sd_bus_message *current_message;
         sd_bus_slot *current_slot;
         sd_bus_message_handler_t current_handler;
         void *current_userdata;
 
         sd_bus **default_bus_ptr;
-        pid_t tid;
 
         struct kdbus_creds fake_creds;
         struct kdbus_pids fake_pids;
@@ -355,6 +359,10 @@ struct sd_bus {
 
 #define BUS_MESSAGE_SIZE_MAX (128*1024*1024)
 #define BUS_AUTH_SIZE_MAX (64*1024)
+/* Note that the D-Bus specification states that bus paths shall have no size limit. We enforce here one
+ * anyway, since truly unbounded strings are a security problem. The limit we pick is relatively large however,
+ * to not clash unnecessarily with real-life applications. */
+#define BUS_PATH_SIZE_MAX (64*1024)
 
 #define BUS_CONTAINER_DEPTH 128
 
index f623dd9..29a5ef7 100644 (file)
@@ -4,12 +4,13 @@
 
 #include "bus-internal.h"
 #include "bus-introspect.h"
+#include "bus-objects.h"
 #include "bus-protocol.h"
 #include "bus-signature.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "memory-util.h"
 #include "string-util.h"
-#include "util.h"
 
 int introspect_begin(struct introspect *i, bool trusted) {
         assert(i);
@@ -86,7 +87,9 @@ static void introspect_write_flags(struct introspect *i, int type, uint64_t flag
                 fputs("   <annotation name=\"org.freedesktop.systemd1.Privileged\" value=\"true\"/>\n", i->f);
 }
 
-static int introspect_write_arguments(struct introspect *i, const char *signature, const char *direction) {
+/* Note that "names" is both an input and an output parameter. It initially points to the first argument name in a
+   NULL-separated list of strings, and is then advanced with each argument, and the resulting pointer is returned. */
+static int introspect_write_arguments(struct introspect *i, const char *signature, const char **names, const char *direction) {
         int r;
 
         for (;;) {
@@ -101,6 +104,11 @@ static int introspect_write_arguments(struct introspect *i, const char *signatur
 
                 fprintf(i->f, "   <arg type=\"%.*s\"", (int) l, signature);
 
+                if (**names != '\0') {
+                        fprintf(i->f, " name=\"%s\"", *names);
+                        *names += strlen(*names) + 1;
+                }
+
                 if (direction)
                         fprintf(i->f, " direction=\"%s\"/>\n", direction);
                 else
@@ -111,10 +119,13 @@ static int introspect_write_arguments(struct introspect *i, const char *signatur
 }
 
 int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
+        const sd_bus_vtable *vtable = v;
+        const char *names = "";
+
         assert(i);
         assert(v);
 
-        for (; v->type != _SD_BUS_VTABLE_END; v++) {
+        for (; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(vtable, v)) {
 
                 /* Ignore methods, signals and properties that are
                  * marked "hidden", but do show the interface
@@ -132,8 +143,10 @@ int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
 
                 case _SD_BUS_VTABLE_METHOD:
                         fprintf(i->f, "  <method name=\"%s\">\n", v->x.method.member);
-                        introspect_write_arguments(i, strempty(v->x.method.signature), "in");
-                        introspect_write_arguments(i, strempty(v->x.method.result), "out");
+                        if (bus_vtable_has_names(vtable))
+                                names = strempty(v->x.method.names);
+                        introspect_write_arguments(i, strempty(v->x.method.signature), &names, "in");
+                        introspect_write_arguments(i, strempty(v->x.method.result), &names, "out");
                         introspect_write_flags(i, v->type, v->flags);
                         fputs("  </method>\n", i->f);
                         break;
@@ -150,7 +163,9 @@ int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
 
                 case _SD_BUS_VTABLE_SIGNAL:
                         fprintf(i->f, "  <signal name=\"%s\">\n", v->x.signal.member);
-                        introspect_write_arguments(i, strempty(v->x.signal.signature), NULL);
+                        if (bus_vtable_has_names(vtable))
+                                names = strempty(v->x.method.names);
+                        introspect_write_arguments(i, strempty(v->x.signal.signature), &names, NULL);
                         introspect_write_flags(i, v->type, v->flags);
                         fputs("  </signal>\n", i->f);
                         break;
index ee8e3be..4d2faf5 100644 (file)
@@ -33,7 +33,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "user-util.h"
-#include "util.h"
+#include "memory-util.h"
 
 #pragma GCC diagnostic ignored "-Wformat"
 
@@ -855,7 +855,7 @@ static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
         m->free_fds = true;
         fds = NULL;
 
-        bus->rqueue[bus->rqueue_size++] = m;
+        bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m, bus);
 
         return 1;
 
@@ -1170,7 +1170,7 @@ int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call
                 if (r < 0)
                         return r;
 
-                bus->rqueue[bus->rqueue_size++] = reply;
+                bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(reply, bus);
 
         } else if (hint_sync_call) {
                 struct kdbus_msg *k;
@@ -1231,7 +1231,7 @@ static int push_name_owner_changed(
         if (r < 0)
                 return r;
 
-        bus->rqueue[bus->rqueue_size++] = m;
+        bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m, bus);
         m = NULL;
 
         return 1;
@@ -1316,7 +1316,7 @@ static int translate_reply(
         if (r < 0)
                 return r;
 
-        bus->rqueue[bus->rqueue_size++] = m;
+        bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m, bus);
         m = NULL;
 
         return 1;
index 9642de1..266dd7f 100644 (file)
@@ -10,6 +10,7 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "hexdecoct.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "strv.h"
 
index 6bb7129..4e841a7 100644 (file)
 #include "fd-util.h"
 #include "io-util.h"
 #include "memfd-util.h"
+#include "memory-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "time-util.h"
 #include "utf8.h"
-#include "util.h"
 
 static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
 
@@ -137,7 +137,8 @@ static sd_bus_message* message_free(sd_bus_message *m) {
         if (m->free_kdbus)
                 free(m->kdbus);
 
-        sd_bus_unref(m->bus);
+        /* Note that we don't unref m->bus here. That's already done by sd_bus_message_unref() as each user
+         * reference to the bus message also is considered a reference to the bus connection itself. */
 
         if (m->free_fds) {
                 close_many(m->fds, m->n_fds);
@@ -156,8 +157,6 @@ static sd_bus_message* message_free(sd_bus_message *m) {
         return mfree(m);
 }
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(sd_bus_message*, message_free);
-
 static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
         void *op, *np;
         size_t old_size, new_size, start;
@@ -305,7 +304,7 @@ static int message_append_field_signature(
         /* dbus1 doesn't allow signatures over 8bit, let's enforce
          * this globally, to not risk convertability */
         l = strlen(s);
-        if (l > 255)
+        if (l > SD_BUS_MAXIMUM_SIGNATURE_LENGTH)
                 return -EINVAL;
 
         /* Signature "(yv)" where the variant contains "g" */
@@ -479,7 +478,6 @@ int bus_message_from_header(
         if (!m)
                 return -ENOMEM;
 
-        m->n_ref = 1;
         m->sealed = true;
         m->header = header;
         m->header_accessible = header_accessible;
@@ -533,7 +531,9 @@ int bus_message_from_header(
                 m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
         }
 
+        m->n_ref = 1;
         m->bus = sd_bus_ref(bus);
+
         *ret = TAKE_PTR(m);
 
         return 0;
@@ -548,7 +548,7 @@ int bus_message_from_malloc(
                 const char *label,
                 sd_bus_message **ret) {
 
-        _cleanup_(message_freep) sd_bus_message *m = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         size_t sz;
         int r;
 
@@ -605,13 +605,13 @@ _public_ int sd_bus_message_new(
                 return -ENOMEM;
 
         t->n_ref = 1;
+        t->bus = sd_bus_ref(bus);
         t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message)));
         t->header->endian = BUS_NATIVE_ENDIAN;
         t->header->type = type;
         t->header->version = bus->message_version;
         t->allow_fds = bus->can_fds || !IN_SET(bus->state, BUS_HELLO, BUS_RUNNING);
         t->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(t);
-        t->bus = sd_bus_ref(bus);
 
         if (bus->allow_interactive_authorization)
                 t->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
@@ -667,7 +667,7 @@ _public_ int sd_bus_message_new_method_call(
                 const char *interface,
                 const char *member) {
 
-        _cleanup_(message_freep) sd_bus_message *t = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
         int r;
 
         assert_return(bus, -ENOTCONN);
@@ -712,7 +712,7 @@ static int message_new_reply(
                 uint8_t type,
                 sd_bus_message **m) {
 
-        _cleanup_(message_freep) sd_bus_message *t = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
         uint64_t cookie;
         int r;
 
@@ -763,7 +763,7 @@ _public_ int sd_bus_message_new_method_error(
                 sd_bus_message **m,
                 const sd_bus_error *e) {
 
-        _cleanup_(message_freep) sd_bus_message *t = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
         int r;
 
         assert_return(sd_bus_error_is_set(e), -EINVAL);
@@ -866,7 +866,7 @@ int bus_message_new_synthetic_error(
                 const sd_bus_error *e,
                 sd_bus_message **m) {
 
-        _cleanup_(message_freep) sd_bus_message *t = NULL;
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
         int r;
 
         assert(bus);
@@ -950,7 +950,79 @@ fail:
         return r;
 }
 
-DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus_message, sd_bus_message, message_free);
+_public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
+        if (!m)
+                return NULL;
+
+        /* We are fine if this message so far was either explicitly reffed or not reffed but queued into at
+         * least one bus connection object. */
+        assert(m->n_ref > 0 || m->n_queued > 0);
+
+        m->n_ref++;
+
+        /* Each user reference to a bus message shall also be considered a ref on the bus */
+        sd_bus_ref(m->bus);
+        return m;
+}
+
+_public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
+        if (!m)
+                return NULL;
+
+        assert(m->n_ref > 0);
+
+        sd_bus_unref(m->bus); /* Each regular ref is also a ref on the bus connection. Let's hence drop it
+                               * here. Note we have to do this before decrementing our own n_ref here, since
+                               * otherwise, if this message is currently queued sd_bus_unref() might call
+                               * bus_message_unref_queued() for this which might then destroy the message
+                               * while we are still processing it. */
+        m->n_ref--;
+
+        if (m->n_ref > 0 || m->n_queued > 0)
+                return NULL;
+
+        /* Unset the bus field if neither the user has a reference nor this message is queued. We are careful
+         * to reset the field only after the last reference to the bus is dropped, after all we might keep
+         * multiple references to the bus, once for each reference kept on outselves. */
+        m->bus = NULL;
+
+        return message_free(m);
+}
+
+sd_bus_message* bus_message_ref_queued(sd_bus_message *m, sd_bus *bus) {
+        if (!m)
+                return NULL;
+
+        /* If this is a different bus than the message is associated with, then implicitly turn this into a
+         * regular reference. This means that you can create a memory leak by enqueuing a message generated
+         * on one bus onto another at the same time as enqueueing a message from the second one on the first,
+         * as we'll not detect the cyclic references there. */
+        if (bus != m->bus)
+                return sd_bus_message_ref(m);
+
+        assert(m->n_ref > 0 || m->n_queued > 0);
+        m->n_queued++;
+
+        return m;
+}
+
+sd_bus_message* bus_message_unref_queued(sd_bus_message *m, sd_bus *bus) {
+        if (!m)
+                return NULL;
+
+        if (bus != m->bus)
+                return sd_bus_message_unref(m);
+
+        assert(m->n_queued > 0);
+        m->n_queued--;
+
+        if (m->n_ref > 0 || m->n_queued > 0)
+                return NULL;
+
+        m->bus = NULL;
+
+        return message_free(m);
+}
 
 _public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
         assert_return(m, -EINVAL);
@@ -5182,7 +5254,7 @@ int bus_message_parse_fields(sd_bus_message *m) {
                                 return -EBADMSG;
 
                         if (*p == 0) {
-                                char *k;
+                                _cleanup_free_ char *k = NULL;
                                 size_t l;
 
                                 /* We found the beginning of the signature
@@ -5200,6 +5272,9 @@ int bus_message_parse_fields(sd_bus_message *m) {
                                 if (!k)
                                         return -ENOMEM;
 
+                                if (!signature_is_valid(k, true))
+                                        return -EBADMSG;
+
                                 free_and_replace(m->root_container.signature, k);
                                 break;
                         }
index 592dd93..083171e 100644 (file)
@@ -48,7 +48,16 @@ struct bus_body_part {
 };
 
 struct sd_bus_message {
-        unsigned n_ref;
+        /* Caveat: a message can be referenced in two different ways: the main (user-facing) way will also
+         * pin the bus connection object the message is associated with. The secondary way ("queued") is used
+         * when a message is in the read or write queues of the bus connection object, which will not pin the
+         * bus connection object. This is necessary so that we don't have to have a pair of cyclic references
+         * between a message that is queued and its connection: as soon as a message is only referenced by
+         * the connection (by means of being queued) and the connection itself has no other references it
+         * will be freed. */
+
+        unsigned n_ref;     /* Counter of references that pin the connection */
+        unsigned n_queued;  /* Counter of references that do not pin the connection */
 
         sd_bus *bus;
 
@@ -220,3 +229,6 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m);
 
 void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m);
 void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m);
+
+sd_bus_message* bus_message_ref_queued(sd_bus_message *m, sd_bus *bus);
+sd_bus_message* bus_message_unref_queued(sd_bus_message *m, sd_bus *bus);
index 58329f3..d9fc256 100644 (file)
@@ -736,7 +736,8 @@ static int vtable_append_all_properties(
         if (c->vtable[0].flags & SD_BUS_VTABLE_HIDDEN)
                 return 1;
 
-        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+        v = c->vtable;
+        for (v = bus_vtable_next(c->vtable, v); v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(c->vtable, v)) {
                 if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
                         continue;
 
@@ -1133,7 +1134,8 @@ static int object_manager_serialize_path_and_fallbacks(
                 const char *path,
                 sd_bus_error *error) {
 
-        char *prefix;
+        _cleanup_free_ char *prefix = NULL;
+        size_t pl;
         int r;
 
         assert(bus);
@@ -1149,7 +1151,12 @@ static int object_manager_serialize_path_and_fallbacks(
                 return 0;
 
         /* Second, add fallback vtables registered for any of the prefixes */
-        prefix = newa(char, strlen(path) + 1);
+        pl = strlen(path);
+        assert(pl <= BUS_PATH_SIZE_MAX);
+        prefix = new(char, pl + 1);
+        if (!prefix)
+                return -ENOMEM;
+
         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
                 r = object_manager_serialize_path(bus, reply, prefix, path, true, error);
                 if (r < 0)
@@ -1345,6 +1352,7 @@ static int object_find_and_run(
 }
 
 int bus_process_object(sd_bus *bus, sd_bus_message *m) {
+        _cleanup_free_ char *prefix = NULL;
         int r;
         size_t pl;
         bool found_object = false;
@@ -1369,9 +1377,12 @@ int bus_process_object(sd_bus *bus, sd_bus_message *m) {
         assert(m->member);
 
         pl = strlen(m->path);
-        do {
-                char prefix[pl+1];
+        assert(pl <= BUS_PATH_SIZE_MAX);
+        prefix = new(char, pl + 1);
+        if (!prefix)
+                return -ENOMEM;
 
+        do {
                 bus->nodes_modified = false;
 
                 r = object_find_and_run(bus, m, m->path, false, &found_object);
@@ -1498,9 +1509,15 @@ static int bus_find_parent_object_manager(sd_bus *bus, struct node **out, const
 
         n = hashmap_get(bus->nodes, path);
         if (!n) {
-                char *prefix;
+                _cleanup_free_ char *prefix = NULL;
+                size_t pl;
+
+                pl = strlen(path);
+                assert(pl <= BUS_PATH_SIZE_MAX);
+                prefix = new(char, pl + 1);
+                if (!prefix)
+                        return -ENOMEM;
 
-                prefix = newa(char, strlen(path) + 1);
                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
                         n = hashmap_get(bus->nodes, prefix);
                         if (n)
@@ -1610,6 +1627,99 @@ static int vtable_member_compare_func(const struct vtable_member *x, const struc
 
 DEFINE_PRIVATE_HASH_OPS(vtable_member_hash_ops, struct vtable_member, vtable_member_hash_func, vtable_member_compare_func);
 
+typedef enum {
+        NAMES_FIRST_PART        = 1 << 0, /* first part of argument name list (input names). It is reset by names_are_valid() */
+        NAMES_PRESENT           = 1 << 1, /* at least one argument name is present, so the names will checked.
+                                             This flag is set and used internally by names_are_valid(), but needs to be stored across calls for 2-parts list  */
+        NAMES_SINGLE_PART       = 1 << 2, /* argument name list consisting of a single part */
+} names_flags;
+
+static bool names_are_valid(const char *signature, const char **names, names_flags *flags) {
+        int r;
+
+        if ((*flags & NAMES_FIRST_PART || *flags & NAMES_SINGLE_PART) && **names != '\0')
+                *flags |= NAMES_PRESENT;
+
+        for (;*flags & NAMES_PRESENT;) {
+                size_t l;
+
+                if (!*signature)
+                        break;
+
+                r = signature_element_length(signature, &l);
+                if (r < 0)
+                        return false;
+
+                if (**names != '\0') {
+                        if (!member_name_is_valid(*names))
+                                return false;
+                        *names += strlen(*names) + 1;
+                } else if (*flags & NAMES_PRESENT)
+                        return false;
+
+                signature += l;
+        }
+        /* let's check if there are more argument names specified than the signature allows */
+        if (*flags & NAMES_PRESENT && **names != '\0' && !(*flags & NAMES_FIRST_PART))
+                return false;
+        *flags &= ~NAMES_FIRST_PART;
+        return true;
+}
+
+/* the current version of this struct is defined in sd-bus-vtable.h, but we need to list here the historical versions
+   to make sure the calling code is compatible with one of these */
+struct sd_bus_vtable_original {
+        uint8_t type:8;
+        uint64_t flags:56;
+        union {
+                struct {
+                        size_t element_size;
+                } start;
+                struct {
+                        const char *member;
+                        const char *signature;
+                        const char *result;
+                        sd_bus_message_handler_t handler;
+                        size_t offset;
+                } method;
+                struct {
+                        const char *member;
+                        const char *signature;
+                } signal;
+                struct {
+                        const char *member;
+                        const char *signature;
+                        sd_bus_property_get_t get;
+                        sd_bus_property_set_t set;
+                        size_t offset;
+                } property;
+        } x;
+};
+/* Structure size up to v241 */
+#define VTABLE_ELEMENT_SIZE_ORIGINAL sizeof(struct sd_bus_vtable_original)
+/* Current structure size */
+#define VTABLE_ELEMENT_SIZE sizeof(struct sd_bus_vtable)
+
+static int vtable_features(const sd_bus_vtable *vtable) {
+        if (vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_ORIGINAL)
+                return 0;
+        return vtable[0].x.start.features;
+}
+
+bool bus_vtable_has_names(const sd_bus_vtable *vtable) {
+        return vtable_features(vtable) & _SD_BUS_VTABLE_PARAM_NAMES;
+}
+
+const sd_bus_vtable* bus_vtable_next(const sd_bus_vtable *vtable, const sd_bus_vtable *v) {
+        if (vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_ORIGINAL) {
+                const struct sd_bus_vtable_original *v2 = (const struct sd_bus_vtable_original *)v;
+                v2++;
+                v = (const sd_bus_vtable*)v2;
+        } else /* current version */
+                v++;
+        return v;
+}
+
 static int add_object_vtable_internal(
                 sd_bus *bus,
                 sd_bus_slot **slot,
@@ -1625,6 +1735,8 @@ static int add_object_vtable_internal(
         const sd_bus_vtable *v;
         struct node *n;
         int r;
+        const char *names = "";
+        names_flags nf;
 
         assert_return(bus, -EINVAL);
         assert_return(bus = bus_resolve(bus), -ENOPKG);
@@ -1632,7 +1744,9 @@ static int add_object_vtable_internal(
         assert_return(interface_name_is_valid(interface), -EINVAL);
         assert_return(vtable, -EINVAL);
         assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
-        assert_return(vtable[0].x.start.element_size == sizeof(struct sd_bus_vtable), -EINVAL);
+        assert_return(vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_ORIGINAL ||
+                      vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE,
+                      -EINVAL);
         assert_return(!bus_pid_changed(bus), -ECHILD);
         assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
                       !streq(interface, "org.freedesktop.DBus.Introspectable") &&
@@ -1684,16 +1798,23 @@ static int add_object_vtable_internal(
                 goto fail;
         }
 
-        for (v = s->node_vtable.vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+        v = s->node_vtable.vtable;
+        for (v = bus_vtable_next(vtable, v); v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(vtable, v)) {
 
                 switch (v->type) {
 
                 case _SD_BUS_VTABLE_METHOD: {
                         struct vtable_member *m;
+                        nf = NAMES_FIRST_PART;
+
+                        if (bus_vtable_has_names(vtable))
+                                names = strempty(v->x.method.names);
 
                         if (!member_name_is_valid(v->x.method.member) ||
                             !signature_is_valid(strempty(v->x.method.signature), false) ||
                             !signature_is_valid(strempty(v->x.method.result), false) ||
+                            !names_are_valid(strempty(v->x.method.signature), &names, &nf) ||
+                            !names_are_valid(strempty(v->x.method.result), &names, &nf) ||
                             !(v->x.method.handler || (isempty(v->x.method.signature) && isempty(v->x.method.result))) ||
                             v->flags & (SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION)) {
                                 r = -EINVAL;
@@ -1770,9 +1891,14 @@ static int add_object_vtable_internal(
                 }
 
                 case _SD_BUS_VTABLE_SIGNAL:
+                        nf = NAMES_SINGLE_PART;
+
+                        if (bus_vtable_has_names(vtable))
+                                names = strempty(v->x.signal.names);
 
                         if (!member_name_is_valid(v->x.signal.member) ||
                             !signature_is_valid(strempty(v->x.signal.signature), false) ||
+                            !names_are_valid(strempty(v->x.signal.signature), &names, &nf) ||
                             v->flags & SD_BUS_VTABLE_UNPRIVILEGED) {
                                 r = -EINVAL;
                                 goto fail;
@@ -1977,7 +2103,8 @@ static int emit_properties_changed_on_interface(
                          * we include all properties that are marked
                          * as changing in the message. */
 
-                        for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+                        v = c->vtable;
+                        for (v = bus_vtable_next(c->vtable, v); v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(c->vtable, v)) {
                                 if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
                                         continue;
 
@@ -2048,7 +2175,8 @@ static int emit_properties_changed_on_interface(
                         } else {
                                 const sd_bus_vtable *v;
 
-                                for (v = c->vtable+1; v->type != _SD_BUS_VTABLE_END; v++) {
+                                v = c->vtable;
+                                for (v = bus_vtable_next(c->vtable, v); v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(c->vtable, v)) {
                                         if (!IN_SET(v->type, _SD_BUS_VTABLE_PROPERTY, _SD_BUS_VTABLE_WRITABLE_PROPERTY))
                                                 continue;
 
@@ -2083,8 +2211,9 @@ _public_ int sd_bus_emit_properties_changed_strv(
                 const char *interface,
                 char **names) {
 
+        _cleanup_free_ char *prefix = NULL;
         bool found_interface = false;
-        char *prefix;
+        size_t pl;
         int r;
 
         assert_return(bus, -EINVAL);
@@ -2105,6 +2234,12 @@ _public_ int sd_bus_emit_properties_changed_strv(
 
         BUS_DONT_DESTROY(bus);
 
+        pl = strlen(path);
+        assert(pl <= BUS_PATH_SIZE_MAX);
+        prefix = new(char, pl + 1);
+        if (!prefix)
+                return -ENOMEM;
+
         do {
                 bus->nodes_modified = false;
 
@@ -2114,7 +2249,6 @@ _public_ int sd_bus_emit_properties_changed_strv(
                 if (bus->nodes_modified)
                         continue;
 
-                prefix = newa(char, strlen(path) + 1);
                 OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
                         r = emit_properties_changed_on_interface(bus, prefix, path, interface, true, &found_interface, names);
                         if (r != 0)
@@ -2246,7 +2380,8 @@ static int object_added_append_all_prefix(
 
 static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
         _cleanup_set_free_ Set *s = NULL;
-        char *prefix;
+        _cleanup_free_ char *prefix = NULL;
+        size_t pl;
         int r;
 
         assert(bus);
@@ -2291,7 +2426,12 @@ static int object_added_append_all(sd_bus *bus, sd_bus_message *m, const char *p
         if (bus->nodes_modified)
                 return 0;
 
-        prefix = newa(char, strlen(path) + 1);
+        pl = strlen(path);
+        assert(pl <= BUS_PATH_SIZE_MAX);
+        prefix = new(char, pl + 1);
+        if (!prefix)
+                return -ENOMEM;
+
         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
                 r = object_added_append_all_prefix(bus, m, s, prefix, path, true);
                 if (r < 0)
@@ -2430,7 +2570,8 @@ static int object_removed_append_all_prefix(
 
 static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char *path) {
         _cleanup_set_free_ Set *s = NULL;
-        char *prefix;
+        _cleanup_free_ char *prefix = NULL;
+        size_t pl;
         int r;
 
         assert(bus);
@@ -2462,7 +2603,12 @@ static int object_removed_append_all(sd_bus *bus, sd_bus_message *m, const char
         if (bus->nodes_modified)
                 return 0;
 
-        prefix = newa(char, strlen(path) + 1);
+        pl = strlen(path);
+        assert(pl <= BUS_PATH_SIZE_MAX);
+        prefix = new(char, pl + 1);
+        if (!prefix)
+                return -ENOMEM;
+
         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
                 r = object_removed_append_all_prefix(bus, m, s, prefix, path, true);
                 if (r < 0)
@@ -2612,7 +2758,8 @@ static int interfaces_added_append_one(
                 const char *path,
                 const char *interface) {
 
-        char *prefix;
+        _cleanup_free_ char *prefix = NULL;
+        size_t pl;
         int r;
 
         assert(bus);
@@ -2626,7 +2773,12 @@ static int interfaces_added_append_one(
         if (bus->nodes_modified)
                 return 0;
 
-        prefix = newa(char, strlen(path) + 1);
+        pl = strlen(path);
+        assert(pl <= BUS_PATH_SIZE_MAX);
+        prefix = new(char, pl + 1);
+        if (!prefix)
+                return -ENOMEM;
+
         OBJECT_PATH_FOREACH_PREFIX(prefix, path) {
                 r = interfaces_added_append_one_prefix(bus, m, prefix, path, interface, true);
                 if (r != 0)
index a119ff9..b45fe63 100644 (file)
@@ -3,5 +3,7 @@
 
 #include "bus-internal.h"
 
+const sd_bus_vtable* bus_vtable_next(const sd_bus_vtable *vtable, const sd_bus_vtable *v);
+bool bus_vtable_has_names(const sd_bus_vtable *vtable);
 int bus_process_object(sd_bus *bus, sd_bus_message *m);
 void bus_node_gc(sd_bus *b, struct node *n);
index 1ecd6e8..b420ba3 100644 (file)
@@ -144,5 +144,5 @@ bool signature_is_valid(const char *s, bool allow_dict_entry) {
                 p += t;
         }
 
-        return p - s <= 255;
+        return p - s <= SD_BUS_MAXIMUM_SIGNATURE_LENGTH;
 }
index d949080..09900f4 100644 (file)
@@ -117,7 +117,7 @@ void bus_slot_disconnect(sd_bus_slot *slot, bool unref) {
                 if (slot->node_vtable.node && slot->node_vtable.interface && slot->node_vtable.vtable) {
                         const sd_bus_vtable *v;
 
-                        for (v = slot->node_vtable.vtable; v->type != _SD_BUS_VTABLE_END; v++) {
+                        for (v = slot->node_vtable.vtable; v->type != _SD_BUS_VTABLE_END; v = bus_vtable_next(slot->node_vtable.vtable, v)) {
                                 struct vtable_member *x = NULL;
 
                                 switch (v->type) {
index e69145a..5f0ea03 100644 (file)
@@ -18,6 +18,7 @@
 #include "hexdecoct.h"
 #include "io-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -28,7 +29,6 @@
 #include "string-util.h"
 #include "user-util.h"
 #include "utf8.h"
-#include "util.h"
 
 #define SNDBUF_SIZE (8*1024*1024)
 
@@ -158,17 +158,24 @@ static int bus_socket_write_auth(sd_bus *b) {
 }
 
 static int bus_socket_auth_verify_client(sd_bus *b) {
-        char *e, *f, *start;
+        char *d, *e, *f, *start;
         sd_id128_t peer;
-        unsigned i;
         int r;
 
         assert(b);
 
-        /* We expect two response lines: "OK" and possibly
-         * "AGREE_UNIX_FD" */
+        /*
+         * We expect three response lines:
+         *   "DATA\r\n"
+         *   "OK <server-id>\r\n"
+         *   "AGREE_UNIX_FD\r\n"        (optional)
+         */
+
+        d = memmem_safe(b->rbuffer, b->rbuffer_size, "\r\n", 2);
+        if (!d)
+                return 0;
 
-        e = memmem_safe(b->rbuffer, b->rbuffer_size, "\r\n", 2);
+        e = memmem(d + 2, b->rbuffer_size - (d - (char*) b->rbuffer) - 2, "\r\n", 2);
         if (!e)
                 return 0;
 
@@ -183,22 +190,38 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
                 start = e + 2;
         }
 
-        /* Nice! We got all the lines we need. First check the OK
-         * line */
+        /* Nice! We got all the lines we need. First check the DATA line. */
+
+        if (d - (char*) b->rbuffer == 4) {
+                if (memcmp(b->rbuffer, "DATA", 4))
+                        return -EPERM;
+        } else if (d - (char*) b->rbuffer == 3 + 32) {
+                /*
+                 * Old versions of the server-side implementation of `sd-bus` replied with "OK <id>" to
+                 * "AUTH" requests from a client, even if the "AUTH" line did not contain inlined
+                 * arguments. Therefore, we also accept "OK <id>" here, even though it is technically the
+                 * wrong reply. We ignore the "<id>" parameter, though, since it has no real value.
+                 */
+                if (memcmp(b->rbuffer, "OK ", 3))
+                        return -EPERM;
+        } else
+                return -EPERM;
+
+        /* Now check the OK line. */
 
-        if (e - (char*) b->rbuffer != 3 + 32)
+        if (e - d != 2 + 3 + 32)
                 return -EPERM;
 
-        if (memcmp(b->rbuffer, "OK ", 3))
+        if (memcmp(d + 2, "OK ", 3))
                 return -EPERM;
 
         b->auth = b->anonymous_auth ? BUS_AUTH_ANONYMOUS : BUS_AUTH_EXTERNAL;
 
-        for (i = 0; i < 32; i += 2) {
+        for (unsigned i = 0; i < 32; i += 2) {
                 int x, y;
 
-                x = unhexchar(((char*) b->rbuffer)[3 + i]);
-                y = unhexchar(((char*) b->rbuffer)[3 + i + 1]);
+                x = unhexchar(d[2 + 3 + i]);
+                y = unhexchar(d[2 + 3 + i + 1]);
 
                 if (x < 0 || y < 0)
                         return -EINVAL;
@@ -212,7 +235,7 @@ static int bus_socket_auth_verify_client(sd_bus *b) {
 
         b->server_id = peer;
 
-        /* And possibly check the second line, too */
+        /* And possibly check the third line, too */
 
         if (f)
                 b->can_fds =
@@ -386,26 +409,36 @@ static int bus_socket_auth_verify_server(sd_bus *b) {
 
                 if (line_begins(line, l, "AUTH ANONYMOUS")) {
 
-                        r = verify_anonymous_token(b, line + 14, l - 14);
+                        r = verify_anonymous_token(b,
+                                                   line + strlen("AUTH ANONYMOUS"),
+                                                   l - strlen("AUTH ANONYMOUS"));
                         if (r < 0)
                                 return r;
                         if (r == 0)
                                 r = bus_socket_auth_write(b, "REJECTED\r\n");
                         else {
                                 b->auth = BUS_AUTH_ANONYMOUS;
-                                r = bus_socket_auth_write_ok(b);
+                                if (l <= strlen("AUTH ANONYMOUS"))
+                                        r = bus_socket_auth_write(b, "DATA\r\n");
+                                else
+                                        r = bus_socket_auth_write_ok(b);
                         }
 
                 } else if (line_begins(line, l, "AUTH EXTERNAL")) {
 
-                        r = verify_external_token(b, line + 13, l - 13);
+                        r = verify_external_token(b,
+                                                  line + strlen("AUTH EXTERNAL"),
+                                                  l - strlen("AUTH EXTERNAL"));
                         if (r < 0)
                                 return r;
                         if (r == 0)
                                 r = bus_socket_auth_write(b, "REJECTED\r\n");
                         else {
                                 b->auth = BUS_AUTH_EXTERNAL;
-                                r = bus_socket_auth_write_ok(b);
+                                if (l <= strlen("AUTH EXTERNAL"))
+                                        r = bus_socket_auth_write(b, "DATA\r\n");
+                                else
+                                        r = bus_socket_auth_write_ok(b);
                         }
 
                 } else if (line_begins(line, l, "AUTH"))
@@ -602,39 +635,39 @@ static void bus_get_peercred(sd_bus *b) {
 }
 
 static int bus_socket_start_auth_client(sd_bus *b) {
-        size_t l;
-        const char *auth_suffix, *auth_prefix;
+        static const char sasl_auth_anonymous[] = {
+                /*
+                 * We use an arbitrary trace-string for the ANONYMOUS authentication. It can be used by the
+                 * message broker to aid debugging of clients. We fully anonymize the connection and use a
+                 * static default.
+                 */
+                "\0AUTH ANONYMOUS\r\n"
+                /* HEX a n o n y m o u s */
+                "DATA 616e6f6e796d6f7573\r\n"
+        };
+        static const char sasl_auth_external[] = {
+                "\0AUTH EXTERNAL\r\n"
+                "DATA\r\n"
+        };
+        static const char sasl_negotiate_unix_fd[] = {
+                "NEGOTIATE_UNIX_FD\r\n"
+        };
+        static const char sasl_begin[] = {
+                "BEGIN\r\n"
+        };
+        size_t i = 0;
 
         assert(b);
 
-        if (b->anonymous_auth) {
-                auth_prefix = "\0AUTH ANONYMOUS ";
-
-                /* For ANONYMOUS auth we send some arbitrary "trace" string */
-                l = 9;
-                b->auth_buffer = hexmem("anonymous", l);
-        } else {
-                char text[DECIMAL_STR_MAX(uid_t) + 1];
-
-                auth_prefix = "\0AUTH EXTERNAL ";
-
-                xsprintf(text, UID_FMT, geteuid());
-
-                l = strlen(text);
-                b->auth_buffer = hexmem(text, l);
-        }
-
-        if (!b->auth_buffer)
-                return -ENOMEM;
+        if (b->anonymous_auth)
+                b->auth_iovec[i++] = IOVEC_MAKE((char*) sasl_auth_anonymous, sizeof(sasl_auth_anonymous) - 1);
+        else
+                b->auth_iovec[i++] = IOVEC_MAKE((char*) sasl_auth_external, sizeof(sasl_auth_external) - 1);
 
         if (b->accept_fd)
-                auth_suffix = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n";
-        else
-                auth_suffix = "\r\nBEGIN\r\n";
+                b->auth_iovec[i++] = IOVEC_MAKE_STRING(sasl_negotiate_unix_fd);
 
-        b->auth_iovec[0] = IOVEC_MAKE((void*) auth_prefix, 1 + strlen(auth_prefix + 1));
-        b->auth_iovec[1] = IOVEC_MAKE(b->auth_buffer, l * 2);
-        b->auth_iovec[2] = IOVEC_MAKE_STRING(auth_suffix);
+        b->auth_iovec[i++] = IOVEC_MAKE_STRING(sasl_begin);
 
         return bus_socket_write_auth(b);
 }
@@ -1102,21 +1135,25 @@ static int bus_socket_make_message(sd_bus *bus, size_t size) {
                                     bus->fds, bus->n_fds,
                                     NULL,
                                     &t);
-        if (r == -EBADMSG)
+        if (r == -EBADMSG) {
                 log_debug_errno(r, "Received invalid message from connection %s, dropping.", strna(bus->description));
-        else if (r < 0) {
+                free(bus->rbuffer); /* We want to drop current rbuffer and proceed with whatever remains in b */
+        } else if (r < 0) {
                 free(b);
                 return r;
         }
 
+        /* rbuffer ownership was either transferred to t, or we got EBADMSG and dropped it. */
         bus->rbuffer = b;
         bus->rbuffer_size -= size;
 
         bus->fds = NULL;
         bus->n_fds = 0;
 
-        if (t)
-                bus->rqueue[bus->rqueue_size++] = t;
+        if (t) {
+                bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(t, bus);
+                sd_bus_message_unref(t);
+        }
 
         return 1;
 }
index 63fe0ef..a6781ed 100644 (file)
 #include "bus-util.h"
 #include "cgroup-util.h"
 #include "def.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "hexdecoct.h"
 #include "hostname-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "parse-util.h"
 #include "process-util.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 #define log_debug_bus_message(m)                                         \
         do {                                                             \
@@ -147,13 +148,13 @@ static void bus_reset_queues(sd_bus *b) {
         assert(b);
 
         while (b->rqueue_size > 0)
-                sd_bus_message_unref(b->rqueue[--b->rqueue_size]);
+                bus_message_unref_queued(b->rqueue[--b->rqueue_size], b);
 
         b->rqueue = mfree(b->rqueue);
         b->rqueue_allocated = 0;
 
         while (b->wqueue_size > 0)
-                sd_bus_message_unref(b->wqueue[--b->wqueue_size]);
+                bus_message_unref_queued(b->wqueue[--b->wqueue_size], b);
 
         b->wqueue = mfree(b->wqueue);
         b->wqueue_allocated = 0;
@@ -243,7 +244,7 @@ _public_ int sd_bus_new(sd_bus **ret) {
                 return -ENOMEM;
 
         *b = (sd_bus) {
-                .n_ref = REFCNT_INIT,
+                .n_ref = 1,
                 .input_fd = -1,
                 .output_fd = -1,
                 .inotify_fd = -1,
@@ -257,12 +258,12 @@ _public_ int sd_bus_new(sd_bus **ret) {
                 .close_on_exit = true,
         };
 
-        assert_se(pthread_mutex_init(&b->memfd_cache_mutex, NULL) == 0);
-
         /* We guarantee that wqueue always has space for at least one entry */
         if (!GREEDY_REALLOC(b->wqueue, b->wqueue_allocated, 1))
                 return -ENOMEM;
 
+        assert_se(pthread_mutex_init(&b->memfd_cache_mutex, NULL) == 0);
+
         *ret = TAKE_PTR(b);
         return 0;
 }
@@ -529,7 +530,7 @@ static int synthesize_connected_signal(sd_bus *bus) {
 
         /* Insert at the very front */
         memmove(bus->rqueue + 1, bus->rqueue, sizeof(sd_bus_message*) * bus->rqueue_size);
-        bus->rqueue[0] = TAKE_PTR(m);
+        bus->rqueue[0] = bus_message_ref_queued(m, bus);
         bus->rqueue_size++;
 
         return 0;
@@ -1784,7 +1785,7 @@ void bus_enter_closing(sd_bus *bus) {
         bus_set_state(bus, BUS_CLOSING);
 }
 
-DEFINE_PUBLIC_ATOMIC_REF_UNREF_FUNC(sd_bus, sd_bus, bus_free);
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_bus, sd_bus, bus_free);
 
 _public_ int sd_bus_is_open(sd_bus *bus) {
         assert_return(bus, -EINVAL);
@@ -1843,6 +1844,47 @@ _public_ int sd_bus_get_bus_id(sd_bus *bus, sd_id128_t *id) {
         return 0;
 }
 
+#define COOKIE_CYCLED (UINT32_C(1) << 31)
+
+static uint64_t cookie_inc(uint64_t cookie) {
+
+        /* Stay within the 32bit range, since classic D-Bus can't deal with more */
+        if (cookie >= UINT32_MAX)
+                return COOKIE_CYCLED; /* Don't go back to zero, but use the highest bit for checking
+                                       * whether we are looping. */
+
+        return cookie + 1;
+}
+
+static int next_cookie(sd_bus *b) {
+        uint64_t new_cookie;
+
+        assert(b);
+
+        new_cookie = cookie_inc(b->cookie);
+
+        /* Small optimization: don't bother with checking for cookie reuse until we overran cookiespace at
+         * least once, but then do it thorougly. */
+        if (FLAGS_SET(new_cookie, COOKIE_CYCLED)) {
+                uint32_t i;
+
+                /* Check if the cookie is currently in use. If so, pick the next one */
+                for (i = 0; i < COOKIE_CYCLED; i++) {
+                        if (!ordered_hashmap_contains(b->reply_callbacks, &new_cookie))
+                                goto good;
+
+                        new_cookie = cookie_inc(new_cookie);
+                }
+
+                /* Can't fulfill request */
+                return -EBUSY;
+        }
+
+good:
+        b->cookie = new_cookie;
+        return 0;
+}
+
 static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
         int r;
 
@@ -1869,7 +1911,11 @@ static int bus_seal_message(sd_bus *b, sd_bus_message *m, usec_t timeout) {
                         return r;
         }
 
-        return sd_bus_message_seal(m, ++b->cookie, timeout);
+        r = next_cookie(b);
+        if (r < 0)
+                return r;
+
+        return sd_bus_message_seal(m, b->cookie, timeout);
 }
 
 static int bus_remarshal_message(sd_bus *b, sd_bus_message **m) {
@@ -1977,7 +2023,7 @@ static int dispatch_wqueue(sd_bus *bus) {
                          * anyway. */
 
                         bus->wqueue_size--;
-                        sd_bus_message_unref(bus->wqueue[0]);
+                        bus_message_unref_queued(bus->wqueue[0], bus);
                         memmove(bus->wqueue, bus->wqueue + 1, sizeof(sd_bus_message*) * bus->wqueue_size);
                         bus->windex = 0;
 
@@ -2009,6 +2055,15 @@ int bus_rqueue_make_room(sd_bus *bus) {
         return 0;
 }
 
+static void rqueue_drop_one(sd_bus *bus, size_t i) {
+        assert(bus);
+        assert(i < bus->rqueue_size);
+
+        bus_message_unref_queued(bus->rqueue[i], bus);
+        memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
+        bus->rqueue_size--;
+}
+
 static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd_bus_message **m) {
         int r, ret = 0;
 
@@ -2023,10 +2078,8 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
         for (;;) {
                 if (bus->rqueue_size > 0) {
                         /* Dispatch a queued message */
-
-                        *m = bus->rqueue[0];
-                        bus->rqueue_size--;
-                        memmove(bus->rqueue, bus->rqueue + 1, sizeof(sd_bus_message*) * bus->rqueue_size);
+                        *m = sd_bus_message_ref(bus->rqueue[0]);
+                        rqueue_drop_one(bus, 0);
                         return 1;
                 }
 
@@ -2034,8 +2087,10 @@ static int dispatch_rqueue(sd_bus *bus, bool hint_priority, int64_t priority, sd
                 r = bus_read_message(bus, hint_priority, priority);
                 if (r < 0)
                         return r;
-                if (r == 0)
+                if (r == 0) {
+                        *m = NULL;
                         return ret;
+                }
 
                 ret = 1;
         }
@@ -2089,7 +2144,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
 
                 r = bus_write_message(bus, m, hint_sync_call, &idx);
                 if (r < 0) {
-                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+                        if (ERRNO_IS_DISCONNECT(r)) {
                                 bus_enter_closing(bus);
                                 return -ECONNRESET;
                         }
@@ -2103,7 +2158,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
                          * of the wqueue array is always allocated so
                          * that we always can remember how much was
                          * written. */
-                        bus->wqueue[0] = sd_bus_message_ref(m);
+                        bus->wqueue[0] = bus_message_ref_queued(m, bus);
                         bus->wqueue_size = 1;
                         bus->windex = idx;
                 }
@@ -2117,7 +2172,7 @@ static int bus_send_internal(sd_bus *bus, sd_bus_message *_m, uint64_t *cookie,
                 if (!GREEDY_REALLOC(bus->wqueue, bus->wqueue_allocated, bus->wqueue_size + 1))
                         return -ENOMEM;
 
-                bus->wqueue[bus->wqueue_size++] = sd_bus_message_ref(m);
+                bus->wqueue[bus->wqueue_size++] = bus_message_ref_queued(m, bus);
         }
 
 finish:
@@ -2300,7 +2355,7 @@ _public_ int sd_bus_call(
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = sd_bus_message_ref(_m);
         usec_t timeout;
         uint64_t cookie;
-        unsigned i;
+        size_t i;
         int r;
 
         bus_assert_return(m, -EINVAL, error);
@@ -2343,37 +2398,30 @@ _public_ int sd_bus_call(
                 usec_t left;
 
                 while (i < bus->rqueue_size) {
-                        sd_bus_message *incoming = NULL;
+                        _cleanup_(sd_bus_message_unrefp) sd_bus_message *incoming = NULL;
 
-                        incoming = bus->rqueue[i];
+                        incoming = sd_bus_message_ref(bus->rqueue[i]);
 
                         if (incoming->reply_cookie == cookie) {
                                 /* Found a match! */
 
-                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
-                                bus->rqueue_size--;
+                                rqueue_drop_one(bus, i);
                                 log_debug_bus_message(incoming);
 
                                 if (incoming->header->type == SD_BUS_MESSAGE_METHOD_RETURN) {
 
                                         if (incoming->n_fds <= 0 || bus->accept_fd) {
                                                 if (reply)
-                                                        *reply = incoming;
-                                                else
-                                                        sd_bus_message_unref(incoming);
+                                                        *reply = TAKE_PTR(incoming);
 
                                                 return 1;
                                         }
 
-                                        r = sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry.");
-                                        sd_bus_message_unref(incoming);
-                                        return r;
+                                        return sd_bus_error_setf(error, SD_BUS_ERROR_INCONSISTENT_MESSAGE, "Reply message contained file descriptors which I couldn't accept. Sorry.");
 
-                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR) {
-                                        r = sd_bus_error_copy(error, &incoming->error);
-                                        sd_bus_message_unref(incoming);
-                                        return r;
-                                } else {
+                                } else if (incoming->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
+                                        return sd_bus_error_copy(error, &incoming->error);
+                                else {
                                         r = -EIO;
                                         goto fail;
                                 }
@@ -2383,15 +2431,11 @@ _public_ int sd_bus_call(
                                    incoming->sender &&
                                    streq(bus->unique_name, incoming->sender)) {
 
-                                memmove(bus->rqueue + i, bus->rqueue + i + 1, sizeof(sd_bus_message*) * (bus->rqueue_size - i - 1));
-                                bus->rqueue_size--;
+                                rqueue_drop_one(bus, i);
 
-                                /* Our own message? Somebody is trying
-                                 * to send its own client a message,
-                                 * let's not dead-lock, let's fail
-                                 * immediately. */
+                                /* Our own message? Somebody is trying to send its own client a message,
+                                 * let's not dead-lock, let's fail immediately. */
 
-                                sd_bus_message_unref(incoming);
                                 r = -ELOOP;
                                 goto fail;
                         }
@@ -2402,7 +2446,7 @@ _public_ int sd_bus_call(
 
                 r = bus_read_message(bus, false, 0);
                 if (r < 0) {
-                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+                        if (ERRNO_IS_DISCONNECT(r)) {
                                 bus_enter_closing(bus);
                                 r = -ECONNRESET;
                         }
@@ -2435,7 +2479,7 @@ _public_ int sd_bus_call(
 
                 r = dispatch_wqueue(bus);
                 if (r < 0) {
-                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+                        if (ERRNO_IS_DISCONNECT(r)) {
                                 bus_enter_closing(bus);
                                 r = -ECONNRESET;
                         }
@@ -2852,7 +2896,6 @@ static int process_builtin(sd_bus *bus, sd_bus_message *m) {
                                 SD_BUS_ERROR_UNKNOWN_METHOD,
                                  "Unknown method '%s' on interface '%s'.", m->member, m->interface);
         }
-
         if (r < 0)
                 return r;
 
@@ -2976,7 +3019,6 @@ static int process_running(sd_bus *bus, bool hint_priority, int64_t priority, sd
                         return r;
 
                 *ret = TAKE_PTR(m);
-
                 return 1;
         }
 
@@ -3198,7 +3240,7 @@ static int bus_process_internal(sd_bus *bus, bool hint_priority, int64_t priorit
                 assert_not_reached("Unknown state");
         }
 
-        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+        if (ERRNO_IS_DISCONNECT(r)) {
                 bus_enter_closing(bus);
                 r = 1;
         } else if (r < 0)
@@ -3329,7 +3371,7 @@ _public_ int sd_bus_flush(sd_bus *bus) {
         for (;;) {
                 r = dispatch_wqueue(bus);
                 if (r < 0) {
-                        if (IN_SET(r, -ENOTCONN, -ECONNRESET, -EPIPE, -ESHUTDOWN)) {
+                        if (ERRNO_IS_DISCONNECT(r)) {
                                 bus_enter_closing(bus);
                                 return -ECONNRESET;
                         }
index db5ff72..70a6df1 100644 (file)
@@ -4,6 +4,7 @@
 #include "log.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 
 static void test_one_address(sd_bus *b,
                              const char *host,
@@ -40,8 +41,8 @@ static void test_bus_set_address_system_remote(char **args) {
                                  -EINVAL, NULL);
         test_one_address(b, "user@host",
                          0, "unixexec:path=ssh,argv1=-xT,argv2=--,argv3=user%40host,argv4=systemd-stdio-bridge");
-         test_one_address(b, "user@host@host",
-                                 -EINVAL, NULL);
+        test_one_address(b, "user@host@host",
+                         -EINVAL, NULL);
         test_one_address(b, "[::1]",
                          0, "unixexec:path=ssh,argv1=-xT,argv2=--,argv3=%3a%3a1,argv4=systemd-stdio-bridge");
         test_one_address(b, "user@[::1]",
@@ -59,9 +60,7 @@ static void test_bus_set_address_system_remote(char **args) {
 }
 
 int main(int argc, char *argv[]) {
-        log_set_max_level(LOG_INFO);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_INFO);
 
         test_bus_set_address_system_remote(argv + 1);
 
index 0e6943e..5d3e96b 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <sys/wait.h>
+#include <unistd.h>
 
 #include "sd-bus.h"
 
index bea722b..99d335e 100644 (file)
@@ -7,7 +7,6 @@
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "bus-util.h"
-#include "refcnt.h"
 #include "tests.h"
 
 static bool use_system_bus = false;
@@ -16,7 +15,7 @@ static void test_bus_new(void) {
         _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));
+        assert_se(bus->n_ref == 1);
 }
 
 static int test_bus_open(void) {
@@ -32,7 +31,7 @@ static int test_bus_open(void) {
         }
 
         assert_se(r >= 0);
-        printf("after open: refcount %u\n", REFCNT_GET(bus->n_ref));
+        assert_se(bus->n_ref >= 1); /* we send a hello message when opening, so the count is above 1 */
 
         return 0;
 }
@@ -45,10 +44,10 @@ static void test_bus_new_method_call(void) {
 
         assert_se(sd_bus_message_new_method_call(bus, &m, "a.service.name", "/an/object/path", "an.interface.name", "AMethodName") >= 0);
 
-        printf("after message_new_method_call: refcount %u\n", REFCNT_GET(bus->n_ref));
-
+        assert_se(m->n_ref == 1); /* We hold the only reference to the message */
+        assert_se(bus->n_ref >= 2);
         sd_bus_flush_close_unref(bus);
-        printf("after bus_flush_close_unref: refcount %u\n", m->n_ref);
+        assert_se(m->n_ref == 1);
 }
 
 static void test_bus_new_signal(void) {
@@ -59,10 +58,10 @@ static void test_bus_new_signal(void) {
 
         assert_se(sd_bus_message_new_signal(bus, &m, "/an/object/path", "an.interface.name", "Name") >= 0);
 
-        printf("after message_new_signal: refcount %u\n", REFCNT_GET(bus->n_ref));
-
+        assert_se(m->n_ref == 1); /* We hold the only reference to the message */
+        assert_se(bus->n_ref >= 2);
         sd_bus_flush_close_unref(bus);
-        printf("after bus_flush_close_unref: refcount %u\n", m->n_ref);
+        assert_se(m->n_ref == 1);
 }
 
 int main(int argc, char **argv) {
index 940dbfe..9c8e93e 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "bus-introspect.h"
 #include "log.h"
+#include "tests.h"
 
 static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
         return -EINVAL;
@@ -29,7 +30,7 @@ static const sd_bus_vtable vtable[] = {
 int main(int argc, char *argv[]) {
         struct introspect intro;
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         assert_se(introspect_begin(&intro, false) >= 0);
 
index 0949d8d..47014c4 100644 (file)
@@ -6,6 +6,7 @@
 #include "bus-util.h"
 #include "log.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "tests.h"
 
 static bool mask[32];
diff --git a/src/libsystemd/sd-bus/test-bus-queue-ref-cycle.c b/src/libsystemd/sd-bus/test-bus-queue-ref-cycle.c
new file mode 100644 (file)
index 0000000..f6506fb
--- /dev/null
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#include "sd-bus.h"
+
+#include "main-func.h"
+#include "tests.h"
+
+static int test_ref_unref(void) {
+        sd_bus_message *m = NULL;
+        sd_bus *bus = NULL;
+        int r;
+
+        /* This test will result in a memory leak in <= v240, but not on v241. Hence to be really useful it
+         * should be run through a leak tracker such as valgrind. */
+
+        r = sd_bus_open_system(&bus);
+        if (r < 0)
+                return log_tests_skipped("Failed to connect to bus");
+
+        /* Create a message and enqueue it (this shouldn't send it though as the connection setup is not complete yet) */
+        assert_se(sd_bus_message_new_method_call(bus, &m, "foo.bar", "/foo", "quux.quux", "waldo") >= 0);
+        assert_se(sd_bus_send(bus, m, NULL) >= 0);
+
+        /* Let's now unref the message first and the bus second. */
+        m = sd_bus_message_unref(m);
+        bus = sd_bus_unref(bus);
+
+        /* We should have a memory leak now on <= v240. Let's do this again, but destory in the opposite
+         * order. On v240 that too should be a leak. */
+
+        r = sd_bus_open_system(&bus);
+        if (r < 0)
+                return log_tests_skipped("Failed to connect to bus");
+
+        assert_se(sd_bus_message_new_method_call(bus, &m, "foo.bar", "/foo", "quux.quux", "waldo") >= 0);
+        assert_se(sd_bus_send(bus, m, NULL) >= 0);
+
+        /* Let's now unref things in the opposite order */
+        bus = sd_bus_unref(bus);
+        m = sd_bus_message_unref(m);
+
+        return 0;
+}
+
+static int run(int argc, char *argv[]) {
+        int r;
+
+        test_setup_logging(LOG_INFO);
+
+        r = test_ref_unref();
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
+DEFINE_MAIN_FUNCTION(run);
index 0f1b964..e38bcdc 100644 (file)
@@ -9,7 +9,7 @@
 #include "bus-util.h"
 #include "log.h"
 #include "macro.h"
-#include "util.h"
+#include "memory-util.h"
 
 struct context {
         int fds[2];
index fd9ad81..b278094 100644 (file)
@@ -39,6 +39,10 @@ static const sd_bus_vtable vtable[] = {
         SD_BUS_METHOD("Exit", "", "", handler, 0),
         SD_BUS_METHOD_WITH_OFFSET("AlterSomething2", "s", "s", handler, 200, 0),
         SD_BUS_METHOD_WITH_OFFSET("Exit2", "", "", handler, 200, 0),
+        SD_BUS_METHOD_WITH_NAMES_OFFSET("AlterSomething3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
+                        "s", SD_BUS_PARAM(returnstring), handler, 200, 0),
+        SD_BUS_METHOD_WITH_NAMES("Exit3", "bx", SD_BUS_PARAM(with_confirmation) SD_BUS_PARAM(after_msec),
+                        "bb", SD_BUS_PARAM(accepted) SD_BUS_PARAM(scheduled), handler, 0),
         SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
         SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -53,9 +57,68 @@ static const sd_bus_vtable vtable[] = {
         SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
         SD_BUS_SIGNAL("DummySignal", "b", 0),
         SD_BUS_SIGNAL("DummySignal2", "so", 0),
+        SD_BUS_SIGNAL_WITH_NAMES("DummySignal3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path), 0),
         SD_BUS_VTABLE_END
 };
 
+struct sd_bus_vtable_original {
+        uint8_t type:8;
+        uint64_t flags:56;
+        union {
+                struct {
+                        size_t element_size;
+                } start;
+                struct {
+                        const char *member;
+                        const char *signature;
+                        const char *result;
+                        sd_bus_message_handler_t handler;
+                        size_t offset;
+                } method;
+                struct {
+                        const char *member;
+                        const char *signature;
+                } signal;
+                struct {
+                        const char *member;
+                        const char *signature;
+                        sd_bus_property_get_t get;
+                        sd_bus_property_set_t set;
+                        size_t offset;
+                } property;
+        } x;
+};
+
+static const struct sd_bus_vtable_original vtable_format_original[] = {
+        {
+                .type = _SD_BUS_VTABLE_START,
+                .flags = 0,
+                .x = {
+                        .start = {
+                                .element_size = sizeof(struct sd_bus_vtable_original)
+                        },
+                },
+        },
+        {
+                .type = _SD_BUS_VTABLE_METHOD,
+                .flags = 0,
+                .x = {
+                        .method = {
+                                .member = "Exit",
+                                .signature = "",
+                                .result = "",
+                                .handler = handler,
+                                .offset = 0,
+                        },
+                },
+        },
+        {
+                .type = _SD_BUS_VTABLE_END,
+                .flags = 0,
+                .x = { { 0 } },
+        }
+};
+
 static void test_vtable(void) {
         sd_bus *bus = NULL;
         struct context c = {};
@@ -65,6 +128,8 @@ static void test_vtable(void) {
 
         assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable", vtable, &c) >= 0);
         assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable2", vtable, &c) >= 0);
+        /* the cast on the line below is needed to test with the old version of the table */
+        assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtableOriginal", (const sd_bus_vtable *)vtable_format_original, &c) >= 0);
 
         assert(sd_bus_set_address(bus, DEFAULT_BUS_PATH) >= 0);
         r = sd_bus_start(bus);
index 4b3da30..2723866 100644 (file)
@@ -16,6 +16,7 @@
 #include "socket-util.h"
 #include "string-util.h"
 #include "tmpfile-util.h"
+#include "tests.h"
 
 static int method_foobar(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
         log_info("Got Foobar() call.");
@@ -198,7 +199,7 @@ int main(int argc, char *argv[]) {
         pthread_t server, client1, client2;
         char *path;
 
-        log_set_max_level(LOG_DEBUG);
+        test_setup_logging(LOG_DEBUG);
 
         /* We use /dev/shm here rather than /tmp, since some weird distros might set up /tmp as some weird fs that
          * doesn't support inotify properly. */
index 87411bf..cf2b261 100644 (file)
@@ -7,6 +7,7 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumeartor);
 int device_enumerator_scan_subsystems(sd_device_enumerator *enumeartor);
 int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *device);
 int device_enumerator_add_match_is_initialized(sd_device_enumerator *enumerator);
+int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent);
 sd_device *device_enumerator_get_first(sd_device_enumerator *enumerator);
 sd_device *device_enumerator_get_next(sd_device_enumerator *enumerator);
 sd_device **device_enumerator_get_devices(sd_device_enumerator *enumerator, size_t *ret_n_devices);
index 20529aa..4357860 100644 (file)
@@ -1,5 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
+#include <unistd.h>
+
 #include "sd-device.h"
 
 #include "alloc-util.h"
@@ -8,9 +11,9 @@
 #include "dirent-util.h"
 #include "fd-util.h"
 #include "set.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 #define DEVICE_ENUMERATE_MAX_DEPTH 256
 
@@ -36,7 +39,7 @@ struct sd_device_enumerator {
         Hashmap *match_property;
         Set *match_sysname;
         Set *match_tag;
-        sd_device *match_parent;
+        Set *match_parent;
         bool match_allow_uninitialized;
 };
 
@@ -75,7 +78,7 @@ static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumer
         hashmap_free_free_free(enumerator->match_property);
         set_free_free(enumerator->match_sysname);
         set_free_free(enumerator->match_tag);
-        sd_device_unref(enumerator->match_parent);
+        set_free_free(enumerator->match_parent);
 
         return mfree(enumerator);
 }
@@ -217,18 +220,42 @@ _public_ int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator
         return 0;
 }
 
-_public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
+static void device_enumerator_clear_match_parent(sd_device_enumerator *enumerator) {
+        if (!enumerator)
+                return;
+
+        set_clear_free(enumerator->match_parent);
+}
+
+int device_enumerator_add_match_parent_incremental(sd_device_enumerator *enumerator, sd_device *parent) {
+        const char *path;
+        int r;
+
         assert_return(enumerator, -EINVAL);
         assert_return(parent, -EINVAL);
 
-        sd_device_unref(enumerator->match_parent);
-        enumerator->match_parent = sd_device_ref(parent);
+        r = sd_device_get_syspath(parent, &path);
+        if (r < 0)
+                return r;
+
+        r = set_ensure_allocated(&enumerator->match_parent, NULL);
+        if (r < 0)
+                return r;
+
+        r = set_put_strdup(enumerator->match_parent, path);
+        if (r < 0)
+                return r;
 
         enumerator->scan_uptodate = false;
 
         return 0;
 }
 
+_public_ int sd_device_enumerator_add_match_parent(sd_device_enumerator *enumerator, sd_device *parent) {
+        device_enumerator_clear_match_parent(enumerator);
+        return device_enumerator_add_match_parent_incremental(enumerator, parent);
+}
+
 _public_ int sd_device_enumerator_allow_uninitialized(sd_device_enumerator *enumerator) {
         assert_return(enumerator, -EINVAL);
 
@@ -399,22 +426,22 @@ static bool match_tag(sd_device_enumerator *enumerator, sd_device *device) {
 }
 
 static bool match_parent(sd_device_enumerator *enumerator, sd_device *device) {
-        const char *devpath, *devpath_dev;
-        int r;
+        const char *syspath_parent, *syspath;
+        Iterator i;
 
         assert(enumerator);
         assert(device);
 
-        if (!enumerator->match_parent)
+        if (set_isempty(enumerator->match_parent))
                 return true;
 
-        r = sd_device_get_devpath(enumerator->match_parent, &devpath);
-        assert(r >= 0);
+        assert_se(sd_device_get_syspath(device, &syspath) >= 0);
 
-        r = sd_device_get_devpath(device, &devpath_dev);
-        assert(r >= 0);
+        SET_FOREACH(syspath_parent, enumerator->match_parent, i)
+                if (path_startswith(syspath, syspath_parent))
+                        return true;
 
-        return startswith(devpath_dev, devpath);
+        return false;
 }
 
 static bool match_sysname(sd_device_enumerator *enumerator, const char *sysname) {
@@ -745,18 +772,17 @@ static int parent_crawl_children(sd_device_enumerator *enumerator, const char *p
 static int enumerator_scan_devices_children(sd_device_enumerator *enumerator) {
         const char *path;
         int r = 0, k;
+        Iterator i;
 
-        r = sd_device_get_syspath(enumerator->match_parent, &path);
-        if (r < 0)
-                return r;
-
-        k = parent_add_child(enumerator, path);
-        if (k < 0)
-                r = k;
+        SET_FOREACH(path, enumerator->match_parent, i) {
+                k = parent_add_child(enumerator, path);
+                if (k < 0)
+                        r = k;
 
-        k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
-        if (k < 0)
-                r = k;
+                k = parent_crawl_children(enumerator, path, DEVICE_ENUMERATE_MAX_DEPTH);
+                if (k < 0)
+                        r = k;
+        }
 
         return r;
 }
index 3ffca35..023fe0f 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "sd-device.h"
 
+#include "device-private.h"
 #include "hashmap.h"
 #include "set.h"
 #include "time-util.h"
@@ -64,6 +65,10 @@ struct sd_device {
         uid_t devuid;
         gid_t devgid;
 
+        /* only set when device is passed through netlink */
+        DeviceAction action;
+        uint64_t seqnum;
+
         bool parent_set:1; /* no need to try to reload parent */
         bool sysattrs_read:1; /* don't try to re-read sysattrs once read */
         bool property_tags_outdated:1; /* need to update TAGS= property */
@@ -81,19 +86,6 @@ struct sd_device {
         bool db_persist:1; /* don't clean up the db when switching from initrd to real root */
 };
 
-typedef enum DeviceAction {
-        DEVICE_ACTION_ADD,
-        DEVICE_ACTION_REMOVE,
-        DEVICE_ACTION_CHANGE,
-        DEVICE_ACTION_MOVE,
-        DEVICE_ACTION_ONLINE,
-        DEVICE_ACTION_OFFLINE,
-        DEVICE_ACTION_BIND,
-        DEVICE_ACTION_UNBIND,
-        _DEVICE_ACTION_MAX,
-        _DEVICE_ACTION_INVALID = -1,
-} DeviceAction;
-
 int device_new_aux(sd_device **ret);
 int device_add_property_aux(sd_device *device, const char *key, const char *value, bool db);
 int device_add_property_internal(sd_device *device, const char *key, const char *value);
@@ -108,6 +100,3 @@ int device_set_devnum(sd_device *device, const char *major, const char *minor);
 int device_set_subsystem(sd_device *device, const char *_subsystem);
 int device_set_driver(sd_device *device, const char *_driver);
 int device_set_usec_initialized(sd_device *device, usec_t when);
-
-DeviceAction device_action_from_string(const char *s) _pure_;
-const char *device_action_to_string(DeviceAction a) _const_;
index 76267a1..a085500 100644 (file)
@@ -16,9 +16,9 @@
 #include "hashmap.h"
 #include "macro.h"
 #include "mkdir.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
-#include "refcnt.h"
 #include "set.h"
 #include "string-table.h"
 #include "string-util.h"
@@ -26,7 +26,6 @@
 #include "strxcpyx.h"
 #include "tmpfile-util.h"
 #include "user-util.h"
-#include "util.h"
 
 int device_add_property(sd_device *device, const char *key, const char *value) {
         int r;
@@ -184,6 +183,72 @@ static int device_set_devgid(sd_device *device, const char *gid) {
         return 0;
 }
 
+int device_get_action(sd_device *device, DeviceAction *action) {
+        assert(device);
+
+        if (device->action < 0)
+                return -ENOENT;
+
+        if (action)
+                *action = device->action;
+
+        return 0;
+}
+
+static int device_set_action(sd_device *device, const char *action) {
+        DeviceAction a;
+        int r;
+
+        assert(device);
+        assert(action);
+
+        a = device_action_from_string(action);
+        if (a < 0)
+                return -EINVAL;
+
+        r = device_add_property_internal(device, "ACTION", action);
+        if (r < 0)
+                return r;
+
+        device->action = a;
+
+        return 0;
+}
+
+int device_get_seqnum(sd_device *device, uint64_t *seqnum) {
+        assert(device);
+
+        if (device->seqnum == 0)
+                return -ENOENT;
+
+        if (seqnum)
+                *seqnum = device->seqnum;
+
+        return 0;
+}
+
+static int device_set_seqnum(sd_device *device, const char *str) {
+        uint64_t seqnum;
+        int r;
+
+        assert(device);
+        assert(str);
+
+        r = safe_atou64(str, &seqnum);
+        if (r < 0)
+                return r;
+        if (seqnum == 0)
+                return -EINVAL;
+
+        r = device_add_property_internal(device, "SEQNUM", str);
+        if (r < 0)
+                return r;
+
+        device->seqnum = seqnum;
+
+        return 0;
+}
+
 static int device_amend(sd_device *device, const char *key, const char *value) {
         int r;
 
@@ -242,6 +307,14 @@ static int device_amend(sd_device *device, const char *key, const char *value) {
                 r = device_set_devgid(device, value);
                 if (r < 0)
                         return log_device_debug_errno(device, r, "sd-device: Failed to set devgid to '%s': %m", value);
+        } else if (streq(key, "ACTION")) {
+                r = device_set_action(device, value);
+                if (r < 0)
+                        return log_device_debug_errno(device, r, "sd-device: Failed to set action to '%s': %m", value);
+        } else if (streq(key, "SEQNUM")) {
+                r = device_set_seqnum(device, value);
+                if (r < 0)
+                        return log_device_debug_errno(device, r, "sd-device: Failed to set SEQNUM to '%s': %m", value);
         } else if (streq(key, "DEVLINKS")) {
                 const char *word, *state;
                 size_t l;
@@ -279,23 +352,7 @@ static int device_amend(sd_device *device, const char *key, const char *value) {
         return 0;
 }
 
-static const char* const device_action_table[_DEVICE_ACTION_MAX] = {
-        [DEVICE_ACTION_ADD] = "add",
-        [DEVICE_ACTION_REMOVE] = "remove",
-        [DEVICE_ACTION_CHANGE] = "change",
-        [DEVICE_ACTION_MOVE] = "move",
-        [DEVICE_ACTION_ONLINE] = "online",
-        [DEVICE_ACTION_OFFLINE] = "offline",
-        [DEVICE_ACTION_BIND] = "bind",
-        [DEVICE_ACTION_UNBIND] = "unbind",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
-
-static int device_append(sd_device *device, char *key, const char **_major, const char **_minor, uint64_t *_seqnum,
-                         DeviceAction *_action) {
-        DeviceAction action = _DEVICE_ACTION_INVALID;
-        uint64_t seqnum = 0;
+static int device_append(sd_device *device, char *key, const char **_major, const char **_minor) {
         const char *major = NULL, *minor = NULL;
         char *value;
         int r;
@@ -304,8 +361,6 @@ static int device_append(sd_device *device, char *key, const char **_major, cons
         assert(key);
         assert(_major);
         assert(_minor);
-        assert(_seqnum);
-        assert(_action);
 
         value = strchr(key, '=');
         if (!value) {
@@ -322,19 +377,6 @@ static int device_append(sd_device *device, char *key, const char **_major, cons
         else if (streq(key, "MINOR"))
                 minor = value;
         else {
-                if (streq(key, "ACTION")) {
-                        action = device_action_from_string(value);
-                        if (action == _DEVICE_ACTION_INVALID)
-                                return -EINVAL;
-                } else if (streq(key, "SEQNUM")) {
-                        r = safe_atou64(value, &seqnum);
-                        if (r < 0)
-                                return r;
-                        else if (seqnum == 0)
-                                 /* kernel only sends seqnum > 0 */
-                                return -EINVAL;
-                }
-
                 r = device_amend(device, key, value);
                 if (r < 0)
                         return r;
@@ -346,12 +388,6 @@ static int device_append(sd_device *device, char *key, const char **_major, cons
         if (minor != 0)
                 *_minor = minor;
 
-        if (action != _DEVICE_ACTION_INVALID)
-                *_action = action;
-
-        if (seqnum > 0)
-                *_seqnum = seqnum;
-
         return 0;
 }
 
@@ -361,10 +397,10 @@ void device_seal(sd_device *device) {
         device->sealed = true;
 }
 
-static int device_verify(sd_device *device, DeviceAction action, uint64_t seqnum) {
+static int device_verify(sd_device *device) {
         assert(device);
 
-        if (!device->devpath || !device->subsystem || action == _DEVICE_ACTION_INVALID || seqnum == 0) {
+        if (!device->devpath || !device->subsystem || device->action < 0 || device->seqnum == 0) {
                 log_device_debug(device, "sd-device: Device created from strv or nulstr lacks devpath, subsystem, action or seqnum.");
                 return -EINVAL;
         }
@@ -378,8 +414,6 @@ int device_new_from_strv(sd_device **ret, char **strv) {
         _cleanup_(sd_device_unrefp) sd_device *device = NULL;
         char **key;
         const char *major = NULL, *minor = NULL;
-        DeviceAction action = _DEVICE_ACTION_INVALID;
-        uint64_t seqnum = 0;
         int r;
 
         assert(ret);
@@ -390,7 +424,7 @@ int device_new_from_strv(sd_device **ret, char **strv) {
                 return r;
 
         STRV_FOREACH(key, strv) {
-                r = device_append(device, *key, &major, &minor, &seqnum, &action);
+                r = device_append(device, *key, &major, &minor);
                 if (r < 0)
                         return r;
         }
@@ -401,7 +435,7 @@ int device_new_from_strv(sd_device **ret, char **strv) {
                         return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
         }
 
-        r = device_verify(device, action, seqnum);
+        r = device_verify(device);
         if (r < 0)
                 return r;
 
@@ -413,8 +447,6 @@ 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_(sd_device_unrefp) sd_device *device = NULL;
         const char *major = NULL, *minor = NULL;
-        DeviceAction action = _DEVICE_ACTION_INVALID;
-        uint64_t seqnum = 0;
         unsigned i = 0;
         int r;
 
@@ -438,7 +470,7 @@ int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
                 }
                 i += end - key + 1;
 
-                r = device_append(device, key, &major, &minor, &seqnum, &action);
+                r = device_append(device, key, &major, &minor);
                 if (r < 0)
                         return r;
         }
@@ -449,7 +481,7 @@ int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) {
                         return log_device_debug_errno(device, r, "sd-device: Failed to set devnum %s:%s: %m", major, minor);
         }
 
-        r = device_verify(device, action, seqnum);
+        r = device_verify(device);
         if (r < 0)
                 return r;
 
@@ -675,7 +707,7 @@ int device_new_from_synthetic_event(sd_device **new_device, const char *syspath,
         if (r < 0)
                 return r;
 
-        r = device_add_property_internal(ret, "ACTION", action);
+        r = device_set_action(ret, action);
         if (r < 0)
                 return r;
 
@@ -954,3 +986,16 @@ int device_delete_db(sd_device *device) {
 
         return 0;
 }
+
+static const char* const device_action_table[_DEVICE_ACTION_MAX] = {
+        [DEVICE_ACTION_ADD]     = "add",
+        [DEVICE_ACTION_REMOVE]  = "remove",
+        [DEVICE_ACTION_CHANGE]  = "change",
+        [DEVICE_ACTION_MOVE]    = "move",
+        [DEVICE_ACTION_ONLINE]  = "online",
+        [DEVICE_ACTION_OFFLINE] = "offline",
+        [DEVICE_ACTION_BIND]    = "bind",
+        [DEVICE_ACTION_UNBIND]  = "unbind",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction);
index 062bfd6..9696f9c 100644 (file)
@@ -8,6 +8,21 @@
 
 #include "sd-device.h"
 
+#include "macro.h"
+
+typedef enum DeviceAction {
+        DEVICE_ACTION_ADD,
+        DEVICE_ACTION_REMOVE,
+        DEVICE_ACTION_CHANGE,
+        DEVICE_ACTION_MOVE,
+        DEVICE_ACTION_ONLINE,
+        DEVICE_ACTION_OFFLINE,
+        DEVICE_ACTION_BIND,
+        DEVICE_ACTION_UNBIND,
+        _DEVICE_ACTION_MAX,
+        _DEVICE_ACTION_INVALID = -1,
+} DeviceAction;
+
 int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len);
 int device_new_from_strv(sd_device **ret, char **strv);
 int device_new_from_stat_rdev(sd_device **ret, const struct stat *st);
@@ -19,6 +34,8 @@ int device_get_watch_handle(sd_device *device, int *handle);
 int device_get_devnode_mode(sd_device *device, mode_t *mode);
 int device_get_devnode_uid(sd_device *device, uid_t *uid);
 int device_get_devnode_gid(sd_device *device, gid_t *gid);
+int device_get_action(sd_device *device, DeviceAction *action);
+int device_get_seqnum(sd_device *device, uint64_t *seqnum);
 
 void device_seal(sd_device *device);
 void device_set_is_initialized(sd_device *device);
@@ -50,7 +67,11 @@ int device_new_from_synthetic_event(sd_device **new_device, const char *syspath,
 int device_tag_index(sd_device *dev, sd_device *dev_old, bool add);
 int device_update_db(sd_device *device);
 int device_delete_db(sd_device *device);
+int device_read_db_internal_filename(sd_device *device, const char *filename); /* For fuzzer */
 int device_read_db_internal(sd_device *device, bool force);
 static inline int device_read_db(sd_device *device) {
         return device_read_db_internal(device, false);
 }
+
+DeviceAction device_action_from_string(const char *s) _pure_;
+const char *device_action_to_string(DeviceAction a) _const_;
index 2a69f2e..c2315c0 100644 (file)
@@ -43,6 +43,7 @@ int device_new_aux(sd_device **ret) {
                 .devmode = (mode_t) -1,
                 .devuid = (uid_t) -1,
                 .devgid = (gid_t) -1,
+                .action = _DEVICE_ACTION_INVALID,
         };
 
         *ret = device;
@@ -236,7 +237,7 @@ _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum)
         assert_return(IN_SET(type, 'b', 'c'), -EINVAL);
 
         /* use /sys/dev/{block,char}/<maj>:<min> link */
-        snprintf(id, sizeof(id), "%u:%u", major(devnum), minor(devnum));
+        xsprintf(id, "%u:%u", major(devnum), minor(devnum));
 
         syspath = strjoina("/sys/dev/", (type == 'b' ? "block" : "char"), "/", id);
 
@@ -1110,6 +1111,7 @@ int device_add_devlink(sd_device *device, const char *devlink) {
 static int device_add_property_internal_from_string(sd_device *device, const char *str) {
         _cleanup_free_ char *key = NULL;
         char *value;
+        int r;
 
         assert(device);
         assert(str);
@@ -1127,7 +1129,13 @@ static int device_add_property_internal_from_string(sd_device *device, const cha
         if (isempty(++value))
                 value = NULL;
 
-        return device_add_property_internal(device, key, value);
+        /* Add the property to both sd_device::properties and sd_device::properties_db,
+         * as this is called by only handle_db_line(). */
+        r = device_add_property_aux(device, key, value, false);
+        if (r < 0)
+                return r;
+
+        return device_add_property_aux(device, key, value, true);
 }
 
 int device_set_usec_initialized(sd_device *device, usec_t when) {
@@ -1266,13 +1274,11 @@ int device_get_id_filename(sd_device *device, const char **ret) {
         return 0;
 }
 
-int device_read_db_internal(sd_device *device, bool force) {
+int device_read_db_internal_filename(sd_device *device, const char *filename) {
         _cleanup_free_ char *db = NULL;
-        char *path;
-        const char *id, *value;
+        const char *value;
+        size_t db_len, i;
         char key;
-        size_t db_len;
-        unsigned i;
         int r;
 
         enum {
@@ -1284,22 +1290,14 @@ int device_read_db_internal(sd_device *device, bool force) {
         } state = PRE_KEY;
 
         assert(device);
+        assert(filename);
 
-        if (device->db_loaded || (!force && device->sealed))
-                return 0;
-
-        r = device_get_id_filename(device, &id);
-        if (r < 0)
-                return r;
-
-        path = strjoina("/run/udev/data/", id);
-
-        r = read_full_file(path, &db, &db_len);
+        r = read_full_file(filename, &db, &db_len);
         if (r < 0) {
                 if (r == -ENOENT)
                         return 0;
-                else
-                        return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", path);
+
+                return log_device_debug_errno(device, r, "sd-device: Failed to read db '%s': %m", filename);
         }
 
         /* devices with a database entry are initialized */
@@ -1352,13 +1350,31 @@ int device_read_db_internal(sd_device *device, bool force) {
 
                         break;
                 default:
-                        assert_not_reached("Invalid state when parsing db");
+                        return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL), "sd-device: invalid db syntax.");
                 }
         }
 
         return 0;
 }
 
+int device_read_db_internal(sd_device *device, bool force) {
+        const char *id, *path;
+        int r;
+
+        assert(device);
+
+        if (device->db_loaded || (!force && device->sealed))
+                return 0;
+
+        r = device_get_id_filename(device, &id);
+        if (r < 0)
+                return r;
+
+        path = strjoina("/run/udev/data/", id);
+
+        return device_read_db_internal_filename(device, path);
+}
+
 _public_ int sd_device_get_is_initialized(sd_device *device) {
         int r;
 
index e459b13..33a25d5 100644 (file)
@@ -6,7 +6,7 @@
 #include "hashmap.h"
 #include "string-util.h"
 #include "tests.h"
-#include "util.h"
+#include "time-util.h"
 
 static void test_sd_device_one(sd_device *d) {
         const char *syspath, *subsystem, *val;
index 04ba7e2..1987f27 100644 (file)
@@ -15,6 +15,7 @@
 #include "hashmap.h"
 #include "list.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "prioq.h"
 #include "process-util.h"
@@ -23,7 +24,6 @@
 #include "string-table.h"
 #include "string-util.h"
 #include "time-util.h"
-#include "util.h"
 
 #define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
 
@@ -3116,7 +3116,7 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) {
                 timeout = 0;
 
         m = epoll_wait(e->epoll_fd, ev_queue, ev_queue_max,
-                       timeout == (uint64_t) -1 ? -1 : (int) ((timeout + USEC_PER_MSEC - 1) / USEC_PER_MSEC));
+                       timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC));
         if (m < 0) {
                 if (errno == EINTR) {
                         e->state = SD_EVENT_PENDING;
index f852967..c83575c 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <ctype.h>
 #include <stdio.h>
+#include <sys/stat.h>
 
 #include "alloc-util.h"
 #include "conf-files.h"
@@ -13,6 +14,7 @@
 #include "label.h"
 #include "mkdir.h"
 #include "path-util.h"
+#include "sort-util.h"
 #include "strbuf.h"
 #include "string-util.h"
 #include "strv.h"
@@ -432,7 +434,7 @@ static int trie_store(struct trie *trie, const char *filename, bool compat) {
  error_fclose:
         r = -errno;
         fclose(t.f);
-        unlink(filename_tmp);
+        (void) unlink(filename_tmp);
         return r;
 }
 
index 233944c..79fe1a8 100644 (file)
@@ -10,6 +10,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/mman.h>
+#include <sys/stat.h>
 
 #include "sd-hwdb.h"
 
 #include "hashmap.h"
 #include "hwdb-internal.h"
 #include "hwdb-util.h"
-#include "refcnt.h"
+#include "nulstr-util.h"
 #include "string-util.h"
-#include "util.h"
+#include "time-util.h"
 
 struct sd_hwdb {
-        RefCount n_ref;
+        unsigned n_ref;
 
         FILE *f;
         struct stat st;
@@ -316,27 +317,27 @@ _public_ int sd_hwdb_new(sd_hwdb **ret) {
         if (!hwdb)
                 return -ENOMEM;
 
-        hwdb->n_ref = REFCNT_INIT;
+        hwdb->n_ref = 1;
 
         /* find hwdb.bin in hwdb_bin_paths */
         NULSTR_FOREACH(hwdb_bin_path, hwdb_bin_paths) {
+                log_debug("Trying to open \"%s\"...", hwdb_bin_path);
                 hwdb->f = fopen(hwdb_bin_path, "re");
                 if (hwdb->f)
                         break;
-                else if (errno == ENOENT)
-                        continue;
-                else
+                if (errno != ENOENT)
                         return log_debug_errno(errno, "Failed to open %s: %m", hwdb_bin_path);
         }
 
-        if (!hwdb->f) {
-                log_debug("hwdb.bin does not exist, please run 'systemd-hwdb update'");
-                return -ENOENT;
-        }
+        if (!hwdb->f)
+                return log_debug_errno(SYNTHETIC_ERRNO(ENOENT),
+                                       "hwdb.bin does not exist, please run 'systemd-hwdb update'");
 
-        if (fstat(fileno(hwdb->f), &hwdb->st) < 0 ||
-            (size_t) hwdb->st.st_size < offsetof(struct trie_header_f, strings_len) + 8)
-                return log_debug_errno(errno, "Failed to read %s: %m", hwdb_bin_path);
+        if (fstat(fileno(hwdb->f), &hwdb->st) < 0)
+                return log_debug_errno(errno, "Failed to stat %s: %m", hwdb_bin_path);
+        if (hwdb->st.st_size < (off_t) offsetof(struct trie_header_f, strings_len) + 8)
+                return log_debug_errno(SYNTHETIC_ERRNO(EIO),
+                                       "File %s is too short: %m", hwdb_bin_path);
 
         hwdb->map = mmap(0, hwdb->st.st_size, PROT_READ, MAP_SHARED, fileno(hwdb->f), 0);
         if (hwdb->map == MAP_FAILED)
@@ -370,7 +371,7 @@ static sd_hwdb *hwdb_free(sd_hwdb *hwdb) {
         return mfree(hwdb);
 }
 
-DEFINE_PUBLIC_ATOMIC_REF_UNREF_FUNC(sd_hwdb, sd_hwdb, hwdb_free)
+DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_hwdb, sd_hwdb, hwdb_free)
 
 bool hwdb_validate(sd_hwdb *hwdb) {
         bool found = false;
@@ -383,12 +384,11 @@ bool hwdb_validate(sd_hwdb *hwdb) {
                 return false;
 
         /* if hwdb.bin doesn't exist anywhere, we need to update */
-        NULSTR_FOREACH(p, hwdb_bin_paths) {
+        NULSTR_FOREACH(p, hwdb_bin_paths)
                 if (stat(p, &st) >= 0) {
                         found = true;
                         break;
                 }
-        }
         if (!found)
                 return true;
 
index e72af15..e5f82b8 100644 (file)
@@ -117,7 +117,6 @@ _public_ int sd_id128_get_boot(sd_id128_t *ret) {
 }
 
 static int get_invocation_from_keyring(sd_id128_t *ret) {
-
         _cleanup_free_ char *description = NULL;
         char *d, *p, *g, *u, *e;
         unsigned long perms;
@@ -136,7 +135,7 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
         if (key == -1) {
                 /* Keyring support not available? No invocation key stored? */
                 if (IN_SET(errno, ENOSYS, ENOKEY))
-                        return 0;
+                        return -ENXIO;
 
                 return -errno;
         }
@@ -212,7 +211,19 @@ static int get_invocation_from_keyring(sd_id128_t *ret) {
         if (c != sizeof(sd_id128_t))
                 return -EIO;
 
-        return 1;
+        return 0;
+}
+
+static int get_invocation_from_environment(sd_id128_t *ret) {
+        const char *e;
+
+        assert(ret);
+
+        e = secure_getenv("INVOCATION_ID");
+        if (!e)
+                return -ENXIO;
+
+        return sd_id128_from_string(e, ret);
 }
 
 _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
@@ -222,31 +233,17 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) {
         assert_return(ret, -EINVAL);
 
         if (sd_id128_is_null(saved_invocation_id)) {
+                /* We first check the environment. The environment variable is primarily relevant for user
+                 * services, and sufficiently safe as long as no privilege boundary is involved. */
+                r = get_invocation_from_environment(&saved_invocation_id);
+                if (r < 0 && r != -ENXIO)
+                        return r;
 
-                /* We first try to read the invocation ID from the kernel keyring. This has the benefit that it is not
-                 * fakeable by unprivileged code. If the information is not available in the keyring, we use
-                 * $INVOCATION_ID but ignore the data if our process was called by less privileged code
-                 * (i.e. secure_getenv() instead of getenv()).
-                 *
-                 * The kernel keyring is only relevant for system services (as for user services we don't store the
-                 * invocation ID in the keyring, as there'd be no trust benefit in that). The environment variable is
-                 * primarily relevant for user services, and sufficiently safe as no privilege boundary is involved. */
-
+                /* The kernel keyring is relevant for system services (as for user services we don't store
+                 * the invocation ID in the keyring, as there'd be no trust benefit in that). */
                 r = get_invocation_from_keyring(&saved_invocation_id);
                 if (r < 0)
                         return r;
-
-                if (r == 0) {
-                        const char *e;
-
-                        e = secure_getenv("INVOCATION_ID");
-                        if (!e)
-                                return -ENXIO;
-
-                        r = sd_id128_from_string(e, &saved_invocation_id);
-                        if (r < 0)
-                                return r;
-                }
         }
 
         *ret = saved_invocation_id;
index 07f21e8..0dc368e 100644 (file)
@@ -818,7 +818,7 @@ _public_ int sd_get_uids(uid_t **users) {
                                 uid_t *t;
 
                                 n = MAX(16, 2*r);
-                                t = realloc(l, sizeof(uid_t) * n);
+                                t = reallocarray(l, sizeof(uid_t), n);
                                 if (!t)
                                         return -ENOMEM;
 
index 1789e54..e9df5f8 100644 (file)
@@ -11,6 +11,7 @@
 #include "log.h"
 #include "string-util.h"
 #include "strv.h"
+#include "time-util.h"
 #include "util.h"
 
 static char* format_uids(char **buf, uid_t* uids, int count) {
index 3445757..384072e 100644 (file)
@@ -10,9 +10,10 @@ typedef struct {
 } genl_family;
 
 static const genl_family genl_families[] = {
-        [SD_GENL_ID_CTRL] = { .name = "", .version = 1 },
+        [SD_GENL_ID_CTRL]   = { .name = "", .version = 1 },
         [SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 },
         [SD_GENL_FOU]       = { .name = "fou", .version = 1 },
+        [SD_GENL_L2TP]      = { .name = "l2tp", .version = 1},
 };
 
 int sd_genl_socket_open(sd_netlink **ret) {
index 5c37279..7511445 100644 (file)
@@ -6,6 +6,7 @@
 #include "local-addresses.h"
 #include "macro.h"
 #include "netlink-util.h"
+#include "sort-util.h"
 
 static int address_compare(const struct local_address *a, const struct local_address *b) {
         int r;
index 98de4f0..4a366d4 100644 (file)
@@ -8,7 +8,7 @@
 #include "list.h"
 #include "netlink-types.h"
 #include "prioq.h"
-#include "refcnt.h"
+#include "time-util.h"
 
 #define RTNL_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
 
@@ -56,7 +56,7 @@ struct sd_netlink_slot {
 };
 
 struct sd_netlink {
-        RefCount n_ref;
+        unsigned n_ref;
 
         int fd;
 
@@ -114,7 +114,7 @@ struct netlink_container {
 };
 
 struct sd_netlink_message {
-        RefCount n_ref;
+        unsigned n_ref;
 
         sd_netlink *rtnl;
 
index 5e9bc45..0dcc53b 100644 (file)
@@ -12,9 +12,8 @@
 #include "netlink-internal.h"
 #include "netlink-types.h"
 #include "netlink-util.h"
-#include "refcnt.h"
 #include "socket-util.h"
-#include "util.h"
+#include "memory-util.h"
 
 #define GET_CONTAINER(m, i) ((i) < (m)->n_containers ? (struct rtattr*)((uint8_t*)(m)->hdr + (m)->containers[i].offset) : NULL)
 #define PUSH_CONTAINER(m, new) (m)->container_offsets[(m)->n_containers++] = (uint8_t*)(new) - (uint8_t*)(m)->hdr;
@@ -36,7 +35,7 @@ int message_new_empty(sd_netlink *rtnl, sd_netlink_message **ret) {
         if (!m)
                 return -ENOMEM;
 
-        m->n_ref = REFCNT_INIT;
+        m->n_ref = 1;
         m->protocol = rtnl->protocol;
         m->sealed = false;
 
@@ -96,12 +95,10 @@ int sd_netlink_message_request_dump(sd_netlink_message *m, int dump) {
         return 0;
 }
 
-DEFINE_ATOMIC_REF_FUNC(sd_netlink_message, sd_netlink_message);
+DEFINE_TRIVIAL_REF_FUNC(sd_netlink_message, sd_netlink_message);
 
 sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
-        sd_netlink_message *t;
-
-        while (m && REFCNT_DEC(m->n_ref) == 0) {
+        while (m && --m->n_ref == 0) {
                 unsigned i;
 
                 free(m->hdr);
@@ -109,7 +106,7 @@ sd_netlink_message *sd_netlink_message_unref(sd_netlink_message *m) {
                 for (i = 0; i <= m->n_containers; i++)
                         free(m->containers[i].attributes);
 
-                t = m;
+                sd_netlink_message *t = m;
                 m = m->next;
                 free(t);
         }
@@ -334,78 +331,61 @@ int sd_netlink_message_append_data(sd_netlink_message *m, unsigned short type, c
         return 0;
 }
 
-int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
+int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data) {
         int r;
 
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
         assert_return(data, -EINVAL);
+        assert_return(IN_SET(family, AF_INET, AF_INET6), -EINVAL);
 
         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
         if (r < 0)
                 return r;
 
-        r = add_rtattr(m, type, data, sizeof(struct in_addr));
+        r = add_rtattr(m, type, data, FAMILY_ADDRESS_SIZE(family));
         if (r < 0)
                 return r;
 
         return 0;
 }
 
-int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(data, -EINVAL);
-
-        r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_IN_ADDR);
-        if (r < 0)
-                return r;
-
-        r = add_rtattr(m, type, data, sizeof(struct in6_addr));
-        if (r < 0)
-                return r;
+int sd_netlink_message_append_in_addr(sd_netlink_message *m, unsigned short type, const struct in_addr *data) {
+        return netlink_message_append_in_addr_union(m, type, AF_INET, (const union in_addr_union *) data);
+}
 
-        return 0;
+int sd_netlink_message_append_in6_addr(sd_netlink_message *m, unsigned short type, const struct in6_addr *data) {
+        return netlink_message_append_in_addr_union(m, type, AF_INET6, (const union in_addr_union *) data);
 }
 
-int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data) {
+int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data) {
         int r;
 
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
         assert_return(data, -EINVAL);
+        assert_return(IN_SET(data->sa.sa_family, AF_INET, AF_INET6), -EINVAL);
 
         r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR);
         if (r < 0)
                 return r;
 
-        r = add_rtattr(m, type, data, sizeof(struct sockaddr_in));
+        r = add_rtattr(m, type, data, data->sa.sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6));
         if (r < 0)
                 return r;
 
         return 0;
 }
 
-int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data) {
-        int r;
-
-        assert_return(m, -EINVAL);
-        assert_return(!m->sealed, -EPERM);
-        assert_return(data, -EINVAL);
-
-        r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_SOCKADDR);
-        if (r < 0)
-                return r;
-
-        r = add_rtattr(m, type, data, sizeof(struct sockaddr_in6));
-        if (r < 0)
-                return r;
+int sd_netlink_message_append_sockaddr_in(sd_netlink_message *m, unsigned short type, const struct sockaddr_in *data) {
+        return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
+}
 
-        return 0;
+int sd_netlink_message_append_sockaddr_in6(sd_netlink_message *m, unsigned short type, const struct sockaddr_in6 *data) {
+        return netlink_message_append_sockaddr_union(m, type, (const union sockaddr_union *) data);
 }
 
+
 int sd_netlink_message_append_ether_addr(sd_netlink_message *m, unsigned short type, const struct ether_addr *data) {
         int r;
 
index 432e8e8..d1c95b2 100644 (file)
@@ -14,7 +14,6 @@
 #include "netlink-internal.h"
 #include "netlink-types.h"
 #include "netlink-util.h"
-#include "refcnt.h"
 #include "socket-util.h"
 #include "util.h"
 
index 5176da0..0c67d1c 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/if_bridge.h>
 #include <linux/if_link.h>
 #include <linux/if_tunnel.h>
+#include <linux/l2tp.h>
 #include <linux/veth.h>
 #include <linux/wireguard.h>
 
@@ -302,6 +303,7 @@ static const NLType rtnl_link_info_data_geneve_types[] = {
 static const NLType rtnl_link_info_data_can_types[] = {
         [IFLA_CAN_BITTIMING]            = { .size = sizeof(struct can_bittiming) },
         [IFLA_CAN_RESTART_MS]           = { .type = NETLINK_TYPE_U32 },
+        [IFLA_CAN_CTRLMODE]             = { .size = sizeof(struct can_ctrlmode) },
 };
 
 /* these strings must match the .kind entries in the kernel */
@@ -645,19 +647,18 @@ static const NLType rtnl_routing_policy_rule_types[] = {
         [FRA_DST]                 = { .type = NETLINK_TYPE_IN_ADDR },
         [FRA_SRC]                 = { .type = NETLINK_TYPE_IN_ADDR },
         [FRA_IIFNAME]             = { .type = NETLINK_TYPE_STRING },
-        [RTA_OIF]                 = { .type = NETLINK_TYPE_U32 },
-        [RTA_GATEWAY]             = { .type = NETLINK_TYPE_IN_ADDR },
+        [FRA_GOTO]                = { .type = NETLINK_TYPE_U32 },
         [FRA_PRIORITY]            = { .type = NETLINK_TYPE_U32 },
         [FRA_FWMARK]              = { .type = NETLINK_TYPE_U32 },
         [FRA_FLOW]                = { .type = NETLINK_TYPE_U32 },
-        [FRA_TUN_ID]              = { .type = NETLINK_TYPE_U32 },
+        [FRA_TUN_ID]              = { .type = NETLINK_TYPE_U64 },
         [FRA_SUPPRESS_IFGROUP]    = { .type = NETLINK_TYPE_U32 },
         [FRA_SUPPRESS_PREFIXLEN]  = { .type = NETLINK_TYPE_U32 },
         [FRA_TABLE]               = { .type = NETLINK_TYPE_U32 },
         [FRA_FWMASK]              = { .type = NETLINK_TYPE_U32 },
         [FRA_OIFNAME]             = { .type = NETLINK_TYPE_STRING },
         [FRA_PAD]                 = { .type = NETLINK_TYPE_U32 },
-        [FRA_L3MDEV]              = { .type = NETLINK_TYPE_U64 },
+        [FRA_L3MDEV]              = { .type = NETLINK_TYPE_U8 },
         [FRA_UID_RANGE]           = { .size = sizeof(struct fib_rule_uid_range) },
         [FRA_PROTOCOL]            = { .type = NETLINK_TYPE_U8 },
         [FRA_IP_PROTO]            = { .type = NETLINK_TYPE_U8 },
@@ -791,10 +792,62 @@ static const NLTypeSystem genl_fou_cmds_type_system = {
         .types = genl_fou_cmds,
 };
 
+static const NLType genl_l2tp_types[] = {
+        [L2TP_ATTR_PW_TYPE]           = { .type = NETLINK_TYPE_U16 },
+        [L2TP_ATTR_ENCAP_TYPE]        = { .type = NETLINK_TYPE_U16 },
+        [L2TP_ATTR_OFFSET]            = { .type = NETLINK_TYPE_U16 },
+        [L2TP_ATTR_DATA_SEQ]          = { .type = NETLINK_TYPE_U16 },
+        [L2TP_ATTR_L2SPEC_TYPE]       = { .type = NETLINK_TYPE_U8 },
+        [L2TP_ATTR_L2SPEC_LEN]        = { .type = NETLINK_TYPE_U8 },
+        [L2TP_ATTR_PROTO_VERSION]     = { .type = NETLINK_TYPE_U8 },
+        [L2TP_ATTR_IFNAME]            = { .type = NETLINK_TYPE_STRING },
+        [L2TP_ATTR_CONN_ID]           = { .type = NETLINK_TYPE_U32 },
+        [L2TP_ATTR_PEER_CONN_ID]      = { .type = NETLINK_TYPE_U32 },
+        [L2TP_ATTR_SESSION_ID]        = { .type = NETLINK_TYPE_U32 },
+        [L2TP_ATTR_PEER_SESSION_ID]   = { .type = NETLINK_TYPE_U32 },
+        [L2TP_ATTR_UDP_CSUM]          = { .type = NETLINK_TYPE_U8 },
+        [L2TP_ATTR_VLAN_ID]           = { .type = NETLINK_TYPE_U16 },
+        [L2TP_ATTR_RECV_SEQ]          = { .type = NETLINK_TYPE_U8 },
+        [L2TP_ATTR_SEND_SEQ]          = { .type = NETLINK_TYPE_U8 },
+        [L2TP_ATTR_LNS_MODE]          = { .type = NETLINK_TYPE_U8 },
+        [L2TP_ATTR_USING_IPSEC]       = { .type = NETLINK_TYPE_U8 },
+        [L2TP_ATTR_FD]                = { .type = NETLINK_TYPE_U32 },
+        [L2TP_ATTR_IP_SADDR]          = { .type = NETLINK_TYPE_IN_ADDR },
+        [L2TP_ATTR_IP_DADDR]          = { .type = NETLINK_TYPE_IN_ADDR },
+        [L2TP_ATTR_UDP_SPORT]         = { .type = NETLINK_TYPE_U16 },
+        [L2TP_ATTR_UDP_DPORT]         = { .type = NETLINK_TYPE_U16 },
+        [L2TP_ATTR_IP6_SADDR]         = { .type = NETLINK_TYPE_IN_ADDR },
+        [L2TP_ATTR_IP6_DADDR]         = { .type = NETLINK_TYPE_IN_ADDR },
+        [L2TP_ATTR_UDP_ZERO_CSUM6_TX] = { .type = NETLINK_TYPE_FLAG },
+        [L2TP_ATTR_UDP_ZERO_CSUM6_RX] = { .type = NETLINK_TYPE_FLAG },
+};
+
+static const NLTypeSystem genl_l2tp_type_system = {
+        .count = ELEMENTSOF(genl_l2tp_types),
+        .types = genl_l2tp_types,
+};
+
+static const NLType genl_l2tp[]   = {
+        [L2TP_CMD_TUNNEL_CREATE]  = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system },
+        [L2TP_CMD_TUNNEL_DELETE]  = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system },
+        [L2TP_CMD_TUNNEL_MODIFY]  = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system },
+        [L2TP_CMD_TUNNEL_GET]     = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system },
+        [L2TP_CMD_SESSION_CREATE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system },
+        [L2TP_CMD_SESSION_DELETE] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system },
+        [L2TP_CMD_SESSION_MODIFY] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system },
+        [L2TP_CMD_SESSION_GET]    = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_type_system },
+};
+
+static const NLTypeSystem genl_l2tp_tunnel_session_type_system = {
+        .count = ELEMENTSOF(genl_l2tp),
+        .types = genl_l2tp,
+};
+
 static const NLType genl_families[] = {
         [SD_GENL_ID_CTRL]   = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system },
         [SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system },
         [SD_GENL_FOU]       = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_fou_cmds_type_system},
+        [SD_GENL_L2TP]      = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_tunnel_session_type_system },
 };
 
 const NLTypeSystem genl_family_type_system_root = {
@@ -803,6 +856,7 @@ const NLTypeSystem genl_family_type_system_root = {
 };
 
 static const NLType genl_types[] = {
+        [NLMSG_ERROR]  = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = sizeof(struct nlmsgerr) },
         [GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_get_family_type_system, .size = sizeof(struct genlmsghdr) },
 };
 
index 3928dfb..628ce50 100644 (file)
@@ -13,6 +13,9 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) {
         assert(ifindex > 0);
         assert(name);
 
+        if (!ifname_valid(name))
+                return -EINVAL;
+
         if (!*rtnl) {
                 r = sd_netlink_open(rtnl);
                 if (r < 0)
index d272328..0d01a4b 100644 (file)
@@ -3,6 +3,8 @@
 
 #include "sd-netlink.h"
 
+#include "in-addr-util.h"
+#include "socket-util.h"
 #include "util.h"
 
 int rtnl_message_new_synthetic_error(sd_netlink *rtnl, int error, uint32_t serial, sd_netlink_message **ret);
@@ -58,3 +60,6 @@ int rtnl_log_create_error(int r);
                                      (sd_netlink_destroy_t) _destroy_,  \
                                      userdata, __func__);               \
         })
+
+int netlink_message_append_in_addr_union(sd_netlink_message *m, unsigned short type, int family, const union in_addr_union *data);
+int netlink_message_append_sockaddr_union(sd_netlink_message *m, unsigned short type, const union sockaddr_union *data);
index 2d4d00e..ccc497d 100644 (file)
@@ -12,7 +12,6 @@
 #include "netlink-internal.h"
 #include "netlink-types.h"
 #include "netlink-util.h"
-#include "refcnt.h"
 #include "socket-util.h"
 #include "util.h"
 
index d83952d..f3e267f 100644 (file)
@@ -28,7 +28,7 @@ static int sd_netlink_new(sd_netlink **ret) {
                 return -ENOMEM;
 
         *rtnl = (sd_netlink) {
-                .n_ref = REFCNT_INIT,
+                .n_ref = 1,
                 .fd = -1,
                 .sockaddr.nl.nl_family = AF_NETLINK,
                 .original_pid = getpid_cached(),
@@ -182,7 +182,7 @@ static sd_netlink *netlink_free(sd_netlink *rtnl) {
         return mfree(rtnl);
 }
 
-DEFINE_ATOMIC_REF_UNREF_FUNC(sd_netlink, sd_netlink, netlink_free);
+DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_netlink, sd_netlink, netlink_free);
 
 static void rtnl_seal_message(sd_netlink *rtnl, sd_netlink_message *m) {
         assert(rtnl);
index 1711426..37505ea 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <stdio.h>
+
 #include "af-list.h"
 #include "alloc-util.h"
 #include "in-addr-util.h"
index df5ce86..f46a3ff 100644 (file)
@@ -3,6 +3,7 @@
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "network-util.h"
+#include "string-table.h"
 #include "strv.h"
 
 bool network_is_online(void) {
@@ -18,3 +19,16 @@ bool network_is_online(void) {
 
         return false;
 }
+
+static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
+        [LINK_OPERSTATE_OFF]              = "off",
+        [LINK_OPERSTATE_NO_CARRIER]       = "no-carrier",
+        [LINK_OPERSTATE_DORMANT]          = "dormant",
+        [LINK_OPERSTATE_DEGRADED_CARRIER] = "degraded-carrier",
+        [LINK_OPERSTATE_CARRIER]          = "carrier",
+        [LINK_OPERSTATE_DEGRADED]         = "degraded",
+        [LINK_OPERSTATE_ENSLAVED]         = "enslaved",
+        [LINK_OPERSTATE_ROUTABLE]         = "routable",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);
index e868bc2..6936fd5 100644 (file)
@@ -3,4 +3,22 @@
 
 #include "sd-network.h"
 
+#include "macro.h"
+
 bool network_is_online(void);
+
+typedef enum LinkOperationalState {
+        LINK_OPERSTATE_OFF,
+        LINK_OPERSTATE_NO_CARRIER,
+        LINK_OPERSTATE_DORMANT,
+        LINK_OPERSTATE_DEGRADED_CARRIER,
+        LINK_OPERSTATE_CARRIER,
+        LINK_OPERSTATE_DEGRADED,
+        LINK_OPERSTATE_ENSLAVED,
+        LINK_OPERSTATE_ROUTABLE,
+        _LINK_OPERSTATE_MAX,
+        _LINK_OPERSTATE_INVALID = -1
+} LinkOperationalState;
+
+const char* link_operstate_to_string(LinkOperationalState s) _const_;
+LinkOperationalState link_operstate_from_string(const char *s) _pure_;
index 812826f..2d71504 100644 (file)
@@ -164,6 +164,27 @@ _public_ int sd_network_link_get_required_for_online(int ifindex) {
         return parse_boolean(s);
 }
 
+_public_ int sd_network_link_get_required_operstate_for_online(int ifindex, char **state) {
+        _cleanup_free_ char *s = NULL;
+        int r;
+
+        assert_return(state, -EINVAL);
+
+        r = network_link_get_string(ifindex, "REQUIRED_OPER_STATE_FOR_ONLINE", &s);
+        if (r < 0) {
+                if (r != -ENODATA)
+                        return r;
+
+                /* For compatibility, assuming degraded. */
+                s = strdup("degraded");
+                if (!s)
+                        return -ENOMEM;
+        }
+
+        *state = TAKE_PTR(s);
+        return 0;
+}
+
 _public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) {
         return network_link_get_string(ifindex, "LLMNR", llmnr);
 }
index 36b9c8d..868cc02 100644 (file)
 
 #include "alloc-util.h"
 #include "dns-domain.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "io-util.h"
 #include "list.h"
+#include "memory-util.h"
 #include "missing.h"
+#include "process-util.h"
 #include "resolve-private.h"
 #include "socket-util.h"
-#include "util.h"
-#include "process-util.h"
 
 #define WORKERS_MIN 1U
 #define WORKERS_MAX 16U
index 1e7d774..357adf6 100644 (file)
  *
  * Returns: the kernel event sequence number, or 0 if there is no sequence number available.
  **/
-_public_ unsigned long long int udev_device_get_seqnum(struct udev_device *udev_device) {
-        const char *seqnum;
-        unsigned long long ret;
-        int r;
+_public_ unsigned long long udev_device_get_seqnum(struct udev_device *udev_device) {
+        uint64_t seqnum;
 
         assert_return_errno(udev_device, 0, EINVAL);
 
-        r = sd_device_get_property_value(udev_device->device, "SEQNUM", &seqnum);
-        if (r == -ENOENT)
+        if (device_get_seqnum(udev_device->device, &seqnum) < 0)
                 return 0;
-        else if (r < 0)
-                return_with_errno(0, r);
-
-        r = safe_atollu(seqnum, &ret);
-        if (r < 0)
-                return_with_errno(0, r);
 
-        return ret;
+        return seqnum;
 }
 
 /**
@@ -652,18 +643,14 @@ _public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct ud
  * Returns: the kernel action value, or #NULL if there is no action value available.
  **/
 _public_ const char *udev_device_get_action(struct udev_device *udev_device) {
-        const char *action;
-        int r;
+        DeviceAction action;
 
         assert_return_errno(udev_device, NULL, EINVAL);
 
-        r = sd_device_get_property_value(udev_device->device, "ACTION", &action);
-        if (r == -ENOENT)
+        if (device_get_action(udev_device->device, &action) < 0)
                 return NULL;
-        if (r < 0)
-                return_with_errno(NULL, r);
 
-        return action;
+        return device_action_to_string(action);
 }
 
 /**
index e54ee57..80d5baf 100644 (file)
@@ -277,9 +277,6 @@ _public_ int udev_enumerate_add_match_tag(struct udev_enumerate *udev_enumerate,
  * Return the devices on the subtree of one given device. The parent
  * itself is included in the list.
  *
- * A reference for the device is held until the udev_enumerate context
- * is cleaned up.
- *
  * Returns: 0 on success, otherwise a negative error value.
  */
 _public_ int udev_enumerate_add_match_parent(struct udev_enumerate *udev_enumerate, struct udev_device *parent) {
index 2737326..00fd58b 100644 (file)
@@ -7,7 +7,7 @@
 
 #include "alloc-util.h"
 #include "libudev-list-internal.h"
-#include "util.h"
+#include "memory-util.h"
 
 /**
  * SECTION:libudev-list
index 7e21719..37660d0 100644 (file)
@@ -175,7 +175,7 @@ size_t util_replace_chars(char *str, const char *white) {
                 }
 
                 /* accept valid utf8 */
-                len = utf8_encoded_valid_unichar(&str[i]);
+                len = utf8_encoded_valid_unichar(str + i, (size_t) -1);
                 if (len > 1) {
                         i += len;
                         continue;
index 6b6b32a..b8bd181 100644 (file)
@@ -3,20 +3,23 @@
 #include <errno.h>
 #include <stdio_ext.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "bus-util.h"
-#include "def.h"
-#include "env-file.h"
 #include "env-file-label.h"
+#include "env-file.h"
 #include "env-util.h"
 #include "fd-util.h"
 #include "fileio-label.h"
 #include "fileio.h"
+#include "kbd-util.h"
 #include "keymap-util.h"
 #include "locale-util.h"
 #include "macro.h"
 #include "mkdir.h"
+#include "nulstr-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tmpfile-util.h"
@@ -29,10 +32,6 @@ static bool startswith_comma(const char *s, const char *prefix) {
         return IN_SET(*s, ',', '\0');
 }
 
-static const char* strnulldash(const char *s) {
-        return isempty(s) || streq(s, "-") ? NULL : s;
-}
-
 static const char* systemd_kbd_model_map(void) {
         const char* s;
 
@@ -419,8 +418,7 @@ int x11_write_data(Context *c) {
                 return 0;
         }
 
-        mkdir_p_label("/etc/X11/xorg.conf.d", 0755);
-
+        (void) mkdir_p_label("/etc/X11/xorg.conf.d", 0755);
         r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path);
         if (r < 0)
                 return r;
@@ -549,15 +547,15 @@ int vconsole_convert_to_x11(Context *c) {
                         if (!streq(c->vc_keymap, a[0]))
                                 continue;
 
-                        if (!streq_ptr(c->x11_layout, strnulldash(a[1])) ||
-                            !streq_ptr(c->x11_model, strnulldash(a[2])) ||
-                            !streq_ptr(c->x11_variant, strnulldash(a[3])) ||
-                            !streq_ptr(c->x11_options, strnulldash(a[4]))) {
+                        if (!streq_ptr(c->x11_layout, empty_or_dash_to_null(a[1])) ||
+                            !streq_ptr(c->x11_model, empty_or_dash_to_null(a[2])) ||
+                            !streq_ptr(c->x11_variant, empty_or_dash_to_null(a[3])) ||
+                            !streq_ptr(c->x11_options, empty_or_dash_to_null(a[4]))) {
 
-                                if (free_and_strdup(&c->x11_layout, strnulldash(a[1])) < 0 ||
-                                    free_and_strdup(&c->x11_model, strnulldash(a[2])) < 0 ||
-                                    free_and_strdup(&c->x11_variant, strnulldash(a[3])) < 0 ||
-                                    free_and_strdup(&c->x11_options, strnulldash(a[4])) < 0)
+                                if (free_and_strdup(&c->x11_layout, empty_or_dash_to_null(a[1])) < 0 ||
+                                    free_and_strdup(&c->x11_model, empty_or_dash_to_null(a[2])) < 0 ||
+                                    free_and_strdup(&c->x11_variant, empty_or_dash_to_null(a[3])) < 0 ||
+                                    free_and_strdup(&c->x11_options, empty_or_dash_to_null(a[4])) < 0)
                                         return -ENOMEM;
 
                                 modified = true;
index 69f5667..c8b195d 100644 (file)
 
 #include "bus-error.h"
 #include "bus-util.h"
-#include "def.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "kbd-util.h"
 #include "locale-util.h"
 #include "main-func.h"
+#include "memory-util.h"
 #include "pager.h"
 #include "pretty-print.h"
 #include "proc-cmdline.h"
 #include "set.h"
 #include "spawn-polkit-agent.h"
 #include "strv.h"
-#include "util.h"
 #include "verbs.h"
 #include "virt.h"
 
index f851d35..8d0eec9 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <errno.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #if HAVE_XKBCOMMON
index 2f82891..f96f5b0 100644 (file)
@@ -4,6 +4,7 @@
 #include "keymap-util.h"
 #include "log.h"
 #include "string-util.h"
+#include "tests.h"
 
 static void test_find_language_fallback(void) {
         _cleanup_free_ char *ans = NULL, *ans2 = NULL;
@@ -189,8 +190,7 @@ static void test_x11_convert_to_vconsole(void) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
+        test_setup_logging(LOG_DEBUG);
 
         test_find_language_fallback();
         test_find_converted_keymap();
index d55e5bf..4bb144a 100644 (file)
@@ -46,6 +46,10 @@ SUBSYSTEM=="firewire", ATTR{units}=="*0x00a02d:0x014001*", TAG+="uaccess"
 
 # DRI video devices
 SUBSYSTEM=="drm", KERNEL=="card*", TAG+="uaccess"
+m4_ifdef(`GROUP_RENDER_UACCESS',``
+# DRI render nodes
+SUBSYSTEM=="drm", KERNEL=="renderD*", TAG+="uaccess"''
+)m4_dnl
 m4_ifdef(`DEV_KVM_UACCESS',``
 # KVM
 SUBSYSTEM=="misc", KERNEL=="kvm", TAG+="uaccess"''
index 1f30900..b67966c 100644 (file)
@@ -13,6 +13,13 @@ TAG=="uaccess", SUBSYSTEM!="sound", TAG+="seat"
 SUBSYSTEM=="sound", KERNEL=="card*", TAG+="seat"
 SUBSYSTEM=="input", KERNEL=="input*", TAG+="seat"
 SUBSYSTEM=="graphics", KERNEL=="fb[0-9]*", TAG+="seat"
+
+# HyperV currently doesn't do DRM, hence we need to synthesize for HyperV's fb device instead
+SUBSYSTEM=="graphics", KERNEL=="fb[0-9]", DRIVERS=="hyperv_fb", TAG+="master-of-seat"
+
+# Allow efifb / uvesafb to be a master if KMS is disabled
+SUBSYSTEM=="graphics", KERNEL=="fb[0-9]", IMPORT{cmdline}="nomodeset", TAG+="master-of-seat"
+
 SUBSYSTEM=="drm", KERNEL=="card[0-9]*", TAG+="seat", TAG+="master-of-seat"
 SUBSYSTEM=="usb", ATTR{bDeviceClass}=="09", TAG+="seat"
 
@@ -24,6 +31,11 @@ SUBSYSTEM=="usb", ATTR{idVendor}=="2230", ATTR{idProduct}=="000[13]", ENV{ID_AUT
 #     http://git.qemu.org/?p=qemu.git;a=blob;f=docs/multiseat.txt
 SUBSYSTEM=="pci", ATTR{vendor}=="0x1b36", ATTR{device}=="0x000a", TAG+="seat", ENV{ID_AUTOSEAT}="1"
 
+# Video adapter of Parallels virtualization platform
+# Seat should be synthesized for it. But there's no in-kernel driver for this
+# device so matching by vid/pid.
+SUBSYSTEM=="pci", ATTRS{vendor}=="0x1ab8", ATTRS{device}=="0x4005", TAG+="seat", TAG+="master-of-seat"
+
 # Mimo 720, with integrated USB hub, displaylink graphics, and e2i
 # touchscreen. This device carries no proper VID/PID in the USB hub,
 # but it does carry good ID data in the graphics component, hence we
index f574d42..47fd9e8 100644 (file)
@@ -286,8 +286,9 @@ static int run(int argc, char *argv[]) {
 
         else {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                _cleanup_close_ int fd = -1;
+                _cleanup_strv_free_ char **arguments = NULL;
                 _cleanup_free_ char *w = NULL;
+                _cleanup_close_ int fd = -1;
                 pid_t pid;
 
                 /* Ignore SIGINT and allow the forked process to receive it */
@@ -303,12 +304,16 @@ static int run(int argc, char *argv[]) {
                 if (fd < 0)
                         return log_error_errno(fd, "Failed to inhibit: %s", bus_error_message(&error, fd));
 
+                arguments = strv_copy(argv + optind);
+                if (!arguments)
+                        return log_oom();
+
                 r = safe_fork("(inhibit)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
                 if (r < 0)
                         return r;
                 if (r == 0) {
                         /* Child */
-                        execvp(argv[optind], argv + optind);
+                        execvp(arguments[0], arguments);
                         log_open();
                         log_error_errno(errno, "Failed to execute %s: %m", argv[optind]);
                         _exit(EXIT_FAILURE);
index ab1b562..342ac56 100644 (file)
@@ -10,7 +10,7 @@
 
 #include "alloc-util.h"
 #include "bus-error.h"
-#include "bus-unit-util.h"
+#include "bus-unit-procs.h"
 #include "bus-util.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
@@ -19,6 +19,7 @@
 #include "logs-show.h"
 #include "macro.h"
 #include "main-func.h"
+#include "memory-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "pretty-print.h"
@@ -33,7 +34,6 @@
 #include "terminal-util.h"
 #include "unit-name.h"
 #include "user-util.h"
-#include "util.h"
 #include "verbs.h"
 
 static char **arg_property = NULL;
@@ -755,7 +755,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                 return bus_log_parse_error(r);
 
                         if (all || !isempty(s))
-                                bus_print_property_value(name, expected_value, value, "%s", s);
+                                bus_print_property_value(name, expected_value, value, s);
 
                         return 1;
 
@@ -771,7 +771,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                                        "Invalid user ID: " UID_FMT,
                                                        uid);
 
-                        bus_print_property_value(name, expected_value, value, UID_FMT, uid);
+                        bus_print_property_valuef(name, expected_value, value, UID_FMT, uid);
                         return 1;
                 }
                 break;
index 60831bb..2467da1 100644 (file)
 #include "conf-parser.h"
 #include "device-util.h"
 #include "fd-util.h"
+#include "limits-util.h"
 #include "logind.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "udev-util.h"
 #include "user-util.h"
 
 void manager_reset_config(Manager *m) {
@@ -238,14 +240,12 @@ int manager_add_button(Manager *m, const char *name, Button **_button) {
 }
 
 int manager_process_seat_device(Manager *m, sd_device *d) {
-        const char *action;
         Device *device;
         int r;
 
         assert(m);
 
-        if (sd_device_get_property_value(d, "ACTION", &action) >= 0 &&
-            streq(action, "remove")) {
+        if (device_for_action(d, DEVICE_ACTION_REMOVE)) {
                 const char *syspath;
 
                 r = sd_device_get_syspath(d, &syspath);
@@ -305,7 +305,7 @@ int manager_process_seat_device(Manager *m, sd_device *d) {
 }
 
 int manager_process_button_device(Manager *m, sd_device *d) {
-        const char *action, *sysname;
+        const char *sysname;
         Button *b;
         int r;
 
@@ -315,8 +315,7 @@ int manager_process_button_device(Manager *m, sd_device *d) {
         if (r < 0)
                 return r;
 
-        if (sd_device_get_property_value(d, "ACTION", &action) >= 0 &&
-            streq(action, "remove")) {
+        if (device_for_action(d, DEVICE_ACTION_REMOVE)) {
 
                 b = hashmap_get(m->buttons, sysname);
                 if (!b)
index 8ab498f..2cebcce 100644 (file)
@@ -3,6 +3,7 @@
 #include <errno.h>
 #include <pwd.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include "sd-device.h"
@@ -10,6 +11,7 @@
 
 #include "alloc-util.h"
 #include "audit-util.h"
+#include "bootspec.h"
 #include "bus-common-errors.h"
 #include "bus-error.h"
 #include "bus-unit-util.h"
@@ -18,6 +20,7 @@
 #include "device-util.h"
 #include "dirent-util.h"
 #include "efivars.h"
+#include "env-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio-label.h"
 #include "logind.h"
 #include "missing_capability.h"
 #include "mkdir.h"
+#include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "reboot-util.h"
 #include "selinux-util.h"
 #include "sleep-config.h"
 #include "special.h"
+#include "stdio-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "tmpfile-util.h"
 #include "unit-name.h"
 #include "user-util.h"
 #include "utmp-wtmp.h"
+#include "virt.h"
 
 static int get_sender_session(Manager *m, sd_bus_message *message, sd_bus_error *error, Session **ret) {
 
@@ -115,7 +122,8 @@ static int get_sender_user(Manager *m, sd_bus_message *message, sd_bus_error *er
         return 0;
 
 err_no_user:
-        return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID, "Caller does not belong to any logged in user or lingering user");
+        return sd_bus_error_setf(error, BUS_ERROR_NO_USER_FOR_PID,
+                                 "Caller does not belong to any logged in user or lingering user");
 }
 
 int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid, sd_bus_error *error, User **ret) {
@@ -130,7 +138,8 @@ int manager_get_user_from_creds(Manager *m, sd_bus_message *message, uid_t uid,
 
         user = hashmap_get(m->users, UID_TO_PTR(uid));
         if (!user)
-                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER, "User ID "UID_FMT" is not logged in or lingering", uid);
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER,
+                                         "User ID "UID_FMT" is not logged in or lingering", uid);
 
         *ret = user;
         return 0;
@@ -164,6 +173,32 @@ int manager_get_seat_from_creds(Manager *m, sd_bus_message *message, const char
         return 0;
 }
 
+static int return_test_polkit(
+                sd_bus_message *message,
+                int capability,
+                const char *action,
+                const char **details,
+                uid_t good_user,
+                sd_bus_error *e) {
+
+        const char *result;
+        bool challenge;
+        int r;
+
+        r = bus_test_polkit(message, capability, action, details, good_user, &challenge, e);
+        if (r < 0)
+                return r;
+
+        if (r > 0)
+                result = "yes";
+        else if (challenge)
+                result = "challenge";
+        else
+                result = "no";
+
+        return sd_bus_reply_method_return(message, "s", result);
+}
+
 static int property_get_idle_hint(
                 sd_bus *bus,
                 const char *path,
@@ -338,7 +373,8 @@ static int method_get_session_by_pid(sd_bus_message *message, void *userdata, sd
                         return r;
 
                 if (!session)
-                        return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID, "PID "PID_FMT" does not belong to any known session", pid);
+                        return sd_bus_error_setf(error, BUS_ERROR_NO_SESSION_FOR_PID,
+                                                 "PID "PID_FMT" does not belong to any known session", pid);
         }
 
         p = session_bus_path(session);
@@ -616,7 +652,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
         assert_cc(sizeof(pid_t) == sizeof(uint32_t));
         assert_cc(sizeof(uid_t) == sizeof(uint32_t));
 
-        r = sd_bus_message_read(message, "uusssssussbss", &uid, &leader, &service, &type, &class, &desktop, &cseat, &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
+        r = sd_bus_message_read(message, "uusssssussbss",
+                                &uid, &leader, &service, &type, &class, &desktop, &cseat,
+                                &vtnr, &tty, &display, &remote, &remote_user, &remote_host);
         if (r < 0)
                 return r;
 
@@ -630,7 +668,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
         else {
                 t = session_type_from_string(type);
                 if (t < 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session type %s", type);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Invalid session type %s", type);
         }
 
         if (isempty(class))
@@ -638,14 +677,16 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
         else {
                 c = session_class_from_string(class);
                 if (c < 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid session class %s", class);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Invalid session class %s", class);
         }
 
         if (isempty(desktop))
                 desktop = NULL;
         else {
                 if (!string_is_safe(desktop))
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid desktop string %s", desktop);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Invalid desktop string %s", desktop);
         }
 
         if (isempty(cseat))
@@ -653,7 +694,8 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
         else {
                 seat = hashmap_get(m->seats, cseat);
                 if (!seat)
-                        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT, "No seat '%s' known", cseat);
+                        return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_SEAT,
+                                                 "No seat '%s' known", cseat);
         }
 
         if (tty_is_vc(tty)) {
@@ -662,35 +704,42 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
                 if (!seat)
                         seat = m->seat0;
                 else if (seat != m->seat0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY %s is virtual console but seat %s is not seat0", tty, seat->id);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "TTY %s is virtual console but seat %s is not seat0", tty, seat->id);
 
                 v = vtnr_from_tty(tty);
                 if (v <= 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot determine VT number from virtual console TTY %s", tty);
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Cannot determine VT number from virtual console TTY %s", tty);
 
                 if (vtnr == 0)
                         vtnr = (uint32_t) v;
                 else if (vtnr != (uint32_t) v)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified TTY and VT number do not match");
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Specified TTY and VT number do not match");
 
         } else if (tty_is_console(tty)) {
 
                 if (!seat)
                         seat = m->seat0;
                 else if (seat != m->seat0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but seat is not seat0");
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Console TTY specified but seat is not seat0");
 
                 if (vtnr != 0)
-                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Console TTY specified but VT number is not 0");
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                 "Console TTY specified but VT number is not 0");
         }
 
         if (seat) {
                 if (seat_has_vts(seat)) {
                         if (vtnr <= 0 || vtnr > 63)
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "VT number out of range");
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                         "VT number out of range");
                 } else {
                         if (vtnr != 0)
-                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Seat has no VTs but VT number not 0");
+                                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                                         "Seat has no VTs but VT number not 0");
                 }
         }
 
@@ -722,13 +771,14 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
                         return r;
         }
 
-        /* Check if we are already in a logind session. Or if we are in user@.service which is a special PAM session
-         * that avoids creating a logind session. */
+        /* Check if we are already in a logind session. Or if we are in user@.service
+         * which is a special PAM session that avoids creating a logind session. */
         r = manager_get_user_by_pid(m, leader, NULL);
         if (r < 0)
                 return r;
         if (r > 0)
-                return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already running in a session or user slice");
+                return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY,
+                                         "Already running in a session or user slice");
 
         /*
          * Old gdm and lightdm start the user-session on the same VT as
@@ -748,7 +798,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
                 return sd_bus_error_setf(error, BUS_ERROR_SESSION_BUSY, "Already occupied by a session");
 
         if (hashmap_size(m->sessions) >= m->sessions_max)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.", m->sessions_max);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED,
+                                         "Maximum number of sessions (%" PRIu64 ") reached, refusing further sessions.",
+                                         m->sessions_max);
 
         (void) audit_session_from_pid(leader, &audit_id);
         if (audit_session_is_valid(audit_id)) {
@@ -790,7 +842,9 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
                 goto fail;
 
         session_set_user(session, user);
-        session_set_leader(session, leader);
+        r = session_set_leader(session, leader);
+        if (r < 0)
+                goto fail;
 
         session->type = t;
         session->class = c;
@@ -952,7 +1006,8 @@ static int method_activate_session_on_seat(sd_bus_message *message, void *userda
                 return r;
 
         if (session->seat != seat)
-                return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name);
+                return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT,
+                                         "Session %s not on seat %s", session_name, seat_name);
 
         r = session_activate(session);
         if (r < 0)
@@ -1163,8 +1218,7 @@ static int method_set_user_linger(sd_bus_message *message, void *userdata, sd_bu
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        mkdir_p_label("/var/lib/systemd", 0755);
-
+        (void) mkdir_p_label("/var/lib/systemd", 0755);
         r = mkdir_safe_label("/var/lib/systemd/linger", 0755, 0, 0, MKDIR_WARN_MODE);
         if (r < 0)
                 return r;
@@ -1761,7 +1815,8 @@ static int method_do_shutdown_or_sleep(
 
         /* Don't allow multiple jobs being executed at the same time */
         if (m->action_what > 0)
-                return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
+                return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
+                                         "There's already a shutdown or sleep operation in progress");
 
         if (sleep_verb) {
                 r = can_sleep(sleep_verb);
@@ -2376,6 +2431,97 @@ static int method_can_suspend_then_hibernate(sd_bus_message *message, void *user
                         error);
 }
 
+static int property_get_reboot_parameter(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+        _cleanup_free_ char *parameter = NULL;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(userdata);
+
+        r = read_reboot_parameter(&parameter);
+        if (r < 0)
+                return r;
+
+        return sd_bus_message_append(reply, "s", parameter);
+}
+
+static int method_set_reboot_parameter(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+        const char *arg;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "s", &arg);
+        if (r < 0)
+                return r;
+
+        r = detect_container();
+        if (r < 0)
+                return r;
+        if (r > 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED,
+                                         "Reboot parameter not supported in containers, refusing.");
+
+        r = bus_verify_polkit_async(message,
+                                    CAP_SYS_ADMIN,
+                                    "org.freedesktop.login1.set-reboot-parameter",
+                                    NULL,
+                                    false,
+                                    UID_INVALID,
+                                    &m->polkit_registry,
+                                    error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        r = update_reboot_parameter_and_warn(arg, false);
+        if (r < 0)
+                return r;
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_can_reboot_parameter(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = detect_container();
+        if (r < 0)
+                return r;
+        if (r > 0) /* Inside containers, specifying a reboot parameter, doesn't make much sense */
+                return sd_bus_reply_method_return(message, "s", "na");
+
+        return return_test_polkit(
+                        message,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.login1.set-reboot-parameter",
+                        NULL,
+                        UID_INVALID,
+                        error);
+}
+
 static int property_get_reboot_to_firmware_setup(
                 sd_bus *bus,
                 const char *path,
@@ -2390,9 +2536,24 @@ static int property_get_reboot_to_firmware_setup(
         assert(reply);
         assert(userdata);
 
-        r = efi_get_reboot_to_firmware();
-        if (r < 0 && r != -EOPNOTSUPP)
-                log_warning_errno(r, "Failed to determine reboot-to-firmware state: %m");
+        r = getenv_bool("SYSTEMD_REBOOT_TO_FIRMWARE_SETUP");
+        if (r == -ENXIO) {
+                /* EFI case: let's see what is currently configured in the EFI variables */
+                r = efi_get_reboot_to_firmware();
+                if (r < 0 && r != -EOPNOTSUPP)
+                        log_warning_errno(r, "Failed to determine reboot-to-firmware-setup state: %m");
+        } else if (r < 0)
+                log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP: %m");
+        else if (r > 0) {
+                /* Non-EFI case: let's see whether /run/systemd/reboot-to-firmware-setup exists. */
+                if (access("/run/systemd/reboot-to-firmware-setup", F_OK) < 0) {
+                        if (errno != ENOENT)
+                                log_warning_errno(errno, "Failed to check whether /run/systemd/reboot-to-firmware-setup exists: %m");
+
+                        r = false;
+                } else
+                        r = true;
+        }
 
         return sd_bus_message_append(reply, "b", r > 0);
 }
@@ -2402,8 +2563,9 @@ static int method_set_reboot_to_firmware_setup(
                 void *userdata,
                 sd_bus_error *error) {
 
-        int b, r;
         Manager *m = userdata;
+        bool use_efi;
+        int b, r;
 
         assert(message);
         assert(m);
@@ -2412,6 +2574,29 @@ static int method_set_reboot_to_firmware_setup(
         if (r < 0)
                 return r;
 
+        r = getenv_bool("SYSTEMD_REBOOT_TO_FIRMWARE_SETUP");
+        if (r == -ENXIO) {
+                /* EFI case: let's see what the firmware supports */
+
+                r = efi_reboot_to_firmware_supported();
+                if (r == -EOPNOTSUPP)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Firmware does not support boot into firmware.");
+                if (r < 0)
+                        return r;
+
+                use_efi = true;
+
+        } else if (r <= 0) {
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP is set to off */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP: %m");
+
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Firmware does not support boot into firmware.");
+        } else
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP is set to on */
+                use_efi = false;
+
         r = bus_verify_polkit_async(message,
                                     CAP_SYS_ADMIN,
                                     "org.freedesktop.login1.set-reboot-to-firmware-setup",
@@ -2425,52 +2610,481 @@ static int method_set_reboot_to_firmware_setup(
         if (r == 0)
                 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
 
-        r = efi_set_reboot_to_firmware(b);
+        if (use_efi) {
+                r = efi_set_reboot_to_firmware(b);
+                if (r < 0)
+                        return r;
+        } else {
+                if (b) {
+                        r = touch("/run/systemd/reboot-to-firmware-setup");
+                        if (r < 0)
+                                return r;
+                } else {
+                        if (unlink("/run/systemd/reboot-to-firmware-setup") < 0 && errno != ENOENT)
+                                return -errno;
+                }
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_can_reboot_to_firmware_setup(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_FIRMWARE_SETUP");
+        if (r == -ENXIO) {
+                /* EFI case: let's see what the firmware supports */
+
+                r = efi_reboot_to_firmware_supported();
+                if (r < 0) {
+                        if (r != -EOPNOTSUPP)
+                                log_warning_errno(r, "Failed to determine whether reboot to firmware is supported: %m");
+
+                        return sd_bus_reply_method_return(message, "s", "na");
+                }
+
+        } else if (r <= 0) {
+                /* Non-EFI case: let's trust $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_FIRMWARE_SETUP: %m");
+
+                return sd_bus_reply_method_return(message, "s", "na");
+        }
+
+        return return_test_polkit(
+                        message,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.login1.set-reboot-to-firmware-setup",
+                        NULL,
+                        UID_INVALID,
+                        error);
+}
+
+static int property_get_reboot_to_boot_loader_menu(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        uint64_t x = UINT64_MAX;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(userdata);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU");
+        if (r == -ENXIO) {
+                _cleanup_free_ char *v = NULL;
+
+                /* EFI case: returns the current value of LoaderConfigTimeoutOneShot. Three cases are distuingished:
+                 *
+                 *     1. Variable not set, boot into boot loader menu is not enabled (we return UINT64_MAX to the user)
+                 *     2. Variable set to "0", boot into boot loader menu is enabled with no timeout (we return 0 to the user)
+                 *     3. Variable set to numeric value formatted in ASCII, boot into boot loader menu with the specified timeout in seconds
+                 */
+
+                r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot", &v);
+                if (r < 0) {
+                        if (r != -ENOENT)
+                                log_warning_errno(r, "Failed to read LoaderConfigTimeoutOneShot variable: %m");
+                } else {
+                        uint64_t sec;
+
+                        r = safe_atou64(v, &sec);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to parse LoaderConfigTimeoutOneShot value '%s': %m", v);
+                        else if (sec > (USEC_INFINITY / USEC_PER_SEC))
+                                log_warning("LoaderConfigTimeoutOneShot too large, ignoring: %m");
+                        else
+                                x = sec * USEC_PER_SEC; /* return in µs */
+                }
+
+        } else if (r < 0)
+                log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU: %m");
+        else if (r > 0) {
+                _cleanup_free_ char *v = NULL;
+
+                /* Non-EFI case, let's process /run/systemd/reboot-to-boot-loader-menu. */
+
+                r = read_one_line_file("/run/systemd/reboot-to-boot-loader-menu", &v);
+                if (r < 0) {
+                        if (r != -ENOENT)
+                                log_warning_errno(r, "Failed to read /run/systemd/reboot-to-boot-loader-menu: %m");
+                } else {
+                        r = safe_atou64(v, &x);
+                        if (r < 0)
+                                log_warning_errno(r, "Failed to parse /run/systemd/reboot-to-boot-loader-menu: %m");
+                }
+        }
+
+        return sd_bus_message_append(reply, "t", x);
+}
+
+static int method_set_reboot_to_boot_loader_menu(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+        bool use_efi;
+        uint64_t x;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = sd_bus_message_read(message, "t", &x);
         if (r < 0)
                 return r;
 
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU");
+        if (r == -ENXIO) {
+                uint64_t features;
+
+                /* EFI case: let's see if booting into boot loader menu is supported. */
+
+                r = efi_loader_get_features(&features);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to determine whether reboot to boot loader menu is supported: %m");
+                if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader does not support boot into boot loader menu.");
+
+                use_efi = true;
+
+        } else if (r <= 0) {
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU is set to off */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU: %m");
+
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader does not support boot into boot loader menu.");
+        } else
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU is set to on */
+                use_efi = false;
+
+        r = bus_verify_polkit_async(message,
+                                    CAP_SYS_ADMIN,
+                                    "org.freedesktop.login1.set-reboot-to-boot-loader-menu",
+                                    NULL,
+                                    false,
+                                    UID_INVALID,
+                                    &m->polkit_registry,
+                                    error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        if (use_efi) {
+                if (x == UINT64_MAX)
+                        r = efi_set_variable(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot", NULL, 0);
+                else {
+                        char buf[DECIMAL_STR_MAX(uint64_t) + 1];
+                        xsprintf(buf, "%" PRIu64, DIV_ROUND_UP(x, USEC_PER_SEC)); /* second granularity */
+
+                        r = efi_set_variable_string(EFI_VENDOR_LOADER, "LoaderConfigTimeoutOneShot", buf);
+                }
+                if (r < 0)
+                        return r;
+        } else {
+                if (x == UINT64_MAX) {
+                        if (unlink("/run/systemd/reboot-to-loader-menu") < 0 && errno != ENOENT)
+                                return -errno;
+                } else {
+                        char buf[DECIMAL_STR_MAX(uint64_t) + 1];
+
+                        xsprintf(buf, "%" PRIu64, x); /* µs granularity */
+
+                        r = write_string_file_atomic_label("/run/systemd/reboot-to-loader-menu", buf);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
         return sd_bus_reply_method_return(message, NULL);
 }
 
-static int method_can_reboot_to_firmware_setup(
+static int method_can_reboot_to_boot_loader_menu(
                 sd_bus_message *message,
                 void *userdata,
                 sd_bus_error *error) {
 
+        Manager *m = userdata;
         int r;
-        bool challenge;
-        const char *result;
+
+        assert(message);
+        assert(m);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU");
+        if (r == -ENXIO) {
+                uint64_t features = 0;
+
+                /* EFI case, let's see if booting into boot loader menu is supported. */
+
+                r = efi_loader_get_features(&features);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to determine whether reboot to boot loader menu is supported: %m");
+                if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_CONFIG_TIMEOUT_ONE_SHOT))
+                        return sd_bus_reply_method_return(message, "s", "na");
+
+        } else if (r <= 0) {
+                /* Non-EFI case: let's trust $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU: %m");
+
+                return sd_bus_reply_method_return(message, "s", "na");
+        }
+
+        return return_test_polkit(
+                        message,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.login1.set-reboot-to-boot-loader-menu",
+                        NULL,
+                        UID_INVALID,
+                        error);
+}
+
+static int property_get_reboot_to_boot_loader_entry(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        _cleanup_free_ char *v = NULL;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(userdata);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY");
+        if (r == -ENXIO) {
+                /* EFI case: let's read the LoaderEntryOneShot variable */
+
+                r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", &v);
+                if (r < 0) {
+                        if (r != -ENOENT)
+                                log_warning_errno(r, "Failed to read LoaderEntryOneShot variable: %m");
+                } else if (!efi_loader_entry_name_valid(v)) {
+                        log_warning("LoaderEntryOneShot contains invalid entry name '%s', ignoring.", v);
+                        v = mfree(v);
+                }
+        } else if (r < 0)
+                log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY: %m");
+        else if (r > 0) {
+
+                /* Non-EFI case, let's process /run/systemd/reboot-to-boot-loader-entry. */
+
+                r = read_one_line_file("/run/systemd/reboot-to-boot-loader-entry", &v);
+                if (r < 0) {
+                        if (r != -ENOENT)
+                                log_warning_errno(r, "Failed to read /run/systemd/reboot-to-boot-loader-entry: %m");
+                } else if (!efi_loader_entry_name_valid(v)) {
+                        log_warning("/run/systemd/reboot-to-boot-loader-entry is not valid, ignoring.");
+                        v = mfree(v);
+                }
+        }
+
+        return sd_bus_message_append(reply, "s", v);
+}
+
+static int boot_loader_entry_exists(const char *id) {
+        _cleanup_(boot_config_free) BootConfig config = {};
+        int r;
+
+        assert(id);
+
+        r = boot_entries_load_config_auto(NULL, NULL, &config);
+        if (r < 0 && r != -ENOKEY) /* don't complain if no GPT is found, hence skip ENOKEY */
+                return r;
+
+        (void) boot_entries_augment_from_loader(&config, true);
+
+        return boot_config_has_entry(&config, id);
+}
+
+static int method_set_reboot_to_boot_loader_entry(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
         Manager *m = userdata;
+        bool use_efi;
+        const char *v;
+        int r;
 
         assert(message);
         assert(m);
 
-        r = efi_reboot_to_firmware_supported();
-        if (r < 0) {
-                if (r != -EOPNOTSUPP)
-                        log_warning_errno(r, "Failed to determine whether reboot to firmware is supported: %m");
+        r = sd_bus_message_read(message, "s", &v);
+        if (r < 0)
+                return r;
+
+        if (isempty(v))
+                v = NULL;
+        else if (efi_loader_entry_name_valid(v)) {
+                r = boot_loader_entry_exists(v);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Boot loader entry '%s' is not known.", v);
+        } else
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Boot loader entry name '%s' is not valid, refusing.", v);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY");
+        if (r == -ENXIO) {
+                uint64_t features;
+
+                /* EFI case: let's see if booting into boot loader entry is supported. */
+
+                r = efi_loader_get_features(&features);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to determine whether reboot into boot loader entry is supported: %m");
+                if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_ENTRY_ONESHOT))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Loader does not support boot into boot loader entry.");
+
+                use_efi = true;
+
+        } else if (r <= 0) {
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY is set to off */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY: %m");
+
+                return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Loader does not support boot into boot loader entry.");
+        } else
+                /* non-EFI case: $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY is set to on */
+                use_efi = false;
+
+        r = bus_verify_polkit_async(message,
+                                    CAP_SYS_ADMIN,
+                                    "org.freedesktop.login1.set-reboot-to-boot-loader-entry",
+                                    NULL,
+                                    false,
+                                    UID_INVALID,
+                                    &m->polkit_registry,
+                                    error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        if (use_efi) {
+                if (isempty(v))
+                        /* Delete item */
+                        r = efi_set_variable(EFI_VENDOR_LOADER, "LoaderEntryOneShot", NULL, 0);
+                else
+                        r = efi_set_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", v);
+                if (r < 0)
+                        return r;
+        } else {
+                if (isempty(v)) {
+                        if (unlink("/run/systemd/reboot-to-boot-loader-entry") < 0 && errno != ENOENT)
+                                return -errno;
+                } else {
+                        r = write_string_file_atomic_label("/run/systemd/reboot-boot-to-loader-entry", v);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+static int method_can_reboot_to_boot_loader_entry(
+                sd_bus_message *message,
+                void *userdata,
+                sd_bus_error *error) {
+
+        Manager *m = userdata;
+        int r;
+
+        assert(message);
+        assert(m);
+
+        r = getenv_bool("SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY");
+        if (r == -ENXIO) {
+                uint64_t features = 0;
+
+                /* EFI case, let's see if booting into boot loader entry is supported. */
+
+                r = efi_loader_get_features(&features);
+                if (r < 0)
+                        log_warning_errno(r, "Failed to determine whether reboot to boot loader entry is supported: %m");
+                if (r < 0 || !FLAGS_SET(features, EFI_LOADER_FEATURE_ENTRY_ONESHOT))
+                        return sd_bus_reply_method_return(message, "s", "na");
+
+        } else if (r <= 0) {
+                /* Non-EFI case: let's trust $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY */
+
+                if (r < 0)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY: %m");
 
                 return sd_bus_reply_method_return(message, "s", "na");
         }
 
-        r = bus_test_polkit(message,
-                            CAP_SYS_ADMIN,
-                            "org.freedesktop.login1.set-reboot-to-firmware-setup",
-                            NULL,
-                            UID_INVALID,
-                            &challenge,
-                            error);
+        return return_test_polkit(
+                        message,
+                        CAP_SYS_ADMIN,
+                        "org.freedesktop.login1.set-reboot-to-boot-loader-entry",
+                        NULL,
+                        UID_INVALID,
+                        error);
+}
+
+static int property_get_boot_loader_entries(
+                sd_bus *bus,
+                const char *path,
+                const char *interface,
+                const char *property,
+                sd_bus_message *reply,
+                void *userdata,
+                sd_bus_error *error) {
+
+        _cleanup_(boot_config_free) BootConfig config = {};
+        size_t i;
+        int r;
+
+        assert(bus);
+        assert(reply);
+        assert(userdata);
+
+        r = boot_entries_load_config_auto(NULL, NULL, &config);
+        if (r < 0 && r != -ENOKEY) /* don't complain if there's no GPT found */
+                return r;
+
+        (void) boot_entries_augment_from_loader(&config, true);
+
+        r = sd_bus_message_open_container(reply, 'a', "s");
         if (r < 0)
                 return r;
 
-        if (r > 0)
-                result = "yes";
-        else if (challenge)
-                result = "challenge";
-        else
-                result = "no";
+        for (i = 0; i < config.n_entries; i++) {
+                BootEntry *e = config.entries + i;
 
-        return sd_bus_reply_method_return(message, "s", result);
+                r = sd_bus_message_append(reply, "s", e->id);
+                if (r < 0)
+                        return r;
+        }
+
+        return sd_bus_message_close_container(reply);
 }
 
 static int method_set_wall_message(
@@ -2534,22 +3148,26 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
 
         w = inhibit_what_from_string(what);
         if (w <= 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid what specification %s", what);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Invalid what specification %s", what);
 
         mm = inhibit_mode_from_string(mode);
         if (mm < 0)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid mode specification %s", mode);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Invalid mode specification %s", mode);
 
         /* Delay is only supported for shutdown/sleep */
         if (mm == INHIBIT_DELAY && (w & ~(INHIBIT_SHUTDOWN|INHIBIT_SLEEP)))
-                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delay inhibitors only supported for shutdown and sleep");
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+                                         "Delay inhibitors only supported for shutdown and sleep");
 
         /* Don't allow taking delay locks while we are already
          * executing the operation. We shouldn't create the impression
          * that the lock was successful if the machine is about to go
          * down/suspend any moment. */
         if (m->action_what & w)
-                return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "The operation inhibition has been requested for is already running");
+                return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS,
+                                         "The operation inhibition has been requested for is already running");
 
         r = bus_verify_polkit_async(
                         message,
@@ -2584,7 +3202,9 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
                 return r;
 
         if (hashmap_size(m->inhibitors) >= m->inhibitors_max)
-                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.", m->inhibitors_max);
+                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED,
+                                         "Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.",
+                                         m->inhibitors_max);
 
         do {
                 id = mfree(id);
@@ -2637,7 +3257,11 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_PROPERTY("KillOnlyUsers", "as", NULL, offsetof(Manager, kill_only_users), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("KillExcludeUsers", "as", NULL, offsetof(Manager, kill_exclude_users), SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("KillUserProcesses", "b", NULL, offsetof(Manager, kill_user_processes), SD_BUS_VTABLE_PROPERTY_CONST),
+        SD_BUS_PROPERTY("RebootParameter", "s", property_get_reboot_parameter, 0, 0),
         SD_BUS_PROPERTY("RebootToFirmwareSetup", "b", property_get_reboot_to_firmware_setup, 0, 0),
+        SD_BUS_PROPERTY("RebootToBootLoaderMenu", "t", property_get_reboot_to_boot_loader_menu, 0, 0),
+        SD_BUS_PROPERTY("RebootToBootLoaderEntry", "s", property_get_reboot_to_boot_loader_entry, 0, 0),
+        SD_BUS_PROPERTY("BootLoaderEntries", "as", property_get_boot_loader_entries, 0, SD_BUS_VTABLE_PROPERTY_CONST),
         SD_BUS_PROPERTY("IdleHint", "b", property_get_idle_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("IdleSinceHint", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("IdleSinceHintMonotonic", "t", property_get_idle_since_hint, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -2710,8 +3334,14 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("ScheduleShutdown", "st", NULL, method_schedule_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CancelScheduledShutdown", NULL, "b", method_cancel_scheduled_shutdown, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CanRebootParameter", NULL, "s", method_can_reboot_parameter, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetRebootParameter", "s", NULL, method_set_reboot_parameter, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CanRebootToBootLoaderMenu", NULL, "s", method_can_reboot_to_boot_loader_menu, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetRebootToBootLoaderMenu", "t", NULL, method_set_reboot_to_boot_loader_menu, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("CanRebootToBootLoaderEntry", NULL, "s", method_can_reboot_to_boot_loader_entry, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetRebootToBootLoaderEntry", "s", NULL, method_set_reboot_to_boot_loader_entry, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("SetWallMessage", "sb", NULL, method_set_wall_message, SD_BUS_VTABLE_UNPRIVILEGED),
 
         SD_BUS_SIGNAL("SessionNew", "so", 0),
@@ -2736,7 +3366,8 @@ static int session_jobs_reply(Session *s, const char *unit, const char *result)
         if (result && !streq(result, "done")) {
                 _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);
+                sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED,
+                                  "Start job for unit '%s' failed with '%s'", unit, result);
                 return session_send_create_reply(s, &e);
         }
 
@@ -3156,7 +3787,7 @@ int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *ret
                         &reply,
                         "s");
         if (r < 0) {
-                /* systemd might have droppped off momentarily, let's
+                /* systemd might have dropped off momentarily, let's
                  * not make this an error */
                 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
                     sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
index 415c26b..d427dca 100644 (file)
@@ -3,6 +3,8 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
@@ -57,7 +59,7 @@ void inhibitor_free(Inhibitor *i) {
         free(i->why);
 
         if (i->state_file) {
-                unlink(i->state_file);
+                (void) unlink(i->state_file);
                 free(i->state_file);
         }
 
@@ -171,7 +173,7 @@ int inhibitor_stop(Inhibitor *i) {
                           inhibit_mode_to_string(i->mode));
 
         if (i->state_file)
-                unlink(i->state_file);
+                (void) unlink(i->state_file);
 
         i->started = false;
 
@@ -318,7 +320,7 @@ void inhibitor_remove_fifo(Inhibitor *i) {
         i->fifo_fd = safe_close(i->fifo_fd);
 
         if (i->fifo_path) {
-                unlink(i->fifo_path);
+                (void) unlink(i->fifo_path);
                 i->fifo_path = mfree(i->fifo_path);
         }
 }
index a6d88f8..b4904c3 100644 (file)
@@ -4,6 +4,7 @@
 #include <fcntl.h>
 #include <stdio_ext.h>
 #include <string.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include "sd-messages.h"
index f358524..7c79a4a 100644 (file)
@@ -387,21 +387,11 @@ void session_device_free(SessionDevice *sd) {
         assert(sd);
 
         /* Make sure to remove the pushed fd. */
-        if (sd->pushed_fd) {
-                _cleanup_free_ char *m = NULL;
-                const char *id;
-                int r;
-
-                /* Session ID does not contain separators. */
-                id = sd->session->id;
-                assert(*(id + strcspn(id, "-\n")) == '\0');
-
-                r = asprintf(&m, "FDSTOREREMOVE=1\n"
-                                 "FDNAME=session-%s-device-%u-%u\n",
-                                 id, major(sd->dev), minor(sd->dev));
-                if (r >= 0)
-                        (void) sd_notify(false, m);
-        }
+        if (sd->pushed_fd)
+                (void) sd_notifyf(false,
+                                  "FDSTOREREMOVE=1\n"
+                                  "FDNAME=session-%s-device-%u-%u",
+                                  sd->session->id, major(sd->dev), minor(sd->dev));
 
         session_device_stop(sd);
         session_device_notify(sd, SESSION_DEVICE_RELEASE);
index 90a9108..3d3bc8a 100644 (file)
@@ -8,6 +8,7 @@
 #include <stdio_ext.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <sys/stat.h>
 #include <unistd.h>
 
 #include "sd-messages.h"
@@ -643,20 +644,26 @@ static int session_start_scope(Session *s, sd_bus_message *properties, sd_bus_er
                                 s->leader,
                                 s->user->slice,
                                 description,
-                                STRV_MAKE(s->user->runtime_dir_service, s->user->service), /* These two have StopWhenUnneeded= set, hence add a dep towards them */
-                                STRV_MAKE("systemd-logind.service", "systemd-user-sessions.service", s->user->runtime_dir_service, s->user->service), /* And order us after some more */
+                                /* These two have StopWhenUnneeded= set, hence add a dep towards them */
+                                STRV_MAKE(s->user->runtime_dir_service,
+                                          s->user->service),
+                                /* And order us after some more */
+                                STRV_MAKE("systemd-logind.service",
+                                          "systemd-user-sessions.service",
+                                          s->user->runtime_dir_service,
+                                          s->user->service),
                                 s->user->home,
                                 properties,
                                 error,
                                 &s->scope_job);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to start session scope %s: %s", scope, bus_error_message(error, r));
+                        return log_error_errno(r, "Failed to start session scope %s: %s",
+                                               scope, bus_error_message(error, r));
 
                 s->scope = TAKE_PTR(scope);
         }
 
-        if (s->scope)
-                (void) hashmap_put(s->manager->session_units, s->scope, s);
+        (void) hashmap_put(s->manager->session_units, s->scope, s);
 
         return 0;
 }
index 92ad011..a46605e 100644 (file)
@@ -20,6 +20,7 @@
 #include "fs-util.h"
 #include "hashmap.h"
 #include "label.h"
+#include "limits-util.h"
 #include "logind-user.h"
 #include "mkdir.h"
 #include "parse-util.h"
@@ -69,6 +70,8 @@ int user_new(User **ret,
         if (!u->home)
                 return -ENOMEM;
 
+        path_simplify(u->home, true);
+
         if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
                 return -ENOMEM;
 
@@ -358,7 +361,8 @@ static void user_start_service(User *u) {
 
         r = manager_start_unit(u->manager, u->service, &error, &u->service_job);
         if (r < 0)
-                log_warning_errno(r, "Failed to start user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
+                log_full_errno(sd_bus_error_has_name(&error, BUS_ERROR_UNIT_MASKED) ? LOG_DEBUG : LOG_WARNING, r,
+                               "Failed to start user service '%s', ignoring: %s", u->service, bus_error_message(&error, r));
 }
 
 int user_start(User *u) {
index 95ec0a5..4c0e8ce 100644 (file)
@@ -26,6 +26,7 @@
 #include "signal-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "udev-util.h"
 
 static Manager* manager_unref(Manager *m);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
@@ -377,73 +378,75 @@ static int parse_fdname(const char *fdname, char **session_id, dev_t *dev) {
         return 0;
 }
 
-static int manager_attach_fds(Manager *m) {
-        _cleanup_strv_free_ char **fdnames = NULL;
-        int n, i, fd;
+static int deliver_fd(Manager *m, const char *fdname, int fd) {
+        _cleanup_free_ char *id = NULL;
+        SessionDevice *sd;
+        struct stat st;
+        Session *s;
+        dev_t dev;
+        int r;
 
-        /* Upon restart, PID1 will send us back all fds of session devices
-         * that we previously opened. Each file descriptor is associated
-         * with a given session. The session ids are passed through FDNAMES. */
+        assert(m);
+        assert(fd >= 0);
 
-        n = sd_listen_fds_with_names(true, &fdnames);
-        if (n <= 0)
-                return n;
-
-        for (i = 0; i < n; i++) {
-                _cleanup_free_ char *id = NULL;
-                dev_t dev;
-                struct stat st;
-                SessionDevice *sd;
-                Session *s;
-                int r;
+        r = parse_fdname(fdname, &id, &dev);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to parse fd name %s: %m", fdname);
 
-                fd = SD_LISTEN_FDS_START + i;
+        s = hashmap_get(m->sessions, id);
+        if (!s)
+                /* If the session doesn't exist anymore, the associated session device attached to this fd
+                 * doesn't either. Let's simply close this fd. */
+                return log_debug_errno(SYNTHETIC_ERRNO(ENXIO), "Failed to attach fd for unknown session: %s", id);
 
-                r = parse_fdname(fdnames[i], &id, &dev);
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to parse fd name %s: %m", fdnames[i]);
-                        close_nointr(fd);
-                        continue;
-                }
+        if (fstat(fd, &st) < 0)
+                /* The device is allowed to go away at a random point, in which case fstat() failing is
+                 * expected. */
+                return log_debug_errno(errno, "Failed to stat device fd for session %s: %m", id);
 
-                s = hashmap_get(m->sessions, id);
-                if (!s) {
-                        /* If the session doesn't exist anymore, the associated session
-                         * device attached to this fd doesn't either. Let's simply close
-                         * this fd. */
-                        log_debug("Failed to attach fd for unknown session: %s", id);
-                        close_nointr(fd);
-                        continue;
-                }
+        if (!S_ISCHR(st.st_mode) || st.st_rdev != dev)
+                return log_debug_errno(SYNTHETIC_ERRNO(ENODEV), "Device fd doesn't point to the expected character device node");
 
-                if (fstat(fd, &st) < 0) {
-                        /* The device is allowed to go away at a random point, in which
-                         * case fstat failing is expected. */
-                        log_debug_errno(errno, "Failed to stat device fd for session %s: %m", id);
-                        close_nointr(fd);
-                        continue;
-                }
+        sd = hashmap_get(s->devices, &dev);
+        if (!sd)
+                /* Weird, we got an fd for a session device which wasn't recorded in the session state
+                 * file... */
+                return log_warning_errno(SYNTHETIC_ERRNO(ENODEV), "Got fd for missing session device [%u:%u] in session %s",
+                                         major(dev), minor(dev), s->id);
 
-                if (!S_ISCHR(st.st_mode) || st.st_rdev != dev) {
-                        log_debug("Device fd doesn't point to the expected character device node");
-                        close_nointr(fd);
-                        continue;
-                }
+        log_debug("Attaching fd to session device [%u:%u] for session %s",
+                  major(dev), minor(dev), s->id);
+
+        session_device_attach_fd(sd, fd, s->was_active);
+        return 0;
+}
+
+static int manager_attach_fds(Manager *m) {
+        _cleanup_strv_free_ char **fdnames = NULL;
+        int n;
+
+        /* Upon restart, PID1 will send us back all fds of session devices that we previously opened. Each
+         * file descriptor is associated with a given session. The session ids are passed through FDNAMES. */
 
-                sd = hashmap_get(s->devices, &dev);
-                if (!sd) {
-                        /* Weird, we got an fd for a session device which wasn't
-                         * recorded in the session state file... */
-                        log_warning("Got fd for missing session device [%u:%u] in session %s",
-                                    major(dev), minor(dev), s->id);
-                        close_nointr(fd);
+        n = sd_listen_fds_with_names(true, &fdnames);
+        if (n < 0)
+                return log_warning_errno(n, "Failed to acquire passed fd list: %m");
+        if (n == 0)
+                return 0;
+
+        for (int i = 0; i < n; i++) {
+                int fd = SD_LISTEN_FDS_START + i;
+
+                if (deliver_fd(m, fdnames[i], fd) >= 0)
                         continue;
-                }
 
-                log_debug("Attaching fd to session device [%u:%u] for session %s",
-                          major(dev), minor(dev), s->id);
+                /* Hmm, we couldn't deliver the fd to any session device object? If so, let's close the fd */
+                safe_close(fd);
 
-                session_device_attach_fd(sd, fd, s->was_active);
+                /* Remove from fdstore as well */
+                (void) sd_notifyf(false,
+                                  "FDSTOREREMOVE=1\n"
+                                  "FDNAME=%s", fdnames[i]);
         }
 
         return 0;
@@ -491,11 +494,9 @@ static int manager_enumerate_sessions(Manager *m) {
                         r = k;
         }
 
-        /* We might be restarted and PID1 could have sent us back the
-         * session device fds we previously saved. */
-        k = manager_attach_fds(m);
-        if (k < 0)
-                log_warning_errno(k, "Failed to reattach session device fds: %m");
+        /* We might be restarted and PID1 could have sent us back the session device fds we previously
+         * saved. */
+        (void) manager_attach_fds(m);
 
         return r;
 }
@@ -559,7 +560,7 @@ static int manager_dispatch_device_udev(sd_device_monitor *monitor, sd_device *d
 
 static int manager_dispatch_vcsa_udev(sd_device_monitor *monitor, sd_device *device, void *userdata) {
         Manager *m = userdata;
-        const char *name, *action;
+        const char *name;
 
         assert(m);
         assert(device);
@@ -569,8 +570,7 @@ static int manager_dispatch_vcsa_udev(sd_device_monitor *monitor, sd_device *dev
 
         if (sd_device_get_sysname(device, &name) >= 0 &&
             startswith(name, "vcsa") &&
-            sd_device_get_property_value(device, "ACTION", &action) >= 0 &&
-            streq(action, "remove"))
+            device_for_action(device, DEVICE_ACTION_REMOVE))
                 seat_preallocate_vts(m->seat0);
 
         return 0;
index 7b774f4..7b6f73c 100644 (file)
@@ -11,6 +11,7 @@
 #include "hashmap.h"
 #include "list.h"
 #include "set.h"
+#include "time-util.h"
 
 typedef struct Manager Manager;
 
index 4de3a9d..2ee8c46 100644 (file)
 
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
+                       send_member="CanRebootParameter"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="SetRebootParameter"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
                        send_member="CanRebootToFirmwareSetup"/>
 
                 <allow send_destination="org.freedesktop.login1"
 
                 <allow send_destination="org.freedesktop.login1"
                        send_interface="org.freedesktop.login1.Manager"
+                       send_member="CanRebootToBootLoaderMenu"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="SetRebootToBootLoaderMenu"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="CanRebootToBootLoaderEntry"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
+                       send_member="SetRebootToBootLoaderEntry"/>
+
+                <allow send_destination="org.freedesktop.login1"
+                       send_interface="org.freedesktop.login1.Manager"
                        send_member="SetWallMessage"/>
 
                 <allow send_destination="org.freedesktop.login1"
index 5ee62ab..6dc79aa 100644 (file)
                 </defaults>
         </action>
 
+        <action id="org.freedesktop.login1.set-reboot-parameter">
+                <description gettext-domain="systemd">Set the reboot "reason" in the kernel</description>
+                <message gettext-domain="systemd">Authentication is required to set the reboot "reason" in the kernel.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>yes</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
+        </action>
+
         <action id="org.freedesktop.login1.set-reboot-to-firmware-setup">
-                <description gettext-domain="systemd">Allow indication to the firmware to boot to setup interface</description>
+                <description gettext-domain="systemd">Indicate to the firmware to boot to setup interface</description>
                 <message gettext-domain="systemd">Authentication is required to indicate to the firmware to boot to setup interface.</message>
                 <defaults>
                         <allow_any>auth_admin_keep</allow_any>
                 <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
         </action>
 
+        <action id="org.freedesktop.login1.set-reboot-to-boot-loader-menu">
+                <description gettext-domain="systemd">Indicate to the boot loader to boot to the boot loader menu</description>
+                <message gettext-domain="systemd">Authentication is required to indicate to the boot loader to boot to the boot loader menu.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>yes</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
+        </action>
+
+        <action id="org.freedesktop.login1.set-reboot-to-boot-loader-entry">
+                <description gettext-domain="systemd">Indicate to the boot loader to boot a specific entry</description>
+                <message gettext-domain="systemd">Authentication is required to indicate to the boot loader to boot into a specific boot loader entry.</message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>yes</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.reboot</annotate>
+        </action>
+
         <action id="org.freedesktop.login1.set-wall-message">
                 <description gettext-domain="systemd">Set a wall message</description>
                 <message gettext-domain="systemd">Authentication is required to set a wall message</message>
index 6712b96..fc1c4a4 100644 (file)
 #include <security/pam_modules.h>
 #include <security/pam_modutil.h>
 #include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "audit-util.h"
 #include "bus-common-errors.h"
 #include "bus-error.h"
+#include "bus-internal.h"
 #include "bus-util.h"
 #include "cgroup-util.h"
-#include "def.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "format-util.h"
@@ -31,7 +34,6 @@
 #include "stdio-util.h"
 #include "strv.h"
 #include "terminal-util.h"
-#include "util.h"
 
 static int parse_argv(
                 pam_handle_t *handle,
@@ -115,6 +117,15 @@ static int get_user_data(
         return PAM_SUCCESS;
 }
 
+static bool display_is_local(const char *display) {
+        assert(display);
+
+        return
+                display[0] == ':' &&
+                display[1] >= '0' &&
+                display[1] <= '9';
+}
+
 static int socket_from_display(const char *display, char **path) {
         size_t k;
         char *f, *c;
@@ -321,14 +332,21 @@ static const char* getenv_harder(pam_handle_t *handle, const char *key, const ch
         assert(handle);
         assert(key);
 
-        /* Looks for an environment variable, preferrably in the environment block associated with the specified PAM
-         * handle, falling back to the process' block instead. */
+        /* Looks for an environment variable, preferrably in the environment block associated with the
+         * specified PAM handle, falling back to the process' block instead. Why check both? Because we want
+         * to permit configuration of session properties from unit files that invoke PAM services, so that
+         * PAM services don't have to be reworked to set systemd-specific properties, but these properties
+         * can still be set from the unit file Environment= block. */
 
         v = pam_getenv(handle, key);
         if (!isempty(v))
                 return v;
 
-        v = getenv(key);
+        /* We use secure_getenv() here, since we might get loaded into su/sudo, which are SUID. Ideally
+         * they'd clean up the environment before invoking foreign code (such as PAM modules), but alas they
+         * currently don't (to be precise, they clean up the environment they pass to their children, but
+         * not their own environ[]). */
+        v = secure_getenv(key);
         if (!isempty(v))
                 return v;
 
index a891b0a..7f9013b 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <unistd.h>
+#include <fcntl.h>
 
 #include "sd-bus.h"
 
@@ -30,7 +31,7 @@ static int inhibit(sd_bus *bus, const char *what) {
         assert_se(r >= 0);
         assert_se(fd >= 0);
 
-        return dup(fd);
+        return fcntl(fd, F_DUPFD_CLOEXEC, 3);
 }
 
 static void print_inhibitors(sd_bus *bus) {
index 3d73353..049999a 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "bus-error.h"
 #include "fs-util.h"
+#include "format-util.h"
 #include "label.h"
 #include "main-func.h"
 #include "mkdir.h"
index 7a558df..1ee8780 100644 (file)
@@ -29,6 +29,7 @@
 #include "machine.h"
 #include "missing_capability.h"
 #include "mkdir.h"
+#include "namespace-util.h"
 #include "os-util.h"
 #include "path-util.h"
 #include "process-util.h"
index 4f89ac0..84454dd 100644 (file)
@@ -4,6 +4,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <stdio_ext.h>
+#include <sys/stat.h>
 
 #include "sd-messages.h"
 
index 31527d0..9ff9a65 100644 (file)
@@ -7,6 +7,7 @@ typedef enum KillWho KillWho;
 #include "list.h"
 #include "machined.h"
 #include "operation.h"
+#include "time-util.h"
 
 typedef enum MachineState {
         MACHINE_OPENING,    /* Machine is being registered */
index 30f2e26..d98027a 100644 (file)
 #include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-error.h"
+#include "bus-unit-procs.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
 #include "copy.h"
@@ -35,6 +37,7 @@
 #include "macro.h"
 #include "main-func.h"
 #include "mkdir.h"
+#include "nulstr-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "rlimit-util.h"
 #include "sigbus.h"
 #include "signal-util.h"
+#include "sort-util.h"
 #include "spawn-polkit-agent.h"
 #include "stdio-util.h"
 #include "string-table.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "unit-name.h"
-#include "util.h"
 #include "verbs.h"
 #include "web-util.h"
 
@@ -1990,16 +1993,6 @@ static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
         return -r;
 }
 
-static const char *nullify_dash(const char *p) {
-        if (isempty(p))
-                return NULL;
-
-        if (streq(p, "-"))
-                return NULL;
-
-        return p;
-}
-
 static int import_tar(int argc, char *argv[], void *userdata) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
         _cleanup_free_ char *ll = NULL, *fn = NULL;
@@ -2011,10 +2004,10 @@ static int import_tar(int argc, char *argv[], void *userdata) {
         assert(bus);
 
         if (argc >= 2)
-                path = nullify_dash(argv[1]);
+                path = empty_or_dash_to_null(argv[1]);
 
         if (argc >= 3)
-                local = nullify_dash(argv[2]);
+                local = empty_or_dash_to_null(argv[2]);
         else if (path) {
                 r = path_extract_filename(path, &fn);
                 if (r < 0)
@@ -2078,10 +2071,10 @@ static int import_raw(int argc, char *argv[], void *userdata) {
         assert(bus);
 
         if (argc >= 2)
-                path = nullify_dash(argv[1]);
+                path = empty_or_dash_to_null(argv[1]);
 
         if (argc >= 3)
-                local = nullify_dash(argv[2]);
+                local = empty_or_dash_to_null(argv[2]);
         else if (path) {
                 r = path_extract_filename(path, &fn);
                 if (r < 0)
@@ -2145,10 +2138,10 @@ static int import_fs(int argc, char *argv[], void *userdata) {
         assert(bus);
 
         if (argc >= 2)
-                path = nullify_dash(argv[1]);
+                path = empty_or_dash_to_null(argv[1]);
 
         if (argc >= 3)
-                local = nullify_dash(argv[2]);
+                local = empty_or_dash_to_null(argv[2]);
         else if (path) {
                 r = path_extract_filename(path, &fn);
                 if (r < 0)
@@ -2227,8 +2220,7 @@ static int export_tar(int argc, char *argv[], void *userdata) {
 
         if (argc >= 3)
                 path = argv[2];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+        path = empty_or_dash_to_null(path);
 
         if (path) {
                 determine_compression_from_filename(path);
@@ -2277,8 +2269,7 @@ static int export_raw(int argc, char *argv[], void *userdata) {
 
         if (argc >= 3)
                 path = argv[2];
-        if (isempty(path) || streq(path, "-"))
-                path = NULL;
+        path = empty_or_dash_to_null(path);
 
         if (path) {
                 determine_compression_from_filename(path);
@@ -2335,8 +2326,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) {
                 local = l;
         }
 
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+        local = empty_or_dash_to_null(local);
 
         if (local) {
                 r = tar_strip_suffixes(local, &ll);
@@ -2399,8 +2389,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) {
                 local = l;
         }
 
-        if (isempty(local) || streq(local, "-"))
-                local = NULL;
+        local = empty_or_dash_to_null(local);
 
         if (local) {
                 r = raw_strip_suffixes(local, &ll);
@@ -2666,10 +2655,15 @@ static int clean_images(int argc, char *argv[], void *userdata) {
                 return bus_log_parse_error(r);
 
         while ((r = sd_bus_message_read(reply, "(st)", &name, &usage)) > 0) {
-                log_info("Removed image '%s'. Freed exclusive disk space: %s",
-                         name, format_bytes(fb, sizeof(fb), usage));
-
-                total += usage;
+                if (usage == UINT64_MAX) {
+                        log_info("Removed image '%s'", name);
+                        total = UINT64_MAX;
+                } else {
+                        log_info("Removed image '%s'. Freed exclusive disk space: %s",
+                                 name, format_bytes(fb, sizeof(fb), usage));
+                        if (total != UINT64_MAX)
+                                total += usage;
+                }
                 c++;
         }
 
@@ -2677,8 +2671,11 @@ static int clean_images(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        log_info("Removed %u images in total. Total freed exclusive disk space %s.",
-                 c, format_bytes(fb, sizeof(fb), total));
+        if (total == UINT64_MAX)
+                log_info("Removed %u images in total.", c);
+        else
+                log_info("Removed %u images in total. Total freed exclusive disk space: %s.",
+                         c, format_bytes(fb, sizeof(fb), total));
 
         return 0;
 }
index 0b92b1c..a3bed03 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <errno.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "sd-daemon.h"
index bbbc91c..b290095 100644 (file)
@@ -8,11 +8,13 @@
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "device-util.h"
 #include "dirent-util.h"
 #include "escape.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "fstab-util.h"
 #include "main-func.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "pretty-print.h"
+#include "sort-util.h"
 #include "spawn-polkit-agent.h"
 #include "stat-util.h"
 #include "strv.h"
+#include "terminal-util.h"
 #include "unit-def.h"
 #include "unit-name.h"
 #include "user-util.h"
-#include "terminal-util.h"
 
 enum {
         ACTION_DEFAULT,
index 37f7cf8..78c8d0c 100644 (file)
@@ -18,7 +18,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         if (size != 0)
                 assert_se(fwrite(data, size, 1, f) == 1);
 
-        rewind(f);
+        fflush(f);
         assert_se(manager_new(&manager) >= 0);
         (void) netdev_load_one(manager, netdev_config);
         return 0;
index 4b79500..b056267 100644 (file)
@@ -11,6 +11,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_(unlink_tempfilep) char network_config[] = "/tmp/fuzz-networkd.XXXXXX";
 
+        if (size > 65535)
+                return 0;
+
         if (!getenv("SYSTEMD_LOG_LEVEL"))
                 log_set_max_level(LOG_CRIT);
 
@@ -18,7 +21,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
         if (size != 0)
                 assert_se(fwrite(data, size, 1, f) == 1);
 
-        rewind(f);
+        fflush(f);
         assert_se(manager_new(&manager) >= 0);
         (void) network_load_one(manager, network_config);
         return 0;
diff --git a/src/network/fuzz-network-parser.options b/src/network/fuzz-network-parser.options
new file mode 100644 (file)
index 0000000..0824b19
--- /dev/null
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
index 8fe4854..c95e750 100644 (file)
@@ -37,6 +37,8 @@ sources = files('''
         netdev/netdevsim.h
         netdev/fou-tunnel.c
         netdev/fou-tunnel.h
+        netdev/l2tp-tunnel.c
+        netdev/l2tp-tunnel.h
         networkd-address-label.c
         networkd-address-label.h
         networkd-address-pool.c
index 550a7f8..7d912ae 100644 (file)
@@ -116,7 +116,7 @@ static const char *const bond_arp_all_targets_table[_NETDEV_BOND_ARP_ALL_TARGETS
 DEFINE_STRING_TABLE_LOOKUP(bond_arp_all_targets, BondArpAllTargets);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_arp_all_targets, bond_arp_all_targets, BondArpAllTargets, "Failed to parse bond Arp all targets");
 
-static const char *bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
+static const char *const bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELECT_MAX] = {
         [NETDEV_BOND_PRIMARY_RESELECT_ALWAYS] = "always",
         [NETDEV_BOND_PRIMARY_RESELECT_BETTER]= "better",
         [NETDEV_BOND_PRIMARY_RESELECT_FAILURE]= "failure",
@@ -177,22 +177,21 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
         assert(b);
 
         if (b->mode != _NETDEV_BOND_MODE_INVALID) {
-                r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE,
-                                              bond_mode_to_kernel(b->mode));
+                r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE, bond_mode_to_kernel(b->mode));
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MODE attribute: %m");
         }
 
         if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) {
                 r = sd_netlink_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY,
-                                              bond_xmit_hash_policy_to_kernel(b->xmit_hash_policy));
+                                                 bond_xmit_hash_policy_to_kernel(b->xmit_hash_policy));
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
         }
 
         if (b->lacp_rate != _NETDEV_BOND_LACP_RATE_INVALID &&
             b->mode == NETDEV_BOND_MODE_802_3AD) {
-                r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate );
+                r = sd_netlink_message_append_u8(m, IFLA_BOND_AD_LACP_RATE, b->lacp_rate);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_LACP_RATE attribute: %m");
         }
@@ -220,8 +219,8 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_INTERVAL attribute: %m");
 
-                if ((b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC) &&
-                    (b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC)) {
+                if (b->lp_interval >= LEARNING_PACKETS_INTERVAL_MIN_SEC &&
+                    b->lp_interval <= LEARNING_PACKETS_INTERVAL_MAX_SEC) {
                         r = sd_netlink_message_append_u32(m, IFLA_BOND_LP_INTERVAL, b->lp_interval / USEC_PER_SEC);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_LP_INTERVAL attribute: %m");
@@ -313,23 +312,20 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_TLB_DYNAMIC_LB attribute: %m");
         }
 
-        if (b->arp_interval > 0)  {
-                if (b->n_arp_ip_targets > 0) {
-
-                        r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
-                        if (r < 0)
-                                return log_netdev_error_errno(netdev, r, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
-
-                        LIST_FOREACH(arp_ip_target, target, b->arp_ip_targets) {
-                                r = sd_netlink_message_append_u32(m, i++, target->ip.in.s_addr);
-                                if (r < 0)
-                                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
-                        }
+        if (b->arp_interval > 0 && b->n_arp_ip_targets > 0) {
+                r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
 
-                        r = sd_netlink_message_close_container(m);
+                LIST_FOREACH(arp_ip_target, target, b->arp_ip_targets) {
+                        r = sd_netlink_message_append_u32(m, i++, target->ip.in.s_addr);
                         if (r < 0)
-                                return log_netdev_error_errno(netdev, r, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
+                                return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
                 }
+
+                r = sd_netlink_message_close_container(m);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not close contaniner IFLA_BOND_ARP_IP_TARGET : %m");
         }
 
         return 0;
index 65dad38..2d4481e 100644 (file)
@@ -5,8 +5,10 @@
 #include <linux/ip.h>
 
 #include "conf-parser.h"
+#include "ip-protocol-list.h"
 #include "missing.h"
 #include "netdev/fou-tunnel.h"
+#include "netlink-util.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "parse-util.h"
@@ -27,6 +29,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_fou_encap_type, fou_encap_type, FooOverUDP
 static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **ret) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
         FouTunnel *t;
+        uint8_t encap_type;
         int r;
 
         assert(netdev);
@@ -43,7 +46,18 @@ static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **r
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_PORT attribute: %m");
 
-        r = sd_netlink_message_append_u8(m, FOU_ATTR_TYPE, FOU_ENCAP_GUE);
+        switch (t->fou_encap_type) {
+        case NETDEV_FOO_OVER_UDP_ENCAP_DIRECT:
+                encap_type = FOU_ENCAP_DIRECT;
+                break;
+        case NETDEV_FOO_OVER_UDP_ENCAP_GUE:
+                encap_type = FOU_ENCAP_GUE;
+                break;
+        default:
+                assert_not_reached("invalid encap type");
+        }
+
+        r = sd_netlink_message_append_u8(m, FOU_ATTR_TYPE, encap_type);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_TYPE attribute: %m");
 
@@ -55,32 +69,84 @@ static int netdev_fill_fou_tunnel_message(NetDev *netdev, sd_netlink_message **r
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append FOU_ATTR_IPPROTO attribute: %m");
 
-        *ret = m;
-        m = NULL;
-
+        *ret = TAKE_PTR(m);
         return 0;
 }
 
-static int netdev_fou_tunnel_create(NetDev *netdev) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
-        uint32_t serial;
-        FouTunnel *t;
+static int fou_tunnel_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
         int r;
 
         assert(netdev);
+        assert(netdev->state != _NETDEV_STATE_INVALID);
 
-        t = FOU(netdev);
+        r = sd_netlink_message_get_errno(m);
+        if (r == -EEXIST)
+                log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
+        else if (r < 0) {
+                log_netdev_warning_errno(netdev, r, "netdev could not be created: %m");
+                netdev_drop(netdev);
 
-        assert(t);
+                return 1;
+        }
+
+        log_netdev_debug(netdev, "FooOverUDP tunnel is created");
+        return 1;
+}
+
+static int netdev_fou_tunnel_create(NetDev *netdev) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+        int r;
+
+        assert(netdev);
+        assert(FOU(netdev));
 
         r = netdev_fill_fou_tunnel_message(netdev, &m);
         if (r < 0)
                 return r;
 
-        r = sd_netlink_send(netdev->manager->genl, m, &serial);
-        if (r < 0 && r != -EADDRINUSE)
-                return log_netdev_error_errno(netdev, r, "Failed to add FooOverUDP tunnel: %m");
+        r = netlink_call_async(netdev->manager->genl, NULL, m, fou_tunnel_create_handler,
+                               netdev_destroy_callback, netdev);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Failed to create FooOverUDP tunnel: %m");
+
+        netdev_ref(netdev);
+        return 0;
+}
+
+int config_parse_ip_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) {
+
+        uint8_t *protocol = data;
+        int r;
 
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        assert_cc(IPPROTO_MAX-1 <= UINT8_MAX);
+
+        r = parse_ip_protocol(rvalue);
+        if (r < 0) {
+                r = safe_atou8(rvalue, protocol);
+                if (r < 0)
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse IP protocol '%s' for Foo over UDP tunnel, "
+                                   "ignoring assignment: %m", rvalue);
+                return 0;
+        }
+
+        *protocol = r;
         return 0;
 }
 
@@ -94,14 +160,21 @@ static int netdev_fou_tunnel_verify(NetDev *netdev, const char *filename) {
 
         assert(t);
 
-        if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_DIRECT && t->fou_protocol <= 0) {
-                log_netdev_error(netdev, "FooOverUDP protocol not configured in %s. Rejecting configuration.", filename);
-                return -EINVAL;
-        }
-
-        if (t->fou_encap_type == NETDEV_FOO_OVER_UDP_ENCAP_GUE && t->fou_protocol > 0) {
-                log_netdev_error(netdev, "FooOverUDP GUE can't be set with protocol configured in %s. Rejecting configuration.", filename);
-                return -EINVAL;
+        switch (t->fou_encap_type) {
+        case NETDEV_FOO_OVER_UDP_ENCAP_DIRECT:
+                if (t->fou_protocol <= 0)
+                        return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                                      "FooOverUDP protocol not configured in %s. Rejecting configuration.",
+                                                      filename);
+                break;
+        case NETDEV_FOO_OVER_UDP_ENCAP_GUE:
+                if (t->fou_protocol > 0)
+                        return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                                      "FooOverUDP GUE can't be set with protocol configured in %s. Rejecting configuration.",
+                                                      filename);
+                break;
+        default:
+                assert_not_reached("Invalid fou encap type");
         }
 
         return 0;
index 9652986..51eeac4 100644 (file)
@@ -31,3 +31,4 @@ const char *fou_encap_type_to_string(FooOverUDPEncapType d) _const_;
 FooOverUDPEncapType fou_encap_type_from_string(const char *d) _pure_;
 
 CONFIG_PARSER_PROTOTYPE(config_parse_fou_encap_type);
+CONFIG_PARSER_PROTOTYPE(config_parse_ip_protocol);
index 089bbfe..0fb0996 100644 (file)
@@ -83,19 +83,16 @@ static int netdev_geneve_create(NetDev *netdev) {
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_ID attribute: %m");
         }
 
-        if (!in_addr_is_null(v->remote_family, &v->remote)) {
-
+        if (in_addr_is_null(v->remote_family, &v->remote) == 0) {
                 if (v->remote_family == AF_INET)
                         r = sd_netlink_message_append_in_addr(m, IFLA_GENEVE_REMOTE, &v->remote.in);
                 else
                         r = sd_netlink_message_append_in6_addr(m, IFLA_GENEVE_REMOTE6, &v->remote.in6);
-
                 if (r < 0)
-                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_GROUP attribute: %m");
-
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_REMOTE/IFLA_GENEVE_REMOTE6 attribute: %m");
         }
 
-        if (v->ttl) {
+        if (v->ttl > 0) {
                 r = sd_netlink_message_append_u8(m, IFLA_GENEVE_TTL, v->ttl);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_TTL attribute: %m");
diff --git a/src/network/netdev/l2tp-tunnel.c b/src/network/netdev/l2tp-tunnel.c
new file mode 100644 (file)
index 0000000..2a74d89
--- /dev/null
@@ -0,0 +1,734 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <arpa/inet.h>
+#include <linux/l2tp.h>
+#include <linux/genetlink.h>
+
+#include "sd-netlink.h"
+
+#include "conf-parser.h"
+#include "hashmap.h"
+#include "l2tp-tunnel.h"
+#include "missing.h"
+#include "netlink-util.h"
+#include "networkd-address.h"
+#include "networkd-manager.h"
+#include "parse-util.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "util.h"
+
+static const char* const l2tp_l2spec_type_table[_NETDEV_L2TP_L2SPECTYPE_MAX] = {
+        [NETDEV_L2TP_L2SPECTYPE_NONE]    = "none",
+        [NETDEV_L2TP_L2SPECTYPE_DEFAULT] = "default",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(l2tp_l2spec_type, L2tpL2specType);
+
+static const char* const l2tp_encap_type_table[_NETDEV_L2TP_ENCAPTYPE_MAX] = {
+        [NETDEV_L2TP_ENCAPTYPE_UDP] = "udp",
+        [NETDEV_L2TP_ENCAPTYPE_IP]  = "ip",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(l2tp_encap_type, L2tpEncapType);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_l2tp_encap_type, l2tp_encap_type, L2tpEncapType, "Failed to parse L2TP Encapsulation Type");
+
+static const char* const l2tp_local_address_type_table[_NETDEV_L2TP_LOCAL_ADDRESS_MAX] = {
+         [NETDEV_L2TP_LOCAL_ADDRESS_AUTO]    = "auto",
+         [NETDEV_L2TP_LOCAL_ADDRESS_STATIC]  = "static",
+         [NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC] = "dynamic",
+};
+
+DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(l2tp_local_address_type, L2tpLocalAddressType);
+
+static void l2tp_session_free(L2tpSession *s) {
+        if (!s)
+                return;
+
+        if (s->tunnel && s->section)
+                ordered_hashmap_remove(s->tunnel->sessions_by_section, s);
+
+        network_config_section_free(s->section);
+
+        free(s->name);
+
+        free(s);
+}
+
+DEFINE_NETWORK_SECTION_FUNCTIONS(L2tpSession, l2tp_session_free);
+
+static int l2tp_session_new_static(L2tpTunnel *t, const char *filename, unsigned section_line, L2tpSession **ret) {
+        _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+        _cleanup_(l2tp_session_freep) L2tpSession *s = NULL;
+        int r;
+
+        assert(t);
+        assert(ret);
+        assert(filename);
+        assert(section_line > 0);
+
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
+
+        s = ordered_hashmap_get(t->sessions_by_section, n);
+        if (s) {
+                *ret = TAKE_PTR(s);
+                return 0;
+        }
+
+        s = new(L2tpSession, 1);
+        if (!s)
+                return -ENOMEM;
+
+        *s = (L2tpSession) {
+                .l2tp_l2spec_type = NETDEV_L2TP_L2SPECTYPE_DEFAULT,
+                .tunnel = t,
+                .section = TAKE_PTR(n),
+        };
+
+        r = ordered_hashmap_ensure_allocated(&t->sessions_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = ordered_hashmap_put(t->sessions_by_section, s->section, s);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(s);
+        return 0;
+}
+
+static int netdev_l2tp_fill_message_tunnel(NetDev *netdev, union in_addr_union *local_address, sd_netlink_message **ret) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+        uint16_t encap_type;
+        L2tpTunnel *t;
+        int r;
+
+        assert(netdev);
+        assert(local_address);
+
+        t = L2TP(netdev);
+
+        assert(t);
+
+        r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_TUNNEL_CREATE, &m);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
+
+        r = sd_netlink_message_append_u32(m, L2TP_ATTR_CONN_ID, t->tunnel_id);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_CONN_ID attribute: %m");
+
+        r = sd_netlink_message_append_u32(m, L2TP_ATTR_PEER_CONN_ID, t->peer_tunnel_id);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_PEER_CONN_ID attribute: %m");
+
+        r = sd_netlink_message_append_u8(m, L2TP_ATTR_PROTO_VERSION, 3);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_PROTO_VERSION attribute: %m");
+
+        switch(t->l2tp_encap_type) {
+        case NETDEV_L2TP_ENCAPTYPE_IP:
+                encap_type = L2TP_ENCAPTYPE_IP;
+                break;
+        case NETDEV_L2TP_ENCAPTYPE_UDP:
+        default:
+                encap_type = L2TP_ENCAPTYPE_UDP;
+                break;
+        }
+
+        r = sd_netlink_message_append_u16(m, L2TP_ATTR_ENCAP_TYPE, encap_type);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_ENCAP_TYPE attribute: %m");
+
+        if (t->family == AF_INET) {
+                r = sd_netlink_message_append_in_addr(m, L2TP_ATTR_IP_SADDR, &local_address->in);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_IP_SADDR attribute: %m");
+
+                r = sd_netlink_message_append_in_addr(m, L2TP_ATTR_IP_DADDR, &t->remote.in);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_IP_DADDR attribute: %m");
+        } else {
+                r = sd_netlink_message_append_in6_addr(m, L2TP_ATTR_IP6_SADDR, &local_address->in6);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_IP6_SADDR attribute: %m");
+
+                r = sd_netlink_message_append_in6_addr(m, L2TP_ATTR_IP6_DADDR, &t->remote.in6);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_IP6_DADDR attribute: %m");
+        }
+
+        if (encap_type == L2TP_ENCAPTYPE_UDP) {
+                r = sd_netlink_message_append_u16(m, L2TP_ATTR_UDP_SPORT, t->l2tp_udp_sport);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_UDP_SPORT, attribute: %m");
+
+                r = sd_netlink_message_append_u16(m, L2TP_ATTR_UDP_DPORT, t->l2tp_udp_dport);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_UDP_DPORT attribute: %m");
+
+                if (t->udp_csum) {
+                        r = sd_netlink_message_append_u8(m, L2TP_ATTR_UDP_CSUM, t->udp_csum);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_UDP_CSUM attribute: %m");
+                }
+
+                if (t->udp6_csum_tx) {
+                        r = sd_netlink_message_append_flag(m, L2TP_ATTR_UDP_ZERO_CSUM6_TX);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_UDP_ZERO_CSUM6_TX attribute: %m");
+                }
+
+                if (t->udp6_csum_rx) {
+                        r = sd_netlink_message_append_flag(m, L2TP_ATTR_UDP_ZERO_CSUM6_RX);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_UDP_ZERO_CSUM6_RX attribute: %m");
+                }
+        }
+
+        *ret = TAKE_PTR(m);
+
+        return 0;
+}
+
+static int netdev_l2tp_fill_message_session(NetDev *netdev, L2tpSession *session, sd_netlink_message **ret) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+        uint16_t l2_spec_len;
+        uint8_t l2_spec_type;
+        int r;
+
+        assert(netdev);
+        assert(session);
+        assert(session->tunnel);
+
+        r = sd_genl_message_new(netdev->manager->genl, SD_GENL_L2TP, L2TP_CMD_SESSION_CREATE, &m);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Failed to create generic netlink message: %m");
+
+        r = sd_netlink_message_append_u32(m, L2TP_ATTR_CONN_ID, session->tunnel->tunnel_id);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_CONN_ID attribute: %m");
+
+        r = sd_netlink_message_append_u32(m, L2TP_ATTR_PEER_CONN_ID, session->tunnel->peer_tunnel_id);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_PEER_CONN_ID attribute: %m");
+
+        r = sd_netlink_message_append_u32(m, L2TP_ATTR_SESSION_ID, session->session_id);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_SESSION_ID attribute: %m");
+
+        r = sd_netlink_message_append_u32(m, L2TP_ATTR_PEER_SESSION_ID, session->peer_session_id);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_PEER_SESSION_ID attribute: %m");
+
+        r = sd_netlink_message_append_u16(m, L2TP_ATTR_PW_TYPE, L2TP_PWTYPE_ETH);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_PW_TYPE attribute: %m");
+
+        switch (session->l2tp_l2spec_type) {
+        case NETDEV_L2TP_L2SPECTYPE_NONE:
+                l2_spec_type = L2TP_L2SPECTYPE_NONE;
+                l2_spec_len = 0;
+                break;
+        case NETDEV_L2TP_L2SPECTYPE_DEFAULT:
+        default:
+                l2_spec_type = L2TP_L2SPECTYPE_DEFAULT;
+                l2_spec_len = 4;
+                break;
+        }
+
+        r = sd_netlink_message_append_u8(m, L2TP_ATTR_L2SPEC_TYPE, l2_spec_type);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_L2SPEC_TYPE attribute: %m");
+
+        r = sd_netlink_message_append_u8(m, L2TP_ATTR_L2SPEC_LEN, l2_spec_len);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_L2SPEC_LEN attribute: %m");
+
+        r = sd_netlink_message_append_string(m, L2TP_ATTR_IFNAME, session->name);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not append L2TP_ATTR_IFNAME attribute: %m");
+
+        *ret = TAKE_PTR(m);
+
+        return 0;
+}
+
+static int l2tp_acquire_local_address_one(L2tpTunnel *t, Address *a, union in_addr_union *ret) {
+        if (a->family != t->family)
+                return -EINVAL;
+
+        if (in_addr_is_null(a->family, &a->in_addr_peer) <= 0)
+                return -EINVAL;
+
+        if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_STATIC &&
+            !FLAGS_SET(a->flags, IFA_F_PERMANENT))
+                return -EINVAL;
+
+        if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC &&
+            FLAGS_SET(a->flags, IFA_F_PERMANENT))
+                return -EINVAL;
+
+        *ret = a->in_addr;
+        return 0;
+}
+
+static int l2tp_acquire_local_address(L2tpTunnel *t, Link *link, union in_addr_union *ret) {
+        Address *a;
+        Iterator i;
+
+        assert(t);
+        assert(link);
+        assert(ret);
+        assert(IN_SET(t->family, AF_INET, AF_INET6));
+
+        if (!in_addr_is_null(t->family, &t->local)) {
+                /* local address is explicitly specified. */
+                *ret = t->local;
+                return 0;
+        }
+
+        SET_FOREACH(a, link->addresses, i)
+                if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
+                        return 1;
+
+        SET_FOREACH(a, link->addresses_foreign, i)
+                if (l2tp_acquire_local_address_one(t, a, ret) >= 0)
+                        return 1;
+
+        return -ENODATA;
+}
+
+static void l2tp_session_destroy_callback(L2tpSession *session) {
+        if (!session)
+                return;
+
+        netdev_unref(NETDEV(session->tunnel));
+}
+
+static int l2tp_create_session_handler(sd_netlink *rtnl, sd_netlink_message *m, L2tpSession *session) {
+        NetDev *netdev;
+        int r;
+
+        assert(session);
+        assert(session->tunnel);
+
+        netdev = NETDEV(session->tunnel);
+
+        r = sd_netlink_message_get_errno(m);
+        if (r == -EEXIST)
+                log_netdev_info(netdev, "L2TP session %s exists, using existing without changing its parameters",
+                                session->name);
+        else if (r < 0) {
+                log_netdev_warning_errno(netdev, r, "L2TP session %s could not be created: %m", session->name);
+                return 1;
+        }
+
+        log_netdev_debug(netdev, "L2TP session %s created", session->name);
+        return 1;
+}
+
+static int l2tp_create_session(NetDev *netdev, L2tpSession *session) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *n = NULL;
+        int r;
+
+        r = netdev_l2tp_fill_message_session(netdev, session, &n);
+        if (r < 0)
+                return r;
+
+        r = netlink_call_async(netdev->manager->genl, NULL, n, l2tp_create_session_handler,
+                               l2tp_session_destroy_callback, session);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Failed to create L2TP session %s: %m", session->name);
+
+        netdev_ref(netdev);
+        return 0;
+}
+
+static int l2tp_create_tunnel_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
+        L2tpSession *session;
+        L2tpTunnel *t;
+        Iterator i;
+        int r;
+
+        assert(netdev);
+        assert(netdev->state != _NETDEV_STATE_INVALID);
+
+        t = L2TP(netdev);
+
+        assert(t);
+
+        r = sd_netlink_message_get_errno(m);
+        if (r == -EEXIST)
+                log_netdev_info(netdev, "netdev exists, using existing without changing its parameters");
+        else if (r < 0) {
+                log_netdev_warning_errno(netdev, r, "netdev could not be created: %m");
+                netdev_drop(netdev);
+
+                return 1;
+        }
+
+        log_netdev_debug(netdev, "L2TP tunnel is created");
+
+        ORDERED_HASHMAP_FOREACH(session, t->sessions_by_section, i)
+                (void) l2tp_create_session(netdev, session);
+
+        return 1;
+}
+
+static int l2tp_create_tunnel(NetDev *netdev, Link *link) {
+        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
+        union in_addr_union local_address;
+        L2tpTunnel *t;
+        int r;
+
+        assert(netdev);
+
+        t = L2TP(netdev);
+
+        assert(t);
+
+        r = l2tp_acquire_local_address(t, link, &local_address);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Could not find local address.");
+
+        if (r > 0 && DEBUG_LOGGING) {
+                _cleanup_free_ char *str = NULL;
+
+                (void) in_addr_to_string(t->family, &local_address, &str);
+                log_netdev_debug(netdev, "Local address %s acquired.", strna(str));
+        }
+
+        r = netdev_l2tp_fill_message_tunnel(netdev, &local_address, &m);
+        if (r < 0)
+                return r;
+
+        r = netlink_call_async(netdev->manager->genl, NULL, m, l2tp_create_tunnel_handler,
+                               netdev_destroy_callback, netdev);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r, "Failed to create L2TP tunnel: %m");
+
+        netdev_ref(netdev);
+
+        return 0;
+}
+
+int config_parse_l2tp_tunnel_address(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        L2tpTunnel *t = userdata;
+        union in_addr_union *addr = data;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        if (streq(lvalue, "Local")) {
+                L2tpLocalAddressType addr_type;
+
+                if (isempty(rvalue))
+                        addr_type = NETDEV_L2TP_LOCAL_ADDRESS_AUTO;
+                else
+                        addr_type = l2tp_local_address_type_from_string(rvalue);
+
+                if (addr_type >= 0) {
+                        if (in_addr_is_null(t->family, &t->remote) != 0)
+                                /* If Remote= is not specified yet, then also clear family. */
+                                t->family = AF_UNSPEC;
+
+                        t->local = IN_ADDR_NULL;
+                        t->local_address_type = addr_type;
+
+                        return 0;
+                }
+        }
+
+        if (t->family == AF_UNSPEC)
+                r = in_addr_from_string_auto(rvalue, &t->family, addr);
+        else
+                r = in_addr_from_string(t->family, rvalue, addr);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Invalid L2TP Tunnel address specified in %s='%s', ignoring assignment: %m", lvalue, rvalue);
+                return 0;
+        }
+
+        return 0;
+}
+
+int config_parse_l2tp_tunnel_id(
+                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) {
+
+        uint32_t *id = data, k;
+        int r;
+
+        assert(filename);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = safe_atou32(rvalue, &k);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse L2TP tunnel id. Ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        if (k == 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Invalid L2TP tunnel id. Ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        *id = k;
+
+        return 0;
+}
+
+int config_parse_l2tp_session_id(
+                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_(l2tp_session_free_or_set_invalidp) L2tpSession *session = NULL;
+        L2tpTunnel *t = userdata;
+        uint32_t k;
+        int r;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = l2tp_session_new_static(t, filename, section_line, &session);
+        if (r < 0)
+                return r;
+
+        r = safe_atou32(rvalue, &k);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse L2TP session id. Ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        if (k == 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Invalid L2TP session id. Ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        if (streq(lvalue, "SessionId"))
+                session->session_id = k;
+        else
+                session->peer_session_id = k;
+
+        session = NULL;
+        return 0;
+}
+
+int config_parse_l2tp_session_l2spec(
+                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_(l2tp_session_free_or_set_invalidp) L2tpSession *session = NULL;
+        L2tpTunnel *t = userdata;
+        L2tpL2specType spec;
+        int r;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = l2tp_session_new_static(t, filename, section_line, &session);
+        if (r < 0)
+                return r;
+
+        spec = l2tp_l2spec_type_from_string(rvalue);
+        if (spec < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Failed to parse layer2 specific header type. Ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        session->l2tp_l2spec_type = spec;
+
+        session = NULL;
+        return 0;
+}
+
+int config_parse_l2tp_session_name(
+                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_(l2tp_session_free_or_set_invalidp) L2tpSession *session = NULL;
+        L2tpTunnel *t = userdata;
+        int r;
+
+        assert(filename);
+        assert(section);
+        assert(lvalue);
+        assert(rvalue);
+        assert(data);
+
+        r = l2tp_session_new_static(t, filename, section_line, &session);
+        if (r < 0)
+                return r;
+
+        if (!ifname_valid(rvalue)) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Failed to parse L2TP tunnel session name. Ignoring assignment: %s", rvalue);
+                return 0;
+        }
+
+        r = free_and_strdup(&session->name, rvalue);
+        if (r < 0)
+                return log_oom();
+
+        session = NULL;
+        return 0;
+}
+
+static void l2tp_tunnel_init(NetDev *netdev) {
+        L2tpTunnel *t;
+
+        assert(netdev);
+
+        t = L2TP(netdev);
+
+        assert(t);
+
+        t->l2tp_encap_type = NETDEV_L2TP_ENCAPTYPE_UDP;
+        t->udp6_csum_rx = true;
+        t->udp6_csum_tx = true;
+}
+
+static int l2tp_session_verify(L2tpSession *session) {
+        NetDev *netdev;
+
+        assert(session);
+        assert(session->tunnel);
+
+        netdev = NETDEV(session->tunnel);
+
+        if (section_is_invalid(session->section))
+                return -EINVAL;
+
+        if (!session->name)
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "%s: L2TP session without name configured. "
+                                              "Ignoring [L2TPSession] section from line %u",
+                                              session->section->filename, session->section->line);
+
+        if (session->session_id == 0 || session->peer_session_id == 0)
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "%s: L2TP session without session IDs configured. "
+                                              "Ignoring [L2TPSession] section from line %u",
+                                              session->section->filename, session->section->line);
+
+        return 0;
+}
+
+static int netdev_l2tp_tunnel_verify(NetDev *netdev, const char *filename) {
+        L2tpTunnel *t;
+        L2tpSession *session;
+        Iterator i;
+
+        assert(netdev);
+        assert(filename);
+
+        t = L2TP(netdev);
+
+        assert(t);
+
+        if (!IN_SET(t->family, AF_INET, AF_INET6))
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "%s: L2TP tunnel with invalid address family configured. Ignoring",
+                                              filename);
+
+        if (in_addr_is_null(t->family, &t->remote))
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "%s: L2TP tunnel without a remote address configured. Ignoring",
+                                              filename);
+
+        if (t->tunnel_id == 0 || t->peer_tunnel_id == 0)
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "%s: L2TP tunnel without tunnel IDs configured. Ignoring",
+                                              filename);
+
+        ORDERED_HASHMAP_FOREACH(session, t->sessions_by_section, i)
+                if (l2tp_session_verify(session) < 0)
+                        l2tp_session_free(session);
+
+        return 0;
+}
+
+static void l2tp_tunnel_done(NetDev *netdev) {
+        L2tpTunnel *t;
+
+        assert(netdev);
+
+        t = L2TP(netdev);
+
+        assert(t);
+
+        ordered_hashmap_free_with_destructor(t->sessions_by_section, l2tp_session_free);
+}
+
+const NetDevVTable l2tptnl_vtable = {
+        .object_size = sizeof(L2tpTunnel),
+        .init = l2tp_tunnel_init,
+        .sections = "Match\0NetDev\0L2TP\0L2TPSession\0",
+        .create_after_configured = l2tp_create_tunnel,
+        .done = l2tp_tunnel_done,
+        .create_type = NETDEV_CREATE_AFTER_CONFIGURED,
+        .config_verify = netdev_l2tp_tunnel_verify,
+};
diff --git a/src/network/netdev/l2tp-tunnel.h b/src/network/netdev/l2tp-tunnel.h
new file mode 100644 (file)
index 0000000..a97c924
--- /dev/null
@@ -0,0 +1,77 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <linux/l2tp.h>
+
+#include "in-addr-util.h"
+#include "netdev.h"
+#include "networkd-util.h"
+
+typedef enum L2tpL2specType {
+        NETDEV_L2TP_L2SPECTYPE_NONE = L2TP_L2SPECTYPE_NONE,
+        NETDEV_L2TP_L2SPECTYPE_DEFAULT = L2TP_L2SPECTYPE_DEFAULT,
+        _NETDEV_L2TP_L2SPECTYPE_MAX,
+        _NETDEV_L2TP_L2SPECTYPE_INVALID = -1,
+} L2tpL2specType;
+
+typedef enum L2tpEncapType {
+        NETDEV_L2TP_ENCAPTYPE_UDP = L2TP_ENCAPTYPE_UDP,
+        NETDEV_L2TP_ENCAPTYPE_IP = L2TP_ENCAPTYPE_IP,
+        _NETDEV_L2TP_ENCAPTYPE_MAX,
+        _NETDEV_L2TP_ENCAPTYPE_INVALID = -1,
+} L2tpEncapType;
+
+typedef enum L2tpLocalAddressType {
+        NETDEV_L2TP_LOCAL_ADDRESS_AUTO,
+        NETDEV_L2TP_LOCAL_ADDRESS_STATIC,
+        NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC,
+        _NETDEV_L2TP_LOCAL_ADDRESS_MAX,
+        _NETDEV_L2TP_LOCAL_ADDRESS_INVALID = -1,
+} L2tpLocalAddressType;
+
+typedef struct L2tpTunnel L2tpTunnel;
+
+typedef struct L2tpSession {
+        L2tpTunnel *tunnel;
+        NetworkConfigSection *section;
+
+        char *name;
+
+        uint32_t session_id;
+        uint32_t peer_session_id;
+        L2tpL2specType l2tp_l2spec_type;
+} L2tpSession;
+
+struct L2tpTunnel {
+        NetDev meta;
+
+        uint16_t l2tp_udp_sport;
+        uint16_t l2tp_udp_dport;
+
+        uint32_t tunnel_id;
+        uint32_t peer_tunnel_id;
+
+        int family;
+
+        bool udp_csum;
+        bool udp6_csum_rx;
+        bool udp6_csum_tx;
+
+        L2tpLocalAddressType local_address_type;
+        union in_addr_union local;
+        union in_addr_union remote;
+
+        L2tpEncapType l2tp_encap_type;
+
+        OrderedHashmap *sessions_by_section;
+};
+
+DEFINE_NETDEV_CAST(L2TP, L2tpTunnel);
+extern const NetDevVTable l2tptnl_vtable;
+
+CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_address);
+CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_tunnel_id);
+CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_encap_type);
+CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_session_l2spec);
+CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_session_id);
+CONFIG_PARSER_PROTOTYPE(config_parse_l2tp_session_name);
index f7ca98f..1a3d6ca 100644 (file)
@@ -20,6 +20,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"")
 #include "netdev/vxcan.h"
 #include "netdev/wireguard.h"
 #include "netdev/fou-tunnel.h"
+#include "netdev/l2tp-tunnel.h"
 #include "vlan-util.h"
 %}
 struct ConfigPerfItem;
@@ -33,11 +34,11 @@ struct ConfigPerfItem;
 %struct-type
 %includes
 %%
-Match.Host,                        config_parse_net_condition,           CONDITION_HOST,                offsetof(NetDev, match_host)
-Match.Virtualization,              config_parse_net_condition,           CONDITION_VIRTUALIZATION,      offsetof(NetDev, match_virt)
-Match.KernelCommandLine,           config_parse_net_condition,           CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, match_kernel_cmdline)
-Match.KernelVersion,               config_parse_net_condition,           CONDITION_KERNEL_VERSION,      offsetof(NetDev, match_kernel_version)
-Match.Architecture,                config_parse_net_condition,           CONDITION_ARCHITECTURE,        offsetof(NetDev, match_arch)
+Match.Host,                        config_parse_net_condition,           CONDITION_HOST,                offsetof(NetDev, conditions)
+Match.Virtualization,              config_parse_net_condition,           CONDITION_VIRTUALIZATION,      offsetof(NetDev, conditions)
+Match.KernelCommandLine,           config_parse_net_condition,           CONDITION_KERNEL_COMMAND_LINE, offsetof(NetDev, conditions)
+Match.KernelVersion,               config_parse_net_condition,           CONDITION_KERNEL_VERSION,      offsetof(NetDev, conditions)
+Match.Architecture,                config_parse_net_condition,           CONDITION_ARCHITECTURE,        offsetof(NetDev, conditions)
 NetDev.Description,                config_parse_string,                  0,                             offsetof(NetDev, description)
 NetDev.Name,                       config_parse_ifname,                  0,                             offsetof(NetDev, ifname)
 NetDev.Kind,                       config_parse_netdev_kind,             0,                             offsetof(NetDev, kind)
@@ -72,11 +73,25 @@ Tunnel.FOUSourcePort,              config_parse_ip_port,                 0,
 Tunnel.Encapsulation,              config_parse_fou_encap_type,          0,                             offsetof(Tunnel, fou_encap_type)
 Tunnel.IPv6RapidDeploymentPrefix,  config_parse_6rd_prefix,              0,                             0
 Tunnel.ERSPANIndex,                config_parse_uint32,                  0,                             offsetof(Tunnel, erspan_index)
-Tunnel.SerializeTunneledPackets,   config_parse_tristate,                0,                             offsetof(Tunnel, erspan_sequence)
+Tunnel.SerializeTunneledPackets,   config_parse_tristate,                0,                             offsetof(Tunnel, gre_erspan_sequence)
 Tunnel.ISATAP,                     config_parse_tristate,                0,                             offsetof(Tunnel, isatap)
-FooOverUDP.Protocol,               config_parse_uint8,                   0,                             offsetof(FouTunnel, fou_protocol)
+FooOverUDP.Protocol,               config_parse_ip_protocol,             0,                             offsetof(FouTunnel, fou_protocol)
 FooOverUDP.Encapsulation,          config_parse_fou_encap_type,          0,                             offsetof(FouTunnel, fou_encap_type)
 FooOverUDP.Port,                   config_parse_ip_port,                 0,                             offsetof(FouTunnel, port)
+L2TP.TunnelId,                     config_parse_l2tp_tunnel_id,          0,                             offsetof(L2tpTunnel, tunnel_id)
+L2TP.PeerTunnelId,                 config_parse_l2tp_tunnel_id,          0,                             offsetof(L2tpTunnel, peer_tunnel_id)
+L2TP.UDPSourcePort,                config_parse_ip_port,                 0,                             offsetof(L2tpTunnel, l2tp_udp_sport)
+L2TP.UDPDestinationPort,           config_parse_ip_port,                 0,                             offsetof(L2tpTunnel, l2tp_udp_dport)
+L2TP.Local,                        config_parse_l2tp_tunnel_address,     0,                             offsetof(L2tpTunnel, local)
+L2TP.Remote,                       config_parse_l2tp_tunnel_address,     0,                             offsetof(L2tpTunnel, remote)
+L2TP.EncapsulationType,            config_parse_l2tp_encap_type,         0,                             offsetof(L2tpTunnel, l2tp_encap_type)
+L2TP.UDPCheckSum,                  config_parse_bool,                    0,                             offsetof(L2tpTunnel, udp_csum)
+L2TP.UDP6CheckSumRx,               config_parse_bool,                    0,                             offsetof(L2tpTunnel, udp6_csum_rx)
+L2TP.UDP6CheckSumTx,               config_parse_bool,                    0,                             offsetof(L2tpTunnel, udp6_csum_tx)
+L2TPSession.SessionId,             config_parse_l2tp_session_id,         0,                             0
+L2TPSession.PeerSessionId,         config_parse_l2tp_session_id,         0,                             0
+L2TPSession.Layer2SpecificHeader,  config_parse_l2tp_session_l2spec,     0,                             0
+L2TPSession.Name,                  config_parse_l2tp_session_name,       0,                             0
 Peer.Name,                         config_parse_ifname,                  0,                             offsetof(Veth, ifname_peer)
 Peer.MACAddress,                   config_parse_hwaddr,                  0,                             offsetof(Veth, mac_peer)
 VXCAN.Peer,                        config_parse_ifname,                  0,                             offsetof(VxCan, ifname_peer)
@@ -167,8 +182,10 @@ VRF.Table,                         config_parse_uint32,                  0,
 WireGuard.FwMark,                  config_parse_unsigned,                0,                             offsetof(Wireguard, fwmark)
 WireGuard.ListenPort,              config_parse_wireguard_listen_port,   0,                             offsetof(Wireguard, port)
 WireGuard.PrivateKey,              config_parse_wireguard_private_key,   0,                             0
+WireGuard.PrivateKeyFile,          config_parse_wireguard_private_key_file, 0,                          0
 WireGuardPeer.AllowedIPs,          config_parse_wireguard_allowed_ips,   0,                             0
 WireGuardPeer.Endpoint,            config_parse_wireguard_endpoint,      0,                             0
 WireGuardPeer.PublicKey,           config_parse_wireguard_public_key,    0,                             0
 WireGuardPeer.PresharedKey,        config_parse_wireguard_preshared_key, 0,                             0
+WireGuardPeer.PresharedKeyFile,    config_parse_wireguard_preshared_key_file, 0,                        0
 WireGuardPeer.PersistentKeepalive, config_parse_wireguard_keepalive,     0,                             0
index 0263917..c1bcfc6 100644 (file)
@@ -7,34 +7,34 @@
 #include "conf-parser.h"
 #include "fd-util.h"
 #include "list.h"
-#include "netlink-util.h"
-#include "network-internal.h"
-#include "netdev/netdev.h"
-#include "networkd-manager.h"
-#include "networkd-link.h"
-#include "siphash24.h"
-#include "stat-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-
-#include "netdev/bridge.h"
 #include "netdev/bond.h"
+#include "netdev/bridge.h"
+#include "netdev/dummy.h"
+#include "netdev/fou-tunnel.h"
 #include "netdev/geneve.h"
-#include "netdev/vlan.h"
-#include "netdev/macvlan.h"
 #include "netdev/ipvlan.h"
-#include "netdev/vxlan.h"
+#include "netdev/l2tp-tunnel.h"
+#include "netdev/macvlan.h"
+#include "netdev/netdev.h"
+#include "netdev/netdevsim.h"
 #include "netdev/tunnel.h"
 #include "netdev/tuntap.h"
+#include "netdev/vcan.h"
 #include "netdev/veth.h"
-#include "netdev/dummy.h"
+#include "netdev/vlan.h"
 #include "netdev/vrf.h"
-#include "netdev/vcan.h"
 #include "netdev/vxcan.h"
+#include "netdev/vxlan.h"
 #include "netdev/wireguard.h"
-#include "netdev/netdevsim.h"
-#include "netdev/fou-tunnel.h"
+#include "netlink-util.h"
+#include "network-internal.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "siphash24.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
 
 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_BRIDGE] = &bridge_vtable,
@@ -65,6 +65,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_NETDEVSIM] = &netdevsim_vtable,
         [NETDEV_KIND_FOU] = &foutnl_vtable,
         [NETDEV_KIND_ERSPAN] = &erspan_vtable,
+        [NETDEV_KIND_L2TP] = &l2tptnl_vtable,
 };
 
 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
@@ -96,6 +97,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_NETDEVSIM] = "netdevsim",
         [NETDEV_KIND_FOU] = "fou",
         [NETDEV_KIND_ERSPAN] = "erspan",
+        [NETDEV_KIND_L2TP] = "l2tp",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
@@ -172,12 +174,7 @@ static NetDev *netdev_free(NetDev *netdev) {
         free(netdev->description);
         free(netdev->ifname);
         free(netdev->mac);
-
-        condition_free_list(netdev->match_host);
-        condition_free_list(netdev->match_virt);
-        condition_free_list(netdev->match_kernel_cmdline);
-        condition_free_list(netdev->match_kernel_version);
-        condition_free_list(netdev->match_arch);
+        condition_free_list(netdev->conditions);
 
         /* Invoke the per-kind done() destructor, but only if the state field is initialized. We conditionalize that
          * because we parse .netdev files twice: once to determine the kind (with a short, minimal NetDev structure
@@ -598,6 +595,14 @@ static int netdev_create(NetDev *netdev, Link *link, link_netlink_message_handle
         return 0;
 }
 
+static int netdev_create_after_configured(NetDev *netdev, Link *link) {
+        assert(netdev);
+        assert(link);
+        assert(NETDEV_VTABLE(netdev)->create_after_configured);
+
+        return NETDEV_VTABLE(netdev)->create_after_configured(netdev, link);
+}
+
 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
 int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
         int r;
@@ -605,9 +610,8 @@ int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callb
         assert(netdev);
         assert(netdev->manager);
         assert(netdev->manager->rtnl);
-        assert(NETDEV_VTABLE(netdev));
 
-        switch (NETDEV_VTABLE(netdev)->create_type) {
+        switch (netdev_get_create_type(netdev)) {
         case NETDEV_CREATE_MASTER:
                 r = netdev_enslave(netdev, link, callback);
                 if (r < 0)
@@ -620,6 +624,11 @@ int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callb
                         return r;
 
                 break;
+        case NETDEV_CREATE_AFTER_CONFIGURED:
+                r = netdev_create_after_configured(netdev, link);
+                if (r < 0)
+                        return r;
+                break;
         default:
                 assert_not_reached("Can not join independent netdev");
         }
@@ -661,7 +670,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
         };
 
         dropin_dirname = strjoina(basename(filename), ".d");
-        r = config_parse_many(filename, network_dirs, dropin_dirname,
+        r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
                               "Match\0NetDev\0",
                               config_item_perf_lookup, network_netdev_gperf_lookup,
                               CONFIG_PARSE_WARN|CONFIG_PARSE_RELAXED, netdev_raw);
@@ -669,20 +678,18 @@ int netdev_load_one(Manager *manager, const char *filename) {
                 return r;
 
         /* skip out early if configuration does not match the environment */
-        if (net_match_config(NULL, NULL, NULL, NULL, NULL,
-                             netdev_raw->match_host, netdev_raw->match_virt,
-                             netdev_raw->match_kernel_cmdline, netdev_raw->match_kernel_version,
-                             netdev_raw->match_arch,
-                             NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
+        if (!condition_test_list(netdev_raw->conditions, NULL, NULL, NULL)) {
+                log_debug("%s: Conditions in the file do not match the system environment, skipping.", filename);
                 return 0;
+        }
 
         if (netdev_raw->kind == _NETDEV_KIND_INVALID) {
-                log_warning("NetDev has no Kind configured in %s. Ignoring", filename);
+                log_warning("NetDev has no Kind= configured in %s. Ignoring", filename);
                 return 0;
         }
 
         if (!netdev_raw->ifname) {
-                log_warning("NetDev without Name configured in %s. Ignoring", filename);
+                log_warning("NetDev without Name= configured in %s. Ignoring", filename);
                 return 0;
         }
 
@@ -697,12 +704,13 @@ int netdev_load_one(Manager *manager, const char *filename) {
         netdev->n_ref = 1;
         netdev->manager = manager;
         netdev->kind = netdev_raw->kind;
-        netdev->state = NETDEV_STATE_LOADING; /* we initialize the state here for the first time, so that done() will be called on destruction */
+        netdev->state = NETDEV_STATE_LOADING; /* we initialize the state here for the first time,
+                                                 so that done() will be called on destruction */
 
         if (NETDEV_VTABLE(netdev)->init)
                 NETDEV_VTABLE(netdev)->init(netdev);
 
-        r = config_parse_many(filename, network_dirs, dropin_dirname,
+        r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
                               NETDEV_VTABLE(netdev)->sections,
                               config_item_perf_lookup, network_netdev_gperf_lookup,
                               CONFIG_PARSE_WARN, netdev);
@@ -723,7 +731,9 @@ int netdev_load_one(Manager *manager, const char *filename) {
         if (!netdev->mac && netdev->kind != NETDEV_KIND_VLAN) {
                 r = netdev_get_mac(netdev->ifname, &netdev->mac);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
+                        return log_netdev_error_errno(netdev, r,
+                                                      "Failed to generate predictable MAC address for %s: %m",
+                                                      netdev->ifname);
         }
 
         r = hashmap_ensure_allocated(&netdev->manager->netdevs, &string_hash_ops);
@@ -731,6 +741,19 @@ int netdev_load_one(Manager *manager, const char *filename) {
                 return r;
 
         r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
+        if (r == -EEXIST) {
+                NetDev *n = hashmap_get(netdev->manager->netdevs, netdev->ifname);
+
+                assert(n);
+                log_netdev_warning_errno(netdev, r,
+                                         "The setting Name=%s in %s conflicts with the one in %s, ignoring",
+                                         netdev->ifname, netdev->filename, n->filename);
+
+                /* Clear ifname before netdev_free() is called. Otherwise, the NetDev object 'n' is
+                 * removed from the hashmap 'manager->netdevs'. */
+                netdev->ifname = mfree(netdev->ifname);
+                return 0;
+        }
         if (r < 0)
                 return r;
 
@@ -738,16 +761,10 @@ int netdev_load_one(Manager *manager, const char *filename) {
 
         log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
 
-        switch (NETDEV_VTABLE(netdev)->create_type) {
-        case NETDEV_CREATE_MASTER:
-        case NETDEV_CREATE_INDEPENDENT:
+        if (IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT)) {
                 r = netdev_create(netdev, NULL, NULL);
                 if (r < 0)
                         return r;
-
-                break;
-        default:
-                break;
         }
 
         switch (netdev->kind) {
@@ -778,6 +795,9 @@ int netdev_load_one(Manager *manager, const char *filename) {
         case NETDEV_KIND_IP6TNL:
                 independent = IP6TNL(netdev)->independent;
                 break;
+        case NETDEV_KIND_ERSPAN:
+                independent = ERSPAN(netdev)->independent;
+                break;
         default:
                 break;
         }
@@ -802,11 +822,11 @@ int netdev_load(Manager *manager) {
 
         hashmap_clear_with_destructor(manager->netdevs, netdev_unref);
 
-        r = conf_files_list_strv(&files, ".netdev", NULL, 0, network_dirs);
+        r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate netdev files: %m");
 
-        STRV_FOREACH_BACKWARDS(f, files) {
+        STRV_FOREACH(f, files) {
                 r = netdev_load_one(manager, *f);
                 if (r < 0)
                         return r;
index d6524da..ad4dd2e 100644 (file)
@@ -46,7 +46,9 @@ typedef enum NetDevKind {
         NETDEV_KIND_NETDEVSIM,
         NETDEV_KIND_FOU,
         NETDEV_KIND_ERSPAN,
+        NETDEV_KIND_L2TP,
         _NETDEV_KIND_MAX,
+        _NETDEV_KIND_TUNNEL, /* Used by config_parse_stacked_netdev() */
         _NETDEV_KIND_INVALID = -1
 } NetDevKind;
 
@@ -64,6 +66,7 @@ typedef enum NetDevCreateType {
         NETDEV_CREATE_INDEPENDENT,
         NETDEV_CREATE_MASTER,
         NETDEV_CREATE_STACKED,
+        NETDEV_CREATE_AFTER_CONFIGURED,
         _NETDEV_CREATE_MAX,
         _NETDEV_CREATE_INVALID = -1,
 } NetDevCreateType;
@@ -78,11 +81,7 @@ typedef struct NetDev {
 
         char *filename;
 
-        Condition *match_host;
-        Condition *match_virt;
-        Condition *match_kernel_cmdline;
-        Condition *match_kernel_version;
-        Condition *match_arch;
+        LIST_HEAD(Condition, conditions);
 
         NetDevState state;
         NetDevKind kind;
@@ -122,6 +121,9 @@ typedef struct NetDevVTable {
         /* create netdev, if not done via rtnl */
         int (*create)(NetDev *netdev);
 
+        /* create netdev after link is fully configured */
+        int (*create_after_configured)(NetDev *netdev, Link *link);
+
         /* perform additional configuration after netdev has been createad */
         int (*post_create)(NetDev *netdev, Link *link, sd_netlink_message *message);
 
@@ -161,10 +163,19 @@ int netdev_get(Manager *manager, const char *name, NetDev **ret);
 int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *newlink);
 int netdev_get_mac(const char *ifname, struct ether_addr **ret);
 int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t cb);
+int netdev_join_after_configured(NetDev *netdev, Link *link, link_netlink_message_handler_t callback);
 
 const char *netdev_kind_to_string(NetDevKind d) _const_;
 NetDevKind netdev_kind_from_string(const char *d) _pure_;
 
+static inline NetDevCreateType netdev_get_create_type(NetDev *netdev) {
+        assert(netdev);
+        assert(NETDEV_VTABLE(netdev));
+
+        return NETDEV_VTABLE(netdev)->create_type;
+}
+
+
 CONFIG_PARSER_PROTOTYPE(config_parse_netdev_kind);
 
 /* gperf */
index 57bd183..84f6af8 100644 (file)
@@ -10,6 +10,7 @@
 
 #include "conf-parser.h"
 #include "missing.h"
+#include "netlink-util.h"
 #include "networkd-link.h"
 #include "netdev/tunnel.h"
 #include "parse-util.h"
@@ -30,14 +31,20 @@ static const char* const ip6tnl_mode_table[_NETDEV_IP6_TNL_MODE_MAX] = {
 DEFINE_STRING_TABLE_LOOKUP(ip6tnl_mode, Ip6TnlMode);
 DEFINE_CONFIG_PARSE_ENUM(config_parse_ip6tnl_mode, ip6tnl_mode, Ip6TnlMode, "Failed to parse ip6 tunnel Mode");
 
-static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
-        Tunnel *t = IPIP(netdev);
+static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+        Tunnel *t;
         int r;
 
         assert(netdev);
+
+        if (netdev->kind == NETDEV_KIND_IPIP)
+                t = IPIP(netdev);
+        else
+                t = SIT(netdev);
+
         assert(m);
         assert(t);
-        assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
+        assert(t->family == AF_INET);
 
         if (link) {
                 r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
@@ -55,14 +62,13 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin
 
         r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
         if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL  attribute: %m");
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
 
         r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
 
         if (t->fou_tunnel) {
-
                 r = sd_netlink_message_append_u16(m, IFLA_IPTUN_ENCAP_TYPE, t->fou_encap_type);
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_TYPE attribute: %m");
@@ -76,80 +82,61 @@ static int netdev_ipip_fill_message_create(NetDev *netdev, Link *link, sd_netlin
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_DPORT attribute: %m");
         }
 
-        return r;
-}
-
-static int netdev_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
-        Tunnel *t = SIT(netdev);
-        int r;
-
-        assert(netdev);
-        assert(m);
-        assert(t);
-        assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
-
-        if (link) {
-                r = sd_netlink_message_append_u32(m, IFLA_IPTUN_LINK, link->ifindex);
-                if (r < 0)
-                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
-        }
-
-        r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
-        if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
-
-        r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_REMOTE, &t->remote.in);
-        if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
-
-        r = sd_netlink_message_append_u8(m, IFLA_IPTUN_TTL, t->ttl);
-        if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_TTL attribute: %m");
-
-        r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PMTUDISC, t->pmtudisc);
-        if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PMTUDISC attribute: %m");
+        if (netdev->kind == NETDEV_KIND_SIT) {
+                if (t->sixrd_prefixlen > 0) {
+                        r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &t->sixrd_prefix);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIX attribute: %m");
 
-        if (t->sixrd_prefixlen > 0) {
-                r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_6RD_PREFIX, &t->sixrd_prefix);
-                if (r < 0)
-                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIX attribute: %m");
-
-                /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
-                 * expecting to receive the prefixlen as a u16.
-                 */
-                r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, t->sixrd_prefixlen);
-                if (r < 0)
-                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIXLEN attribute: %m");
-        }
+                        /* u16 is deliberate here, even though we're passing a netmask that can never be >128. The kernel is
+                         * expecting to receive the prefixlen as a u16.
+                         */
+                        r = sd_netlink_message_append_u16(m, IFLA_IPTUN_6RD_PREFIXLEN, t->sixrd_prefixlen);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_6RD_PREFIXLEN attribute: %m");
+                }
 
-        if (t->isatap >= 0) {
-                uint16_t flags = 0;
+                if (t->isatap >= 0) {
+                        uint16_t flags = 0;
 
-                SET_FLAG(flags, SIT_ISATAP, t->isatap);
+                        SET_FLAG(flags, SIT_ISATAP, t->isatap);
 
-                r = sd_netlink_message_append_u16(m, IFLA_IPTUN_FLAGS, flags);
-                if (r < 0)
-                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
+                        r = sd_netlink_message_append_u16(m, IFLA_IPTUN_FLAGS, flags);
+                        if (r < 0)
+                                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_FLAGS attribute: %m");
+                }
         }
 
         return r;
 }
 
-static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
+        uint32_t ikey = 0;
+        uint32_t okey = 0;
+        uint16_t iflags = 0;
+        uint16_t oflags = 0;
         Tunnel *t;
         int r;
 
         assert(netdev);
+        assert(m);
 
-        if (netdev->kind == NETDEV_KIND_GRE)
+        switch (netdev->kind) {
+        case NETDEV_KIND_GRE:
                 t = GRE(netdev);
-        else
+                break;
+        case NETDEV_KIND_ERSPAN:
+                t = ERSPAN(netdev);
+                break;
+        case NETDEV_KIND_GRETAP:
                 t = GRETAP(netdev);
+                break;
+        default:
+                assert_not_reached("invalid netdev kind");
+        }
 
         assert(t);
-        assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
-        assert(m);
+        assert(t->family == AF_INET);
 
         if (link) {
                 r = sd_netlink_message_append_u32(m, IFLA_GRE_LINK, link->ifindex);
@@ -157,13 +144,19 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
         }
 
+        if (netdev->kind == NETDEV_KIND_ERSPAN) {
+                r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ERSPAN_INDEX attribute: %m");
+        }
+
         r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
 
         r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
         if (r < 0)
-                log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
 
         r = sd_netlink_message_append_u8(m, IFLA_GRE_TTL, t->ttl);
         if (r < 0)
@@ -171,35 +164,12 @@ static int netdev_gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink
 
         r = sd_netlink_message_append_u8(m, IFLA_GRE_TOS, t->tos);
         if (r < 0)
-                log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TOS attribute: %m");
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_TOS attribute: %m");
 
         r = sd_netlink_message_append_u8(m, IFLA_GRE_PMTUDISC, t->pmtudisc);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_PMTUDISC attribute: %m");
 
-        return r;
-}
-
-static int netdev_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
-        uint32_t ikey = 0;
-        uint32_t okey = 0;
-        uint16_t iflags = 0;
-        uint16_t oflags = 0;
-        Tunnel *t;
-        int r;
-
-        assert(netdev);
-
-        t = ERSPAN(netdev);
-
-        assert(t);
-        assert(IN_SET(t->family, AF_INET, AF_UNSPEC));
-        assert(m);
-
-        r = sd_netlink_message_append_u32(m, IFLA_GRE_ERSPAN_INDEX, t->erspan_index);
-        if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ERSPAN_INDEX attribute: %m");
-
         if (t->key != 0) {
                 ikey = okey = htobe32(t->key);
                 iflags |= GRE_KEY;
@@ -216,10 +186,10 @@ static int netdev_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netl
                 oflags |= GRE_KEY;
         }
 
-        if (t->erspan_sequence > 0) {
+        if (t->gre_erspan_sequence > 0) {
                 iflags |= GRE_SEQ;
                 oflags |= GRE_SEQ;
-        } else if (t->erspan_sequence == 0) {
+        } else if (t->gre_erspan_sequence == 0) {
                 iflags &= ~GRE_SEQ;
                 oflags &= ~GRE_SEQ;
         }
@@ -240,13 +210,19 @@ static int netdev_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netl
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_OFLAGS, attribute: %m");
 
-        r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
-        if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
+        if (t->fou_tunnel) {
+                r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_TYPE, t->fou_encap_type);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ENCAP_TYPE attribute: %m");
 
-        r = sd_netlink_message_append_in_addr(m, IFLA_GRE_REMOTE, &t->remote.in);
-        if (r < 0)
-                log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_REMOTE attribute: %m");
+                r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_SPORT, htobe16(t->encap_src_port));
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ENCAP_SPORT attribute: %m");
+
+                r = sd_netlink_message_append_u16(m, IFLA_GRE_ENCAP_DPORT, htobe16(t->fou_destination_port));
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ENCAP_DPORT attribute: %m");
+        }
 
         return r;
 }
@@ -297,11 +273,12 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl
         return r;
 }
 
-static int netdev_vti_fill_message_key(NetDev *netdev, Link *link, sd_netlink_message *m) {
+static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
         uint32_t ikey, okey;
         Tunnel *t;
         int r;
 
+        assert(netdev);
         assert(m);
 
         if (netdev->kind == NETDEV_KIND_VTI)
@@ -310,6 +287,14 @@ static int netdev_vti_fill_message_key(NetDev *netdev, Link *link, sd_netlink_me
                 t = VTI6(netdev);
 
         assert(t);
+        assert((netdev->kind == NETDEV_KIND_VTI && t->family == AF_INET) ||
+               (netdev->kind == NETDEV_KIND_VTI6 && t->family == AF_INET6));
+
+        if (link) {
+                r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
+                if (r < 0)
+                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_LINK attribute: %m");
+        }
 
         if (t->key != 0)
                 ikey = okey = htobe32(t->key);
@@ -326,65 +311,13 @@ static int netdev_vti_fill_message_key(NetDev *netdev, Link *link, sd_netlink_me
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m");
 
-        return 0;
-}
-
-static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
-        Tunnel *t = VTI(netdev);
-        int r;
-
-        assert(netdev);
-        assert(m);
-        assert(t);
-        assert(t->family == AF_INET);
-
-        if (link) {
-                r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
-                if (r < 0)
-                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
-        }
-
-        r = netdev_vti_fill_message_key(netdev, link, m);
-        if (r < 0)
-                return r;
-
-        r = sd_netlink_message_append_in_addr(m, IFLA_VTI_LOCAL, &t->local.in);
-        if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
-
-        r = sd_netlink_message_append_in_addr(m, IFLA_VTI_REMOTE, &t->remote.in);
-        if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
-
-        return r;
-}
-
-static int netdev_vti6_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
-        Tunnel *t = VTI6(netdev);
-        int r;
-
-        assert(netdev);
-        assert(m);
-        assert(t);
-        assert(t->family == AF_INET6);
-
-        if (link) {
-                r = sd_netlink_message_append_u32(m, IFLA_VTI_LINK, link->ifindex);
-                if (r < 0)
-                        return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
-        }
-
-        r = netdev_vti_fill_message_key(netdev, link, m);
-        if (r < 0)
-                return r;
-
-        r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_LOCAL, &t->local.in6);
+        r = netlink_message_append_in_addr_union(m, IFLA_VTI_LOCAL, t->family, &t->local);
         if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_LOCAL attribute: %m");
 
-        r = sd_netlink_message_append_in6_addr(m, IFLA_VTI_REMOTE, &t->remote.in6);
+        r = netlink_message_append_in_addr_union(m, IFLA_VTI_REMOTE, t->family, &t->remote);
         if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_REMOTE attribute: %m");
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_REMOTE attribute: %m");
 
         return r;
 }
@@ -426,7 +359,7 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl
         if (t->copy_dscp)
                 t->flags |= IP6_TNL_F_RCV_DSCP_COPY;
 
-        if (t->allow_localremote != -1)
+        if (t->allow_localremote >= 0)
                 SET_FLAG(t->flags, IP6_TNL_F_ALLOW_LOCAL_REMOTE, t->allow_localremote);
 
         if (t->encap_limit != IPV6_DEFAULT_TNL_ENCAP_LIMIT) {
@@ -454,7 +387,7 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl
 
         r = sd_netlink_message_append_u8(m, IFLA_IPTUN_PROTO, proto);
         if (r < 0)
-                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_MODE attribute: %m");
+                return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_PROTO attribute: %m");
 
         return r;
 }
@@ -502,42 +435,37 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
 
         assert(t);
 
-        if (!IN_SET(t->family, AF_INET, AF_INET6, AF_UNSPEC)) {
-                log_netdev_error(netdev,
-                                 "Tunnel with invalid address family configured in %s. Ignoring", filename);
-                return -EINVAL;
-        }
+        if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_IPIP, NETDEV_KIND_SIT, NETDEV_KIND_GRE, NETDEV_KIND_GRETAP) &&
+            t->family != AF_INET)
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "vti/ipip/sit/gre tunnel without a local/remote IPv4 address configured in %s. Ignoring", filename);
 
-        if (IN_SET(netdev->kind, NETDEV_KIND_VTI, NETDEV_KIND_IPIP, NETDEV_KIND_SIT, NETDEV_KIND_GRE, NETDEV_KIND_GRETAP, NETDEV_KIND_ERSPAN) &&
-            (t->family != AF_INET || in_addr_is_null(t->family, &t->local))) {
-                log_netdev_error(netdev,
-                                 "vti/ipip/sit/gre/gretap/erspan tunnel without a local IPv4 address configured in %s. Ignoring", filename);
-                return -EINVAL;
-        }
+        if (IN_SET(netdev->kind, NETDEV_KIND_GRETAP, NETDEV_KIND_ERSPAN) &&
+            (t->family != AF_INET || in_addr_is_null(t->family, &t->remote)))
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "gretap/erspan tunnel without a remote IPv4 address configured in %s. Ignoring", filename);
 
         if (IN_SET(netdev->kind, NETDEV_KIND_VTI6, NETDEV_KIND_IP6TNL, NETDEV_KIND_IP6GRE, NETDEV_KIND_IP6GRETAP) &&
-            (t->family != AF_INET6 || in_addr_is_null(t->family, &t->local))) {
-                log_netdev_error(netdev,
-                                 "vti6/ip6tnl/ip6gre/ip6gretap tunnel without a local IPv6 address configured in %s. Ignoring", filename);
-                return -EINVAL;
-        }
+            t->family != AF_INET6)
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "vti6/ip6tnl/ip6gre tunnel without a local/remote IPv6 address configured in %s. Ignoring", filename);
+
+        if (netdev->kind == NETDEV_KIND_IP6GRETAP &&
+            (t->family != AF_INET6 || in_addr_is_null(t->family, &t->remote)))
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "ip6gretap tunnel without a remote IPv6 address configured in %s. Ignoring", filename);
 
         if (netdev->kind == NETDEV_KIND_IP6TNL &&
-            t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID) {
-                log_netdev_error(netdev,
-                                 "ip6tnl without mode configured in %s. Ignoring", filename);
-                return -EINVAL;
-        }
+            t->ip6tnl_mode == _NETDEV_IP6_TNL_MODE_INVALID)
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "ip6tnl without mode configured in %s. Ignoring", filename);
 
-        if (t->fou_tunnel && t->fou_destination_port <= 0) {
-                log_netdev_error(netdev, "FooOverUDP missing port configured in %s. Ignoring", filename);
-                return -EINVAL;
-        }
+        if (t->fou_tunnel && t->fou_destination_port <= 0)
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "FooOverUDP missing port configured in %s. Ignoring", filename);
 
-        if (netdev->kind == NETDEV_KIND_ERSPAN && (t->erspan_index >= (1 << 20) || t->erspan_index == 0)) {
-                log_netdev_error(netdev, "Invalid erspan index %d. Ignoring", t->erspan_index);
-                return -EINVAL;
-        }
+        if (netdev->kind == NETDEV_KIND_ERSPAN && (t->erspan_index >= (1 << 20) || t->erspan_index == 0))
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Invalid erspan index %d. Ignoring", t->erspan_index);
 
         return 0;
 }
@@ -574,8 +502,8 @@ int config_parse_tunnel_address(const char *unit,
                  * unspecified, also clear the address family.
                  */
                 if (t->family != AF_UNSPEC &&
-                    in_addr_is_null(t->family, &t->local) &&
-                    in_addr_is_null(t->family, &t->remote))
+                    in_addr_is_null(t->family, &t->local) != 0 &&
+                    in_addr_is_null(t->family, &t->remote) != 0)
                         t->family = AF_UNSPEC;
                 return 0;
         }
@@ -751,23 +679,26 @@ int config_parse_6rd_prefix(const char* unit,
         return 0;
 }
 
-static void ipip_init(NetDev *n) {
-        Tunnel *t = IPIP(n);
+static void ipip_sit_init(NetDev *n) {
+        Tunnel *t;
 
         assert(n);
-        assert(t);
-
-        t->pmtudisc = true;
-        t->fou_encap_type = FOU_ENCAP_DIRECT;
-}
 
-static void sit_init(NetDev *n) {
-        Tunnel *t = SIT(n);
+        switch (n->kind) {
+        case NETDEV_KIND_IPIP:
+                t = IPIP(n);
+                break;
+        case NETDEV_KIND_SIT:
+                t = SIT(n);
+                break;
+        default:
+                assert_not_reached("invalid netdev kind");
+        }
 
-        assert(n);
         assert(t);
 
         t->pmtudisc = true;
+        t->fou_encap_type = FOU_ENCAP_DIRECT;
         t->isatap = -1;
 }
 
@@ -786,19 +717,30 @@ static void vti_init(NetDev *n) {
         t->pmtudisc = true;
 }
 
-static void gre_init(NetDev *n) {
+static void gre_erspan_init(NetDev *n) {
         Tunnel *t;
 
         assert(n);
 
-        if (n->kind == NETDEV_KIND_GRE)
+        switch (n->kind) {
+        case NETDEV_KIND_GRE:
                 t = GRE(n);
-        else
+                break;
+        case NETDEV_KIND_ERSPAN:
+                t = ERSPAN(n);
+                break;
+        case NETDEV_KIND_GRETAP:
                 t = GRETAP(n);
+                break;
+        default:
+                assert_not_reached("invalid netdev kind");
+        }
 
         assert(t);
 
         t->pmtudisc = true;
+        t->gre_erspan_sequence = -1;
+        t->fou_encap_type = FOU_ENCAP_DIRECT;
 }
 
 static void ip6gre_init(NetDev *n) {
@@ -816,18 +758,6 @@ static void ip6gre_init(NetDev *n) {
         t->ttl = DEFAULT_TNL_HOP_LIMIT;
 }
 
-static void erspan_init(NetDev *n) {
-        Tunnel *t;
-
-        assert(n);
-
-        t = ERSPAN(n);
-
-        assert(t);
-
-        t->erspan_sequence = -1;
-}
-
 static void ip6tnl_init(NetDev *n) {
         Tunnel *t = IP6TNL(n);
 
@@ -843,18 +773,18 @@ static void ip6tnl_init(NetDev *n) {
 
 const NetDevVTable ipip_vtable = {
         .object_size = sizeof(Tunnel),
-        .init = ipip_init,
+        .init = ipip_sit_init,
         .sections = "Match\0NetDev\0Tunnel\0",
-        .fill_message_create = netdev_ipip_fill_message_create,
+        .fill_message_create = netdev_ipip_sit_fill_message_create,
         .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
 
 const NetDevVTable sit_vtable = {
         .object_size = sizeof(Tunnel),
-        .init = sit_init,
+        .init = ipip_sit_init,
         .sections = "Match\0NetDev\0Tunnel\0",
-        .fill_message_create = netdev_sit_fill_message_create,
+        .fill_message_create = netdev_ipip_sit_fill_message_create,
         .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
@@ -872,25 +802,25 @@ const NetDevVTable vti6_vtable = {
         .object_size = sizeof(Tunnel),
         .init = vti_init,
         .sections = "Match\0NetDev\0Tunnel\0",
-        .fill_message_create = netdev_vti6_fill_message_create,
+        .fill_message_create = netdev_vti_fill_message_create,
         .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
 
 const NetDevVTable gre_vtable = {
         .object_size = sizeof(Tunnel),
-        .init = gre_init,
+        .init = gre_erspan_init,
         .sections = "Match\0NetDev\0Tunnel\0",
-        .fill_message_create = netdev_gre_fill_message_create,
+        .fill_message_create = netdev_gre_erspan_fill_message_create,
         .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
 
 const NetDevVTable gretap_vtable = {
         .object_size = sizeof(Tunnel),
-        .init = gre_init,
+        .init = gre_erspan_init,
         .sections = "Match\0NetDev\0Tunnel\0",
-        .fill_message_create = netdev_gre_fill_message_create,
+        .fill_message_create = netdev_gre_erspan_fill_message_create,
         .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
@@ -924,9 +854,9 @@ const NetDevVTable ip6tnl_vtable = {
 
 const NetDevVTable erspan_vtable = {
         .object_size = sizeof(Tunnel),
-        .init = erspan_init,
+        .init = gre_erspan_init,
         .sections = "Match\0NetDev\0Tunnel\0",
-        .fill_message_create = netdev_erspan_fill_message_create,
-        .create_type = NETDEV_CREATE_INDEPENDENT,
+        .fill_message_create = netdev_gre_erspan_fill_message_create,
+        .create_type = NETDEV_CREATE_STACKED,
         .config_verify = netdev_tunnel_verify,
 };
index 8f511dd..3637e4f 100644 (file)
@@ -29,7 +29,7 @@ typedef struct Tunnel {
         int family;
         int ipv6_flowlabel;
         int allow_localremote;
-        int erspan_sequence;
+        int gre_erspan_sequence;
         int isatap;
 
         unsigned ttl;
index 4cb2eca..4b855ae 100644 (file)
@@ -33,24 +33,20 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_ID attribute: %m");
         }
 
-        if (!in_addr_is_null(v->remote_family, &v->remote)) {
-
+        if (in_addr_is_null(v->remote_family, &v->remote) == 0) {
                 if (v->remote_family == AF_INET)
                         r = sd_netlink_message_append_in_addr(m, IFLA_VXLAN_GROUP, &v->remote.in);
                 else
                         r = sd_netlink_message_append_in6_addr(m, IFLA_VXLAN_GROUP6, &v->remote.in6);
-
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GROUP attribute: %m");
         }
 
-        if (!in_addr_is_null(v->local_family, &v->local)) {
-
+        if (in_addr_is_null(v->local_family, &v->local) == 0) {
                 if (v->local_family == AF_INET)
                         r = sd_netlink_message_append_in_addr(m, IFLA_VXLAN_LOCAL, &v->local.in);
                 else
                         r = sd_netlink_message_append_in6_addr(m, IFLA_VXLAN_LOCAL6, &v->local.in6);
-
                 if (r < 0)
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_LOCAL attribute: %m");
         }
index 0c0b16d..7959c1c 100644 (file)
 #include "sd-resolve.h"
 
 #include "alloc-util.h"
+#include "event-util.h"
 #include "fd-util.h"
+#include "fileio.h"
 #include "hexdecoct.h"
+#include "memory-util.h"
+#include "netlink-util.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-util.h"
 #include "parse-util.h"
+#include "path-util.h"
 #include "resolve-private.h"
 #include "string-util.h"
 #include "strv.h"
-#include "wireguard.h"
 #include "wireguard-netlink.h"
+#include "wireguard.h"
 
 static void resolve_endpoints(NetDev *netdev);
 
-static WireguardPeer *wireguard_peer_new(Wireguard *w, unsigned section) {
-        WireguardPeer *peer;
+static void wireguard_peer_free(WireguardPeer *peer) {
+        WireguardIPmask *mask;
+
+        if (!peer)
+                return;
+
+        if (peer->wireguard) {
+                LIST_REMOVE(peers, peer->wireguard->peers, peer);
+
+                set_remove(peer->wireguard->peers_with_unresolved_endpoint, peer);
+                set_remove(peer->wireguard->peers_with_failed_endpoint, peer);
+
+                if (peer->section)
+                        hashmap_remove(peer->wireguard->peers_by_section, peer->section);
+        }
+
+        network_config_section_free(peer->section);
+
+        while ((mask = peer->ipmasks)) {
+                LIST_REMOVE(ipmasks, peer->ipmasks, mask);
+                free(mask);
+        }
+
+        free(peer->endpoint_host);
+        free(peer->endpoint_port);
+        free(peer->preshared_key_file);
+        explicit_bzero_safe(peer->preshared_key, WG_KEY_LEN);
+
+        free(peer);
+}
+
+DEFINE_NETWORK_SECTION_FUNCTIONS(WireguardPeer, wireguard_peer_free);
+
+static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigned section_line, WireguardPeer **ret) {
+        _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
+        _cleanup_(wireguard_peer_freep) WireguardPeer *peer = NULL;
+        int r;
 
         assert(w);
+        assert(ret);
+        assert(filename);
+        assert(section_line > 0);
+
+        r = network_config_section_new(filename, section_line, &n);
+        if (r < 0)
+                return r;
 
-        if (w->last_peer_section == section && w->peers)
-                return w->peers;
+        peer = hashmap_get(w->peers_by_section, n);
+        if (peer) {
+                *ret = TAKE_PTR(peer);
+                return 0;
+        }
 
         peer = new(WireguardPeer, 1);
         if (!peer)
-                return NULL;
+                return -ENOMEM;
 
         *peer = (WireguardPeer) {
                 .flags = WGPEER_F_REPLACE_ALLOWEDIPS,
+                .wireguard = w,
+                .section = TAKE_PTR(n),
         };
 
         LIST_PREPEND(peers, w->peers, peer);
-        w->last_peer_section = section;
 
-        return peer;
+        r = hashmap_ensure_allocated(&w->peers_by_section, &network_config_hash_ops);
+        if (r < 0)
+                return r;
+
+        r = hashmap_put(w->peers_by_section, peer->section, peer);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(peer);
+        return 0;
 }
 
 static int wireguard_set_ipmask_one(NetDev *netdev, sd_netlink_message *message, const WireguardIPmask *mask, uint16_t index) {
@@ -62,10 +122,7 @@ static int wireguard_set_ipmask_one(NetDev *netdev, sd_netlink_message *message,
         if (r < 0)
                 goto cancel;
 
-        if (mask->family == AF_INET)
-                r = sd_netlink_message_append_in_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in);
-        else if (mask->family == AF_INET6)
-                r = sd_netlink_message_append_in6_addr(message, WGALLOWEDIP_A_IPADDR, &mask->ip.in6);
+        r = netlink_message_append_in_addr_union(message, WGALLOWEDIP_A_IPADDR, mask->family, &mask->ip);
         if (r < 0)
                 goto cancel;
 
@@ -122,12 +179,11 @@ static int wireguard_set_peer_one(NetDev *netdev, sd_netlink_message *message, c
                 if (r < 0)
                         goto cancel;
 
-                if (peer->endpoint.sa.sa_family == AF_INET)
-                        r = sd_netlink_message_append_sockaddr_in(message, WGPEER_A_ENDPOINT, &peer->endpoint.in);
-                else if (peer->endpoint.sa.sa_family == AF_INET6)
-                        r = sd_netlink_message_append_sockaddr_in6(message, WGPEER_A_ENDPOINT, &peer->endpoint.in6);
-                if (r < 0)
-                        goto cancel;
+                if (IN_SET(peer->endpoint.sa.sa_family, AF_INET, AF_INET6)) {
+                        r = netlink_message_append_sockaddr_union(message, WGPEER_A_ENDPOINT, &peer->endpoint);
+                        if (r < 0)
+                                goto cancel;
+                }
         }
 
         r = sd_netlink_message_open_container(message, WGPEER_A_ALLOWEDIPS);
@@ -229,23 +285,19 @@ static int wireguard_set_interface(NetDev *netdev) {
         return 0;
 }
 
-static WireguardEndpoint* wireguard_endpoint_free(WireguardEndpoint *e) {
-        if (!e)
-                return NULL;
-        e->host = mfree(e->host);
-        e->port = mfree(e->port);
-        return mfree(e);
-}
+static void wireguard_peer_destroy_callback(WireguardPeer *peer) {
+        NetDev *netdev;
 
-static void wireguard_endpoint_destroy_callback(WireguardEndpoint *e) {
-        assert(e);
-        assert(e->netdev);
+        assert(peer);
+        assert(peer->wireguard);
 
-        netdev_unref(e->netdev);
-        wireguard_endpoint_free(e);
-}
+        netdev = NETDEV(peer->wireguard);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(WireguardEndpoint*, wireguard_endpoint_free);
+        if (section_is_invalid(peer->section))
+                wireguard_peer_free(peer);
+
+        netdev_unref(netdev);
+}
 
 static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
         NetDev *netdev = userdata;
@@ -258,8 +310,9 @@ static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
         if (!netdev_is_managed(netdev))
                 return 0;
 
-        assert(!w->unresolved_endpoints);
-        w->unresolved_endpoints = TAKE_PTR(w->failed_endpoints);
+        assert(set_isempty(w->peers_with_unresolved_endpoint));
+
+        SWAP_TWO(w->peers_with_unresolved_endpoint, w->peers_with_failed_endpoint);
 
         resolve_endpoints(netdev);
 
@@ -271,69 +324,70 @@ static int on_resolve_retry(sd_event_source *s, usec_t usec, void *userdata) {
  * increasing time in milliseconds to wait starting at 200ms and capped at 25 seconds.
  */
 static int exponential_backoff_milliseconds(unsigned n_retries) {
-        return (2 << MAX(n_retries, 7U)) * 100 * USEC_PER_MSEC;
+        return (2 << MIN(n_retries, 7U)) * 100 * USEC_PER_MSEC;
 }
 
 static int wireguard_resolve_handler(sd_resolve_query *q,
                                      int ret,
                                      const struct addrinfo *ai,
-                                     WireguardEndpoint *e) {
-        _cleanup_(netdev_unrefp) NetDev *netdev_will_unrefed = NULL;
+                                     WireguardPeer *peer) {
         NetDev *netdev;
         Wireguard *w;
         int r;
 
-        assert(e);
-        assert(e->netdev);
+        assert(peer);
+        assert(peer->wireguard);
 
-        netdev = e->netdev;
-        w = WIREGUARD(netdev);
-        assert(w);
+        w = peer->wireguard;
+        netdev = NETDEV(w);
 
         if (!netdev_is_managed(netdev))
                 return 0;
 
         if (ret != 0) {
-                log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", e->host, e->port, gai_strerror(ret));
-                LIST_PREPEND(endpoints, w->failed_endpoints, e);
-                (void) sd_resolve_query_set_destroy_callback(q, NULL); /* Avoid freeing endpoint by destroy callback. */
-                netdev_will_unrefed = netdev; /* But netdev needs to be unrefed. */
+                log_netdev_error(netdev, "Failed to resolve host '%s:%s': %s", peer->endpoint_host, peer->endpoint_port, gai_strerror(ret));
+
+                r = set_ensure_allocated(&w->peers_with_failed_endpoint, NULL);
+                if (r < 0) {
+                        log_oom();
+                        peer->section->invalid = true;
+                        goto resolve_next;
+                }
+
+                r = set_put(w->peers_with_failed_endpoint, peer);
+                if (r < 0) {
+                        log_netdev_error(netdev, "Failed to save a peer, dropping the peer: %m");
+                        peer->section->invalid = true;
+                        goto resolve_next;
+                }
+
         } else if ((ai->ai_family == AF_INET && ai->ai_addrlen == sizeof(struct sockaddr_in)) ||
                    (ai->ai_family == AF_INET6 && ai->ai_addrlen == sizeof(struct sockaddr_in6)))
-                memcpy(&e->peer->endpoint, ai->ai_addr, ai->ai_addrlen);
+                memcpy(&peer->endpoint, ai->ai_addr, ai->ai_addrlen);
         else
-                log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint: %s:%s", e->host, e->port);
+                log_netdev_error(netdev, "Neither IPv4 nor IPv6 address found for peer endpoint %s:%s, ignoring the address.",
+                                 peer->endpoint_host, peer->endpoint_port);
 
-        if (w->unresolved_endpoints) {
+resolve_next:
+        if (!set_isempty(w->peers_with_unresolved_endpoint)) {
                 resolve_endpoints(netdev);
                 return 0;
         }
 
         (void) wireguard_set_interface(netdev);
-        if (w->failed_endpoints) {
-                _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
+
+        if (!set_isempty(w->peers_with_failed_endpoint)) {
+                usec_t usec;
 
                 w->n_retries++;
-                r = sd_event_add_time(netdev->manager->event,
-                                      &s,
-                                      CLOCK_MONOTONIC,
-                                      now(CLOCK_MONOTONIC) + exponential_backoff_milliseconds(w->n_retries),
-                                      0,
-                                      on_resolve_retry,
-                                      netdev);
+                usec = usec_add(now(CLOCK_MONOTONIC), exponential_backoff_milliseconds(w->n_retries));
+                r = event_reset_time(netdev->manager->event, &w->resolve_retry_event_source,
+                                     CLOCK_MONOTONIC, usec, 0, on_resolve_retry, netdev,
+                                     0, "wireguard-resolve-retry", true);
                 if (r < 0) {
                         log_netdev_warning_errno(netdev, r, "Could not arm resolve retry handler: %m");
                         return 0;
                 }
-
-                r = sd_event_source_set_destroy_callback(s, (sd_event_destroy_t) netdev_destroy_callback);
-                if (r < 0) {
-                        log_netdev_warning_errno(netdev, r, "Failed to set destroy callback to event source: %m");
-                        return 0;
-                }
-
-                (void) sd_event_source_set_floating(s, true);
-                netdev_ref(netdev);
         }
 
         return 0;
@@ -345,24 +399,24 @@ static void resolve_endpoints(NetDev *netdev) {
                 .ai_socktype = SOCK_DGRAM,
                 .ai_protocol = IPPROTO_UDP
         };
-        WireguardEndpoint *endpoint;
+        WireguardPeer *peer;
         Wireguard *w;
+        Iterator i;
         int r = 0;
 
         assert(netdev);
         w = WIREGUARD(netdev);
         assert(w);
 
-        LIST_FOREACH(endpoints, endpoint, w->unresolved_endpoints) {
+        SET_FOREACH(peer, w->peers_with_unresolved_endpoint, i) {
                 r = resolve_getaddrinfo(netdev->manager->resolve,
                                         NULL,
-                                        endpoint->host,
-                                        endpoint->port,
+                                        peer->endpoint_host,
+                                        peer->endpoint_port,
                                         &hints,
                                         wireguard_resolve_handler,
-                                        wireguard_endpoint_destroy_callback,
-                                        endpoint);
-
+                                        wireguard_peer_destroy_callback,
+                                        peer);
                 if (r == -ENOBUFS)
                         break;
                 if (r < 0) {
@@ -373,32 +427,31 @@ static void resolve_endpoints(NetDev *netdev) {
                 /* Avoid freeing netdev. It will be unrefed by the destroy callback. */
                 netdev_ref(netdev);
 
-                LIST_REMOVE(endpoints, w->unresolved_endpoints, endpoint);
+                (void) set_remove(w->peers_with_unresolved_endpoint, peer);
         }
 }
 
 static int netdev_wireguard_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
-        Wireguard *w;
-
         assert(netdev);
-        w = WIREGUARD(netdev);
-        assert(w);
+        assert(WIREGUARD(netdev));
 
         (void) wireguard_set_interface(netdev);
         resolve_endpoints(netdev);
         return 0;
 }
 
-int config_parse_wireguard_listen_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) {
+int config_parse_wireguard_listen_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) {
+
         uint16_t *s = data;
         uint16_t port = 0;
         int r;
@@ -407,175 +460,249 @@ int config_parse_wireguard_listen_port(const char *unit,
         assert(data);
 
         if (!streq(rvalue, "auto")) {
-                r = parse_ip_port(rvalue, &port);
-                if (r < 0)
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid port specification, ignoring assignment: %s", rvalue);
+                r = parse_ip_port(rvalue, s);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Invalid port specification, ignoring assignment: %s", rvalue);
+                        return 0;
+                }
         }
 
         *s = port;
-
         return 0;
 }
 
-static int parse_wireguard_key(const char *unit,
-                               const char *filename,
-                               unsigned line,
-                               const char *section,
-                               unsigned section_line,
-                               const char *lvalue,
-                               int ltype,
-                               const char *rvalue,
-                               void *data,
-                               void *userdata) {
+static int wireguard_decode_key_and_warn(
+                const char *rvalue,
+                uint8_t ret[static WG_KEY_LEN],
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *lvalue) {
+
         _cleanup_free_ void *key = NULL;
         size_t len;
         int r;
 
-        assert(filename);
         assert(rvalue);
-        assert(userdata);
+        assert(ret);
+        assert(filename);
+        assert(lvalue);
 
-        r = unbase64mem(rvalue, strlen(rvalue), &key, &len);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse wireguard key \"%s\", ignoring assignment: %m", rvalue);
+        if (isempty(rvalue)) {
+                memzero(ret, WG_KEY_LEN);
                 return 0;
         }
+
+        if (!streq(lvalue, "PublicKey"))
+                (void) warn_file_is_world_accessible(filename, NULL, unit, line);
+
+        r = unbase64mem_full(rvalue, strlen(rvalue), true, &key, &len);
+        if (r < 0)
+                return log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to decode wireguard key provided by %s=, ignoring assignment: %m", lvalue);
         if (len != WG_KEY_LEN) {
-                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "Wireguard key is too short, ignoring assignment: %s", rvalue);
-                return 0;
+                explicit_bzero_safe(key, len);
+                return log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Wireguard key provided by %s= has invalid length (%zu bytes), ignoring assignment.",
+                           lvalue, len);
         }
 
-        memcpy(userdata, key, WG_KEY_LEN);
-        return true;
+        memcpy(ret, key, WG_KEY_LEN);
+        return 0;
 }
 
-int config_parse_wireguard_private_key(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_wireguard_private_key(
+                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) {
+
         Wireguard *w;
 
         assert(data);
-
         w = WIREGUARD(data);
+        assert(w);
+
+        (void) wireguard_decode_key_and_warn(rvalue, w->private_key, unit, filename, line, lvalue);
+        return 0;
+}
+
+int config_parse_wireguard_private_key_file(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        _cleanup_free_ char *path = NULL;
+        Wireguard *w;
 
+        assert(data);
+        w = WIREGUARD(data);
         assert(w);
 
-        return parse_wireguard_key(unit,
-                                   filename,
-                                   line,
-                                   section,
-                                   section_line,
-                                   lvalue,
-                                   ltype,
-                                   rvalue,
-                                   data,
-                                   &w->private_key);
+        if (isempty(rvalue)) {
+                w->private_key_file = mfree(w->private_key_file);
+                return 0;
+        }
+
+        path = strdup(rvalue);
+        if (!path)
+                return log_oom();
+
+        if (path_simplify_and_warn(path, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue) < 0)
+                return 0;
 
+        return free_and_replace(w->private_key_file, path);
 }
 
-int config_parse_wireguard_preshared_key(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_wireguard_preshared_key(
+                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_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
         Wireguard *w;
-        WireguardPeer *peer;
+        int r;
 
         assert(data);
-
         w = WIREGUARD(data);
+        assert(w);
+
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
 
+        r = wireguard_decode_key_and_warn(rvalue, peer->preshared_key, unit, filename, line, lvalue);
+        if (r < 0)
+                return r;
+
+        TAKE_PTR(peer);
+        return 0;
+}
+
+int config_parse_wireguard_preshared_key_file(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
+        _cleanup_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
+        _cleanup_free_ char *path = NULL;
+        Wireguard *w;
+        int r;
+
+        assert(data);
+        w = WIREGUARD(data);
         assert(w);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
+
+        if (isempty(rvalue)) {
+                peer->preshared_key_file = mfree(peer->preshared_key_file);
+                TAKE_PTR(peer);
+                return 0;
+        }
+
+        path = strdup(rvalue);
+        if (!path)
                 return log_oom();
 
-        return parse_wireguard_key(unit,
-                                   filename,
-                                   line,
-                                   section,
-                                   section_line,
-                                   lvalue,
-                                   ltype,
-                                   rvalue,
-                                   data,
-                                   peer->preshared_key);
+        if (path_simplify_and_warn(path, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue) < 0)
+                return 0;
+
+        free_and_replace(peer->preshared_key_file, path);
+        TAKE_PTR(peer);
+        return 0;
 }
 
-int config_parse_wireguard_public_key(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_wireguard_public_key(
+                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_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
         Wireguard *w;
-        WireguardPeer *peer;
+        int r;
 
         assert(data);
-
         w = WIREGUARD(data);
-
         assert(w);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
-                return log_oom();
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
+
+        r = wireguard_decode_key_and_warn(rvalue, peer->public_key, unit, filename, line, lvalue);
+        if (r < 0)
+                return r;
 
-        return parse_wireguard_key(unit,
-                                   filename,
-                                   line,
-                                   section,
-                                   section_line,
-                                   lvalue,
-                                   ltype,
-                                   rvalue,
-                                   data,
-                                   peer->public_key);
+        TAKE_PTR(peer);
+        return 0;
 }
 
-int config_parse_wireguard_allowed_ips(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_wireguard_allowed_ips(
+                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_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
         union in_addr_union addr;
         unsigned char prefixlen;
         int r, family;
         Wireguard *w;
-        WireguardPeer *peer;
         WireguardIPmask *ipmask;
 
         assert(rvalue);
         assert(data);
 
         w = WIREGUARD(data);
+        assert(w);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
-                return log_oom();
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
 
         for (;;) {
                 _cleanup_free_ char *word = NULL;
@@ -586,14 +713,16 @@ int config_parse_wireguard_allowed_ips(const char *unit,
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split allowed ips \"%s\" option: %m", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to split allowed ips \"%s\" option: %m", rvalue);
                         break;
                 }
 
                 r = in_addr_prefix_from_string_auto(word, &family, &addr, &prefixlen);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Network address is invalid, ignoring assignment: %s", word);
-                        return 0;
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Network address is invalid, ignoring assignment: %s", word);
+                        continue;
                 }
 
                 ipmask = new(WireguardIPmask, 1);
@@ -609,48 +738,53 @@ int config_parse_wireguard_allowed_ips(const char *unit,
                 LIST_PREPEND(ipmasks, peer->ipmasks, ipmask);
         }
 
+        TAKE_PTR(peer);
         return 0;
 }
 
-int config_parse_wireguard_endpoint(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_wireguard_endpoint(
+                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_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
+        const char *begin, *end;
         Wireguard *w;
-        WireguardPeer *peer;
         size_t len;
-        const char *begin, *end = NULL;
-        _cleanup_free_ char *host = NULL, *port = NULL;
-        _cleanup_(wireguard_endpoint_freep) WireguardEndpoint *endpoint = NULL;
+        int r;
 
         assert(data);
         assert(rvalue);
 
         w = WIREGUARD(data);
-
         assert(w);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
-                return log_oom();
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
 
         if (rvalue[0] == '[') {
                 begin = &rvalue[1];
                 end = strchr(rvalue, ']');
                 if (!end) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find matching brace of endpoint, ignoring assignment: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Unable to find matching brace of endpoint, ignoring assignment: %s",
+                                   rvalue);
                         return 0;
                 }
                 len = end - begin;
                 ++end;
                 if (*end != ':' || !*(end + 1)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Unable to find port of endpoint, ignoring assignment: %s",
+                                   rvalue);
                         return 0;
                 }
                 ++end;
@@ -658,71 +792,77 @@ int config_parse_wireguard_endpoint(const char *unit,
                 begin = rvalue;
                 end = strrchr(rvalue, ':');
                 if (!end || !*(end + 1)) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Unable to find port of endpoint: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Unable to find port of endpoint, ignoring assignment: %s",
+                                   rvalue);
                         return 0;
                 }
                 len = end - begin;
                 ++end;
         }
 
-        host = strndup(begin, len);
-        if (!host)
+        r = free_and_strndup(&peer->endpoint_host, begin, len);
+        if (r < 0)
                 return log_oom();
 
-        port = strdup(end);
-        if (!port)
+        r = free_and_strdup(&peer->endpoint_port, end);
+        if (r < 0)
                 return log_oom();
 
-        endpoint = new(WireguardEndpoint, 1);
-        if (!endpoint)
+        r = set_ensure_allocated(&w->peers_with_unresolved_endpoint, NULL);
+        if (r < 0)
                 return log_oom();
 
-        *endpoint = (WireguardEndpoint) {
-                .peer = TAKE_PTR(peer),
-                .host = TAKE_PTR(host),
-                .port = TAKE_PTR(port),
-                .netdev = data,
-        };
-        LIST_PREPEND(endpoints, w->unresolved_endpoints, TAKE_PTR(endpoint));
+        r = set_put(w->peers_with_unresolved_endpoint, peer);
+        if (r < 0)
+                return r;
 
+        TAKE_PTR(peer);
         return 0;
 }
 
-int config_parse_wireguard_keepalive(const char *unit,
-                                     const char *filename,
-                                     unsigned line,
-                                     const char *section,
-                                     unsigned section_line,
-                                     const char *lvalue,
-                                     int ltype,
-                                     const char *rvalue,
-                                     void *data,
-                                     void *userdata) {
-        int r;
+int config_parse_wireguard_keepalive(
+                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_(wireguard_peer_free_or_set_invalidp) WireguardPeer *peer = NULL;
         uint16_t keepalive = 0;
         Wireguard *w;
-        WireguardPeer *peer;
+        int r;
 
         assert(rvalue);
         assert(data);
 
         w = WIREGUARD(data);
-
         assert(w);
 
-        peer = wireguard_peer_new(w, section_line);
-        if (!peer)
-                return log_oom();
+        r = wireguard_peer_new_static(w, filename, section_line, &peer);
+        if (r < 0)
+                return r;
 
         if (streq(rvalue, "off"))
                 keepalive = 0;
         else {
                 r = safe_atou16(rvalue, &keepalive);
-                if (r < 0)
-                        log_syntax(unit, LOG_ERR, filename, line, r, "The persistent keepalive interval must be 0-65535. Ignore assignment: %s", rvalue);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "The persistent keepalive interval must be 0-65535. Ignore assignment: %s",
+                                   rvalue);
+                        return 0;
+                }
         }
 
         peer->persistent_keepalive_interval = keepalive;
+
+        TAKE_PTR(peer);
         return 0;
 }
 
@@ -730,9 +870,7 @@ static void wireguard_init(NetDev *netdev) {
         Wireguard *w;
 
         assert(netdev);
-
         w = WIREGUARD(netdev);
-
         assert(w);
 
         w->flags = WGDEVICE_F_REPLACE_PEERS;
@@ -740,32 +878,96 @@ static void wireguard_init(NetDev *netdev) {
 
 static void wireguard_done(NetDev *netdev) {
         Wireguard *w;
-        WireguardPeer *peer;
-        WireguardIPmask *mask;
-        WireguardEndpoint *e;
 
         assert(netdev);
         w = WIREGUARD(netdev);
         assert(w);
 
-        while ((peer = w->peers)) {
-                LIST_REMOVE(peers, w->peers, peer);
-                while ((mask = peer->ipmasks)) {
-                        LIST_REMOVE(ipmasks, peer->ipmasks, mask);
-                        free(mask);
-                }
-                free(peer);
-        }
+        sd_event_source_unref(w->resolve_retry_event_source);
 
-        while ((e = w->unresolved_endpoints)) {
-                LIST_REMOVE(endpoints, w->unresolved_endpoints, e);
-                wireguard_endpoint_free(e);
-        }
+        explicit_bzero_safe(w->private_key, WG_KEY_LEN);
+        free(w->private_key_file);
+
+        hashmap_free_with_destructor(w->peers_by_section, wireguard_peer_free);
+        set_free(w->peers_with_unresolved_endpoint);
+        set_free(w->peers_with_failed_endpoint);
+}
+
+static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_KEY_LEN]) {
+        _cleanup_free_ char *key = NULL;
+        size_t key_len;
+        int r;
+
+        if (!filename)
+                return 0;
 
-        while ((e = w->failed_endpoints)) {
-                LIST_REMOVE(endpoints, w->failed_endpoints, e);
-                wireguard_endpoint_free(e);
+        r = read_full_file_full(filename, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64, &key, &key_len);
+        if (r < 0)
+                return r;
+
+        if (key_len != WG_KEY_LEN) {
+                r = -EINVAL;
+                goto finalize;
         }
+
+        memcpy(dest, key, WG_KEY_LEN);
+        r = 0;
+
+finalize:
+        explicit_bzero_safe(key, key_len);
+        return r;
+}
+
+static int wireguard_peer_verify(WireguardPeer *peer) {
+        NetDev *netdev = NETDEV(peer->wireguard);
+        int r;
+
+        if (section_is_invalid(peer->section))
+                return -EINVAL;
+
+        if (eqzero(peer->public_key))
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "%s: WireGuardPeer section without PublicKey= configured. "
+                                              "Ignoring [WireGuardPeer] section from line %u.",
+                                              peer->section->filename, peer->section->line);
+
+        r = wireguard_read_key_file(peer->preshared_key_file, peer->preshared_key);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r,
+                                              "%s: Failed to read preshared key from '%s'. "
+                                              "Ignoring [WireGuardPeer] section from line %u.",
+                                              peer->section->filename, peer->preshared_key_file,
+                                              peer->section->line);
+
+        return 0;
+}
+
+static int wireguard_verify(NetDev *netdev, const char *filename) {
+        WireguardPeer *peer, *peer_next;
+        Wireguard *w;
+        int r;
+
+        assert(netdev);
+        w = WIREGUARD(netdev);
+        assert(w);
+
+        r = wireguard_read_key_file(w->private_key_file, w->private_key);
+        if (r < 0)
+                return log_netdev_error_errno(netdev, r,
+                                              "Failed to read private key from %s. Dropping network device %s.",
+                                              w->private_key_file, netdev->ifname);
+
+        if (eqzero(w->private_key))
+                return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
+                                              "%s: Missing PrivateKey= or PrivateKeyFile=, "
+                                              "Dropping network device %s.",
+                                              filename, netdev->ifname);
+
+        LIST_FOREACH_SAFE(peers, peer, peer_next, w->peers)
+                if (wireguard_peer_verify(peer) < 0)
+                        wireguard_peer_free(peer);
+
+        return 0;
 }
 
 const NetDevVTable wireguard_vtable = {
@@ -775,4 +977,5 @@ const NetDevVTable wireguard_vtable = {
         .init = wireguard_init,
         .done = wireguard_done,
         .create_type = NETDEV_CREATE_INDEPENDENT,
+        .config_verify = wireguard_verify,
 };
index 4c26d10..862f2a9 100644 (file)
@@ -8,10 +8,6 @@ typedef struct Wireguard Wireguard;
 #include "netdev.h"
 #include "socket-util.h"
 
-#ifndef IFNAMSIZ
-#define IFNAMSIZ 16
-#endif
-
 typedef struct WireguardIPmask {
         uint16_t family;
         union in_addr_union ip;
@@ -21,44 +17,41 @@ typedef struct WireguardIPmask {
 } WireguardIPmask;
 
 typedef struct WireguardPeer {
+        Wireguard *wireguard;
+        NetworkConfigSection *section;
+
         uint8_t public_key[WG_KEY_LEN];
         uint8_t preshared_key[WG_KEY_LEN];
+        char *preshared_key_file;
         uint32_t flags;
+        uint16_t persistent_keepalive_interval;
 
         union sockaddr_union endpoint;
-
-        uint16_t persistent_keepalive_interval;
+        char *endpoint_host;
+        char *endpoint_port;
 
         LIST_HEAD(WireguardIPmask, ipmasks);
         LIST_FIELDS(struct WireguardPeer, peers);
 } WireguardPeer;
 
-typedef struct WireguardEndpoint {
-        char *host;
-        char *port;
-
-        NetDev *netdev;
-        WireguardPeer *peer;
-
-        LIST_FIELDS(struct WireguardEndpoint, endpoints);
-} WireguardEndpoint;
-
 struct Wireguard {
         NetDev meta;
         unsigned last_peer_section;
 
         uint32_t flags;
-
         uint8_t private_key[WG_KEY_LEN];
+        char *private_key_file;
+        uint16_t port;
         uint32_t fwmark;
 
-        uint16_t port;
+        Hashmap *peers_by_section;
+        Set *peers_with_unresolved_endpoint;
+        Set *peers_with_failed_endpoint;
 
         LIST_HEAD(WireguardPeer, peers);
 
-        LIST_HEAD(WireguardEndpoint, unresolved_endpoints);
-        LIST_HEAD(WireguardEndpoint, failed_endpoints);
         unsigned n_retries;
+        sd_event_source *resolve_retry_event_source;
 };
 
 DEFINE_NETDEV_CAST(WIREGUARD, Wireguard);
@@ -70,5 +63,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_listen_port);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_public_key);
 CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key);
+CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_private_key_file);
 CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_preshared_key);
+CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_preshared_key_file);
 CONFIG_PARSER_PROTOTYPE(config_parse_wireguard_keepalive);
index b14b81c..3881aaa 100644 (file)
@@ -4,6 +4,9 @@
 #include <linux/if_addrlabel.h>
 #include <net/if.h>
 #include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "sd-device.h"
 #include "sd-hwdb.h"
@@ -26,6 +29,7 @@
 #include "parse-util.h"
 #include "pretty-print.h"
 #include "socket-util.h"
+#include "sort-util.h"
 #include "sparse-endian.h"
 #include "stdio-util.h"
 #include "string-table.h"
@@ -33,7 +37,6 @@
 #include "strv.h"
 #include "strxcpyx.h"
 #include "terminal-util.h"
-#include "util.h"
 #include "verbs.h"
 
 static PagerFlags arg_pager_flags = 0;
@@ -65,7 +68,7 @@ static void operational_state_to_color(const char *state, const char **on, const
         assert(on);
         assert(off);
 
-        if (streq_ptr(state, "routable")) {
+        if (STRPTR_IN_SET(state, "routable", "enslaved")) {
                 *on = ansi_highlight_green();
                 *off = ansi_normal();
         } else if (streq_ptr(state, "degraded")) {
@@ -107,10 +110,10 @@ static int link_info_compare(const LinkInfo *a, const LinkInfo *b) {
         return CMP(a->ifindex, b->ifindex);
 }
 
-static int decode_link(sd_netlink_message *m, LinkInfo *info) {
+static int decode_link(sd_netlink_message *m, LinkInfo *info, char **patterns) {
         const char *name;
         uint16_t type;
-        int r;
+        int ifindex, r;
 
         assert(m);
         assert(info);
@@ -122,7 +125,7 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info) {
         if (type != RTM_NEWLINK)
                 return 0;
 
-        r = sd_rtnl_message_link_get_ifindex(m, &info->ifindex);
+        r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
         if (r < 0)
                 return r;
 
@@ -130,11 +133,21 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info) {
         if (r < 0)
                 return r;
 
+        if (patterns) {
+                char str[DECIMAL_STR_MAX(int)];
+
+                xsprintf(str, "%i", ifindex);
+
+                if (!strv_fnmatch(patterns, str, 0) && !strv_fnmatch(patterns, name, 0))
+                        return 0;
+        }
+
         r = sd_rtnl_message_link_get_type(m, &info->iftype);
         if (r < 0)
                 return r;
 
         strscpy(info->name, sizeof info->name, name);
+        info->ifindex = ifindex;
 
         info->has_mac_address =
                 sd_netlink_message_read_ether_addr(m, IFLA_ADDRESS, &info->mac_address) >= 0 &&
@@ -147,54 +160,7 @@ static int decode_link(sd_netlink_message *m, LinkInfo *info) {
         return 1;
 }
 
-static int acquire_link_info_strv(sd_netlink *rtnl, char **l, LinkInfo **ret) {
-        _cleanup_free_ LinkInfo *links = NULL;
-        char **i;
-        size_t c = 0;
-        int r;
-
-        assert(rtnl);
-        assert(ret);
-
-        links = new(LinkInfo, strv_length(l));
-        if (!links)
-                return log_oom();
-
-        STRV_FOREACH(i, l) {
-                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
-                int ifindex;
-
-                if (parse_ifindex(*i, &ifindex) >= 0)
-                        r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, ifindex);
-                else {
-                        r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
-                        if (r < 0)
-                                return rtnl_log_create_error(r);
-
-                        r = sd_netlink_message_append_string(req, IFLA_IFNAME, *i);
-                }
-                if (r < 0)
-                        return rtnl_log_create_error(r);
-
-                r = sd_netlink_call(rtnl, req, 0, &reply);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to request link: %m");
-
-                r = decode_link(reply, links + c);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        c++;
-        }
-
-        typesafe_qsort(links, c, link_info_compare);
-
-        *ret = TAKE_PTR(links);
-
-        return (int) c;
-}
-
-static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) {
+static int acquire_link_info(sd_netlink *rtnl, char **patterns, LinkInfo **ret) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
         _cleanup_free_ LinkInfo *links = NULL;
         size_t allocated = 0, c = 0;
@@ -220,7 +186,7 @@ static int acquire_link_info_all(sd_netlink *rtnl, LinkInfo **ret) {
                 if (!GREEDY_REALLOC(links, allocated, c+1))
                         return -ENOMEM;
 
-                r = decode_link(i, links + c);
+                r = decode_link(i, links + c, patterns);
                 if (r < 0)
                         return r;
                 if (r > 0)
@@ -243,17 +209,14 @@ static int list_links(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
-        if (argc > 1)
-                c = acquire_link_info_strv(rtnl, argv + 1, &links);
-        else
-                c = acquire_link_info_all(rtnl, &links);
+        c = acquire_link_info(rtnl, argc > 1 ? argv + 1 : NULL, &links);
         if (c < 0)
                 return c;
 
         (void) pager_open(arg_pager_flags);
 
         if (arg_legend)
-                printf("%3s %-16s %-18s %-11s %-10s\n",
+                printf("%3s %-16s %-18s %-16s %-10s\n",
                        "IDX",
                        "LINK",
                        "TYPE",
@@ -281,7 +244,7 @@ static int list_links(int argc, char *argv[], void *userdata) {
 
                 t = link_get_type_string(links[i].iftype, d);
 
-                printf("%3i %-16s %-18s %s%-11s%s %s%-10s%s\n",
+                printf("%3i %-16s %-18s %s%-16s%s %s%-10s%s\n",
                        links[i].ifindex, links[i].name, strna(t),
                        on_color_operational, strna(operational_state), off_color_operational,
                        on_color_setup, strna(setup_state), off_color_setup);
@@ -887,11 +850,11 @@ static int link_status(int argc, char *argv[], void *userdata) {
                 log_debug_errno(r, "Failed to open hardware database: %m");
 
         if (arg_all)
-                c = acquire_link_info_all(rtnl, &links);
+                c = acquire_link_info(rtnl, NULL, &links);
         else if (argc <= 1)
                 return system_status(rtnl, hwdb);
         else
-                c = acquire_link_info_strv(rtnl, argv + 1, &links);
+                c = acquire_link_info(rtnl, argv + 1, &links);
         if (c < 0)
                 return c;
 
@@ -965,10 +928,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return log_error_errno(r, "Failed to connect to netlink: %m");
 
-        if (argc > 1)
-                c = acquire_link_info_strv(rtnl, argv + 1, &links);
-        else
-                c = acquire_link_info_all(rtnl, &links);
+        c = acquire_link_info(rtnl, argc > 1 ? argv + 1 : NULL, &links);
         if (c < 0)
                 return c;
 
@@ -1078,9 +1038,9 @@ static int help(void) {
                "     --no-legend        Do not show the headers and footers\n"
                "  -a --all              Show status for all links\n\n"
                "Commands:\n"
-               "  list [LINK...]        List links\n"
-               "  status [LINK...]      Show link status\n"
-               "  lldp [LINK...]        Show LLDP neighbors\n"
+               "  list [PATTERN...]     List links\n"
+               "  status [PATTERN...]   Show link status\n"
+               "  lldp [PATTERN...]     Show LLDP neighbors\n"
                "  label                 Show current address label entries in the kernel\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
index 94a12f8..ab73844 100644 (file)
@@ -159,7 +159,7 @@ int config_parse_address_label_prefix(const char *unit,
                                       void *data,
                                       void *userdata) {
 
-        _cleanup_(address_label_freep) AddressLabel *n = NULL;
+        _cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -196,7 +196,7 @@ int config_parse_address_label(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(address_label_freep) AddressLabel *n = NULL;
+        _cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
         Network *network = userdata;
         uint32_t k;
         int r;
index 6922cb0..595072a 100644 (file)
@@ -11,6 +11,7 @@ typedef struct AddressLabel AddressLabel;
 
 #include "networkd-link.h"
 #include "networkd-network.h"
+#include "networkd-util.h"
 
 typedef struct Network Network;
 typedef struct Link Link;
@@ -30,7 +31,7 @@ struct AddressLabel {
 
 void address_label_free(AddressLabel *label);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(AddressLabel*, address_label_free);
+DEFINE_NETWORK_SECTION_FUNCTIONS(AddressLabel, address_label_free);
 
 int address_label_configure(AddressLabel *address, Link *link, link_netlink_message_handler_t callback, bool update);
 
index 1650515..eaf056d 100644 (file)
@@ -6,7 +6,9 @@
 #include "set.h"
 #include "string-util.h"
 
-int address_pool_new(
+#define RANDOM_PREFIX_TRIAL_MAX  1024
+
+static int address_pool_new(
                 Manager *m,
                 AddressPool **ret,
                 int family,
@@ -121,35 +123,34 @@ static bool address_pool_prefix_is_taken(
 
 int address_pool_acquire(AddressPool *p, unsigned prefixlen, union in_addr_union *found) {
         union in_addr_union u;
+        unsigned i;
+        int r;
 
         assert(p);
         assert(prefixlen > 0);
         assert(found);
 
-        if (p->prefixlen > prefixlen)
+        if (p->prefixlen >= prefixlen)
                 return 0;
 
         u = p->in_addr;
-        for (;;) {
-                if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
-                        _cleanup_free_ char *s = NULL;
-                        int r;
 
-                        r = in_addr_to_string(p->family, &u, &s);
-                        if (r < 0)
-                                return r;
+        for (i = 0; i < RANDOM_PREFIX_TRIAL_MAX; i++) {
+                r = in_addr_random_prefix(p->family, &u, p->prefixlen, prefixlen);
+                if (r <= 0)
+                        return r;
 
-                        log_debug("Found range %s/%u", strna(s), prefixlen);
+                if (!address_pool_prefix_is_taken(p, &u, prefixlen)) {
+                        if (DEBUG_LOGGING) {
+                                _cleanup_free_ char *s = NULL;
+
+                                (void) in_addr_to_string(p->family, &u, &s);
+                                log_debug("Found range %s/%u", strna(s), prefixlen);
+                        }
 
                         *found = u;
                         return 1;
                 }
-
-                if (!in_addr_prefix_next(p->family, &u, prefixlen))
-                        return 0;
-
-                if (!in_addr_prefix_intersect(p->family, &p->in_addr, p->prefixlen, &u, prefixlen))
-                        return 0;
         }
 
         return 0;
index bd479a5..7db1c4f 100644 (file)
@@ -19,7 +19,6 @@ struct AddressPool {
         LIST_FIELDS(AddressPool, address_pools);
 };
 
-int address_pool_new(Manager *m, AddressPool **ret, int family, const union in_addr_union *u, unsigned prefixlen);
 int address_pool_new_from_string(Manager *m, AddressPool **ret, int family, const char *p, unsigned prefixlen);
 void address_pool_free(AddressPool *p);
 
index 3cdbd9e..42d61cc 100644 (file)
@@ -5,6 +5,7 @@
 #include "alloc-util.h"
 #include "conf-parser.h"
 #include "firewall-util.h"
+#include "memory-util.h"
 #include "missing_network.h"
 #include "netlink-util.h"
 #include "networkd-address.h"
@@ -15,7 +16,6 @@
 #include "string-util.h"
 #include "strv.h"
 #include "utf8.h"
-#include "util.h"
 
 #define ADDRESSES_PER_LINK_MAX 2048U
 #define STATIC_ADDRESSES_PER_NETWORK_MAX 1024U
@@ -39,7 +39,7 @@ int address_new(Address **ret) {
         return 0;
 }
 
-int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
+static int address_new_static(Network *network, const char *filename, unsigned section_line, Address **ret) {
         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
         _cleanup_(address_freep) Address *address = NULL;
         int r;
@@ -223,7 +223,7 @@ static int address_establish(Address *address, Link *link) {
 
                 r = fw_add_masquerade(masq, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
                 if (r < 0)
-                        log_link_warning_errno(link, r, "Could not enable IP masquerading: %m");
+                        return r;
 
                 address->ip_masquerade_done = masq;
         }
@@ -321,7 +321,7 @@ static int address_release(Address *address) {
 
                 r = fw_add_masquerade(false, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0);
                 if (r < 0)
-                        log_link_warning_errno(address->link, r, "Failed to disable IP masquerading: %m");
+                        return r;
 
                 address->ip_masquerade_done = false;
         }
@@ -351,7 +351,7 @@ int address_update(
         address->scope = scope;
         address->cinfo = *cinfo;
 
-        link_update_operstate(address->link);
+        link_update_operstate(address->link, true);
         link_check_ready(address->link);
 
         if (!ready &&
@@ -371,16 +371,20 @@ int address_update(
 int address_drop(Address *address) {
         Link *link;
         bool ready;
+        int r;
 
         assert(address);
 
         ready = address_is_ready(address);
         link = address->link;
 
-        address_release(address);
+        r = address_release(address);
+        if (r < 0)
+                log_link_warning_errno(link, r, "Failed to disable IP masquerading, ignoring: %m");
+
         address_free(address);
 
-        link_update_operstate(link);
+        link_update_operstate(link, true);
 
         if (link && !ready)
                 link_check_ready(link);
@@ -445,7 +449,6 @@ int address_remove(
                 link_netlink_message_handler_t callback) {
 
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
-        _cleanup_free_ char *b = NULL;
         int r;
 
         assert(address);
@@ -456,31 +459,30 @@ int address_remove(
         assert(link->manager->rtnl);
 
         if (DEBUG_LOGGING) {
-                if (in_addr_to_string(address->family, &address->in_addr, &b) >= 0)
-                        log_link_debug(link, "Removing address %s", b);
+                _cleanup_free_ char *b = NULL;
+
+                (void) in_addr_to_string(address->family, &address->in_addr, &b);
+                log_link_debug(link, "Removing address %s", strna(b));
         }
 
         r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR,
                                      link->ifindex, address->family);
         if (r < 0)
-                return log_error_errno(r, "Could not allocate RTM_DELADDR message: %m");
+                return log_link_error_errno(link, r, "Could not allocate RTM_DELADDR message: %m");
 
         r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
         if (r < 0)
-                return log_error_errno(r, "Could not set prefixlen: %m");
+                return log_link_error_errno(link, r, "Could not set prefixlen: %m");
 
-        if (address->family == AF_INET)
-                r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
-        else if (address->family == AF_INET6)
-                r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
+        r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr);
         if (r < 0)
-                return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
+                return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m");
 
         r = netlink_call_async(link->manager->rtnl, NULL, req,
                                callback ?: address_remove_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
-                return log_error_errno(r, "Could not send rtnetlink message: %m");
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
         link_ref(link);
 
@@ -498,18 +500,17 @@ static int address_acquire(Link *link, Address *original, Address **ret) {
         assert(ret);
 
         /* Something useful was configured? just use it */
-        if (in_addr_is_null(original->family, &original->in_addr) <= 0)
-                return 0;
+        r = in_addr_is_null(original->family, &original->in_addr);
+        if (r <= 0)
+                return r;
 
         /* The address is configured to be 0.0.0.0 or [::] by the user?
          * Then let's acquire something more useful from the pool. */
         r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr);
         if (r < 0)
-                return log_link_error_errno(link, r, "Failed to acquire address from pool: %m");
-        if (r == 0) {
-                log_link_error(link, "Couldn't find free address for interface, all taken.");
+                return r;
+        if (r == 0)
                 return -EBUSY;
-        }
 
         if (original->family == AF_INET) {
                 /* Pick first address in range for ourselves ... */
@@ -568,11 +569,12 @@ int address_configure(
         /* If this is a new address, then refuse adding more than the limit */
         if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
             set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
-                return -E2BIG;
+                return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
+                                            "Too many addresses are configured, refusing: %m");
 
         r = address_acquire(link, address, &address);
         if (r < 0)
-                return r;
+                return log_link_error_errno(link, r, "Failed to acquire an address from pool: %m");
 
         if (update)
                 r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req,
@@ -581,11 +583,11 @@ int address_configure(
                 r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR,
                                              link->ifindex, address->family);
         if (r < 0)
-                return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m");
+                return log_link_error_errno(link, r, "Could not allocate RTM_NEWADDR message: %m");
 
         r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen);
         if (r < 0)
-                return log_error_errno(r, "Could not set prefixlen: %m");
+                return log_link_error_errno(link, r, "Could not set prefixlen: %m");
 
         address->flags |= IFA_F_PERMANENT;
 
@@ -606,56 +608,50 @@ int address_configure(
 
         r = sd_rtnl_message_addr_set_flags(req, (address->flags & 0xff));
         if (r < 0)
-                return log_error_errno(r, "Could not set flags: %m");
+                return log_link_error_errno(link, r, "Could not set flags: %m");
 
         if (address->flags & ~0xff) {
                 r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags);
                 if (r < 0)
-                        return log_error_errno(r, "Could not set extended flags: %m");
+                        return log_link_error_errno(link, r, "Could not set extended flags: %m");
         }
 
         r = sd_rtnl_message_addr_set_scope(req, address->scope);
         if (r < 0)
-                return log_error_errno(r, "Could not set scope: %m");
+                return log_link_error_errno(link, r, "Could not set scope: %m");
 
-        if (address->family == AF_INET)
-                r = sd_netlink_message_append_in_addr(req, IFA_LOCAL, &address->in_addr.in);
-        else if (address->family == AF_INET6)
-                r = sd_netlink_message_append_in6_addr(req, IFA_LOCAL, &address->in_addr.in6);
+        r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr);
         if (r < 0)
-                return log_error_errno(r, "Could not append IFA_LOCAL attribute: %m");
+                return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m");
 
-        if (!in_addr_is_null(address->family, &address->in_addr_peer)) {
-                if (address->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, IFA_ADDRESS, &address->in_addr_peer.in);
-                else if (address->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &address->in_addr_peer.in6);
+        if (in_addr_is_null(address->family, &address->in_addr_peer) == 0) {
+                r = netlink_message_append_in_addr_union(req, IFA_ADDRESS, address->family, &address->in_addr_peer);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
         } else if (address->family == AF_INET && address->prefixlen <= 30) {
                 r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append IFA_BROADCAST attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append IFA_BROADCAST attribute: %m");
         }
 
         if (address->label) {
                 r = sd_netlink_message_append_string(req, IFA_LABEL, address->label);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append IFA_LABEL attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append IFA_LABEL attribute: %m");
         }
 
         r = sd_netlink_message_append_cache_info(req, IFA_CACHEINFO, &address->cinfo);
         if (r < 0)
-                return log_error_errno(r, "Could not append IFA_CACHEINFO attribute: %m");
+                return log_link_error_errno(link, r, "Could not append IFA_CACHEINFO attribute: %m");
 
         r = address_establish(address, link);
         if (r < 0)
-                return r;
+                log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
 
         r = netlink_call_async(link->manager->rtnl, NULL, req, callback, link_netlink_destroy_callback, link);
         if (r < 0) {
                 address_release(address);
-                return log_error_errno(r, "Could not send rtnetlink message: %m");
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
         }
 
         link_ref(link);
@@ -666,7 +662,7 @@ int address_configure(
                 r = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
         if (r < 0) {
                 address_release(address);
-                return log_error_errno(r, "Could not add address: %m");
+                return log_link_error_errno(link, r, "Could not add address: %m");
         }
 
         return 0;
@@ -685,7 +681,7 @@ int config_parse_broadcast(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(address_freep) Address *n = NULL;
+        _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         int r;
 
         assert(filename);
@@ -699,13 +695,15 @@ int config_parse_broadcast(
                 return r;
 
         if (n->family == AF_INET6) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
         r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Broadcast is invalid, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
@@ -727,7 +725,7 @@ int config_parse_address(const char *unit,
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(address_freep) Address *n = NULL;
+        _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         union in_addr_union buffer;
         unsigned char prefixlen;
         int r, f;
@@ -768,6 +766,19 @@ int config_parse_address(const char *unit,
                 return 0;
         }
 
+        if (in_addr_is_null(f, &buffer)) {
+                /* Will use address from address pool. Note that for ipv6 case, prefix of the address
+                 * pool is 8, but 40 bit is used by the global ID and 16 bit by the subnet ID. So,
+                 * let's limit the prefix length to 64 or larger. See RFC4193. */
+                if ((f == AF_INET && prefixlen < 8) ||
+                    (f == AF_INET6 && prefixlen < 64)) {
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Null address with invalid prefixlen='%u', ignoring assignment: %s",
+                                   prefixlen, rvalue);
+                        return 0;
+                }
+        }
+
         n->family = f;
         n->prefixlen = prefixlen;
 
@@ -796,7 +807,7 @@ int config_parse_label(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(address_freep) Address *n = NULL;
+        _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -811,7 +822,8 @@ int config_parse_label(
                 return r;
 
         if (!address_label_valid(rvalue)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Interface label is too long or invalid, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
@@ -820,7 +832,6 @@ int config_parse_label(
                 return log_oom();
 
         n = NULL;
-
         return 0;
 }
 
@@ -835,7 +846,7 @@ int config_parse_lifetime(const char *unit,
                           void *data,
                           void *userdata) {
         Network *network = userdata;
-        _cleanup_(address_freep) Address *n = NULL;
+        _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         unsigned k;
         int r;
 
@@ -849,25 +860,19 @@ int config_parse_lifetime(const char *unit,
         if (r < 0)
                 return r;
 
-        if (STR_IN_SET(rvalue, "forever", "infinity")) {
-                n->cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME;
-                n = NULL;
-
-                return 0;
-        }
-
-        r = safe_atou(rvalue, &k);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse PreferredLifetime, ignoring: %s", rvalue);
+        /* We accept only "forever", "infinity", or "0". */
+        if (STR_IN_SET(rvalue, "forever", "infinity"))
+                k = CACHE_INFO_INFINITY_LIFE_TIME;
+        else if (streq(rvalue, "0"))
+                k = 0;
+        else {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Invalid PreferredLifetime= value, ignoring: %s", rvalue);
                 return 0;
         }
 
-        if (k != 0)
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid PreferredLifetime value, ignoring: %d", k);
-        else {
-                n->cinfo.ifa_prefered = k;
-                n = NULL;
-        }
+        n->cinfo.ifa_prefered = k;
+        n = NULL;
 
         return 0;
 }
@@ -883,7 +888,7 @@ int config_parse_address_flags(const char *unit,
                                void *data,
                                void *userdata) {
         Network *network = userdata;
-        _cleanup_(address_freep) Address *n = NULL;
+        _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         int r;
 
         assert(filename);
@@ -898,7 +903,8 @@ int config_parse_address_flags(const char *unit,
 
         r = parse_boolean(rvalue);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address flag, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse address flag, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -912,7 +918,10 @@ int config_parse_address_flags(const char *unit,
                 n->prefix_route = r;
         else if (streq(lvalue, "AutoJoin"))
                 n->autojoin = r;
+        else
+                assert_not_reached("Invalid address flag type.");
 
+        n = NULL;
         return 0;
 }
 
@@ -927,7 +936,7 @@ int config_parse_address_scope(const char *unit,
                                void *data,
                                void *userdata) {
         Network *network = userdata;
-        _cleanup_(address_freep) Address *n = NULL;
+        _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
         int r;
 
         assert(filename);
@@ -949,13 +958,13 @@ int config_parse_address_scope(const char *unit,
         else {
                 r = safe_atou8(rvalue , &n->scope);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Could not parse address scope \"%s\", ignoring assignment: %m", rvalue);
                         return 0;
                 }
         }
 
         n = NULL;
-
         return 0;
 }
 
@@ -967,3 +976,19 @@ bool address_is_ready(const Address *a) {
         else
                 return !(a->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED));
 }
+
+int address_section_verify(Address *address) {
+        if (section_is_invalid(address->section))
+                return -EINVAL;
+
+        if (address->family == AF_UNSPEC) {
+                assert(address->section);
+
+                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                         "%s: Address section without Address= field configured. "
+                                         "Ignoring [Address] section from line %u.",
+                                         address->section->filename, address->section->line);
+        }
+
+        return 0;
+}
index 4714c07..455985d 100644 (file)
@@ -11,6 +11,7 @@ typedef struct Address Address;
 
 #include "networkd-link.h"
 #include "networkd-network.h"
+#include "networkd-util.h"
 
 #define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
 
@@ -46,7 +47,6 @@ struct Address {
         LIST_FIELDS(Address, addresses);
 };
 
-int address_new_static(Network *network, const char *filename, unsigned section, Address **ret);
 int address_new(Address **ret);
 void address_free(Address *address);
 int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
@@ -58,8 +58,9 @@ int address_configure(Address *address, Link *link, link_netlink_message_handler
 int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback);
 bool address_equal(Address *a1, Address *a2);
 bool address_is_ready(const Address *a);
+int address_section_verify(Address *a);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(Address*, address_free);
+DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_address);
 CONFIG_PARSER_PROTOTYPE(config_parse_broadcast);
index d8ac455..85685d6 100644 (file)
@@ -6,7 +6,6 @@
 #include "alloc-util.h"
 #include "hostname-util.h"
 #include "parse-util.h"
-#include "netdev/vrf.h"
 #include "network-internal.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
@@ -52,7 +51,8 @@ static int route_scope_from_address(const Route *route, const struct in_addr *se
 static int link_set_dhcp_routes(Link *link) {
         _cleanup_free_ sd_dhcp_route **static_routes = NULL;
         bool classless_route = false, static_route = false;
-        struct in_addr gateway, address;
+        const struct in_addr *router;
+        struct in_addr address;
         int r, n, i;
         uint32_t table;
 
@@ -67,11 +67,7 @@ static int link_set_dhcp_routes(Link *link) {
         if (!link->network->dhcp_use_routes)
                 return 0;
 
-        /* When the interface is part of an VRF use the VRFs routing table, unless
-         * there is a another table specified. */
-        table = link->network->dhcp_route_table;
-        if (!link->network->dhcp_route_table_set && link->network->vrf != NULL)
-                table = VRF(link->network->vrf)->table;
+        table = link_get_dhcp_route_table(link);
 
         r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
         if (r < 0)
@@ -123,26 +119,21 @@ static int link_set_dhcp_routes(Link *link) {
                 link->dhcp4_messages++;
         }
 
-        r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
-        if (r == -ENODATA)
-                log_link_info_errno(link, r, "DHCP: No gateway received from DHCP server: %m");
+        r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
+        if (IN_SET(r, 0, -ENODATA))
+                log_link_info(link, "DHCP: No gateway received from DHCP server.");
         else if (r < 0)
                 log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
+        else if (in4_addr_is_null(&router[0]))
+                log_link_info(link, "DHCP: Received gateway is null.");
 
         /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
            a Router option, the DHCP client MUST ignore the Router option. */
         if (classless_route && static_route)
                 log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");
 
-        if (r >= 0 && !classless_route) {
-                _cleanup_(route_freep) Route *route = NULL;
-                _cleanup_(route_freep) Route *route_gw = NULL;
-
-                r = route_new(&route);
-                if (r < 0)
-                        return log_link_error_errno(link, r, "Could not allocate route: %m");
-
-                route->protocol = RTPROT_DHCP;
+        if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) {
+                _cleanup_(route_freep) Route *route = NULL, *route_gw = NULL;
 
                 r = route_new(&route_gw);
                 if (r < 0)
@@ -152,7 +143,7 @@ static int link_set_dhcp_routes(Link *link) {
                  * route for the gw host so that we can route no matter the
                  * netmask or existing kernel route tables. */
                 route_gw->family = AF_INET;
-                route_gw->dst.in = gateway;
+                route_gw->dst.in = router[0];
                 route_gw->dst_prefixlen = 32;
                 route_gw->prefsrc.in = address;
                 route_gw->scope = RT_SCOPE_LINK;
@@ -166,9 +157,14 @@ static int link_set_dhcp_routes(Link *link) {
 
                 link->dhcp4_messages++;
 
+                r = route_new(&route);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not allocate route: %m");
+
                 route->family = AF_INET;
-                route->gw.in = gateway;
+                route->gw.in = router[0];
                 route->prefsrc.in = address;
+                route->protocol = RTPROT_DHCP;
                 route->priority = link->network->dhcp_route_metric;
                 route->table = table;
 
@@ -187,9 +183,9 @@ static int link_set_dhcp_routes(Link *link) {
 
 static int dhcp_lease_lost(Link *link) {
         _cleanup_(address_freep) Address *address = NULL;
+        const struct in_addr *router;
         struct in_addr addr;
         struct in_addr netmask;
-        struct in_addr gateway;
         unsigned prefixlen = 0;
         int r;
 
@@ -222,15 +218,15 @@ static int dhcp_lease_lost(Link *link) {
 
         r = address_new(&address);
         if (r >= 0) {
-                r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
-                if (r >= 0) {
+                r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
+                if (r > 0 && !in4_addr_is_null(&router[0])) {
                         _cleanup_(route_freep) Route *route_gw = NULL;
                         _cleanup_(route_freep) Route *route = NULL;
 
                         r = route_new(&route_gw);
                         if (r >= 0) {
                                 route_gw->family = AF_INET;
-                                route_gw->dst.in = gateway;
+                                route_gw->dst.in = router[0];
                                 route_gw->dst_prefixlen = 32;
                                 route_gw->scope = RT_SCOPE_LINK;
 
@@ -240,7 +236,7 @@ static int dhcp_lease_lost(Link *link) {
                         r = route_new(&route);
                         if (r >= 0) {
                                 route->family = AF_INET;
-                                route->gw.in = gateway;
+                                route->gw.in = router[0];
 
                                 route_remove(route, link, NULL);
                         }
@@ -265,7 +261,7 @@ static int dhcp_lease_lost(Link *link) {
 
                 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
                 if (r >= 0 && link->original_mtu != mtu) {
-                        r = link_set_mtu(link, link->original_mtu);
+                        r = link_set_mtu(link, link->original_mtu, true);
                         if (r < 0) {
                                 log_link_warning(link,
                                                  "DHCP error: could not reset MTU");
@@ -399,10 +395,10 @@ static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
 }
 
 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
+        const struct in_addr *router;
         sd_dhcp_lease *lease;
         struct in_addr address;
         struct in_addr netmask;
-        struct in_addr gateway;
         unsigned prefixlen;
         uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
         int r;
@@ -424,20 +420,20 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
 
         prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
 
-        r = sd_dhcp_lease_get_router(lease, &gateway);
+        r = sd_dhcp_lease_get_router(lease, &router);
         if (r < 0 && r != -ENODATA)
                 return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
 
-        if (r >= 0)
+        if (r > 0 && !in4_addr_is_null(&router[0]))
                 log_struct(LOG_INFO,
                            LOG_LINK_INTERFACE(link),
                            LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
                                             ADDRESS_FMT_VAL(address),
                                             prefixlen,
-                                            ADDRESS_FMT_VAL(gateway)),
+                                            ADDRESS_FMT_VAL(router[0])),
                            "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
                            "PREFIXLEN=%u", prefixlen,
-                           "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway));
+                           "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0]));
         else
                 log_struct(LOG_INFO,
                            LOG_LINK_INTERFACE(link),
@@ -455,7 +451,7 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
 
                 r = sd_dhcp_lease_get_mtu(lease, &mtu);
                 if (r >= 0) {
-                        r = link_set_mtu(link, mtu);
+                        r = link_set_mtu(link, mtu, true);
                         if (r < 0)
                                 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
                 }
index c1fba03..90361c9 100644 (file)
@@ -142,10 +142,15 @@ int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link) {
                                 continue;
                         }
 
-                        route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
-                                  0, 0, 0, &route);
-                        route_update(route, NULL, 0, NULL, NULL, 0, 0,
-                                     RTN_UNREACHABLE);
+                        r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, 0, 0, 0, &route);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Failed to add unreachable route to delete for DHCPv6 delegated subnet %s/%u: %m",
+                                                       strnull(buf),
+                                                       pd_prefix_len);
+                                continue;
+                        }
+
+                        route_update(route, NULL, 0, NULL, NULL, 0, 0, RTN_UNREACHABLE);
 
                         r = route_remove(route, link, dhcp6_route_remove_handler);
                         if (r < 0) {
@@ -288,7 +293,8 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
                 }
 
                 if (pd_prefix_len < 64) {
-                        Route *route = NULL;
+                        _cleanup_(route_freep) Route *route = NULL;
+                        uint32_t table;
 
                         (void) in_addr_to_string(AF_INET6, &pd_prefix, &buf);
 
@@ -300,22 +306,26 @@ static int dhcp6_lease_pd_prefix_acquired(sd_dhcp6_client *client, Link *link) {
                                 continue;
                         }
 
-                        route_add(link, AF_INET6, &pd_prefix, pd_prefix_len,
-                                  0, 0, 0, &route);
-                        route_update(route, NULL, 0, NULL, NULL, 0, 0,
-                                     RTN_UNREACHABLE);
+                        table = link_get_dhcp_route_table(link);
+
+                        r = route_add(link, AF_INET6, &pd_prefix, pd_prefix_len, 0, 0, table, &route);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "Failed to add unreachable route for DHCPv6 delegated subnet %s/%u: %m",
+                                                       strnull(buf),
+                                                       pd_prefix_len);
+                                continue;
+                        }
+
+                        route_update(route, NULL, 0, NULL, NULL, 0, 0, RTN_UNREACHABLE);
 
                         r = route_configure(route, link, dhcp6_route_handler);
                         if (r < 0) {
                                 log_link_warning_errno(link, r, "Cannot configure unreachable route for delegated subnet %s/%u: %m",
                                                        strnull(buf),
                                                        pd_prefix_len);
-                                route_free(route);
                                 continue;
                         }
 
-                        route_free(route);
-
                         log_link_debug(link, "Configuring unreachable route for %s/%u",
                                        strnull(buf), pd_prefix_len);
 
index 324f6a5..fa13949 100644 (file)
@@ -18,7 +18,7 @@
 #define STATIC_FDB_ENTRIES_PER_NETWORK_MAX 1024U
 
 /* create a new FDB entry or get an existing one. */
-int fdb_entry_new_static(
+static int fdb_entry_new_static(
                 Network *network,
                 const char *filename,
                 unsigned section_line,
@@ -189,7 +189,7 @@ int config_parse_fdb_hwaddr(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(fdb_entry_freep) FdbEntry *fdb_entry = NULL;
+        _cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL;
         int r;
 
         assert(filename);
@@ -235,7 +235,7 @@ int config_parse_fdb_vlan_id(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(fdb_entry_freep) FdbEntry *fdb_entry = NULL;
+        _cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL;
         int r;
 
         assert(filename);
index 55fc3a2..6b7da2e 100644 (file)
@@ -8,6 +8,7 @@
 #include "conf-parser.h"
 #include "list.h"
 #include "macro.h"
+#include "networkd-util.h"
 
 typedef struct Network Network;
 typedef struct FdbEntry FdbEntry;
@@ -24,11 +25,10 @@ struct FdbEntry {
         LIST_FIELDS(FdbEntry, static_fdb_entries);
 };
 
-int fdb_entry_new_static(Network *network, const char *filename, unsigned section_line, FdbEntry **ret);
 void fdb_entry_free(FdbEntry *fdb_entry);
 int fdb_entry_configure(Link *link, FdbEntry *fdb_entry);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(FdbEntry*, fdb_entry_free);
+DEFINE_NETWORK_SECTION_FUNCTIONS(FdbEntry, fdb_entry_free);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_fdb_hwaddr);
 CONFIG_PARSER_PROTOTYPE(config_parse_fdb_vlan_id);
index 3562e90..829dc48 100644 (file)
@@ -65,12 +65,28 @@ static int ipv4ll_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *l
 
         link->ipv4ll_route = true;
 
-        if (link->ipv4ll_address == true)
-                link_check_ready(link);
+        link_check_ready(link);
 
         return 1;
 }
 
+static int ipv4ll_route_configure(Link *link) {
+        _cleanup_(route_freep) Route *route = NULL;
+        int r;
+
+        r = route_new(&route);
+        if (r < 0)
+                return r;
+
+        route->family = AF_INET;
+        route->scope = RT_SCOPE_LINK;
+        route->protocol = RTPROT_STATIC;
+        route->priority = IPV4LL_ROUTE_METRIC;
+        route->table = link_get_vrf_table(link);
+
+        return route_configure(route, link, ipv4ll_route_handler);
+}
+
 static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
         int r;
 
@@ -86,21 +102,26 @@ static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link
 
         link->ipv4ll_address = true;
 
-        if (link->ipv4ll_route)
-                link_check_ready(link);
+        r = ipv4ll_route_configure(link);
+        if (r < 0) {
+                log_link_error_errno(link, r, "Failed to configure ipv4ll route: %m");
+                link_enter_failed(link);
+        }
 
         return 1;
 }
 
 static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
         _cleanup_(address_freep) Address *ll_addr = NULL;
-        _cleanup_(route_freep) Route *route = NULL;
         struct in_addr address;
         int r;
 
         assert(ll);
         assert(link);
 
+        link->ipv4ll_address = false;
+        link->ipv4ll_route = false;
+
         r = sd_ipv4ll_get_address(ll, &address);
         if (r == -ENOENT)
                 return 0;
@@ -124,23 +145,6 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) {
         if (r < 0)
                 return r;
 
-        link->ipv4ll_address = false;
-
-        r = route_new(&route);
-        if (r < 0)
-                return r;
-
-        route->family = AF_INET;
-        route->scope = RT_SCOPE_LINK;
-        route->protocol = RTPROT_STATIC;
-        route->priority = IPV4LL_ROUTE_METRIC;
-
-        r = route_configure(route, link, ipv4ll_route_handler);
-        if (r < 0)
-                return r;
-
-        link->ipv4ll_route = false;
-
         return 0;
 }
 
@@ -176,6 +180,7 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) {
                 case SD_IPV4LL_EVENT_BIND:
                         r = ipv4ll_address_claimed(ll, link);
                         if (r < 0) {
+                                log_link_error(link, "Failed to configure ipv4ll address: %m");
                                 link_enter_failed(link);
                                 return;
                         }
index f594b27..e2d77e9 100644 (file)
@@ -10,8 +10,9 @@
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "networkd-network.h"
-#include "string-util.h"
 #include "socket-util.h"
+#include "string-util.h"
+#include "sysctl-util.h"
 
 static bool ipv6_proxy_ndp_is_needed(Link *link) {
         assert(link);
@@ -32,8 +33,8 @@ static bool ipv6_proxy_ndp_is_needed(Link *link) {
 }
 
 static int ipv6_proxy_ndp_set(Link *link) {
-        const char *p = NULL;
-        int r, v;
+        bool v;
+        int r;
 
         assert(link);
 
@@ -41,16 +42,15 @@ static int ipv6_proxy_ndp_set(Link *link) {
                 return 0;
 
         v = ipv6_proxy_ndp_is_needed(link);
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/proxy_ndp");
 
-        r = write_string_file(p, one_zero(v), WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "proxy_ndp", v);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot configure proxy NDP for interface: %m");
 
         return 0;
 }
 
-int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress **ret) {
+static int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress **ret) {
         _cleanup_(ipv6_proxy_ndp_address_freep) IPv6ProxyNDPAddress *ipv6_proxy_ndp_address = NULL;
 
         assert(network);
@@ -122,9 +122,8 @@ int config_parse_ipv6_proxy_ndp_address(
                 return 0;
         }
 
-        r = in_addr_is_null(AF_INET6, &buffer);
-        if (r != 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
+        if (in_addr_is_null(AF_INET6, &buffer)) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
                            "IPv6 proxy NDP address cannot be the ANY address, ignoring: %s", rvalue);
                 return 0;
         }
index 546e856..d6666be 100644 (file)
@@ -10,13 +10,12 @@ typedef struct IPv6ProxyNDPAddress IPv6ProxyNDPAddress;
 typedef struct Link Link;
 
 struct IPv6ProxyNDPAddress {
-    Network *network;
-    struct in6_addr in_addr;
+        Network *network;
+        struct in6_addr in_addr;
 
-    LIST_FIELDS(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
+        LIST_FIELDS(IPv6ProxyNDPAddress, ipv6_proxy_ndp_addresses);
 };
 
-int ipv6_proxy_ndp_address_new_static(Network *network, IPv6ProxyNDPAddress ** ipv6_proxy_ndp_address);
 void ipv6_proxy_ndp_address_free(IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
 int ipv6_proxy_ndp_address_configure(Link *link, IPv6ProxyNDPAddress *ipv6_proxy_ndp_address);
 int ipv6_proxy_ndp_addresses_configure(Link *link);
index 22392d7..3e334c8 100644 (file)
@@ -14,6 +14,7 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "missing_network.h"
+#include "netdev/vrf.h"
 #include "netlink-util.h"
 #include "network-internal.h"
 #include "networkd-ipv6-proxy-ndp.h"
 #include "stdio-util.h"
 #include "string-table.h"
 #include "strv.h"
+#include "sysctl-util.h"
 #include "tmpfile-util.h"
+#include "udev-util.h"
 #include "util.h"
 #include "virt.h"
 
+uint32_t link_get_vrf_table(Link *link) {
+        return link->network->vrf ? VRF(link->network->vrf)->table : RT_TABLE_MAIN;
+}
+
+uint32_t link_get_dhcp_route_table(Link *link) {
+        /* When the interface is part of an VRF use the VRFs routing table, unless
+         * another table is explicitly specified. */
+        if (link->network->dhcp_route_table_set)
+                return link->network->dhcp_route_table;
+        return link_get_vrf_table(link);
+}
+
+uint32_t link_get_ipv6_accept_ra_route_table(Link *link) {
+        if (link->network->ipv6_accept_ra_route_table_set)
+                return link->network->ipv6_accept_ra_route_table;
+        return link_get_vrf_table(link);
+}
+
 DUID* link_get_duid(Link *link) {
         if (link->network->duid.type != _DUID_TYPE_INVALID)
                 return &link->network->duid;
@@ -51,6 +72,12 @@ static bool link_dhcp6_enabled(Link *link) {
         if (!link->network)
                 return false;
 
+        if (link->network->bond)
+                return false;
+
+        if (manager_sysctl_ipv6_enabled(link->manager) == 0)
+                return false;
+
         return link->network->dhcp & ADDRESS_FAMILY_IPV6;
 }
 
@@ -63,6 +90,9 @@ static bool link_dhcp4_enabled(Link *link) {
         if (!link->network)
                 return false;
 
+        if (link->network->bond)
+                return false;
+
         return link->network->dhcp & ADDRESS_FAMILY_IPV4;
 }
 
@@ -75,6 +105,9 @@ static bool link_dhcp4_server_enabled(Link *link) {
         if (!link->network)
                 return false;
 
+        if (link->network->bond)
+                return false;
+
         return link->network->dhcp_server;
 }
 
@@ -87,7 +120,10 @@ static bool link_ipv4ll_enabled(Link *link) {
         if (!link->network)
                 return false;
 
-        if (streq_ptr(link->kind, "wireguard"))
+        if (STRPTR_IN_SET(link->kind, "vrf", "wireguard"))
+                return false;
+
+        if (link->network->bond)
                 return false;
 
         return link->network->link_local & ADDRESS_FAMILY_IPV4;
@@ -105,7 +141,13 @@ static bool link_ipv6ll_enabled(Link *link) {
         if (!link->network)
                 return false;
 
-        if (streq_ptr(link->kind, "wireguard"))
+        if (STRPTR_IN_SET(link->kind, "vrf", "wireguard"))
+                return false;
+
+        if (link->network->bond)
+                return false;
+
+        if (manager_sysctl_ipv6_enabled(link->manager) == 0)
                 return false;
 
         return link->network->link_local & ADDRESS_FAMILY_IPV6;
@@ -117,7 +159,10 @@ static bool link_ipv6_enabled(Link *link) {
         if (!socket_ipv6_is_supported())
                 return false;
 
-        if (link->network->bridge)
+        if (link->network->bond)
+                return false;
+
+        if (manager_sysctl_ipv6_enabled(link->manager) == 0)
                 return false;
 
         /* DHCPv6 client will not be started if no IPv6 link-local address is configured. */
@@ -199,6 +244,9 @@ static bool link_ipv6_forward_enabled(Link *link) {
         if (link->network->ip_forward == _ADDRESS_FAMILY_BOOLEAN_INVALID)
                 return false;
 
+        if (manager_sysctl_ipv6_enabled(link->manager) == 0)
+                return false;
+
         return link->network->ip_forward & ADDRESS_FAMILY_IPV6;
 }
 
@@ -263,7 +311,6 @@ static IPv6PrivacyExtensions link_ipv6_privacy_extensions(Link *link) {
 }
 
 static int link_enable_ipv6(Link *link) {
-        const char *p = NULL;
         bool disabled;
         int r;
 
@@ -272,9 +319,7 @@ static int link_enable_ipv6(Link *link) {
 
         disabled = !link_ipv6_enabled(link);
 
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/disable_ipv6");
-
-        r = write_string_file(p, one_zero(disabled), WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property_boolean(AF_INET6, link->ifname, "disable_ipv6", disabled);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot %s IPv6 for interface %s: %m",
                                        enable_disable(!disabled), link->ifname);
@@ -284,8 +329,40 @@ static int link_enable_ipv6(Link *link) {
         return 0;
 }
 
-void link_update_operstate(Link *link) {
+static bool link_is_enslaved(Link *link) {
+        if (link->flags & IFF_SLAVE)
+                /* Even if the link is not managed by networkd, honor IFF_SLAVE flag. */
+                return true;
+
+        if (!link->enslaved_raw)
+                return false;
+
+        if (!link->network)
+                return false;
+
+        if (link->network->bridge)
+                /* TODO: support the case when link is not managed by networkd. */
+                return true;
+
+        return false;
+}
+
+static void link_update_master_operstate(Link *link, NetDev *netdev) {
+        Link *master;
+
+        if (!netdev)
+                return;
+
+        if (link_get(link->manager, netdev->ifindex, &master) < 0)
+                return;
+
+        link_update_operstate(master, true);
+}
+
+void link_update_operstate(Link *link, bool also_update_master) {
         LinkOperationalState operstate;
+        Iterator i;
+
         assert(link);
 
         if (link->kernel_operstate == IF_OPER_DORMANT)
@@ -293,7 +370,6 @@ void link_update_operstate(Link *link) {
         else if (link_has_carrier(link)) {
                 Address *address;
                 uint8_t scope = RT_SCOPE_NOWHERE;
-                Iterator i;
 
                 /* if we have carrier, check what addresses we have */
                 SET_FOREACH(address, link->addresses, i) {
@@ -327,11 +403,31 @@ void link_update_operstate(Link *link) {
         else
                 operstate = LINK_OPERSTATE_OFF;
 
+        if (IN_SET(operstate, LINK_OPERSTATE_DEGRADED, LINK_OPERSTATE_CARRIER) &&
+            link_is_enslaved(link))
+                operstate = LINK_OPERSTATE_ENSLAVED;
+
+        if (operstate >= LINK_OPERSTATE_CARRIER) {
+                Link *slave;
+
+                HASHMAP_FOREACH(slave, link->slaves, i) {
+                        link_update_operstate(slave, false);
+
+                        if (slave->operstate < LINK_OPERSTATE_CARRIER)
+                                operstate = LINK_OPERSTATE_DEGRADED_CARRIER;
+                }
+        }
+
         if (link->operstate != operstate) {
                 link->operstate = operstate;
                 link_send_changed(link, "OperationalState", NULL);
                 link_dirty(link);
         }
+
+        if (also_update_master && link->network) {
+                link_update_master_operstate(link, link->network->bond);
+                link_update_master_operstate(link, link->network->bridge);
+        }
 }
 
 #define FLAG_STRING(string, flag, old, new) \
@@ -406,7 +502,7 @@ static int link_update_flags(Link *link, sd_netlink_message *m) {
         link->flags = flags;
         link->kernel_operstate = operstate;
 
-        link_update_operstate(link);
+        link_update_operstate(link, true);
 
         return 0;
 }
@@ -520,8 +616,8 @@ static void link_detach_from_manager(Link *link) {
 }
 
 static Link *link_free(Link *link) {
+        Link *carrier, *master;
         Address *address;
-        Link *carrier;
         Route *route;
         Iterator i;
 
@@ -587,6 +683,18 @@ static Link *link_free(Link *link) {
                 hashmap_remove(link->bound_by_links, INT_TO_PTR(carrier->ifindex));
         hashmap_free(link->bound_by_links);
 
+        hashmap_free(link->slaves);
+
+        if (link->network) {
+                if (link->network->bond &&
+                    link_get(link->manager, link->network->bond->ifindex, &master) >= 0)
+                        (void) hashmap_remove(master->slaves, INT_TO_PTR(link->ifindex));
+
+                if (link->network->bridge &&
+                    link_get(link->manager, link->network->bridge->ifindex, &master) >= 0)
+                        (void) hashmap_remove(master->slaves, INT_TO_PTR(link->ifindex));
+        }
+
         return mfree(link);
 }
 
@@ -714,6 +822,35 @@ static Address* link_find_dhcp_server_address(Link *link) {
         return NULL;
 }
 
+static int link_join_netdevs_after_configured(Link *link) {
+        NetDev *netdev;
+        Iterator i;
+        int r;
+
+        HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
+                if (netdev->ifindex > 0)
+                        /* Assume already enslaved. */
+                        continue;
+
+                if (netdev_get_create_type(netdev) != NETDEV_CREATE_AFTER_CONFIGURED)
+                        continue;
+
+                log_struct(LOG_DEBUG,
+                           LOG_LINK_INTERFACE(link),
+                           LOG_NETDEV_INTERFACE(netdev),
+                           LOG_LINK_MESSAGE(link, "Enslaving by '%s'", netdev->ifname));
+
+                r = netdev_join(netdev, link, NULL);
+                if (r < 0)
+                        return log_struct_errno(LOG_WARNING, r,
+                                                LOG_LINK_INTERFACE(link),
+                                                LOG_NETDEV_INTERFACE(netdev),
+                                                LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", netdev->ifname));
+        }
+
+        return 0;
+}
+
 static void link_enter_configured(Link *link) {
         assert(link);
         assert(link->network);
@@ -725,6 +862,8 @@ static void link_enter_configured(Link *link) {
 
         link_set_state(link, LINK_STATE_CONFIGURED);
 
+        (void) link_join_netdevs_after_configured(link);
+
         link_dirty(link);
 }
 
@@ -879,23 +1018,20 @@ void link_check_ready(Link *link) {
                     !link->ipv4ll_route)
                         return;
 
-        if (!link->network->bridge) {
-
-                if (link_ipv6ll_enabled(link))
-                        if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0)
-                                return;
+        if (link_ipv6ll_enabled(link) &&
+            in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address))
+                return;
 
-                if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
-                     !link->dhcp4_configured) ||
-                    (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
-                     !link->dhcp6_configured) ||
-                    (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
-                     !link->dhcp4_configured && !link->dhcp6_configured))
-                        return;
+        if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
+             !link->dhcp4_configured) ||
+            (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
+             !link->dhcp6_configured) ||
+            (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
+             !link->dhcp4_configured && !link->dhcp6_configured))
+                return;
 
-                if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
-                        return;
-        }
+        if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
+                return;
 
         if (link->state != LINK_STATE_CONFIGURED)
                 link_enter_configured(link);
@@ -994,7 +1130,7 @@ static int link_push_uplink_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
 
         if (link->network->dhcp_use_dns && link->dhcp_lease) {
                 const struct in_addr *da = NULL;
-                int n;
+                int j, n;
 
                 n = sd_dhcp_lease_get_dns(link->dhcp_lease, &da);
                 if (n > 0) {
@@ -1002,8 +1138,9 @@ static int link_push_uplink_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
                         if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n))
                                 return log_oom();
 
-                        memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr));
-                        n_addresses += n;
+                        for (j = 0; j < n; j++)
+                                if (in4_addr_is_non_local(&da[j]))
+                                        addresses[n_addresses++] = da[j];
                 }
         }
 
@@ -1042,7 +1179,7 @@ static int link_push_uplink_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) {
 
         if (link->network->dhcp_use_ntp && link->dhcp_lease) {
                 const struct in_addr *da = NULL;
-                int n;
+                int j, n;
 
                 n = sd_dhcp_lease_get_ntp(link->dhcp_lease, &da);
                 if (n > 0) {
@@ -1050,8 +1187,9 @@ static int link_push_uplink_ntp_to_dhcp_server(Link *link, sd_dhcp_server *s) {
                         if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n))
                                 return log_oom();
 
-                        memcpy(addresses + n_addresses, da, n * sizeof(struct in_addr));
-                        n_addresses += n;
+                        for (j = 0; j < n; j++)
+                                if (in4_addr_is_non_local(&da[j]))
+                                        addresses[n_addresses++] = da[j];
                 }
         }
 
@@ -1264,15 +1402,12 @@ static int link_set_bridge_vlan(Link *link) {
 }
 
 static int link_set_proxy_arp(Link *link) {
-        const char *p = NULL;
         int r;
 
         if (!link_proxy_arp_enabled(link))
                 return 0;
 
-        p = strjoina("/proc/sys/net/ipv4/conf/", link->ifname, "/proxy_arp");
-
-        r = write_string_file(p, one_zero(link->network->proxy_arp), WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "proxy_arp", link->network->proxy_arp > 0);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot configure proxy ARP for interface: %m");
 
@@ -1323,7 +1458,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
         return 1;
 }
 
-int link_set_mtu(Link *link, uint32_t mtu) {
+int link_set_mtu(Link *link, uint32_t mtu, bool force) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -1331,7 +1466,10 @@ int link_set_mtu(Link *link, uint32_t mtu) {
         assert(link->manager);
         assert(link->manager->rtnl);
 
-        if (link->mtu == mtu || link->setting_mtu)
+        if (mtu == 0 || link->setting_mtu)
+                return 0;
+
+        if (force ? link->mtu == mtu : link->mtu >= mtu)
                 return 0;
 
         log_link_debug(link, "Setting MTU: %" PRIu32, mtu);
@@ -1341,7 +1479,7 @@ int link_set_mtu(Link *link, uint32_t mtu) {
                 return log_link_error_errno(link, r, "Could not allocate RTM_SETLINK message: %m");
 
         /* If IPv6 not configured (no static IPv6 address and IPv6LL autoconfiguration is disabled)
-         * for this interface, or if it is a bridge slave, then disable IPv6 else enable it. */
+         * for this interface, then disable IPv6 else enable it. */
         (void) link_enable_ipv6(link);
 
         /* IPv6 protocol requires a minimum MTU of IPV6_MTU_MIN(1280) bytes
@@ -1488,12 +1626,30 @@ static int link_set_bridge(Link *link) {
                         return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_UNICAST_FLOOD attribute: %m");
         }
 
+        if (link->network->multicast_flood >= 0) {
+                r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_FLOOD, link->network->multicast_flood);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_FLOOD attribute: %m");
+        }
+
         if (link->network->multicast_to_unicast >= 0) {
                 r = sd_netlink_message_append_u8(req, IFLA_BRPORT_MCAST_TO_UCAST, link->network->multicast_to_unicast);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_MCAST_TO_UCAST attribute: %m");
         }
 
+        if (link->network->neighbor_suppression >= 0) {
+                r = sd_netlink_message_append_u8(req, IFLA_BRPORT_NEIGH_SUPPRESS, link->network->neighbor_suppression);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_NEIGH_SUPPRESS attribute: %m");
+        }
+
+        if (link->network->learning >= 0) {
+                r = sd_netlink_message_append_u8(req, IFLA_BRPORT_LEARNING, link->network->learning);
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_BRPORT_LEARNING attribute: %m");
+        }
+
         if (link->network->cost != 0) {
                 r = sd_netlink_message_append_u32(req, IFLA_BRPORT_COST, link->network->cost);
                 if (r < 0)
@@ -1520,7 +1676,26 @@ static int link_set_bridge(Link *link) {
         return r;
 }
 
-static int link_bond_set(Link *link) {
+static int link_set_bond_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
+        int r;
+
+        assert(m);
+        assert(link);
+        assert(link->ifname);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return 1;
+
+        r = sd_netlink_message_get_errno(m);
+        if (r < 0) {
+                log_link_warning_errno(link, r, "Could not set bonding interface: %m");
+                return 1;
+        }
+
+        return 1;
+}
+
+static int link_set_bond(Link *link) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -1563,7 +1738,7 @@ static int link_bond_set(Link *link) {
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFLA_INFO_DATA attribute: %m");
 
-        r = netlink_call_async(link->manager->rtnl, NULL, req, set_flags_handler,
+        r = netlink_call_async(link->manager->rtnl, NULL, req, link_set_bond_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_link_error_errno(link, r,  "Could not send rtnetlink message: %m");
@@ -1573,6 +1748,28 @@ static int link_bond_set(Link *link) {
         return r;
 }
 
+static int link_append_to_master(Link *link, NetDev *netdev) {
+        Link *master;
+        int r;
+
+        assert(link);
+        assert(netdev);
+
+        r = link_get(link->manager, netdev->ifindex, &master);
+        if (r < 0)
+                return r;
+
+        r = hashmap_ensure_allocated(&master->slaves, NULL);
+        if (r < 0)
+                return r;
+
+        r = hashmap_put(master->slaves, INT_TO_PTR(link->ifindex), link);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 static int link_lldp_save(Link *link) {
         _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
@@ -1734,7 +1931,7 @@ static int link_acquire_conf(Link *link) {
         if (r < 0)
                 return r;
 
-        if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) == 0) {
+        if (!in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) {
                 r = link_acquire_ipv6_conf(link);
                 if (r < 0)
                         return r;
@@ -1804,20 +2001,12 @@ static int link_configure_addrgen_mode(Link *link) {
 
         if (!link_ipv6ll_enabled(link))
                 ipv6ll_mode = IN6_ADDR_GEN_MODE_NONE;
-        else {
-                const char *p = NULL;
-                _cleanup_free_ char *stable_secret = NULL;
-
-                p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/stable_secret");
-
+        else if (sysctl_read_ip_property(AF_INET6, link->ifname, "stable_secret", NULL) < 0)
                 /* The file may not exist. And event if it exists, when stable_secret is unset,
-                 * then reading the file fails and EIO is returned. */
-                r = read_one_line_file(p, &stable_secret);
-                if (r < 0)
-                        ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64;
-                else
-                        ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
-        }
+                 * reading the file fails with EIO. */
+                ipv6ll_mode = IN6_ADDR_GEN_MODE_EUI64;
+        else
+                ipv6ll_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
 
         r = sd_netlink_message_append_u8(req, IFLA_INET6_ADDR_GEN_MODE, ipv6ll_mode);
         if (r < 0)
@@ -2022,6 +2211,19 @@ static int link_set_can(Link *link) {
                         return log_link_error_errno(link, r, "Could not append IFLA_CAN_RESTART_MS attribute: %m");
         }
 
+        if (link->network->can_triple_sampling >= 0) {
+                struct can_ctrlmode cm = {
+                        .mask = CAN_CTRLMODE_3_SAMPLES,
+                        .flags = link->network->can_triple_sampling ? CAN_CTRLMODE_3_SAMPLES : 0,
+                };
+
+                log_link_debug(link, "%sabling triple-sampling", link->network->can_triple_sampling ? "En" : "Dis");
+
+                r = sd_netlink_message_append_data(m, IFLA_CAN_CTRLMODE, &cm, sizeof(cm));
+                if (r < 0)
+                        return log_link_error_errno(link, r, "Could not append IFLA_CAN_CTRLMODE attribute: %m");
+        }
+
         r = sd_netlink_message_close_container(m);
         if (r < 0)
                 return log_link_error_errno(link, r, "Failed to close netlink container: %m");
@@ -2371,12 +2573,20 @@ static int link_joined(Link *link) {
                 r = link_set_bridge(link);
                 if (r < 0)
                         log_link_error_errno(link, r, "Could not set bridge message: %m");
+
+                r = link_append_to_master(link, link->network->bridge);
+                if (r < 0)
+                        log_link_error_errno(link, r, "Failed to add to bridge master's slave list: %m");
         }
 
         if (link->network->bond) {
-                r = link_bond_set(link);
+                r = link_set_bond(link);
                 if (r < 0)
                         log_link_error_errno(link, r, "Could not set bond message: %m");
+
+                r = link_append_to_master(link, link->network->bond);
+                if (r < 0)
+                        log_link_error_errno(link, r, "Failed to add to bond master's slave list: %m");
         }
 
         if (link->network->use_br_vlan &&
@@ -2400,6 +2610,8 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
 
         assert(link);
         assert(link->network);
+        assert(link->enslaving > 0);
+        assert(!link->enslaved_raw);
 
         link->enslaving--;
 
@@ -2414,8 +2626,10 @@ static int netdev_join_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
         } else
                 log_link_debug(link, "Joined netdev");
 
-        if (link->enslaving <= 0)
+        if (link->enslaving == 0) {
+                link->enslaved_raw = true;
                 link_joined(link);
+        }
 
         return 1;
 }
@@ -2432,12 +2646,8 @@ static int link_enter_join_netdev(Link *link) {
         link_set_state(link, LINK_STATE_CONFIGURING);
 
         link_dirty(link);
-
-        if (!link->network->bridge &&
-            !link->network->bond &&
-            !link->network->vrf &&
-            hashmap_isempty(link->network->stacked_netdevs))
-                return link_joined(link);
+        link->enslaving = 0;
+        link->enslaved_raw = false;
 
         if (link->network->bond) {
                 if (link->network->bond->state == NETDEV_STATE_READY &&
@@ -2449,6 +2659,8 @@ static int link_enter_join_netdev(Link *link) {
                            LOG_NETDEV_INTERFACE(link->network->bond),
                            LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bond->ifname));
 
+                link->enslaving++;
+
                 r = netdev_join(link->network->bond, link, netdev_join_handler);
                 if (r < 0) {
                         log_struct_errno(LOG_WARNING, r,
@@ -2458,8 +2670,6 @@ static int link_enter_join_netdev(Link *link) {
                         link_enter_failed(link);
                         return r;
                 }
-
-                link->enslaving++;
         }
 
         if (link->network->bridge) {
@@ -2468,6 +2678,8 @@ static int link_enter_join_netdev(Link *link) {
                            LOG_NETDEV_INTERFACE(link->network->bridge),
                            LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->bridge->ifname));
 
+                link->enslaving++;
+
                 r = netdev_join(link->network->bridge, link, netdev_join_handler);
                 if (r < 0) {
                         log_struct_errno(LOG_WARNING, r,
@@ -2477,8 +2689,6 @@ static int link_enter_join_netdev(Link *link) {
                         link_enter_failed(link);
                         return r;
                 }
-
-                link->enslaving++;
         }
 
         if (link->network->vrf) {
@@ -2487,6 +2697,8 @@ static int link_enter_join_netdev(Link *link) {
                            LOG_NETDEV_INTERFACE(link->network->vrf),
                            LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->vrf->ifname));
 
+                link->enslaving++;
+
                 r = netdev_join(link->network->vrf, link, netdev_join_handler);
                 if (r < 0) {
                         log_struct_errno(LOG_WARNING, r,
@@ -2496,22 +2708,24 @@ static int link_enter_join_netdev(Link *link) {
                         link_enter_failed(link);
                         return r;
                 }
-
-                link->enslaving++;
         }
 
         HASHMAP_FOREACH(netdev, link->network->stacked_netdevs, i) {
 
-                if (netdev->ifindex > 0) {
-                        link_joined(link);
+                if (netdev->ifindex > 0)
+                        /* Assume already enslaved. */
+                        continue;
+
+                if (netdev_get_create_type(netdev) != NETDEV_CREATE_STACKED)
                         continue;
-                }
 
                 log_struct(LOG_DEBUG,
                            LOG_LINK_INTERFACE(link),
                            LOG_NETDEV_INTERFACE(netdev),
                            LOG_LINK_MESSAGE(link, "Enslaving by '%s'", netdev->ifname));
 
+                link->enslaving++;
+
                 r = netdev_join(netdev, link, netdev_join_handler);
                 if (r < 0) {
                         log_struct_errno(LOG_WARNING, r,
@@ -2521,10 +2735,11 @@ static int link_enter_join_netdev(Link *link) {
                         link_enter_failed(link);
                         return r;
                 }
-
-                link->enslaving++;
         }
 
+        if (link->enslaving == 0)
+                return link_joined(link);
+
         return 0;
 }
 
@@ -2541,7 +2756,7 @@ static int link_set_ipv4_forward(Link *link) {
          * primarily to keep IPv4 and IPv6 packet forwarding behaviour
          * somewhat in sync (see below). */
 
-        r = write_string_file("/proc/sys/net/ipv4/ip_forward", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property(AF_INET, NULL, "ip_forward", "1");
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot turn on IPv4 packet forwarding, ignoring: %m");
 
@@ -2563,7 +2778,7 @@ static int link_set_ipv6_forward(Link *link) {
          * same behaviour there and also propagate the setting from
          * one to all, to keep things simple (see above). */
 
-        r = write_string_file("/proc/sys/net/ipv6/conf/all/forwarding", "1", WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property(AF_INET6, "all", "forwarding", "1");
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot configure IPv6 packet forwarding, ignoring: %m");
 
@@ -2571,19 +2786,14 @@ static int link_set_ipv6_forward(Link *link) {
 }
 
 static int link_set_ipv6_privacy_extensions(Link *link) {
-        char buf[DECIMAL_STR_MAX(unsigned) + 1];
         IPv6PrivacyExtensions s;
-        const char *p = NULL;
         int r;
 
         s = link_ipv6_privacy_extensions(link);
         if (s < 0)
                 return 0;
 
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/use_tempaddr");
-        xsprintf(buf, "%u", (unsigned) link->network->ipv6_privacy_extensions);
-
-        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property_int(AF_INET6, link->ifname, "use_tempaddr", (int) link->network->ipv6_privacy_extensions);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot configure IPv6 privacy extension for interface: %m");
 
@@ -2591,7 +2801,6 @@ static int link_set_ipv6_privacy_extensions(Link *link) {
 }
 
 static int link_set_ipv6_accept_ra(Link *link) {
-        const char *p = NULL;
         int r;
 
         /* Make this a NOP if IPv6 is not available */
@@ -2604,10 +2813,7 @@ static int link_set_ipv6_accept_ra(Link *link) {
         if (!link->network)
                 return 0;
 
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/accept_ra");
-
-        /* We handle router advertisements ourselves, tell the kernel to GTFO */
-        r = write_string_file(p, "0", WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property(AF_INET6, link->ifname, "accept_ra", "0");
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot disable kernel IPv6 accept_ra for interface: %m");
 
@@ -2615,8 +2821,6 @@ static int link_set_ipv6_accept_ra(Link *link) {
 }
 
 static int link_set_ipv6_dad_transmits(Link *link) {
-        char buf[DECIMAL_STR_MAX(int) + 1];
-        const char *p = NULL;
         int r;
 
         /* Make this a NOP if IPv6 is not available */
@@ -2632,10 +2836,7 @@ static int link_set_ipv6_dad_transmits(Link *link) {
         if (link->network->ipv6_dad_transmits < 0)
                 return 0;
 
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/dad_transmits");
-        xsprintf(buf, "%i", link->network->ipv6_dad_transmits);
-
-        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property_int(AF_INET6, link->ifname, "dad_transmits", link->network->ipv6_dad_transmits);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv6 dad transmits for interface: %m");
 
@@ -2643,8 +2844,6 @@ static int link_set_ipv6_dad_transmits(Link *link) {
 }
 
 static int link_set_ipv6_hop_limit(Link *link) {
-        char buf[DECIMAL_STR_MAX(int) + 1];
-        const char *p = NULL;
         int r;
 
         /* Make this a NOP if IPv6 is not available */
@@ -2660,10 +2859,7 @@ static int link_set_ipv6_hop_limit(Link *link) {
         if (link->network->ipv6_hop_limit < 0)
                 return 0;
 
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/hop_limit");
-        xsprintf(buf, "%i", link->network->ipv6_hop_limit);
-
-        r = write_string_file(p, buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface: %m");
 
@@ -2671,8 +2867,6 @@ static int link_set_ipv6_hop_limit(Link *link) {
 }
 
 static int link_set_ipv6_mtu(Link *link) {
-        char buf[DECIMAL_STR_MAX(unsigned) + 1];
-        const char *p = NULL;
         int r;
 
         /* Make this a NOP if IPv6 is not available */
@@ -2685,11 +2879,7 @@ static int link_set_ipv6_mtu(Link *link) {
         if (link->network->ipv6_mtu == 0)
                 return 0;
 
-        p = strjoina("/proc/sys/net/ipv6/conf/", link->ifname, "/mtu");
-
-        xsprintf(buf, "%" PRIu32, link->network->ipv6_mtu);
-
-        r = write_string_file(p, buf, WRITE_STRING_FILE_DISABLE_BUFFER);
+        r = sysctl_write_ip_property_uint32(AF_INET6, link->ifname, "mtu", link->network->ipv6_mtu);
         if (r < 0)
                 log_link_warning_errno(link, r, "Cannot set IPv6 MTU for interface: %m");
 
@@ -2995,11 +3185,9 @@ static int link_configure(Link *link) {
                         return r;
         }
 
-        if (link->network->mtu > 0) {
-                r = link_set_mtu(link, link->network->mtu);
-                if (r < 0)
-                        return r;
-        }
+        r = link_set_mtu(link, link->network->mtu, link->network->mtu_is_set);
+        if (r < 0)
+                return r;
 
         if (socket_ipv6_is_supported()) {
                 r = link_configure_addrgen_mode(link);
@@ -3500,6 +3688,16 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) {
                         return 0;
                 }
 
+                r = device_is_renaming(device);
+                if (r < 0) {
+                        log_link_warning_errno(link, r, "Failed to determine the device is renamed or not: %m");
+                        goto failed;
+                }
+                if (r > 0) {
+                        log_link_debug(link, "Interface is under renaming, pending initialization.");
+                        return 0;
+                }
+
                 r = link_initialized(link, device);
                 if (r < 0)
                         goto failed;
@@ -3565,6 +3763,9 @@ static int link_carrier_lost(Link *link) {
 
         assert(link);
 
+        if (link->network && link->network->ignore_carrier_loss)
+                return 0;
+
         /* Some devices reset itself while setting the MTU. This causes the DHCP client fall into a loop.
          * setting_mtu keep track whether the device got reset because of setting MTU and does not drop the
          * configuration and stop the clients as well. */
@@ -3640,20 +3841,14 @@ int link_update(Link *link, sd_netlink_message *m) {
 
         r = sd_netlink_message_read_string(m, IFLA_IFNAME, &ifname);
         if (r >= 0 && !streq(ifname, link->ifname)) {
-                log_link_info(link, "Interface name change detected, %s has been renamed to %s.", link->ifname, ifname);
+                Manager *manager = link->manager;
 
-                if (link->state == LINK_STATE_PENDING) {
-                        r = free_and_strdup(&link->ifname, ifname);
-                        if (r < 0)
-                                return r;
-                } else {
-                        Manager *manager = link->manager;
+                log_link_info(link, "Interface name change detected, %s has been renamed to %s.", link->ifname, ifname);
 
-                        link_drop(link);
-                        r = link_add(manager, m, &link);
-                        if (r < 0)
-                                return r;
-                }
+                link_drop(link);
+                r = link_add(manager, m, &link);
+                if (r < 0)
+                        return r;
         }
 
         r = sd_netlink_message_read_u32(m, IFLA_MTU, &mtu);
@@ -3823,7 +4018,7 @@ int link_save(Link *link) {
         assert(link->manager);
 
         if (link->state == LINK_STATE_LINGER) {
-                unlink(link->state_file);
+                (void) unlink(link->state_file);
                 return 0;
         }
 
@@ -3859,6 +4054,9 @@ int link_save(Link *link) {
                 fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
                         yes_no(link->network->required_for_online));
 
+                fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s\n",
+                        strempty(link_operstate_to_string(link->network->required_operstate_for_online)));
+
                 if (link->dhcp6_client) {
                         r = sd_dhcp6_client_get_lease(link->dhcp6_client, &dhcp6_lease);
                         if (r < 0 && r != -ENOMSG)
@@ -3891,12 +4089,9 @@ int link_save(Link *link) {
                         const struct in_addr *addresses;
 
                         r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
-                        if (r > 0) {
-                                if (space)
-                                        fputc(' ', f);
-                                serialize_in_addrs(f, addresses, r);
-                                space = true;
-                        }
+                        if (r > 0)
+                                if (serialize_in_addrs(f, addresses, r, space, in4_addr_is_non_local) > 0)
+                                        space = true;
                 }
 
                 if (link->network->dhcp_use_dns && dhcp6_lease) {
@@ -3937,12 +4132,9 @@ int link_save(Link *link) {
                         const struct in_addr *addresses;
 
                         r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
-                        if (r > 0) {
-                                if (space)
-                                        fputc(' ', f);
-                                serialize_in_addrs(f, addresses, r);
-                                space = true;
-                        }
+                        if (r > 0)
+                                if (serialize_in_addrs(f, addresses, r, space, in4_addr_is_non_local) > 0)
+                                        space = true;
                 }
 
                 if (link->network->dhcp_use_ntp && dhcp6_lease) {
@@ -3974,9 +4166,7 @@ int link_save(Link *link) {
                                 (void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
                 }
 
-                fputs("DOMAINS=", f);
-                space = false;
-                fputstrv(f, link->network->search_domains, NULL, &space);
+                ordered_set_print(f, "DOMAINS=", link->network->search_domains);
 
                 if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
                         NDiscDNSSL *dd;
@@ -3994,9 +4184,7 @@ int link_save(Link *link) {
 
                 fputc('\n', f);
 
-                fputs("ROUTE_DOMAINS=", f);
-                space = false;
-                fputstrv(f, link->network->route_domains, NULL, &space);
+                ordered_set_print(f, "ROUTE_DOMAINS=", link->network->route_domains);
 
                 if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
                         NDiscDNSSL *dd;
@@ -4087,7 +4275,7 @@ int link_save(Link *link) {
                 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
                 if (r >= 0) {
                         fputs("DHCP4_ADDRESS=", f);
-                        serialize_in_addrs(f, &address, 1);
+                        serialize_in_addrs(f, &address, 1, false, NULL);
                         fputc('\n', f);
                 }
 
@@ -4099,7 +4287,7 @@ int link_save(Link *link) {
                         "DHCP_LEASE=%s\n",
                         link->lease_file);
         } else
-                unlink(link->lease_file);
+                (void) unlink(link->lease_file);
 
         if (link->ipv4ll) {
                 struct in_addr address;
@@ -4107,7 +4295,7 @@ int link_save(Link *link) {
                 r = sd_ipv4ll_get_address(link->ipv4ll, &address);
                 if (r >= 0) {
                         fputs("IPV4LL_ADDRESS=", f);
-                        serialize_in_addrs(f, &address, 1);
+                        serialize_in_addrs(f, &address, 1, false, NULL);
                         fputc('\n', f);
                 }
         }
@@ -4171,14 +4359,3 @@ static const char* const link_state_table[_LINK_STATE_MAX] = {
 };
 
 DEFINE_STRING_TABLE_LOOKUP(link_state, LinkState);
-
-static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = {
-        [LINK_OPERSTATE_OFF] = "off",
-        [LINK_OPERSTATE_NO_CARRIER] = "no-carrier",
-        [LINK_OPERSTATE_DORMANT] = "dormant",
-        [LINK_OPERSTATE_CARRIER] = "carrier",
-        [LINK_OPERSTATE_DEGRADED] = "degraded",
-        [LINK_OPERSTATE_ROUTABLE] = "routable",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState);
index dcb1ea6..e65246c 100644 (file)
@@ -15,6 +15,8 @@
 #include "sd-netlink.h"
 
 #include "list.h"
+#include "log-link.h"
+#include "network-util.h"
 #include "set.h"
 
 typedef enum LinkState {
@@ -28,17 +30,6 @@ typedef enum LinkState {
         _LINK_STATE_INVALID = -1
 } LinkState;
 
-typedef enum LinkOperationalState {
-        LINK_OPERSTATE_OFF,
-        LINK_OPERSTATE_NO_CARRIER,
-        LINK_OPERSTATE_DORMANT,
-        LINK_OPERSTATE_CARRIER,
-        LINK_OPERSTATE_DEGRADED,
-        LINK_OPERSTATE_ROUTABLE,
-        _LINK_OPERSTATE_MAX,
-        _LINK_OPERSTATE_INVALID = -1
-} LinkOperationalState;
-
 typedef struct Manager Manager;
 typedef struct Network Network;
 typedef struct Address Address;
@@ -75,6 +66,8 @@ typedef struct Link {
         unsigned routing_policy_rule_messages;
         unsigned routing_policy_rule_remove_messages;
         unsigned enslaving;
+        /* link_is_enslaved() has additional checks. So, it is named _raw. */
+        bool enslaved_raw;
 
         Set *addresses;
         Set *addresses_foreign;
@@ -128,6 +121,7 @@ typedef struct Link {
 
         Hashmap *bound_by_links;
         Hashmap *bound_to_links;
+        Hashmap *slaves;
 } Link;
 
 typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
@@ -150,7 +144,7 @@ int link_initialized(Link *link, sd_device *device);
 
 void link_check_ready(Link *link);
 
-void link_update_operstate(Link *link);
+void link_update_operstate(Link *link, bool also_update_bond_master);
 int link_update(Link *link, sd_netlink_message *message);
 
 void link_dirty(Link *link);
@@ -162,7 +156,7 @@ bool link_has_carrier(Link *link);
 
 int link_ipv6ll_gained(Link *link, const struct in6_addr *address);
 
-int link_set_mtu(Link *link, uint32_t mtu);
+int link_set_mtu(Link *link, uint32_t mtu, bool force);
 
 int ipv4ll_configure(Link *link);
 int dhcp4_configure(Link *link);
@@ -176,38 +170,15 @@ int dhcp6_lease_pd_prefix_lost(sd_dhcp6_client *client, Link* link);
 const char* link_state_to_string(LinkState s) _const_;
 LinkState link_state_from_string(const char *s) _pure_;
 
-const char* link_operstate_to_string(LinkOperationalState s) _const_;
-LinkOperationalState link_operstate_from_string(const char *s) _pure_;
-
 extern const sd_bus_vtable link_vtable[];
 
 int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error);
 int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error);
 int link_send_changed(Link *link, const char *property, ...) _sentinel_;
 
-/* Macros which append INTERFACE= to the message */
-
-#define log_link_full(link, level, error, ...)                          \
-        ({                                                              \
-                const Link *_l = (link);                                \
-                _l ? log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", _l->ifname, NULL, NULL, ##__VA_ARGS__) : \
-                        log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
-        })                                                              \
-
-#define log_link_debug(link, ...)   log_link_full(link, LOG_DEBUG, 0, ##__VA_ARGS__)
-#define log_link_info(link, ...)    log_link_full(link, LOG_INFO, 0, ##__VA_ARGS__)
-#define log_link_notice(link, ...)  log_link_full(link, LOG_NOTICE, 0, ##__VA_ARGS__)
-#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, 0, ##__VA_ARGS__)
-#define log_link_error(link, ...)   log_link_full(link, LOG_ERR, 0, ##__VA_ARGS__)
-
-#define log_link_debug_errno(link, error, ...)   log_link_full(link, LOG_DEBUG, error, ##__VA_ARGS__)
-#define log_link_info_errno(link, error, ...)    log_link_full(link, LOG_INFO, error, ##__VA_ARGS__)
-#define log_link_notice_errno(link, error, ...)  log_link_full(link, LOG_NOTICE, error, ##__VA_ARGS__)
-#define log_link_warning_errno(link, error, ...) log_link_full(link, LOG_WARNING, error, ##__VA_ARGS__)
-#define log_link_error_errno(link, error, ...)   log_link_full(link, LOG_ERR, error, ##__VA_ARGS__)
-
-#define LOG_LINK_MESSAGE(link, fmt, ...) "MESSAGE=%s: " fmt, (link)->ifname, ##__VA_ARGS__
-#define LOG_LINK_INTERFACE(link) "INTERFACE=%s", (link)->ifname
+uint32_t link_get_vrf_table(Link *link);
+uint32_t link_get_dhcp_route_table(Link *link);
+uint32_t link_get_ipv6_accept_ra_route_table(Link *link);
 
 #define ADDRESS_FMT_VAL(address)                   \
         be32toh((address).s_addr) >> 24,           \
index c8d369e..9075b0a 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/if.h>
 #include <linux/fib_rules.h>
 #include <stdio_ext.h>
+#include <unistd.h>
 
 #include "sd-daemon.h"
 #include "sd-netlink.h"
 #include "bus-util.h"
 #include "conf-parser.h"
 #include "def.h"
+#include "device-private.h"
 #include "device-util.h"
 #include "dns-domain.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "local-addresses.h"
 #include "netlink-util.h"
+#include "network-internal.h"
 #include "networkd-manager.h"
 #include "ordered-set.h"
 #include "path-util.h"
 #include "set.h"
 #include "strv.h"
+#include "sysctl-util.h"
 #include "tmpfile-util.h"
+#include "udev-util.h"
 #include "virt.h"
 
 /* use 8 MB for receive socket kernel queue. */
 #define RCVBUF_SIZE    (8*1024*1024)
 
-const char* const network_dirs[] = {
-        "/etc/systemd/network",
-        "/run/systemd/network",
-        "/usr/lib/systemd/network",
-#if HAVE_SPLIT_USR
-        "/lib/systemd/network",
-#endif
-        NULL};
-
 static int setup_default_address_pool(Manager *m) {
         AddressPool *p;
         int r;
@@ -46,11 +42,11 @@ static int setup_default_address_pool(Manager *m) {
 
         /* Add in the well-known private address ranges. */
 
-        r = address_pool_new_from_string(m, &p, AF_INET6, "fc00::", 7);
+        r = address_pool_new_from_string(m, &p, AF_INET6, "fd00::", 8);
         if (r < 0)
                 return r;
 
-        r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
+        r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
         if (r < 0)
                 return r;
 
@@ -58,7 +54,7 @@ static int setup_default_address_pool(Manager *m) {
         if (r < 0)
                 return r;
 
-        r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
+        r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
         if (r < 0)
                 return r;
 
@@ -188,21 +184,21 @@ int manager_connect_bus(Manager *m) {
 
 static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) {
         Manager *m = userdata;
-        const char *action;
+        DeviceAction action;
         Link *link = NULL;
         int r, ifindex;
 
         assert(m);
         assert(device);
 
-        r = sd_device_get_property_value(device, "ACTION", &action);
+        r = device_get_action(device, &action);
         if (r < 0) {
-                log_device_debug_errno(device, r, "Failed to get 'ACTION' property, ignoring device: %m");
+                log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m");
                 return 0;
         }
 
-        if (!STR_IN_SET(action, "add", "change")) {
-                log_device_debug(device, "Ignoring udev %s event for device.", action);
+        if (!IN_SET(action, DEVICE_ACTION_ADD, DEVICE_ACTION_CHANGE, DEVICE_ACTION_MOVE)) {
+                log_device_debug(device, "Ignoring udev %s event for device.", device_action_to_string(action));
                 return 0;
         }
 
@@ -212,6 +208,17 @@ static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *devi
                 return 0;
         }
 
+        r = device_is_renaming(device);
+        if (r < 0) {
+                log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m",
+                                       device_action_to_string(action));
+                return 0;
+        }
+        if (r > 0) {
+                log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed: %m");
+                return 0;
+        }
+
         r = link_get(m, ifindex, &link);
         if (r < 0) {
                 if (r != -ENODEV)
@@ -422,6 +429,28 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, vo
 
         (void) route_get(link, family, &dst, dst_prefixlen, tos, priority, table, &route);
 
+        if (DEBUG_LOGGING) {
+                _cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL,
+                        *buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL;
+
+                if (!in_addr_is_null(family, &dst)) {
+                        (void) in_addr_to_string(family, &dst, &buf_dst);
+                        (void) asprintf(&buf_dst_prefixlen, "/%u", dst_prefixlen);
+                }
+                if (!in_addr_is_null(family, &src))
+                        (void) in_addr_to_string(family, &src, &buf_src);
+                if (!in_addr_is_null(family, &gw))
+                        (void) in_addr_to_string(family, &gw, &buf_gw);
+                if (!in_addr_is_null(family, &prefsrc))
+                        (void) in_addr_to_string(family, &prefsrc, &buf_prefsrc);
+
+                log_link_debug(link,
+                               "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s",
+                               type == RTM_DELROUTE ? "Removing" : route ? "Updating" : "Adding",
+                               strna(buf_dst), strempty(buf_dst_prefixlen),
+                               strna(buf_src), strna(buf_gw), strna(buf_prefsrc));
+        }
+
         switch (type) {
         case RTM_NEWROUTE:
                 if (!route) {
@@ -1022,14 +1051,19 @@ static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address
         return r;
 }
 
-static int ordered_set_put_in4_addrv(OrderedSet *s, const struct in_addr *addresses, unsigned n) {
+static int ordered_set_put_in4_addrv(OrderedSet *s,
+                                     const struct in_addr *addresses,
+                                     size_t n,
+                                     bool (*predicate)(const struct in_addr *addr)) {
         int r, c = 0;
-        unsigned i;
+        size_t i;
 
         assert(s);
         assert(n == 0 || addresses);
 
         for (i = 0; i < n; i++) {
+                if (predicate && !predicate(&addresses[i]))
+                        continue;
                 r = ordered_set_put_in4_addr(s, addresses+i);
                 if (r < 0)
                         return r;
@@ -1040,22 +1074,6 @@ static int ordered_set_put_in4_addrv(OrderedSet *s, const struct in_addr *addres
         return c;
 }
 
-static void print_string_set(FILE *f, const char *field, OrderedSet *s) {
-        bool space = false;
-        Iterator i;
-        char *p;
-
-        if (ordered_set_isempty(s))
-                return;
-
-        fputs(field, f);
-
-        ORDERED_SET_FOREACH(p, s, i)
-                fputs_with_space(f, p, NULL, &space);
-
-        fputc('\n', f);
-}
-
 static int manager_save(Manager *m) {
         _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *search_domains = NULL, *route_domains = NULL;
         Link *link;
@@ -1105,11 +1123,11 @@ static int manager_save(Manager *m) {
                 if (r < 0)
                         return r;
 
-                r = ordered_set_put_strdupv(search_domains, link->network->search_domains);
+                r = ordered_set_put_string_set(search_domains, link->network->search_domains);
                 if (r < 0)
                         return r;
 
-                r = ordered_set_put_strdupv(route_domains, link->network->route_domains);
+                r = ordered_set_put_string_set(route_domains, link->network->route_domains);
                 if (r < 0)
                         return r;
 
@@ -1122,7 +1140,7 @@ static int manager_save(Manager *m) {
 
                         r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
                         if (r > 0) {
-                                r = ordered_set_put_in4_addrv(dns, addresses, r);
+                                r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local);
                                 if (r < 0)
                                         return r;
                         } else if (r < 0 && r != -ENODATA)
@@ -1134,7 +1152,7 @@ static int manager_save(Manager *m) {
 
                         r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
                         if (r > 0) {
-                                r = ordered_set_put_in4_addrv(ntp, addresses, r);
+                                r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local);
                                 if (r < 0)
                                         return r;
                         } else if (r < 0 && r != -ENODATA)
@@ -1178,10 +1196,10 @@ static int manager_save(Manager *m) {
                 "# This is private data. Do not parse.\n"
                 "OPER_STATE=%s\n", operstate_str);
 
-        print_string_set(f, "DNS=", dns);
-        print_string_set(f, "NTP=", ntp);
-        print_string_set(f, "DOMAINS=", search_domains);
-        print_string_set(f, "ROUTE_DOMAINS=", route_domains);
+        ordered_set_print(f, "DNS=", dns);
+        ordered_set_print(f, "NTP=", ntp);
+        ordered_set_print(f, "DOMAINS=", search_domains);
+        ordered_set_print(f, "ROUTE_DOMAINS=", route_domains);
 
         r = routing_policy_serialize_rules(m->rules, f);
         if (r < 0)
@@ -1360,6 +1378,8 @@ int manager_new(Manager **ret) {
         if (!m->state_file)
                 return -ENOMEM;
 
+        m->sysctl_ipv6_enabled = -1;
+
         r = sd_event_default(&m->event);
         if (r < 0)
                 return r;
@@ -1421,9 +1441,6 @@ void manager_free(Manager *m) {
         sd_netlink_unref(m->genl);
         sd_resolve_unref(m->resolve);
 
-        while ((network = m->networks))
-                network_free(network);
-
         while ((link = hashmap_first(m->dhcp6_prefixes)))
                 manager_dhcp6_prefix_remove_all(m, link);
         hashmap_free(m->dhcp6_prefixes);
@@ -1439,6 +1456,9 @@ void manager_free(Manager *m) {
         m->links_requesting_uuid = set_free(m->links_requesting_uuid);
         set_free(m->duids_requesting_uuid);
 
+        while ((network = m->networks))
+                network_free(network);
+
         hashmap_free(m->networks_by_name);
 
         m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
@@ -1485,7 +1505,7 @@ int manager_load_config(Manager *m) {
         int r;
 
         /* update timestamp */
-        paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
+        paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, true);
 
         r = netdev_load(m);
         if (r < 0)
@@ -1499,7 +1519,7 @@ int manager_load_config(Manager *m) {
 }
 
 bool manager_should_reload(Manager *m) {
-        return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
+        return paths_check_timestamp(NETWORK_DIRS, &m->network_dirs_ts_usec, false);
 }
 
 int manager_rtnl_enumerate_links(Manager *m) {
@@ -1858,3 +1878,18 @@ int manager_request_product_uuid(Manager *m, Link *link) {
 
         return 0;
 }
+
+int manager_sysctl_ipv6_enabled(Manager *manager) {
+        _cleanup_free_ char *value = NULL;
+        int r;
+
+        if (manager->sysctl_ipv6_enabled >= 0)
+                return manager->sysctl_ipv6_enabled;
+
+        r = sysctl_read_ip_property(AF_INET6, "all", "disable_ipv6", &value);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to read net.ipv6.conf.all.disable_ipv6 sysctl property: %m");
+
+        manager->sysctl_ipv6_enabled = value[0] == '0';
+        return manager->sysctl_ipv6_enabled;
+}
index 289ca96..35ab6be 100644 (file)
@@ -18,8 +18,6 @@
 #include "networkd-link.h"
 #include "networkd-network.h"
 
-extern const char* const network_dirs[];
-
 struct Manager {
         sd_netlink *rtnl;
         /* lazy initialized */
@@ -58,6 +56,8 @@ struct Manager {
         Set *rules;
         Set *rules_foreign;
         Set *rules_saved;
+
+        int sysctl_ipv6_enabled;
 };
 
 extern const sd_bus_vtable manager_vtable[];
@@ -95,4 +95,6 @@ Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr);
 int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link);
 int manager_dhcp6_prefix_remove_all(Manager *m, Link *link);
 
+int manager_sysctl_ipv6_enabled(Manager *manager);
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
index e5b8d11..eb470a4 100644 (file)
@@ -103,7 +103,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
                 return log_link_error_errno(link, r, "Could not allocate route: %m");
 
         route->family = AF_INET6;
-        route->table = link->network->ipv6_accept_ra_route_table;
+        route->table = link_get_ipv6_accept_ra_route_table(link);
         route->priority = link->network->dhcp_route_metric;
         route->protocol = RTPROT_RA;
         route->pref = preference;
@@ -238,7 +238,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
                 return log_link_error_errno(link, r, "Could not allocate route: %m");
 
         route->family = AF_INET6;
-        route->table = link->network->ipv6_accept_ra_route_table;
+        route->table = link_get_ipv6_accept_ra_route_table(link);
         route->priority = link->network->dhcp_route_metric;
         route->protocol = RTPROT_RA;
         route->flags = RTM_F_PREFIX;
@@ -299,7 +299,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
                 return log_link_error_errno(link, r, "Could not allocate route: %m");
 
         route->family = AF_INET6;
-        route->table = link->network->ipv6_accept_ra_route_table;
+        route->table = link_get_ipv6_accept_ra_route_table(link);
         route->protocol = RTPROT_RA;
         route->pref = preference;
         route->gw.in6 = gateway;
@@ -493,7 +493,7 @@ static void ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
         }
 }
 
-static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
+static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
         int r;
 
         assert(link);
@@ -503,18 +503,14 @@ static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
         for (;;) {
                 uint8_t type;
 
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "Failed to iterate through options: %m");
-                        return;
-                }
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Failed to iterate through options: %m");
                 if (r == 0) /* EOF */
                         break;
 
                 r = sd_ndisc_router_option_get_type(rt, &type);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "Failed to get RA option type: %m");
-                        return;
-                }
+                if (r < 0)
+                        return log_link_warning_errno(link, r, "Failed to get RA option type: %m");
 
                 switch (type) {
 
@@ -522,14 +518,15 @@ static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
                         uint8_t flags;
 
                         r = sd_ndisc_router_prefix_get_flags(rt, &flags);
-                        if (r < 0) {
-                                log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
-                                return;
-                        }
+                        if (r < 0)
+                                return log_link_warning_errno(link, r, "Failed to get RA prefix flags: %m");
 
-                        if (flags & ND_OPT_PI_FLAG_ONLINK)
+                        if (link->network->ipv6_accept_ra_use_onlink_prefix &&
+                            FLAGS_SET(flags, ND_OPT_PI_FLAG_ONLINK))
                                 (void) ndisc_router_process_onlink_prefix(link, rt);
-                        if (flags & ND_OPT_PI_FLAG_AUTO)
+
+                        if (link->network->ipv6_accept_ra_use_autonomous_prefix &&
+                            FLAGS_SET(flags, ND_OPT_PI_FLAG_AUTO))
                                 (void) ndisc_router_process_autonomous_prefix(link, rt);
 
                         break;
@@ -552,6 +549,8 @@ static void ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
 
                 r = sd_ndisc_router_option_next(rt);
         }
+
+        return 0;
 }
 
 static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
@@ -578,8 +577,8 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
                 }
         }
 
-        ndisc_router_process_default(link, rt);
-        ndisc_router_process_options(link, rt);
+        (void) ndisc_router_process_default(link, rt);
+        (void) ndisc_router_process_options(link, rt);
 
         return r;
 }
index 762f42d..0b614bf 100644 (file)
@@ -2,6 +2,7 @@
 #pragma once
 
 #include "networkd-link.h"
+#include "time-util.h"
 
 typedef struct NDiscRDNSS {
         usec_t valid_until;
index 254a60b..d0275fd 100644 (file)
@@ -137,20 +137,9 @@ int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_hand
         if (r < 0)
                 return log_error_errno(r, "Could not append NDA_LLADDR attribute: %m");
 
-        switch (neighbor->family) {
-        case AF_INET6:
-                r = sd_netlink_message_append_in6_addr(req, NDA_DST, &neighbor->in_addr.in6);
-                if (r < 0)
-                        return log_error_errno(r, "Could not append NDA_DST attribute: %m");
-                break;
-        case AF_INET:
-                r = sd_netlink_message_append_in_addr(req, NDA_DST, &neighbor->in_addr.in);
-                if (r < 0)
-                        return log_error_errno(r, "Could not append NDA_DST attribute: %m");
-                break;
-        default:
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Neighbor with invalid address family");
-        }
+        r = netlink_message_append_in_addr_union(req, NDA_DST, neighbor->family, &neighbor->in_addr);
+        if (r < 0)
+                return log_error_errno(r, "Could not append NDA_DST attribute: %m");
 
         r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: neighbor_handler,
                                link_netlink_destroy_callback, link);
@@ -175,7 +164,7 @@ int config_parse_neighbor_address(const char *unit,
                                   void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(neighbor_freep) Neighbor *n = NULL;
+        _cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
         int r;
 
         assert(filename);
@@ -211,7 +200,7 @@ int config_parse_neighbor_hwaddr(const char *unit,
                                  void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(neighbor_freep) Neighbor *n = NULL;
+        _cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
         int r;
 
         assert(filename);
index 094bf79..f591f0b 100644 (file)
@@ -13,6 +13,7 @@ typedef struct Neighbor Neighbor;
 
 #include "networkd-link.h"
 #include "networkd-network.h"
+#include "networkd-util.h"
 
 struct Neighbor {
         Network *network;
@@ -29,7 +30,7 @@ struct Neighbor {
 
 void neighbor_free(Neighbor *neighbor);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(Neighbor*, neighbor_free);
+DEFINE_NETWORK_SECTION_FUNCTIONS(Neighbor, neighbor_free);
 
 int neighbor_configure(Neighbor *neighbor, Link *link, link_netlink_message_handler_t callback);
 
index 5d8aede..47a9f7d 100644 (file)
@@ -25,28 +25,29 @@ Match.Path,                             config_parse_strv,
 Match.Driver,                           config_parse_strv,                              0,                             offsetof(Network, match_driver)
 Match.Type,                             config_parse_strv,                              0,                             offsetof(Network, match_type)
 Match.Name,                             config_parse_ifnames,                           0,                             offsetof(Network, match_name)
-Match.Host,                             config_parse_net_condition,                     CONDITION_HOST,                offsetof(Network, match_host)
-Match.Virtualization,                   config_parse_net_condition,                     CONDITION_VIRTUALIZATION,      offsetof(Network, match_virt)
-Match.KernelCommandLine,                config_parse_net_condition,                     CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, match_kernel_cmdline)
-Match.KernelVersion,                    config_parse_net_condition,                     CONDITION_KERNEL_VERSION,      offsetof(Network, match_kernel_version)
-Match.Architecture,                     config_parse_net_condition,                     CONDITION_ARCHITECTURE,        offsetof(Network, match_arch)
+Match.Host,                             config_parse_net_condition,                     CONDITION_HOST,                offsetof(Network, conditions)
+Match.Virtualization,                   config_parse_net_condition,                     CONDITION_VIRTUALIZATION,      offsetof(Network, conditions)
+Match.KernelCommandLine,                config_parse_net_condition,                     CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, conditions)
+Match.KernelVersion,                    config_parse_net_condition,                     CONDITION_KERNEL_VERSION,      offsetof(Network, conditions)
+Match.Architecture,                     config_parse_net_condition,                     CONDITION_ARCHITECTURE,        offsetof(Network, conditions)
 Link.MACAddress,                        config_parse_hwaddr,                            0,                             offsetof(Network, mac)
 Link.MTUBytes,                          config_parse_mtu,                               AF_UNSPEC,                     offsetof(Network, mtu)
 Link.ARP,                               config_parse_tristate,                          0,                             offsetof(Network, arp)
 Link.Multicast,                         config_parse_tristate,                          0,                             offsetof(Network, multicast)
 Link.AllMulticast,                      config_parse_tristate,                          0,                             offsetof(Network, allmulticast)
 Link.Unmanaged,                         config_parse_bool,                              0,                             offsetof(Network, unmanaged)
-Link.RequiredForOnline,                 config_parse_bool,                              0,                             offsetof(Network, required_for_online)
+Link.RequiredForOnline,                 config_parse_required_for_online,               0,                             0
 Network.Description,                    config_parse_string,                            0,                             offsetof(Network, description)
-Network.Bridge,                         config_parse_netdev,                            0,                             0
-Network.Bond,                           config_parse_netdev,                            0,                             0
-Network.VLAN,                           config_parse_netdev,                            0,                             0
-Network.MACVLAN,                        config_parse_netdev,                            0,                             0
-Network.MACVTAP,                        config_parse_netdev,                            0,                             0
-Network.IPVLAN,                         config_parse_netdev,                            0,                             0
-Network.VXLAN,                          config_parse_netdev,                            0,                             0
-Network.Tunnel,                         config_parse_tunnel,                            0,                             0
-Network.VRF,                            config_parse_netdev,                            0,                             0
+Network.Bridge,                         config_parse_ifname,                            0,                             offsetof(Network, bridge_name)
+Network.Bond,                           config_parse_ifname,                            0,                             offsetof(Network, bond_name)
+Network.VLAN,                           config_parse_stacked_netdev,                    NETDEV_KIND_VLAN,              offsetof(Network, stacked_netdev_names)
+Network.MACVLAN,                        config_parse_stacked_netdev,                    NETDEV_KIND_MACVLAN,           offsetof(Network, stacked_netdev_names)
+Network.MACVTAP,                        config_parse_stacked_netdev,                    NETDEV_KIND_MACVTAP,           offsetof(Network, stacked_netdev_names)
+Network.IPVLAN,                         config_parse_stacked_netdev,                    NETDEV_KIND_IPVLAN,            offsetof(Network, stacked_netdev_names)
+Network.VXLAN,                          config_parse_stacked_netdev,                    NETDEV_KIND_VXLAN,             offsetof(Network, stacked_netdev_names)
+Network.L2TP,                           config_parse_stacked_netdev,                    NETDEV_KIND_L2TP,              offsetof(Network, stacked_netdev_names)
+Network.Tunnel,                         config_parse_stacked_netdev,                    _NETDEV_KIND_TUNNEL,           offsetof(Network, stacked_netdev_names)
+Network.VRF,                            config_parse_ifname,                            0,                             offsetof(Network, vrf_name)
 Network.DHCP,                           config_parse_dhcp,                              0,                             offsetof(Network, dhcp)
 Network.DHCPServer,                     config_parse_bool,                              0,                             offsetof(Network, dhcp_server)
 Network.LinkLocalAddressing,            config_parse_address_family_boolean,            0,                             offsetof(Network, link_local)
@@ -81,6 +82,7 @@ Network.ProxyARP,                       config_parse_tristate,
 Network.IPv6ProxyNDPAddress,            config_parse_ipv6_proxy_ndp_address,            0,                             0
 Network.BindCarrier,                    config_parse_strv,                              0,                             offsetof(Network, bind_carrier)
 Network.ConfigureWithoutCarrier,        config_parse_bool,                              0,                             offsetof(Network, configure_without_carrier)
+Network.IgnoreCarrierLoss,              config_parse_bool,                              0,                             offsetof(Network, ignore_carrier_loss)
 Address.Address,                        config_parse_address,                           0,                             0
 Address.Peer,                           config_parse_address,                           0,                             0
 Address.Broadcast,                      config_parse_broadcast,                         0,                             0
@@ -116,6 +118,7 @@ Route.Scope,                            config_parse_route_scope,
 Route.PreferredSource,                  config_parse_preferred_src,                     0,                             0
 Route.Table,                            config_parse_route_table,                       0,                             0
 Route.MTUBytes,                         config_parse_route_mtu,                         AF_UNSPEC,                     0
+Route.GatewayOnLink,                    config_parse_gateway_onlink,                    0,                             0
 Route.GatewayOnlink,                    config_parse_gateway_onlink,                    0,                             0
 Route.IPv6Preference,                   config_parse_ipv6_route_preference,             0,                             0
 Route.Protocol,                         config_parse_route_protocol,                    0,                             0
@@ -140,15 +143,17 @@ DHCP.UserClass,                         config_parse_dhcp_user_class,
 DHCP.DUIDType,                          config_parse_duid_type,                         0,                             offsetof(Network, duid)
 DHCP.DUIDRawData,                       config_parse_duid_rawdata,                      0,                             offsetof(Network, duid)
 DHCP.RouteMetric,                       config_parse_unsigned,                          0,                             offsetof(Network, dhcp_route_metric)
-DHCP.RouteTable,                        config_parse_dhcp_route_table,                  0,                             0
+DHCP.RouteTable,                        config_parse_section_route_table,               0,                             0
 DHCP.UseTimezone,                       config_parse_bool,                              0,                             offsetof(Network, dhcp_use_timezone)
 DHCP.IAID,                              config_parse_iaid,                              0,                             0
 DHCP.ListenPort,                        config_parse_uint16,                            0,                             offsetof(Network, dhcp_client_port)
 DHCP.RapidCommit,                       config_parse_bool,                              0,                             offsetof(Network, rapid_commit)
 DHCP.ForceDHCPv6PDOtherInformation,     config_parse_bool,                              0,                             offsetof(Network, dhcp6_force_pd_other_information)
+IPv6AcceptRA.UseAutonomousPrefix,       config_parse_bool,                              0,                             offsetof(Network, ipv6_accept_ra_use_autonomous_prefix)
+IPv6AcceptRA.UseOnLinkPrefix,           config_parse_bool,                              0,                             offsetof(Network, ipv6_accept_ra_use_onlink_prefix)
 IPv6AcceptRA.UseDNS,                    config_parse_bool,                              0,                             offsetof(Network, ipv6_accept_ra_use_dns)
 IPv6AcceptRA.UseDomains,                config_parse_dhcp_use_domains,                  0,                             offsetof(Network, ipv6_accept_ra_use_domains)
-IPv6AcceptRA.RouteTable,                config_parse_uint32,                            0,                             offsetof(Network, ipv6_accept_ra_route_table)
+IPv6AcceptRA.RouteTable,                config_parse_section_route_table,               0,                             0
 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)
@@ -166,7 +171,10 @@ Bridge.HairPin,                         config_parse_tristate,
 Bridge.FastLeave,                       config_parse_tristate,                          0,                             offsetof(Network, fast_leave)
 Bridge.AllowPortToBeRoot,               config_parse_tristate,                          0,                             offsetof(Network, allow_port_to_be_root)
 Bridge.UnicastFlood,                    config_parse_tristate,                          0,                             offsetof(Network, unicast_flood)
+Bridge.MulticastFlood,                  config_parse_tristate,                          0,                             offsetof(Network, multicast_flood)
 Bridge.MulticastToUnicast,              config_parse_tristate,                          0,                             offsetof(Network, multicast_to_unicast)
+Bridge.NeighborSuppression,             config_parse_tristate,                          0,                             offsetof(Network, neighbor_suppression)
+Bridge.Learning,                        config_parse_tristate,                          0,                             offsetof(Network, learning)
 Bridge.Priority,                        config_parse_bridge_port_priority,              0,                             offsetof(Network, priority)
 BridgeFDB.MACAddress,                   config_parse_fdb_hwaddr,                        0,                             0
 BridgeFDB.VLANId,                       config_parse_fdb_vlan_id,                       0,                             0
@@ -191,6 +199,7 @@ IPv6Prefix.PreferredLifetimeSec,        config_parse_prefix_lifetime,
 CAN.BitRate,                            config_parse_si_size,                           0,                             offsetof(Network, can_bitrate)
 CAN.SamplePoint,                        config_parse_permille,                          0,                             offsetof(Network, can_sample_point)
 CAN.RestartSec,                         config_parse_sec,                               0,                             offsetof(Network, can_restart_us)
+CAN.TripleSampling,                     config_parse_tristate,                          0,                             offsetof(Network, can_triple_sampling)
 /* 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_use_dns)
index f995f45..2c88965 100644 (file)
 #include "networkd-network.h"
 #include "parse-util.h"
 #include "set.h"
+#include "socket-util.h"
 #include "stat-util.h"
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
 #include "util.h"
 
-static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) {
-        siphash24_compress(c->filename, strlen(c->filename), state);
-        siphash24_compress(&c->line, sizeof(c->line), state);
-}
-
-static int network_config_compare_func(const NetworkConfigSection *x, const NetworkConfigSection *y) {
-        int r;
-
-        r = strcmp(x->filename, y->filename);
-        if (r != 0)
-                return r;
-
-        return CMP(x->line, y->line);
-}
-
-DEFINE_HASH_OPS(network_config_hash_ops, NetworkConfigSection, network_config_hash_func, network_config_compare_func);
-
-int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
-        NetworkConfigSection *cs;
-
-        cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
-        if (!cs)
-                return -ENOMEM;
-
-        strcpy(cs->filename, filename);
-        cs->line = line;
-
-        *s = TAKE_PTR(cs);
-
-        return 0;
-}
-
-void network_config_section_free(NetworkConfigSection *cs) {
-        free(cs);
-}
+/* Let's assume that anything above this number is a user misconfiguration. */
+#define MAX_NTP_SERVERS 128
 
 /* Set defaults following RFC7844 */
 void network_apply_anonymize_if_set(Network *network) {
@@ -95,13 +63,229 @@ void network_apply_anonymize_if_set(Network *network) {
         network->dhcp_use_timezone = false;
 }
 
+static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) {
+        const char *kind_string;
+        NetDev *netdev;
+        int r;
+
+        /* For test-networkd-conf, the check must be earlier than the assertions. */
+        if (!name)
+                return 0;
+
+        assert(network);
+        assert(network->manager);
+        assert(network->filename);
+        assert(ret_netdev);
+
+        if (kind == _NETDEV_KIND_TUNNEL)
+                kind_string = "tunnel";
+        else {
+                kind_string = netdev_kind_to_string(kind);
+                if (!kind_string)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "%s: Invalid NetDev kind of %s, ignoring assignment.",
+                                               network->filename, name);
+        }
+
+        r = netdev_get(network->manager, name, &netdev);
+        if (r < 0)
+                return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.",
+                                       network->filename, name);
+
+        if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL &&
+                                      IN_SET(netdev->kind,
+                                             NETDEV_KIND_IPIP,
+                                             NETDEV_KIND_SIT,
+                                             NETDEV_KIND_GRE,
+                                             NETDEV_KIND_GRETAP,
+                                             NETDEV_KIND_IP6GRE,
+                                             NETDEV_KIND_IP6GRETAP,
+                                             NETDEV_KIND_VTI,
+                                             NETDEV_KIND_VTI6,
+                                             NETDEV_KIND_IP6TNL,
+                                             NETDEV_KIND_ERSPAN)))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "%s: NetDev %s is not a %s, ignoring assignment",
+                                       network->filename, name, kind_string);
+
+        *ret_netdev = netdev_ref(netdev);
+        return 1;
+}
+
+static int network_resolve_stacked_netdevs(Network *network) {
+        void *name, *kind;
+        Iterator i;
+        int r;
+
+        assert(network);
+
+        HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names, i) {
+                _cleanup_(netdev_unrefp) NetDev *netdev = NULL;
+
+                r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev);
+                if (r <= 0)
+                        continue;
+
+                r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
+                if (r < 0)
+                        return log_oom();
+
+                r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
+                if (r < 0)
+                        return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m",
+                                               network->filename, (const char *) name);
+
+                netdev = NULL;
+        }
+
+        return 0;
+}
+
+static uint32_t network_get_stacked_netdevs_mtu(Network *network) {
+        uint32_t mtu = 0;
+        NetDev *dev;
+        Iterator i;
+
+        HASHMAP_FOREACH(dev, network->stacked_netdevs, i)
+                if (dev->kind == NETDEV_KIND_VLAN && dev->mtu > 0)
+                        /* See vlan_dev_change_mtu() in kernel.
+                         * Note that the additional 4bytes may not be necessary for all devices. */
+                        mtu = MAX(mtu, dev->mtu + 4);
+
+                else if (dev->kind == NETDEV_KIND_MACVLAN && dev->mtu > mtu)
+                        /* See macvlan_change_mtu() in kernel. */
+                        mtu = dev->mtu;
+
+        return mtu;
+}
+
+int network_verify(Network *network) {
+        Address *address, *address_next;
+        Route *route, *route_next;
+        FdbEntry *fdb, *fdb_next;
+        Neighbor *neighbor, *neighbor_next;
+        AddressLabel *label, *label_next;
+        Prefix *prefix, *prefix_next;
+        RoutingPolicyRule *rule, *rule_next;
+        uint32_t mtu;
+
+        assert(network);
+        assert(network->filename);
+
+        /* skip out early if configuration does not match the environment */
+        if (!condition_test_list(network->conditions, NULL, NULL, NULL))
+                return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "%s: Conditions in the file do not match the system environment, skipping.",
+                                       network->filename);
+
+        (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond);
+        (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge);
+        (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf);
+        (void) network_resolve_stacked_netdevs(network);
+
+        /* Free unnecessary entries. */
+        network->bond_name = mfree(network->bond_name);
+        network->bridge_name = mfree(network->bridge_name);
+        network->vrf_name = mfree(network->vrf_name);
+        network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names);
+
+        if (network->bond) {
+                /* Bonding slave does not support addressing. */
+                if (network->ipv6_accept_ra > 0) {
+                        log_warning("%s: Cannot enable IPv6AcceptRA= when Bond= is specified, disabling IPv6AcceptRA=.",
+                                    network->filename);
+                        network->ipv6_accept_ra = 0;
+                }
+                if (network->link_local >= 0 && network->link_local != ADDRESS_FAMILY_NO) {
+                        log_warning("%s: Cannot enable LinkLocalAddressing= when Bond= is specified, disabling LinkLocalAddressing=.",
+                                    network->filename);
+                        network->link_local = ADDRESS_FAMILY_NO;
+                }
+                if (network->dhcp != ADDRESS_FAMILY_NO) {
+                        log_warning("%s: Cannot enable DHCP= when Bond= is specified, disabling DHCP=.",
+                                    network->filename);
+                        network->dhcp = ADDRESS_FAMILY_NO;
+                }
+                if (network->dhcp_server) {
+                        log_warning("%s: Cannot enable DHCPServer= when Bond= is specified, disabling DHCPServer=.",
+                                    network->filename);
+                        network->dhcp_server = false;
+                }
+                if (network->n_static_addresses > 0) {
+                        log_warning("%s: Cannot set addresses when Bond= is specified, ignoring addresses.",
+                                    network->filename);
+                        while ((address = network->static_addresses))
+                                address_free(address);
+                }
+                if (network->n_static_routes > 0) {
+                        log_warning("%s: Cannot set routes when Bond= is specified, ignoring routes.",
+                                    network->filename);
+                        while ((route = network->static_routes))
+                                route_free(route);
+                }
+        }
+
+        if (network->link_local < 0)
+                network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6;
+
+        if (network->ipv6_accept_ra < 0 && network->bridge)
+                network->ipv6_accept_ra = false;
+
+        /* IPMasquerade=yes implies IPForward=yes */
+        if (network->ip_masquerade)
+                network->ip_forward |= ADDRESS_FAMILY_IPV4;
+
+        network->mtu_is_set = network->mtu > 0;
+        mtu = network_get_stacked_netdevs_mtu(network);
+        if (network->mtu < mtu) {
+                if (network->mtu_is_set)
+                        log_notice("%s: Bumping MTUBytes= from %"PRIu32" to %"PRIu32" because of stacked device",
+                                   network->filename, network->mtu, mtu);
+                network->mtu = mtu;
+        }
+
+        if (network->mtu_is_set && network->dhcp_use_mtu) {
+                log_warning("%s: MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set. "
+                            "Disabling UseMTU=.", network->filename);
+                network->dhcp_use_mtu = false;
+        }
+
+        LIST_FOREACH_SAFE(addresses, address, address_next, network->static_addresses)
+                if (address_section_verify(address) < 0)
+                        address_free(address);
+
+        LIST_FOREACH_SAFE(routes, route, route_next, network->static_routes)
+                if (route_section_verify(route, network) < 0)
+                        route_free(route);
+
+        LIST_FOREACH_SAFE(static_fdb_entries, fdb, fdb_next, network->static_fdb_entries)
+                if (section_is_invalid(fdb->section))
+                        fdb_entry_free(fdb);
+
+        LIST_FOREACH_SAFE(neighbors, neighbor, neighbor_next, network->neighbors)
+                if (section_is_invalid(neighbor->section))
+                        neighbor_free(neighbor);
+
+        LIST_FOREACH_SAFE(labels, label, label_next, network->address_labels)
+                if (section_is_invalid(label->section))
+                        address_label_free(label);
+
+        LIST_FOREACH_SAFE(prefixes, prefix, prefix_next, network->static_prefixes)
+                if (section_is_invalid(prefix->section))
+                        prefix_free(prefix);
+
+        LIST_FOREACH_SAFE(rules, rule, rule_next, network->rules)
+                if (section_is_invalid(rule->section))
+                        routing_policy_rule_free(rule);
+
+        return 0;
+}
+
 int network_load_one(Manager *manager, const char *filename) {
         _cleanup_free_ char *fname = NULL, *name = NULL;
         _cleanup_(network_freep) Network *network = NULL;
         _cleanup_fclose_ FILE *file = NULL;
         const char *dropin_dirname;
-        Address *address;
-        Route *route;
         char *d;
         int r;
 
@@ -142,11 +326,11 @@ int network_load_one(Manager *manager, const char *filename) {
                 return log_oom();
 
         *network = (Network) {
-                .manager = manager,
                 .filename = TAKE_PTR(fname),
                 .name = TAKE_PTR(name),
 
                 .required_for_online = true,
+                .required_operstate_for_online = LINK_OPERSTATE_DEGRADED,
                 .dhcp = ADDRESS_FAMILY_NO,
                 .dhcp_use_ntp = true,
                 .dhcp_use_dns = true,
@@ -180,7 +364,10 @@ int network_load_one(Manager *manager, const char *filename) {
                 .fast_leave = -1,
                 .allow_port_to_be_root = -1,
                 .unicast_flood = -1,
+                .multicast_flood = -1,
                 .multicast_to_unicast = -1,
+                .neighbor_suppression = -1,
+                .learning = -1,
                 .priority = LINK_BRIDGE_PORT_PRIORITY_INVALID,
 
                 .lldp_mode = LLDP_MODE_ROUTERS_ONLY,
@@ -191,7 +378,8 @@ int network_load_one(Manager *manager, const char *filename) {
                 .dnssec_mode = _DNSSEC_MODE_INVALID,
                 .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
 
-                .link_local = ADDRESS_FAMILY_IPV6,
+                /* If LinkLocalAddressing= is not set, then set to ADDRESS_FAMILY_IPV6 later. */
+                .link_local = _ADDRESS_FAMILY_BOOLEAN_INVALID,
 
                 .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO,
                 .ipv6_accept_ra = -1,
@@ -204,10 +392,15 @@ int network_load_one(Manager *manager, const char *filename) {
                 .multicast = -1,
                 .allmulticast = -1,
                 .ipv6_accept_ra_use_dns = true,
+                .ipv6_accept_ra_use_autonomous_prefix = true,
+                .ipv6_accept_ra_use_onlink_prefix = true,
                 .ipv6_accept_ra_route_table = RT_TABLE_MAIN,
+                .ipv6_accept_ra_route_table_set = false,
+
+                .can_triple_sampling = -1,
         };
 
-        r = config_parse_many(filename, network_dirs, dropin_dirname,
+        r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
                               "Match\0"
                               "Link\0"
                               "Network\0"
@@ -229,25 +422,17 @@ int network_load_one(Manager *manager, const char *filename) {
                               "CAN\0",
                               config_item_perf_lookup, network_network_gperf_lookup,
                               CONFIG_PARSE_WARN, network);
-        if (r < 0) {
-                /* Unset manager here. Otherwise, LIST_REMOVE() in network_free() fails. */
-                network->manager = NULL;
+        if (r < 0)
                 return r;
-        }
 
         network_apply_anonymize_if_set(network);
 
-        /* IPMasquerade=yes implies IPForward=yes */
-        if (network->ip_masquerade)
-                network->ip_forward |= ADDRESS_FAMILY_IPV4;
-
-        if (network->mtu > 0 && network->dhcp_use_mtu) {
-                log_warning("MTUBytes= in [Link] section and UseMTU= in [DHCP] section are set in %s. "
-                            "Disabling UseMTU=.", filename);
-                network->dhcp_use_mtu = false;
-        }
+        r = network_add_ipv4ll_route(network);
+        if (r < 0)
+                log_warning_errno(r, "%s: Failed to add IPv4LL route, ignoring: %m", network->filename);
 
         LIST_PREPEND(networks, manager->networks, network);
+        network->manager = manager;
 
         r = hashmap_ensure_allocated(&manager->networks_by_name, &string_hash_ops);
         if (r < 0)
@@ -257,22 +442,10 @@ int network_load_one(Manager *manager, const char *filename) {
         if (r < 0)
                 return r;
 
-        LIST_FOREACH(routes, route, network->static_routes)
-                if (!route->family) {
-                        log_warning("Route section without Gateway field configured in %s. "
-                                    "Ignoring", filename);
-                        return 0;
-                }
-
-        LIST_FOREACH(addresses, address, network->static_addresses)
-                if (!address->family) {
-                        log_warning("Address section without Address field configured in %s. "
-                                    "Ignoring", filename);
-                        return 0;
-                }
+        if (network_verify(network) < 0)
+                return 0;
 
         network = NULL;
-
         return 0;
 }
 
@@ -287,7 +460,7 @@ int network_load(Manager *manager) {
         while ((network = manager->networks))
                 network_free(network);
 
-        r = conf_files_list_strv(&files, ".network", NULL, 0, network_dirs);
+        r = conf_files_list_strv(&files, ".network", NULL, 0, NETWORK_DIRS);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate network files: %m");
 
@@ -320,6 +493,7 @@ void network_free(Network *network) {
         strv_free(network->match_driver);
         strv_free(network->match_type);
         strv_free(network->match_name);
+        condition_free_list(network->conditions);
 
         free(network->description);
         free(network->dhcp_vendor_class_identifier);
@@ -330,17 +504,20 @@ void network_free(Network *network) {
 
         strv_free(network->ntp);
         free(network->dns);
-        strv_free(network->search_domains);
-        strv_free(network->route_domains);
+        ordered_set_free_free(network->search_domains);
+        ordered_set_free_free(network->route_domains);
         strv_free(network->bind_carrier);
 
-        strv_free(network->router_search_domains);
+        ordered_set_free_free(network->router_search_domains);
         free(network->router_dns);
 
+        free(network->bridge_name);
+        free(network->bond_name);
+        free(network->vrf_name);
+        hashmap_free_free_key(network->stacked_netdev_names);
         netdev_unref(network->bridge);
         netdev_unref(network->bond);
         netdev_unref(network->vrf);
-
         hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref);
 
         while ((route = network->static_routes))
@@ -388,12 +565,6 @@ void network_free(Network *network) {
 
         free(network->name);
 
-        condition_free_list(network->match_host);
-        condition_free_list(network->match_virt);
-        condition_free_list(network->match_kernel_cmdline);
-        condition_free_list(network->match_kernel_version);
-        condition_free_list(network->match_arch);
-
         free(network->dhcp_server_timezone);
         free(network->dhcp_server_dns);
         free(network->dhcp_server_ntp);
@@ -422,8 +593,7 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) {
 int network_get(Manager *manager, sd_device *device,
                 const char *ifname, const struct ether_addr *address,
                 Network **ret) {
-        const char *path = NULL, *parent_driver = NULL, *driver = NULL, *devtype = NULL;
-        sd_device *parent;
+        const char *path = NULL, *driver = NULL, *devtype = NULL;
         Network *network;
 
         assert(manager);
@@ -432,9 +602,6 @@ int network_get(Manager *manager, sd_device *device,
         if (device) {
                 (void) sd_device_get_property_value(device, "ID_PATH", &path);
 
-                if (sd_device_get_parent(device, &parent) >= 0)
-                        (void) sd_device_get_driver(parent, &parent_driver);
-
                 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver);
 
                 (void) sd_device_get_devtype(device, &devtype);
@@ -443,11 +610,8 @@ int network_get(Manager *manager, sd_device *device,
         LIST_FOREACH(networks, network, manager->networks) {
                 if (net_match_config(network->match_mac, network->match_path,
                                      network->match_driver, network->match_type,
-                                     network->match_name, network->match_host,
-                                     network->match_virt, network->match_kernel_cmdline,
-                                     network->match_kernel_version, network->match_arch,
-                                     address, path, parent_driver, driver,
-                                     devtype, ifname)) {
+                                     network->match_name,
+                                     address, path, driver, devtype, ifname)) {
                         if (network->match_name && device) {
                                 const char *attr;
                                 uint8_t name_assign_type = NET_NAME_UNKNOWN;
@@ -474,37 +638,15 @@ int network_get(Manager *manager, sd_device *device,
 }
 
 int network_apply(Network *network, Link *link) {
-        int r;
-
         assert(network);
         assert(link);
 
         link->network = network;
 
-        if (network->ipv4ll_route) {
-                Route *route;
-
-                r = route_new_static(network, NULL, 0, &route);
-                if (r < 0)
-                        return r;
-
-                r = inet_pton(AF_INET, "169.254.0.0", &route->dst.in);
-                if (r == 0)
-                        return -EINVAL;
-                if (r < 0)
-                        return -errno;
-
-                route->family = AF_INET;
-                route->dst_prefixlen = 16;
-                route->scope = RT_SCOPE_LINK;
-                route->priority = IPV4LL_ROUTE_METRIC;
-                route->protocol = RTPROT_STATIC;
-        }
-
         if (network->n_dns > 0 ||
             !strv_isempty(network->ntp) ||
-            !strv_isempty(network->search_domains) ||
-            !strv_isempty(network->route_domains))
+            !ordered_set_isempty(network->search_domains) ||
+            !ordered_set_isempty(network->route_domains))
                 link_dirty(link);
 
         return 0;
@@ -523,7 +665,7 @@ bool network_has_static_ipv6_addresses(Network *network) {
         return false;
 }
 
-int config_parse_netdev(const char *unit,
+int config_parse_stacked_netdev(const char *unit,
                 const char *filename,
                 unsigned line,
                 const char *section,
@@ -533,81 +675,43 @@ int config_parse_netdev(const char *unit,
                 const char *rvalue,
                 void *data,
                 void *userdata) {
-        Network *network = userdata;
-        _cleanup_free_ char *kind_string = NULL;
-        char *p;
-        NetDev *netdev;
-        NetDevKind kind;
+        _cleanup_free_ char *name = NULL;
+        NetDevKind kind = ltype;
+        Hashmap **h = data;
         int r;
 
         assert(filename);
         assert(lvalue);
         assert(rvalue);
         assert(data);
+        assert(IN_SET(kind,
+                      NETDEV_KIND_VLAN, NETDEV_KIND_MACVLAN, NETDEV_KIND_MACVTAP,
+                      NETDEV_KIND_IPVLAN, NETDEV_KIND_VXLAN, NETDEV_KIND_L2TP,
+                      _NETDEV_KIND_TUNNEL));
 
-        kind_string = strdup(lvalue);
-        if (!kind_string)
-                return log_oom();
-
-        /* the keys are CamelCase versions of the kind */
-        for (p = kind_string; *p; p++)
-                *p = tolower(*p);
-
-        kind = netdev_kind_from_string(kind_string);
-        if (kind == _NETDEV_KIND_INVALID) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid NetDev kind: %s", lvalue);
-                return 0;
-        }
-
-        r = netdev_get(network->manager, rvalue, &netdev);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "%s could not be found, ignoring assignment: %s", lvalue, rvalue);
-                return 0;
-        }
-
-        if (netdev->kind != kind) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue);
+        if (!ifname_valid(rvalue)) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue);
                 return 0;
         }
 
-        switch (kind) {
-        case NETDEV_KIND_BRIDGE:
-                network->bridge = netdev_unref(network->bridge);
-                network->bridge = netdev;
-
-                break;
-        case NETDEV_KIND_BOND:
-                network->bond = netdev_unref(network->bond);
-                network->bond = netdev;
-
-                break;
-        case NETDEV_KIND_VRF:
-                network->vrf = netdev_unref(network->vrf);
-                network->vrf = netdev;
-
-                break;
-        case NETDEV_KIND_VLAN:
-        case NETDEV_KIND_MACVLAN:
-        case NETDEV_KIND_MACVTAP:
-        case NETDEV_KIND_IPVLAN:
-        case NETDEV_KIND_VXLAN:
-        case NETDEV_KIND_VCAN:
-                r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
-                if (r < 0)
-                        return log_oom();
-
-                r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
-                if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue);
-                        return 0;
-                }
+        name = strdup(rvalue);
+        if (!name)
+                return log_oom();
 
-                break;
-        default:
-                assert_not_reached("Cannot parse NetDev");
-        }
+        r = hashmap_ensure_allocated(h, &string_hash_ops);
+        if (r < 0)
+                return log_oom();
 
-        netdev_ref(netdev);
+        r = hashmap_put(*h, name, INT_TO_PTR(kind));
+        if (r < 0)
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Cannot add NetDev '%s' to network, ignoring assignment: %m", name);
+        else if (r == 0)
+                log_syntax(unit, LOG_DEBUG, filename, line, r,
+                           "NetDev '%s' specified twice, ignoring.", name);
+        else
+                name = NULL;
 
         return 0;
 }
@@ -633,8 +737,8 @@ int config_parse_domains(
         assert(rvalue);
 
         if (isempty(rvalue)) {
-                n->search_domains = strv_free(n->search_domains);
-                n->route_domains = strv_free(n->route_domains);
+                n->search_domains = ordered_set_free_free(n->search_domains);
+                n->route_domains = ordered_set_free_free(n->route_domains);
                 return 0;
         }
 
@@ -646,7 +750,8 @@ int config_parse_domains(
 
                 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);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to extract search or route domain, ignoring: %s", rvalue);
                         break;
                 }
                 if (r == 0)
@@ -656,91 +761,39 @@ int config_parse_domains(
                 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. */
+                        /* 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 "." */
+                        domain = "."; /* make sure we don't allow empty strings, thus write the root
+                                       * domain as "." */
                 } else {
                         r = dns_name_normalize(domain, 0, &normalized);
                         if (r < 0) {
-                                log_syntax(unit, LOG_ERR, filename, line, r, "'%s' is not a valid domain name, ignoring.", domain);
+                                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);
+                                log_syntax(unit, LOG_ERR, filename, line, 0,
+                                           "'localhost' domain may not be configured as search or route domain, ignoring assignment: %s",
+                                           domain);
                                 continue;
                         }
                 }
 
-                if (is_route)
-                        r = strv_extend(&n->route_domains, domain);
-                else
-                        r = strv_extend(&n->search_domains, domain);
+                OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
+                r = ordered_set_ensure_allocated(set, &string_hash_ops);
                 if (r < 0)
-                        return log_oom();
-        }
-
-        strv_uniq(n->route_domains);
-        strv_uniq(n->search_domains);
-
-        return 0;
-}
-
-int config_parse_tunnel(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;
-        NetDev *netdev;
-        int r;
-
-        assert(filename);
-        assert(lvalue);
-        assert(rvalue);
-        assert(data);
-
-        r = netdev_get(network->manager, rvalue, &netdev);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Tunnel is invalid, ignoring assignment: %s", rvalue);
-                return 0;
-        }
-
-        if (!IN_SET(netdev->kind,
-                    NETDEV_KIND_IPIP,
-                    NETDEV_KIND_SIT,
-                    NETDEV_KIND_GRE,
-                    NETDEV_KIND_GRETAP,
-                    NETDEV_KIND_IP6GRE,
-                    NETDEV_KIND_IP6GRETAP,
-                    NETDEV_KIND_VTI,
-                    NETDEV_KIND_VTI6,
-                    NETDEV_KIND_IP6TNL)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0,
-                           "NetDev is not a tunnel, ignoring assignment: %s", rvalue);
-                return 0;
-        }
-
-        r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops);
-        if (r < 0)
-                return log_oom();
+                        return r;
 
-        r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev);
-        if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add VLAN '%s' to network, ignoring: %m", rvalue);
-                return 0;
+                r = ordered_set_put_strdup(*set, domain);
+                if (r < 0)
+                        return log_oom();
         }
 
-        netdev_ref(netdev);
-
         return 0;
 }
 
@@ -810,9 +863,14 @@ int config_parse_dhcp(
                 else if (streq(rvalue, "both"))
                         s = ADDRESS_FAMILY_YES;
                 else {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DHCP option, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Failed to parse DHCP option, ignoring: %s", rvalue);
                         return 0;
                 }
+
+                log_syntax(unit, LOG_WARNING, filename, line, 0,
+                           "DHCP=%s is deprecated, please use DHCP=%s instead.",
+                           rvalue, address_family_boolean_to_string(s));
         }
 
         *dhcp = s;
@@ -826,7 +884,8 @@ static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
 };
 
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier, "Failed to parse client identifier type");
+DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
+                         "Failed to parse client identifier type");
 
 int config_parse_ipv6token(
                 const char* unit,
@@ -851,18 +910,20 @@ int config_parse_ipv6token(
 
         r = in_addr_from_string(AF_INET6, rvalue, &buffer);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse IPv6 token, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to parse IPv6 token, ignoring: %s", rvalue);
                 return 0;
         }
 
-        r = in_addr_is_null(AF_INET6, &buffer);
-        if (r != 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
+        if (in_addr_is_null(AF_INET6, &buffer)) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "IPv6 token cannot be the ANY address, ignoring: %s", rvalue);
                 return 0;
         }
 
         if ((buffer.in6.s6_addr32[0] | buffer.in6.s6_addr32[1]) != 0) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "IPv6 token cannot be longer than 64 bits, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -916,7 +977,8 @@ int config_parse_ipv6_privacy_extensions(
                         if (streq(rvalue, "kernel"))
                                 s = _IPV6_PRIVACY_EXTENSIONS_INVALID;
                         else {
-                                log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
+                                log_syntax(unit, LOG_ERR, filename, line, 0,
+                                           "Failed to parse IPv6 privacy extensions option, ignoring: %s", rvalue);
                                 return 0;
                         }
                 }
@@ -952,17 +1014,20 @@ int config_parse_hostname(
                 return r;
 
         if (!hostname_is_valid(hn, false)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Hostname is not valid, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
         r = dns_name_is_valid(hn);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Failed to check validity of hostname '%s', ignoring assignment: %m", rvalue);
                 return 0;
         }
         if (r == 0) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Hostname is not a valid DNS domain name, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
@@ -994,7 +1059,8 @@ int config_parse_timezone(
                 return r;
 
         if (!timezone_is_valid(tz, LOG_ERR)) {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Timezone is not valid, ignoring assignment: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Timezone is not valid, ignoring assignment: %s", rvalue);
                 return 0;
         }
 
@@ -1029,14 +1095,16 @@ int config_parse_dhcp_server_dns(
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to extract word, ignoring: %s", rvalue);
                         return 0;
                 }
                 if (r == 0)
                         break;
 
                 if (inet_pton(AF_INET, w, &a) <= 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Failed to parse DNS server address, ignoring: %s", w);
                         continue;
                 }
 
@@ -1079,7 +1147,8 @@ int config_parse_radv_dns(
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to extract word, ignoring: %s", rvalue);
                         return 0;
                 }
                 if (r == 0)
@@ -1096,8 +1165,8 @@ int config_parse_radv_dns(
                         n->router_dns = m;
 
                 } else
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse DNS server address, ignoring: %s", w);
-
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Failed to parse DNS server address, ignoring: %s", w);
         }
 
         return 0;
@@ -1130,7 +1199,8 @@ int config_parse_radv_search_domains(
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to extract word, ignoring: %s", rvalue);
                         return 0;
                 }
                 if (r == 0)
@@ -1138,18 +1208,20 @@ int config_parse_radv_search_domains(
 
                 r = dns_name_apply_idna(w, &idna);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to apply IDNA to domain name '%s', ignoring: %m", w);
                         continue;
-                }
-                if (r > 0) {
-                        r = strv_push(&n->router_search_domains, idna);
-                        if (r >= 0)
-                                idna = NULL;
-                } else {
-                        r = strv_push(&n->router_search_domains, w);
-                        if (r >= 0)
-                                w = NULL;
-                }
+                } else if (r == 0)
+                        /* transfer ownership to simplify subsequent operations */
+                        idna = TAKE_PTR(w);
+
+                r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
+                if (r < 0)
+                        return r;
+
+                r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
+                if (r < 0)
+                        return r;
         }
 
         return 0;
@@ -1183,14 +1255,16 @@ int config_parse_dhcp_server_ntp(
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract word, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to extract word, ignoring: %s", rvalue);
                         return 0;
                 }
                 if (r == 0)
                         return 0;
 
                 if (inet_pton(AF_INET, w, &a) <= 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse NTP server address, ignoring: %s", w);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "Failed to parse NTP server address, ignoring: %s", w);
                         continue;
                 }
 
@@ -1232,7 +1306,8 @@ int config_parse_dns(
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Invalid syntax, ignoring: %s", rvalue);
                         break;
                 }
                 if (r == 0)
@@ -1240,7 +1315,8 @@ int config_parse_dns(
 
                 r = in_addr_from_string_auto(w, &family, &a);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse dns server address, ignoring: %s", w);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse dns server address, ignoring: %s", w);
                         continue;
                 }
 
@@ -1289,7 +1365,8 @@ int config_parse_dnssec_negative_trust_anchors(
 
                 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);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to extract negative trust anchor domain, ignoring: %s", rvalue);
                         break;
                 }
                 if (r == 0)
@@ -1297,7 +1374,8 @@ int config_parse_dnssec_negative_trust_anchors(
 
                 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);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "%s is not a valid domain name, ignoring.", w);
                         continue;
                 }
 
@@ -1346,7 +1424,8 @@ int config_parse_ntp(
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to extract NTP server name, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to extract NTP server name, ignoring: %s", rvalue);
                         break;
                 }
                 if (r == 0)
@@ -1354,15 +1433,21 @@ int config_parse_ntp(
 
                 r = dns_name_is_valid_or_address(w);
                 if (r <= 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "%s is not a valid domain name or IP address, ignoring.", w);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "%s is not a valid domain name or IP address, ignoring.", w);
                         continue;
                 }
 
-                r = strv_push(l, w);
+                if (strv_length(*l) > MAX_NTP_SERVERS) {
+                        log_syntax(unit, LOG_WARNING, filename, line, 0,
+                                   "More than %u NTP servers specified, ignoring \"%s\" and any subsequent entries.",
+                                   MAX_NTP_SERVERS, w);
+                        break;
+                }
+
+                r = strv_consume(l, TAKE_PTR(w));
                 if (r < 0)
                         return log_oom();
-
-                w = NULL;
         }
 
         return 0;
@@ -1399,14 +1484,16 @@ int config_parse_dhcp_user_class(
                 if (r == -ENOMEM)
                         return log_oom();
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to split user classes option, ignoring: %s", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to split user classes option, ignoring: %s", rvalue);
                         break;
                 }
                 if (r == 0)
                         break;
 
                 if (strlen(w) > 255) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "%s length is not in the range 1-255, ignoring.", w);
+                        log_syntax(unit, LOG_ERR, filename, line, 0,
+                                   "%s length is not in the range 1-255, ignoring.", w);
                         continue;
                 }
 
@@ -1420,16 +1507,18 @@ int config_parse_dhcp_user_class(
         return 0;
 }
 
-int config_parse_dhcp_route_table(const char *unit,
-                                  const char *filename,
-                                  unsigned line,
-                                  const char *section,
-                                  unsigned section_line,
-                                  const char *lvalue,
-                                  int ltype,
-                                  const char *rvalue,
-                                  void *data,
-                                  void *userdata) {
+int config_parse_section_route_table(
+                const char *unit,
+                const char *filename,
+                unsigned line,
+                const char *section,
+                unsigned section_line,
+                const char *lvalue,
+                int ltype,
+                const char *rvalue,
+                void *data,
+                void *userdata) {
+
         Network *network = data;
         uint32_t rt;
         int r;
@@ -1442,17 +1531,23 @@ int config_parse_dhcp_route_table(const char *unit,
         r = safe_atou32(rvalue, &rt);
         if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Unable to read RouteTable, ignoring assignment: %s", rvalue);
+                           "Failed to parse RouteTable=%s, ignoring assignment: %m", rvalue);
                 return 0;
         }
 
-        network->dhcp_route_table = rt;
-        network->dhcp_route_table_set = true;
+        if (streq_ptr(section, "DHCP")) {
+                network->dhcp_route_table = rt;
+                network->dhcp_route_table_set = true;
+        } else { /* section is IPv6AcceptRA */
+                network->ipv6_accept_ra_route_table = rt;
+                network->ipv6_accept_ra_route_table_set = true;
+        }
 
         return 0;
 }
 
-DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_use_domains, dhcp_use_domains, DHCPUseDomains, "Failed to parse DHCP use domains setting");
+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",
@@ -1503,3 +1598,46 @@ int config_parse_iaid(const char *unit,
 
         return 0;
 }
+
+int config_parse_required_for_online(
+                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 = data;
+        LinkOperationalState s;
+        bool required = true;
+        int r;
+
+        if (isempty(rvalue)) {
+                network->required_for_online = true;
+                network->required_operstate_for_online = LINK_OPERSTATE_DEGRADED;
+                return 0;
+        }
+
+        s = link_operstate_from_string(rvalue);
+        if (s < 0) {
+                r = parse_boolean(rvalue);
+                if (r < 0) {
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Failed to parse %s= setting, ignoring assignment: %s",
+                                   lvalue, rvalue);
+                        return 0;
+                }
+
+                required = r;
+                s = LINK_OPERSTATE_DEGRADED;
+        }
+
+        network->required_for_online = required;
+        network->required_operstate_for_online = s;
+
+        return 0;
+}
index f6e62cd..852144d 100644 (file)
@@ -20,6 +20,7 @@
 #include "networkd-route.h"
 #include "networkd-routing-policy-rule.h"
 #include "networkd-util.h"
+#include "ordered-set.h"
 #include "resolve-util.h"
 
 #define DHCP_ROUTE_METRIC 1024
@@ -83,16 +84,6 @@ typedef enum RADVPrefixDelegation {
         _RADV_PREFIX_DELEGATION_INVALID = -1,
 } RADVPrefixDelegation;
 
-typedef struct NetworkConfigSection {
-        unsigned line;
-        char filename[];
-} NetworkConfigSection;
-
-int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s);
-void network_config_section_free(NetworkConfigSection *network);
-DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free);
-extern const struct hash_ops network_config_hash_ops;
-
 typedef struct Manager Manager;
 
 struct Network {
@@ -106,12 +97,7 @@ struct Network {
         char **match_driver;
         char **match_type;
         char **match_name;
-
-        Condition *match_host;
-        Condition *match_virt;
-        Condition *match_kernel_cmdline;
-        Condition *match_kernel_version;
-        Condition *match_arch;
+        LIST_HEAD(Condition, conditions);
 
         char *description;
 
@@ -119,6 +105,10 @@ struct Network {
         NetDev *bond;
         NetDev *vrf;
         Hashmap *stacked_netdevs;
+        char *bridge_name;
+        char *bond_name;
+        char *vrf_name;
+        Hashmap *stacked_netdev_names;
 
         /* DHCP Client Support */
         AddressFamilyBoolean dhcp;
@@ -173,7 +163,7 @@ struct Network {
         usec_t router_dns_lifetime_usec;
         struct in6_addr *router_dns;
         unsigned n_router_dns;
-        char **router_search_domains;
+        OrderedSet *router_search_domains;
         bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O'
                                                   RA flag is set, see RFC 7084,
                                                   WPD-4 */
@@ -184,7 +174,10 @@ struct Network {
         int fast_leave;
         int allow_port_to_be_root;
         int unicast_flood;
+        int multicast_flood;
         int multicast_to_unicast;
+        int neighbor_suppression;
+        int learning;
         uint32_t cost;
         uint16_t priority;
 
@@ -197,6 +190,7 @@ struct Network {
         size_t can_bitrate;
         unsigned can_sample_point;
         usec_t can_restart_us;
+        int can_triple_sampling;
 
         AddressFamilyBoolean ip_forward;
         bool ip_masquerade;
@@ -209,27 +203,33 @@ struct Network {
         uint32_t ipv6_mtu;
 
         bool ipv6_accept_ra_use_dns;
+        bool ipv6_accept_ra_use_autonomous_prefix;
+        bool ipv6_accept_ra_use_onlink_prefix;
         bool active_slave;
         bool primary_slave;
         DHCPUseDomains ipv6_accept_ra_use_domains;
         uint32_t ipv6_accept_ra_route_table;
+        bool ipv6_accept_ra_route_table_set;
 
         union in_addr_union ipv6_token;
         IPv6PrivacyExtensions ipv6_privacy_extensions;
 
         struct ether_addr *mac;
         uint32_t mtu;
+        bool mtu_is_set; /* Indicate MTUBytes= is specified. */
         int arp;
         int multicast;
         int allmulticast;
         bool unmanaged;
         bool configure_without_carrier;
+        bool ignore_carrier_loss;
         uint32_t iaid;
         DUID duid;
 
         bool iaid_set;
 
         bool required_for_online; /* Is this network required to be considered online? */
+        LinkOperationalState required_operstate_for_online;
 
         LLDPMode lldp_mode; /* LLDP reception */
         LLDPEmit lldp_emit; /* LLDP transmission */
@@ -263,7 +263,8 @@ struct Network {
         /* All kinds of DNS configuration */
         struct in_addr_data *dns;
         unsigned n_dns;
-        char **search_domains, **route_domains;
+        OrderedSet *search_domains, *route_domains;
+
         int dns_default_route;
         ResolveSupport llmnr;
         ResolveSupport mdns;
@@ -283,6 +284,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Network*, network_free);
 
 int network_load(Manager *manager);
 int network_load_one(Manager *manager, const char *filename);
+int network_verify(Network *network);
 
 int network_get_by_name(Manager *manager, const char *name, Network **ret);
 int network_get(Manager *manager, sd_device *device, const char *ifname, const struct ether_addr *mac, Network **ret);
@@ -291,7 +293,7 @@ void network_apply_anonymize_if_set(Network *network);
 
 bool network_has_static_ipv6_addresses(Network *network);
 
-CONFIG_PARSER_PROTOTYPE(config_parse_netdev);
+CONFIG_PARSER_PROTOTYPE(config_parse_stacked_netdev);
 CONFIG_PARSER_PROTOTYPE(config_parse_domains);
 CONFIG_PARSER_PROTOTYPE(config_parse_tunnel);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp);
@@ -308,10 +310,11 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_ntp);
 CONFIG_PARSER_PROTOTYPE(config_parse_dnssec_negative_trust_anchors);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_domains);
 CONFIG_PARSER_PROTOTYPE(config_parse_lldp_mode);
-CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_route_table);
+CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table);
 CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class);
 CONFIG_PARSER_PROTOTYPE(config_parse_ntp);
 CONFIG_PARSER_PROTOTYPE(config_parse_iaid);
+CONFIG_PARSER_PROTOTYPE(config_parse_required_for_online);
 /* Legacy IPv4LL support */
 CONFIG_PARSER_PROTOTYPE(config_parse_ipv4ll);
 
index 92cead0..8cb14b5 100644 (file)
@@ -124,8 +124,8 @@ int prefix_new(Prefix **ret) {
         return 0;
 }
 
-int prefix_new_static(Network *network, const char *filename,
-                      unsigned section_line, Prefix **ret) {
+static int prefix_new_static(Network *network, const char *filename,
+                             unsigned section_line, Prefix **ret) {
         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
         _cleanup_(prefix_freep) Prefix *prefix = NULL;
         int r;
@@ -186,7 +186,7 @@ int config_parse_prefix(const char *unit,
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(prefix_freep) Prefix *p = NULL;
+        _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
         uint8_t prefixlen = 64;
         union in_addr_union in6addr;
         int r;
@@ -228,7 +228,7 @@ int config_parse_prefix_flags(const char *unit,
                               void *data,
                               void *userdata) {
         Network *network = userdata;
-        _cleanup_(prefix_freep) Prefix *p = NULL;
+        _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
         int r, val;
 
         assert(filename);
@@ -272,7 +272,7 @@ int config_parse_prefix_lifetime(const char *unit,
                                  void *data,
                                  void *userdata) {
         Network *network = userdata;
-        _cleanup_(prefix_freep) Prefix *p = NULL;
+        _cleanup_(prefix_free_or_set_invalidp) Prefix *p = NULL;
         usec_t usec;
         int r;
 
@@ -391,8 +391,9 @@ static int radv_set_dns(Link *link, Link *uplink) {
 }
 
 static int radv_set_domains(Link *link, Link *uplink) {
-        char **search_domains;
+        OrderedSet *search_domains;
         usec_t lifetime_usec;
+        _cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */
 
         if (!link->network->router_emit_domains)
                 return 0;
@@ -423,9 +424,13 @@ static int radv_set_domains(Link *link, Link *uplink) {
         return 0;
 
  set_domains:
+        s = ordered_set_get_strv(search_domains);
+        if (!s)
+                return log_oom();
+
         return sd_radv_set_dnssl(link->radv,
                                  DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
-                                 search_domains);
+                                 s);
 
 }
 
index bb88f8a..3192bb8 100644 (file)
@@ -8,6 +8,7 @@
 #include "conf-parser.h"
 #include "networkd-address.h"
 #include "networkd-link.h"
+#include "networkd-util.h"
 
 typedef struct Prefix Prefix;
 
@@ -22,9 +23,8 @@ struct Prefix {
 
 int prefix_new(Prefix **ret);
 void prefix_free(Prefix *prefix);
-int prefix_new_static(Network *network, const char *filename, unsigned section, Prefix **ret);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(Prefix*, prefix_free);
+DEFINE_NETWORK_SECTION_FUNCTIONS(Prefix, prefix_free);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_router_prefix_delegation);
 CONFIG_PARSER_PROTOTYPE(config_parse_router_preference);
index 5553a7e..379077c 100644 (file)
@@ -59,6 +59,7 @@ int route_new(Route **ret) {
                 .table = RT_TABLE_MAIN,
                 .lifetime = USEC_INFINITY,
                 .quickack = -1,
+                .gateway_onlink = -1,
         };
 
         *ret = TAKE_PTR(route);
@@ -66,7 +67,7 @@ int route_new(Route **ret) {
         return 0;
 }
 
-int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
+static int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret) {
         _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
         _cleanup_(route_freep) Route *route = NULL;
         int r;
@@ -406,71 +407,59 @@ int route_remove(Route *route, Link *link,
                                       RTM_DELROUTE, route->family,
                                       route->protocol);
         if (r < 0)
-                return log_error_errno(r, "Could not create RTM_DELROUTE message: %m");
+                return log_link_error_errno(link, r, "Could not create RTM_DELROUTE message: %m");
 
-        if (!in_addr_is_null(route->family, &route->gw)) {
-                if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
-                else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
+        if (in_addr_is_null(route->family, &route->gw) == 0) {
+                r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
         }
 
         if (route->dst_prefixlen) {
-                if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
-                else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
+                r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_DST attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
 
                 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
                 if (r < 0)
-                        return log_error_errno(r, "Could not set destination prefix length: %m");
+                        return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
         }
 
         if (route->src_prefixlen) {
-                if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
-                else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
+                r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
 
                 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
                 if (r < 0)
-                        return log_error_errno(r, "Could not set source prefix length: %m");
+                        return log_link_error_errno(link, r, "Could not set source prefix length: %m");
         }
 
-        if (!in_addr_is_null(route->family, &route->prefsrc)) {
-                if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
-                else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
+        if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
+                r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
         }
 
         r = sd_rtnl_message_route_set_scope(req, route->scope);
         if (r < 0)
-                return log_error_errno(r, "Could not set scope: %m");
+                return log_link_error_errno(link, r, "Could not set scope: %m");
 
         r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
         if (r < 0)
-                return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
+                return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
 
         if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
                 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
         }
 
         r = netlink_call_async(link->manager->rtnl, NULL, req,
                                callback ?: route_remove_handler,
                                link_netlink_destroy_callback, link);
         if (r < 0)
-                return log_error_errno(r, "Could not send rtnetlink message: %m");
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
         link_ref(link);
 
@@ -511,148 +500,158 @@ int route_configure(
 
         if (route_get(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, NULL) <= 0 &&
             set_size(link->routes) >= routes_max())
-                return -E2BIG;
+                return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
+                                            "Too many routes are configured, refusing: %m");
+
+        if (DEBUG_LOGGING) {
+                _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL;
+
+                if (!in_addr_is_null(route->family, &route->dst)) {
+                        (void) in_addr_to_string(route->family, &route->dst, &dst);
+                        (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen);
+                }
+                if (!in_addr_is_null(route->family, &route->src))
+                        (void) in_addr_to_string(route->family, &route->src, &src);
+                if (!in_addr_is_null(route->family, &route->gw))
+                        (void) in_addr_to_string(route->family, &route->gw, &gw);
+                if (!in_addr_is_null(route->family, &route->prefsrc))
+                        (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc);
+
+                log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s",
+                               strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc));
+        }
 
         r = sd_rtnl_message_new_route(link->manager->rtnl, &req,
                                       RTM_NEWROUTE, route->family,
                                       route->protocol);
         if (r < 0)
-                return log_error_errno(r, "Could not create RTM_NEWROUTE message: %m");
+                return log_link_error_errno(link, r, "Could not create RTM_NEWROUTE message: %m");
 
-        if (!in_addr_is_null(route->family, &route->gw)) {
-                if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_GATEWAY, &route->gw.in);
-                else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_GATEWAY, &route->gw.in6);
+        if (in_addr_is_null(route->family, &route->gw) == 0) {
+                r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->family, &route->gw);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_GATEWAY attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_GATEWAY attribute: %m");
 
                 r = sd_rtnl_message_route_set_family(req, route->family);
                 if (r < 0)
-                        return log_error_errno(r, "Could not set route family: %m");
+                        return log_link_error_errno(link, r, "Could not set route family: %m");
         }
 
         if (route->dst_prefixlen) {
-                if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_DST, &route->dst.in);
-                else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_DST, &route->dst.in6);
+                r = netlink_message_append_in_addr_union(req, RTA_DST, route->family, &route->dst);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_DST attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_DST attribute: %m");
 
                 r = sd_rtnl_message_route_set_dst_prefixlen(req, route->dst_prefixlen);
                 if (r < 0)
-                        return log_error_errno(r, "Could not set destination prefix length: %m");
+                        return log_link_error_errno(link, r, "Could not set destination prefix length: %m");
         }
 
         if (route->src_prefixlen) {
-                if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_SRC, &route->src.in);
-                else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_SRC, &route->src.in6);
+                r = netlink_message_append_in_addr_union(req, RTA_SRC, route->family, &route->src);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_SRC attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_SRC attribute: %m");
 
                 r = sd_rtnl_message_route_set_src_prefixlen(req, route->src_prefixlen);
                 if (r < 0)
-                        return log_error_errno(r, "Could not set source prefix length: %m");
+                        return log_link_error_errno(link, r, "Could not set source prefix length: %m");
         }
 
-        if (!in_addr_is_null(route->family, &route->prefsrc)) {
-                if (route->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(req, RTA_PREFSRC, &route->prefsrc.in);
-                else if (route->family == AF_INET6)
-                        r = sd_netlink_message_append_in6_addr(req, RTA_PREFSRC, &route->prefsrc.in6);
+        if (in_addr_is_null(route->family, &route->prefsrc) == 0) {
+                r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_PREFSRC attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m");
         }
 
         r = sd_rtnl_message_route_set_scope(req, route->scope);
         if (r < 0)
-                return log_error_errno(r, "Could not set scope: %m");
+                return log_link_error_errno(link, r, "Could not set scope: %m");
+
+        if (route->gateway_onlink >= 0)
+                SET_FLAG(route->flags, RTNH_F_ONLINK, route->gateway_onlink);
 
         r = sd_rtnl_message_route_set_flags(req, route->flags);
         if (r < 0)
-                return log_error_errno(r, "Could not set flags: %m");
+                return log_link_error_errno(link, r, "Could not set flags: %m");
 
         if (route->table != RT_TABLE_MAIN) {
                 if (route->table < 256) {
                         r = sd_rtnl_message_route_set_table(req, route->table);
                         if (r < 0)
-                                return log_error_errno(r, "Could not set route table: %m");
+                                return log_link_error_errno(link, r, "Could not set route table: %m");
                 } else {
                         r = sd_rtnl_message_route_set_table(req, RT_TABLE_UNSPEC);
                         if (r < 0)
-                                return log_error_errno(r, "Could not set route table: %m");
+                                return log_link_error_errno(link, r, "Could not set route table: %m");
 
                         /* Table attribute to allow more than 256. */
                         r = sd_netlink_message_append_data(req, RTA_TABLE, &route->table, sizeof(route->table));
                         if (r < 0)
-                                return log_error_errno(r, "Could not append RTA_TABLE attribute: %m");
+                                return log_link_error_errno(link, r, "Could not append RTA_TABLE attribute: %m");
                 }
         }
 
         r = sd_netlink_message_append_u32(req, RTA_PRIORITY, route->priority);
         if (r < 0)
-                return log_error_errno(r, "Could not append RTA_PRIORITY attribute: %m");
+                return log_link_error_errno(link, r, "Could not append RTA_PRIORITY attribute: %m");
 
         r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref);
         if (r < 0)
-                return log_error_errno(r, "Could not append RTA_PREF attribute: %m");
+                return log_link_error_errno(link, r, "Could not append RTA_PREF attribute: %m");
 
         if (route->lifetime != USEC_INFINITY && kernel_route_expiration_supported()) {
                 r = sd_netlink_message_append_u32(req, RTA_EXPIRES,
                         DIV_ROUND_UP(usec_sub_unsigned(route->lifetime, now(clock_boottime_or_monotonic())), USEC_PER_SEC));
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_EXPIRES attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_EXPIRES attribute: %m");
         }
 
         r = sd_rtnl_message_route_set_type(req, route->type);
         if (r < 0)
-                return log_error_errno(r, "Could not set route type: %m");
+                return log_link_error_errno(link, r, "Could not set route type: %m");
 
         if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) {
                 r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTA_OIF attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m");
         }
 
         r = sd_netlink_message_open_container(req, RTA_METRICS);
         if (r < 0)
-                return log_error_errno(r, "Could not append RTA_METRICS attribute: %m");
+                return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
 
         if (route->mtu > 0) {
                 r = sd_netlink_message_append_u32(req, RTAX_MTU, route->mtu);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTAX_MTU attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTAX_MTU attribute: %m");
         }
 
         if (route->initcwnd > 0) {
                 r = sd_netlink_message_append_u32(req, RTAX_INITCWND, route->initcwnd);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTAX_INITCWND attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTAX_INITCWND attribute: %m");
         }
 
         if (route->initrwnd > 0) {
                 r = sd_netlink_message_append_u32(req, RTAX_INITRWND, route->initrwnd);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTAX_INITRWND attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTAX_INITRWND attribute: %m");
         }
 
         if (route->quickack != -1) {
                 r = sd_netlink_message_append_u32(req, RTAX_QUICKACK, route->quickack);
                 if (r < 0)
-                        return log_error_errno(r, "Could not append RTAX_QUICKACK attribute: %m");
+                        return log_link_error_errno(link, r, "Could not append RTAX_QUICKACK attribute: %m");
         }
 
         r = sd_netlink_message_close_container(req);
         if (r < 0)
-                return log_error_errno(r, "Could not append RTA_METRICS attribute: %m");
+                return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m");
 
         r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
                                link_netlink_destroy_callback, link);
         if (r < 0)
-                return log_error_errno(r, "Could not send rtnetlink message: %m");
+                return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
 
         link_ref(link);
 
@@ -660,7 +659,7 @@ int route_configure(
 
         r = route_add(link, route->family, &route->dst, route->dst_prefixlen, route->tos, route->priority, route->table, &route);
         if (r < 0)
-                return log_error_errno(r, "Could not add route: %m");
+                return log_link_error_errno(link, r, "Could not add route: %m");
 
         /* TODO: drop expiration handling once it can be pushed into the kernel */
         route->lifetime = lifetime;
@@ -669,7 +668,7 @@ int route_configure(
                 r = sd_event_add_time(link->manager->event, &expire, clock_boottime_or_monotonic(),
                                       route->lifetime, 0, route_expire_handler, route);
                 if (r < 0)
-                        return log_error_errno(r, "Could not arm expiration timer: %m");
+                        return log_link_error_errno(link, r, "Could not arm expiration timer: %m");
         }
 
         sd_event_source_unref(route->expire);
@@ -678,6 +677,34 @@ int route_configure(
         return 0;
 }
 
+int network_add_ipv4ll_route(Network *network) {
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
+        int r;
+
+        assert(network);
+
+        if (!network->ipv4ll_route)
+                return 0;
+
+        /* IPv4LLRoute= is in [Network] section. */
+        r = route_new_static(network, NULL, 0, &n);
+        if (r < 0)
+                return r;
+
+        r = in_addr_from_string(AF_INET, "169.254.0.0", &n->dst);
+        if (r < 0)
+                return r;
+
+        n->family = AF_INET;
+        n->dst_prefixlen = 16;
+        n->scope = RT_SCOPE_LINK;
+        n->priority = IPV4LL_ROUTE_METRIC;
+        n->protocol = RTPROT_STATIC;
+
+        TAKE_PTR(n);
+        return 0;
+}
+
 int config_parse_gateway(
                 const char *unit,
                 const char *filename,
@@ -691,7 +718,7 @@ int config_parse_gateway(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         int r;
 
         assert(filename);
@@ -706,18 +733,20 @@ int config_parse_gateway(
                 r = route_new_static(network, NULL, 0, &n);
         } else
                 r = route_new_static(network, filename, section_line, &n);
-
         if (r < 0)
                 return r;
 
-        r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
+        if (n->family == AF_UNSPEC)
+                r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
+        else
+                r = in_addr_from_string(n->family, rvalue, &n->gw);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Route is invalid, ignoring assignment: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
                 return 0;
         }
 
         TAKE_PTR(n);
-
         return 0;
 }
 
@@ -734,7 +763,7 @@ int config_parse_preferred_src(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         int r;
 
         assert(filename);
@@ -747,15 +776,17 @@ int config_parse_preferred_src(
         if (r < 0)
                 return r;
 
-        r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
+        if (n->family == AF_UNSPEC)
+                r = in_addr_from_string_auto(rvalue, &n->family, &n->prefsrc);
+        else
+                r = in_addr_from_string(n->family, rvalue, &n->prefsrc);
         if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
-                           "Preferred source is invalid, ignoring assignment: %s", rvalue);
+                           "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
                 return 0;
         }
 
         TAKE_PTR(n);
-
         return 0;
 }
 
@@ -772,7 +803,7 @@ int config_parse_destination(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         union in_addr_union *buffer;
         unsigned char *prefixlen;
         int r;
@@ -796,11 +827,13 @@ int config_parse_destination(
         } else
                 assert_not_reached(lvalue);
 
-        r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
+        if (n->family == AF_UNSPEC)
+                r = in_addr_prefix_from_string_auto(rvalue, &n->family, buffer, prefixlen);
+        else
+                r = in_addr_prefix_from_string(rvalue, n->family, buffer, prefixlen);
         if (r < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Route %s= prefix is invalid, ignoring assignment: %s",
-                           lvalue, rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+                           "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
                 return 0;
         }
 
@@ -821,7 +854,7 @@ int config_parse_route_priority(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         int r;
 
         assert(filename);
@@ -858,7 +891,7 @@ int config_parse_route_scope(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         int r;
 
         assert(filename);
@@ -898,7 +931,7 @@ int config_parse_route_table(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -936,7 +969,7 @@ int config_parse_gateway_onlink(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         int r;
 
         assert(filename);
@@ -952,11 +985,12 @@ int config_parse_gateway_onlink(
         r = parse_boolean(rvalue);
         if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Could not parse gateway onlink \"%s\", ignoring assignment: %m", rvalue);
+                           "Could not parse %s=\"%s\", ignoring assignment: %m", lvalue, rvalue);
                 return 0;
         }
 
-        SET_FLAG(n->flags, RTNH_F_ONLINK, r);
+        n->gateway_onlink = r;
+
         TAKE_PTR(n);
         return 0;
 }
@@ -974,7 +1008,7 @@ int config_parse_ipv6_route_preference(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         int r;
 
         r = route_new_static(network, filename, section_line, &n);
@@ -1009,7 +1043,7 @@ int config_parse_route_protocol(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         int r;
 
         r = route_new_static(network, filename, section_line, &n);
@@ -1025,7 +1059,8 @@ int config_parse_route_protocol(
         else {
                 r = safe_atou8(rvalue , &n->protocol);
                 if (r < 0) {
-                        log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
+                        log_syntax(unit, LOG_ERR, filename, line, r,
+                                   "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue);
                         return 0;
                 }
         }
@@ -1047,7 +1082,7 @@ int config_parse_route_type(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         int r;
 
         r = route_new_static(network, filename, section_line, &n);
@@ -1065,7 +1100,8 @@ int config_parse_route_type(
         else if (streq(rvalue, "throw"))
                 n->type = RTN_THROW;
         else {
-                log_syntax(unit, LOG_ERR, filename, line, r, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, r,
+                           "Could not parse route type \"%s\", ignoring assignment: %m", rvalue);
                 return 0;
         }
 
@@ -1085,7 +1121,7 @@ int config_parse_tcp_window(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         Network *network = userdata;
         uint64_t k;
         int r;
@@ -1101,9 +1137,14 @@ int config_parse_tcp_window(
                 return r;
 
         r = parse_size(rvalue, 1024, &k);
-        if (r < 0 || k > UINT32_MAX)  {
+        if (r < 0) {
                 log_syntax(unit, LOG_ERR, filename, line, r,
-                           "Could not parse TCP %s \"%s\" bytes, ignoring assignment: %m", rvalue, lvalue);
+                           "Could not parse TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue);
+                return 0;
+        }
+        if (k > UINT32_MAX) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue);
                 return 0;
         }
 
@@ -1111,10 +1152,8 @@ int config_parse_tcp_window(
                 n->initcwnd = k;
         else if (streq(lvalue, "InitialAdvertisedReceiveWindow"))
                 n->initrwnd = k;
-        else {
-                log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse TCP %s: %s", lvalue, rvalue);
-                return 0;
-        }
+        else
+                assert_not_reached("Invalid TCP window type.");
 
         TAKE_PTR(n);
         return 0;
@@ -1132,7 +1171,7 @@ int config_parse_quickack(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         Network *network = userdata;
         int k, r;
 
@@ -1148,7 +1187,8 @@ int config_parse_quickack(
 
         k = parse_boolean(rvalue);
         if (k < 0) {
-                log_syntax(unit, LOG_ERR, filename, line, k, "Failed to parse TCP quickack, ignoring: %s", rvalue);
+                log_syntax(unit, LOG_ERR, filename, line, k,
+                           "Failed to parse TCP quickack, ignoring: %s", rvalue);
                 return 0;
         }
 
@@ -1170,7 +1210,7 @@ int config_parse_route_mtu(
                 void *userdata) {
 
         Network *network = userdata;
-        _cleanup_(route_freep) Route *n = NULL;
+        _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
         int r;
 
         assert(filename);
@@ -1190,3 +1230,29 @@ int config_parse_route_mtu(
         TAKE_PTR(n);
         return 0;
 }
+
+int route_section_verify(Route *route, Network *network) {
+        if (section_is_invalid(route->section))
+                return -EINVAL;
+
+        if (route->family == AF_UNSPEC) {
+                assert(route->section);
+
+                return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
+                                         "%s: Route section without Gateway=, Destination=, Source=, "
+                                         "or PreferredSource= field configured. "
+                                         "Ignoring [Route] section from line %u.",
+                                         route->section->filename, route->section->line);
+        }
+
+        if (network->n_static_addresses == 0 &&
+            in_addr_is_null(route->family, &route->gw) == 0 &&
+            route->gateway_onlink < 0) {
+                log_warning("%s: Gateway= without static address configured. "
+                            "Enabling GatewayOnLink= option.",
+                            network->filename);
+                route->gateway_onlink = true;
+        }
+
+        return 0;
+}
index 4eddf51..1e8320f 100644 (file)
@@ -7,6 +7,7 @@ typedef struct Route Route;
 typedef struct NetworkConfigSection NetworkConfigSection;
 
 #include "networkd-network.h"
+#include "networkd-util.h"
 
 struct Route {
         Network *network;
@@ -30,6 +31,7 @@ struct Route {
         uint32_t initrwnd;
         unsigned char pref;
         unsigned flags;
+        int gateway_onlink;
 
         union in_addr_union gw;
         union in_addr_union dst;
@@ -42,7 +44,6 @@ struct Route {
         LIST_FIELDS(Route, routes);
 };
 
-int route_new_static(Network *network, const char *filename, unsigned section_line, Route **ret);
 int route_new(Route **ret);
 void route_free(Route *route);
 int route_configure(Route *route, Link *link, link_netlink_message_handler_t callback);
@@ -55,8 +56,11 @@ void route_update(Route *route, const union in_addr_union *src, unsigned char sr
 bool route_equal(Route *r1, Route *r2);
 
 int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdata);
+int route_section_verify(Route *route, Network *network);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(Route*, route_free);
+DEFINE_NETWORK_SECTION_FUNCTIONS(Route, route_free);
+
+int network_add_ipv4ll_route(Network *network);
 
 CONFIG_PARSER_PROTOTYPE(config_parse_gateway);
 CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src);
index 2dc7862..f625321 100644 (file)
@@ -369,12 +369,8 @@ int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *lin
         if (r < 0)
                 return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m");
 
-        if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from)) {
-                if (routing_policy_rule->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(m, FRA_SRC, &routing_policy_rule->from.in);
-                else
-                        r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &routing_policy_rule->from.in6);
-
+        if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->from) == 0) {
+                r = netlink_message_append_in_addr_union(m, FRA_SRC, routing_policy_rule->family, &routing_policy_rule->from);
                 if (r < 0)
                         return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
 
@@ -383,12 +379,8 @@ int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *lin
                         return log_error_errno(r, "Could not set source prefix length: %m");
         }
 
-        if (!in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to)) {
-                if (routing_policy_rule->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(m, FRA_DST, &routing_policy_rule->to.in);
-                else
-                        r = sd_netlink_message_append_in6_addr(m, FRA_DST, &routing_policy_rule->to.in6);
-
+        if (in_addr_is_null(routing_policy_rule->family, &routing_policy_rule->to) == 0) {
+                r = netlink_message_append_in_addr_union(m, FRA_DST, routing_policy_rule->family, &routing_policy_rule->to);
                 if (r < 0)
                         return log_error_errno(r, "Could not append FRA_DST attribute: %m");
 
@@ -496,12 +488,8 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl
         if (r < 0)
                 return log_error_errno(r, "Could not allocate RTM_NEWRULE message: %m");
 
-        if (!in_addr_is_null(rule->family, &rule->from)) {
-                if (rule->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(m, FRA_SRC, &rule->from.in);
-                else
-                        r = sd_netlink_message_append_in6_addr(m, FRA_SRC, &rule->from.in6);
-
+        if (in_addr_is_null(rule->family, &rule->from) == 0) {
+                r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from);
                 if (r < 0)
                         return log_error_errno(r, "Could not append FRA_SRC attribute: %m");
 
@@ -510,12 +498,8 @@ int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link, link_netl
                         return log_error_errno(r, "Could not set source prefix length: %m");
         }
 
-        if (!in_addr_is_null(rule->family, &rule->to)) {
-                if (rule->family == AF_INET)
-                        r = sd_netlink_message_append_in_addr(m, FRA_DST, &rule->to.in);
-                else
-                        r = sd_netlink_message_append_in6_addr(m, FRA_DST, &rule->to.in6);
-
+        if (in_addr_is_null(rule->family, &rule->to) == 0) {
+                r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to);
                 if (r < 0)
                         return log_error_errno(r, "Could not append FRA_DST attribute: %m");
 
@@ -652,7 +636,7 @@ int config_parse_routing_policy_rule_tos(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+        _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -689,7 +673,7 @@ int config_parse_routing_policy_rule_priority(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+        _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -726,7 +710,7 @@ int config_parse_routing_policy_rule_table(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+        _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -763,7 +747,7 @@ int config_parse_routing_policy_rule_fwmark_mask(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+        _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -800,7 +784,7 @@ int config_parse_routing_policy_rule_prefix(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+        _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
         union in_addr_union *buffer;
         uint8_t *prefixlen;
@@ -847,7 +831,7 @@ int config_parse_routing_policy_rule_device(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+        _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -892,7 +876,7 @@ int config_parse_routing_policy_rule_port_range(
                 const char *rvalue,
                 void *data,
                 void *userdata) {
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+        _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
         uint16_t low, high;
         int r;
@@ -938,7 +922,7 @@ int config_parse_routing_policy_rule_ip_protocol(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+        _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -977,7 +961,7 @@ int config_parse_routing_policy_rule_invert(
                 void *data,
                 void *userdata) {
 
-        _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *n = NULL;
+        _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL;
         Network *network = userdata;
         int r;
 
@@ -1250,6 +1234,26 @@ int routing_policy_load_rules(const char *state_file, Set **rules) {
         return 0;
 }
 
+static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) {
+        RoutingPolicyRule *link_rule;
+        Iterator i;
+        Link *link;
+
+        assert(m);
+        assert(rule);
+
+        HASHMAP_FOREACH(link, m->links, i) {
+                if (!link->network)
+                        continue;
+
+                LIST_FOREACH(rules, link_rule, link->network->rules)
+                        if (routing_policy_rule_compare_func(link_rule, rule) == 0)
+                                return true;
+        }
+
+        return false;
+}
+
 void routing_policy_rule_purge(Manager *m, Link *link) {
         RoutingPolicyRule *rule, *existing;
         Iterator i;
@@ -1260,15 +1264,24 @@ void routing_policy_rule_purge(Manager *m, Link *link) {
 
         SET_FOREACH(rule, m->rules_saved, i) {
                 existing = set_get(m->rules_foreign, rule);
-                if (existing) {
+                if (!existing)
+                        continue; /* Saved rule does not exist anymore. */
 
-                        r = routing_policy_rule_remove(rule, link, NULL);
-                        if (r < 0) {
-                                log_warning_errno(r, "Could not remove routing policy rules: %m");
-                                continue;
-                        }
+                if (manager_links_have_routing_policy_rule(m, existing))
+                        continue; /* Existing links have the saved rule. */
 
-                        link->routing_policy_rule_remove_messages++;
+                /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it
+                 * later when it is requested. */
+
+                r = routing_policy_rule_remove(existing, link, NULL);
+                if (r < 0) {
+                        log_warning_errno(r, "Could not remove routing policy rules: %m");
+                        continue;
                 }
+
+                link->routing_policy_rule_remove_messages++;
+
+                assert_se(set_remove(m->rules_foreign, existing) == existing);
+                routing_policy_rule_free(existing);
         }
 }
index dc0bd40..28699ba 100644 (file)
@@ -12,6 +12,7 @@ typedef struct RoutingPolicyRule RoutingPolicyRule;
 
 #include "networkd-link.h"
 #include "networkd-network.h"
+#include "networkd-util.h"
 
 typedef struct Network Network;
 typedef struct Link Link;
@@ -53,7 +54,7 @@ struct RoutingPolicyRule {
 int routing_policy_rule_new(RoutingPolicyRule **ret);
 void routing_policy_rule_free(RoutingPolicyRule *rule);
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(RoutingPolicyRule*, routing_policy_rule_free);
+DEFINE_NETWORK_SECTION_FUNCTIONS(RoutingPolicyRule, routing_policy_rule_free);
 
 int routing_policy_rule_configure(RoutingPolicyRule *address, Link *link, link_netlink_message_handler_t callback, bool update);
 int routing_policy_rule_remove(RoutingPolicyRule *routing_policy_rule, Link *link, link_netlink_message_handler_t callback);
index 9b6bc12..a392aad 100644 (file)
@@ -102,3 +102,39 @@ int kernel_route_expiration_supported(void) {
         }
         return cached;
 }
+
+static void network_config_hash_func(const NetworkConfigSection *c, struct siphash *state) {
+        siphash24_compress(c->filename, strlen(c->filename), state);
+        siphash24_compress(&c->line, sizeof(c->line), state);
+}
+
+static int network_config_compare_func(const NetworkConfigSection *x, const NetworkConfigSection *y) {
+        int r;
+
+        r = strcmp(x->filename, y->filename);
+        if (r != 0)
+                return r;
+
+        return CMP(x->line, y->line);
+}
+
+DEFINE_HASH_OPS(network_config_hash_ops, NetworkConfigSection, network_config_hash_func, network_config_compare_func);
+
+int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s) {
+        NetworkConfigSection *cs;
+
+        cs = malloc0(offsetof(NetworkConfigSection, filename) + strlen(filename) + 1);
+        if (!cs)
+                return -ENOMEM;
+
+        strcpy(cs->filename, filename);
+        cs->line = line;
+
+        *s = TAKE_PTR(cs);
+
+        return 0;
+}
+
+void network_config_section_free(NetworkConfigSection *cs) {
+        free(cs);
+}
index 435fdb7..a49e289 100644 (file)
@@ -2,18 +2,25 @@
 #pragma once
 
 #include "conf-parser.h"
+#include "hash-funcs.h"
 #include "macro.h"
 
 typedef enum AddressFamilyBoolean {
         /* This is a bitmask, though it usually doesn't feel that way! */
-        ADDRESS_FAMILY_NO = 0,
-        ADDRESS_FAMILY_IPV4 = 1,
-        ADDRESS_FAMILY_IPV6 = 2,
-        ADDRESS_FAMILY_YES = 3,
+        ADDRESS_FAMILY_NO   = 0,
+        ADDRESS_FAMILY_IPV4 = 1 << 0,
+        ADDRESS_FAMILY_IPV6 = 1 << 1,
+        ADDRESS_FAMILY_YES  = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6,
         _ADDRESS_FAMILY_BOOLEAN_MAX,
         _ADDRESS_FAMILY_BOOLEAN_INVALID = -1,
 } AddressFamilyBoolean;
 
+typedef struct NetworkConfigSection {
+        unsigned line;
+        bool invalid;
+        char filename[];
+} NetworkConfigSection;
+
 CONFIG_PARSER_PROTOTYPE(config_parse_address_family_boolean);
 CONFIG_PARSER_PROTOTYPE(config_parse_address_family_boolean_with_kernel);
 
@@ -21,3 +28,29 @@ const char *address_family_boolean_to_string(AddressFamilyBoolean b) _const_;
 AddressFamilyBoolean address_family_boolean_from_string(const char *s) _const_;
 
 int kernel_route_expiration_supported(void);
+
+int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s);
+void network_config_section_free(NetworkConfigSection *network);
+DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free);
+extern const struct hash_ops network_config_hash_ops;
+
+static inline bool section_is_invalid(NetworkConfigSection *section) {
+        /* If this retuns false, then it does _not_ mean the section is valid. */
+
+        if (!section)
+                return false;
+
+        return section->invalid;
+}
+
+#define DEFINE_NETWORK_SECTION_FUNCTIONS(type, free_func)               \
+        static inline void free_func##_or_set_invalid(type *p) {        \
+                assert(p);                                              \
+                                                                        \
+                if (p->section)                                         \
+                        p->section->invalid = true;                     \
+                else                                                    \
+                        free_func(p);                                   \
+        }                                                               \
+        DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func);                  \
+        DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid);
index fcecafe..4b04aa0 100644 (file)
@@ -1,5 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include "sd-daemon.h"
 #include "sd-event.h"
 
index 86d4e7e..6408719 100644 (file)
@@ -172,7 +172,10 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign
         _cleanup_(network_freep) Network *network = NULL;
 
         assert_se(network = new0(Network, 1));
+        assert_se(network->filename = strdup("hogehoge.network"));
         assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0);
+        assert_se(network->n_static_addresses == 1);
+        assert_se(network_verify(network) >= 0);
         assert_se(network->n_static_addresses == n_addresses);
         if (n_addresses > 0) {
                 assert_se(network->static_addresses);
index 87d54fe..a13373f 100644 (file)
@@ -10,6 +10,7 @@
 
 int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) {
         _cleanup_(link_freep) Link *l = NULL;
+        _cleanup_free_ char *n = NULL;
         int r;
 
         assert(m);
@@ -23,30 +24,33 @@ int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) {
         if (r < 0)
                 return r;
 
-        l = new0(Link, 1);
-        if (!l)
+        n = strdup(ifname);
+        if (!n)
                 return -ENOMEM;
 
-        l->manager = m;
-
-        l->ifname = strdup(ifname);
-        if (!l->ifname)
+        l = new(Link, 1);
+        if (!l)
                 return -ENOMEM;
 
+        *l = (Link) {
+                .manager = m,
+                .ifname = TAKE_PTR(n),
+                .ifindex = ifindex,
+                .required_operstate = LINK_OPERSTATE_DEGRADED,
+        };
+
         r = hashmap_put(m->links_by_name, l->ifname, l);
         if (r < 0)
                 return r;
 
-        l->ifindex = ifindex;
-
         r = hashmap_put(m->links, INT_TO_PTR(ifindex), l);
         if (r < 0)
                 return r;
 
         if (ret)
                 *ret = l;
-        l = NULL;
 
+        TAKE_PTR(l);
         return 0;
 }
 
@@ -60,6 +64,7 @@ Link *link_free(Link *l) {
                 hashmap_remove(l->manager->links_by_name, l->ifname);
         }
 
+        free(l->state);
         free(l->ifname);
         return mfree(l);
  }
@@ -87,9 +92,8 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) {
                 if (!new_ifname)
                         return -ENOMEM;
 
-                hashmap_remove(l->manager->links_by_name, l->ifname);
-                free(l->ifname);
-                l->ifname = new_ifname;
+                assert_se(hashmap_remove(l->manager->links_by_name, l->ifname) == l);
+                free_and_replace(l->ifname, new_ifname);
 
                 r = hashmap_put(l->manager->links_by_name, l->ifname, l);
                 if (r < 0)
@@ -100,17 +104,49 @@ int link_update_rtnl(Link *l, sd_netlink_message *m) {
 }
 
 int link_update_monitor(Link *l) {
-        assert(l);
+        _cleanup_free_ char *operstate = NULL, *required_operstate = NULL, *state = NULL;
+        LinkOperationalState s;
+        int r, ret = 0;
 
-        l->required_for_online = sd_network_link_get_required_for_online(l->ifindex) != 0;
+        assert(l);
+        assert(l->ifname);
 
-        l->operational_state = mfree(l->operational_state);
+        r = sd_network_link_get_required_for_online(l->ifindex);
+        if (r < 0)
+                ret = log_link_debug_errno(l, r, "Failed to determine whether the link is required for online or not, "
+                                           "ignoring: %m");
+        else
+                l->required_for_online = r > 0;
 
-        sd_network_link_get_operational_state(l->ifindex, &l->operational_state);
+        r = sd_network_link_get_required_operstate_for_online(l->ifindex, &required_operstate);
+        if (r < 0)
+                ret = log_link_debug_errno(l, r, "Failed to get required operational state, ignoring: %m");
+        else {
+                s = link_operstate_from_string(required_operstate);
+                if (s < 0)
+                        ret = log_link_debug_errno(l, SYNTHETIC_ERRNO(EINVAL),
+                                                   "Failed to parse required operational state, ignoring: %m");
+                else
+                        l->required_operstate = s;
+        }
 
-        l->state = mfree(l->state);
+        r = sd_network_link_get_operational_state(l->ifindex, &operstate);
+        if (r < 0)
+                ret = log_link_debug_errno(l, r, "Failed to get operational state, ignoring: %m");
+        else {
+                s = link_operstate_from_string(operstate);
+                if (s < 0)
+                        ret = log_link_debug_errno(l, SYNTHETIC_ERRNO(EINVAL),
+                                                   "Failed to parse operational state, ignoring: %m");
+                else
+                        l->operational_state = s;
+        }
 
-        sd_network_link_get_setup_state(l->ifindex, &l->state);
+        r = sd_network_link_get_setup_state(l->ifindex, &state);
+        if (r < 0)
+                ret = log_link_debug_errno(l, r, "Failed to get setup state, ignoring: %m");
+        else
+                free_and_replace(l->state, state);
 
-        return 0;
+        return ret;
 }
index 57e8f12..d58129d 100644 (file)
@@ -3,6 +3,9 @@
 
 #include "sd-netlink.h"
 
+#include "log-link.h"
+#include "network-util.h"
+
 typedef struct Link Link;
 typedef struct Manager Manager;
 
@@ -14,7 +17,8 @@ struct Link {
         unsigned flags;
 
         bool required_for_online;
-        char *operational_state;
+        LinkOperationalState required_operstate;
+        LinkOperationalState operational_state;
         char *state;
 };
 
index 67218b6..e1f9a81 100644 (file)
@@ -13,7 +13,7 @@
 #include "time-util.h"
 #include "util.h"
 
-bool manager_ignore_link(Manager *m, Link *link) {
+static bool manager_ignore_link(Manager *m, Link *link) {
         assert(m);
         assert(link);
 
@@ -22,7 +22,7 @@ bool manager_ignore_link(Manager *m, Link *link) {
                 return true;
 
         /* if interfaces are given on the command line, ignore all others */
-        if (m->interfaces && !strv_contains(m->interfaces, link->ifname))
+        if (m->interfaces && !hashmap_contains(m->interfaces, link->ifname))
                 return true;
 
         if (!link->required_for_online)
@@ -32,45 +32,82 @@ bool manager_ignore_link(Manager *m, Link *link) {
         return strv_fnmatch(m->ignore, link->ifname, 0);
 }
 
-bool manager_all_configured(Manager *m) {
+static int manager_link_is_online(Manager *m, Link *l, LinkOperationalState s) {
+        /* This returns the following:
+         * -EAGAIN: not processed by udev or networkd
+         *       0: operstate is not enough
+         *       1: online */
+
+        if (!l->state)
+                return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
+                                            "link has not yet been processed by udev");
+
+        if (STR_IN_SET(l->state, "configuring", "pending"))
+                return log_link_debug_errno(l, SYNTHETIC_ERRNO(EAGAIN),
+                                            "link is being processed by networkd");
+
+        if (s < 0)
+                s = m->required_operstate >= 0 ? m->required_operstate : l->required_operstate;
+
+        if (l->operational_state < s) {
+                log_link_debug(l, "Operational state '%s' is below '%s'",
+                               link_operstate_to_string(l->operational_state),
+                               link_operstate_to_string(s));
+                return 0;
+        }
+
+        return 1;
+}
+
+bool manager_configured(Manager *m) {
+        bool one_ready = false;
         Iterator i;
+        const char *ifname;
+        void *p;
         Link *l;
-        char **ifname;
-        bool one_ready = false;
+        int r;
 
-        /* wait for all the links given on the command line to appear */
-        STRV_FOREACH(ifname, m->interfaces) {
-                l = hashmap_get(m->links_by_name, *ifname);
-                if (!l) {
-                        log_debug("still waiting for %s", *ifname);
-                        return false;
+        if (!hashmap_isempty(m->interfaces)) {
+                /* wait for all the links given on the command line to appear */
+                HASHMAP_FOREACH_KEY(p, ifname, m->interfaces, i) {
+                        LinkOperationalState s = PTR_TO_INT(p);
+
+                        l = hashmap_get(m->links_by_name, ifname);
+                        if (!l) {
+                                log_debug("still waiting for %s", ifname);
+                                if (!m->any)
+                                        return false;
+                                continue;
+                        }
+
+                        if (manager_link_is_online(m, l, s) <= 0) {
+                                if (!m->any)
+                                        return false;
+                                continue;
+                        }
+
+                        one_ready = true;
                 }
+
+                /* all interfaces given by the command line are online, or
+                 * one of the specified interfaces is online. */
+                return one_ready;
         }
 
         /* wait for all links networkd manages to be in admin state 'configured'
-           and at least one link to gain a carrier */
+         * and at least one link to gain a carrier */
         HASHMAP_FOREACH(l, m->links, i) {
                 if (manager_ignore_link(m, l)) {
-                        log_info("ignoring: %s", l->ifname);
+                        log_link_info(l, "link is ignored");
                         continue;
                 }
 
-                if (!l->state) {
-                        log_debug("link %s has not yet been processed by udev",
-                                  l->ifname);
-                        return false;
-                }
-
-                if (STR_IN_SET(l->state, "configuring", "pending")) {
-                        log_debug("link %s is being processed by networkd",
-                                  l->ifname);
+                r = manager_link_is_online(m, l, _LINK_OPERSTATE_INVALID);
+                if (r < 0 && !m->any)
                         return false;
-                }
-
-                if (l->operational_state &&
-                    STR_IN_SET(l->operational_state, "degraded", "routable"))
+                if (r > 0)
                         /* we wait for at least one link to be ready,
-                           regardless of who manages it */
+                         * regardless of who manages it */
                         one_ready = true;
         }
 
@@ -120,21 +157,21 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *
                         r = link_new(m, &l, ifindex, ifname);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to create link object: %m");
-
-                        r = link_update_monitor(l);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to initialize link object: %m");
                 }
 
                 r = link_update_rtnl(l, mm);
                 if (r < 0)
-                        return log_warning_errno(r, "Failed to process RTNL link message: %m");;
+                        log_link_warning_errno(l, r, "Failed to process RTNL link message, ignoring: %m");
+
+                r = link_update_monitor(l);
+                if (r < 0)
+                        log_link_warning_errno(l, r, "Failed to update link state, ignoring: %m");
 
                 break;
 
         case RTM_DELLINK:
                 if (l) {
-                        log_debug("Removing link %i", l->ifindex);
+                        log_link_debug(l, "Removing link");
                         link_free(l);
                 }
 
@@ -152,7 +189,7 @@ static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdat
         if (r < 0)
                 return r;
 
-        if (manager_all_configured(m))
+        if (manager_configured(m))
                 sd_event_exit(m->event, 0);
 
         return 1;
@@ -217,10 +254,10 @@ static int on_network_event(sd_event_source *s, int fd, uint32_t revents, void *
         HASHMAP_FOREACH(l, m->links, i) {
                 r = link_update_monitor(l);
                 if (r < 0)
-                        log_warning_errno(r, "Failed to update monitor information for %i: %m", l->ifindex);
+                        log_link_warning_errno(l, r, "Failed to update monitor information: %m");
         }
 
-        if (manager_all_configured(m))
+        if (manager_configured(m))
                 sd_event_exit(m->event, 0);
 
         return 0;
@@ -251,18 +288,24 @@ static int manager_network_monitor_listen(Manager *m) {
         return 0;
 }
 
-int manager_new(Manager **ret, char **interfaces, char **ignore, usec_t timeout) {
+int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
+                LinkOperationalState required_operstate,
+                bool any, usec_t timeout) {
         _cleanup_(manager_freep) Manager *m = NULL;
         int r;
 
         assert(ret);
 
-        m = new0(Manager, 1);
+        m = new(Manager, 1);
         if (!m)
                 return -ENOMEM;
 
-        m->interfaces = interfaces;
-        m->ignore = ignore;
+        *m = (Manager) {
+                .interfaces = interfaces,
+                .ignore = ignore,
+                .required_operstate = required_operstate,
+                .any = any,
+        };
 
         r = sd_event_default(&m->event);
         if (r < 0)
index 0fde272..dd7d847 100644 (file)
@@ -6,6 +6,8 @@
 #include "sd-network.h"
 
 #include "hashmap.h"
+#include "network-util.h"
+#include "time-util.h"
 
 typedef struct Manager Manager;
 typedef struct Link Link;
@@ -14,9 +16,13 @@ struct Manager {
         Hashmap *links;
         Hashmap *links_by_name;
 
-        char **interfaces;
+        /* Do not free the two members below. */
+        Hashmap *interfaces;
         char **ignore;
 
+        LinkOperationalState required_operstate;
+        bool any;
+
         sd_netlink *rtnl;
         sd_event_source *rtnl_event_source;
 
@@ -27,9 +33,10 @@ struct Manager {
 };
 
 void manager_free(Manager *m);
-int manager_new(Manager **ret, char **interfaces, char **ignore, usec_t timeout);
+int manager_new(Manager **ret, Hashmap *interfaces, char **ignore,
+                LinkOperationalState required_operstate,
+                bool any, usec_t timeout);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free);
 
-bool manager_all_configured(Manager *m);
-bool manager_ignore_link(Manager *m, Link *link);
+bool manager_configured(Manager *m);
index 71b6cf6..4ce2ac3 100644 (file)
@@ -1,6 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <getopt.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "sd-daemon.h"
 
 #include "manager.h"
 #include "pretty-print.h"
 #include "signal-util.h"
+#include "socket-util.h"
 #include "strv.h"
 
 static bool arg_quiet = false;
 static usec_t arg_timeout = 120 * USEC_PER_SEC;
-static char **arg_interfaces = NULL;
+static Hashmap *arg_interfaces = NULL;
 static char **arg_ignore = NULL;
+static LinkOperationalState arg_required_operstate = _LINK_OPERSTATE_INVALID;
+static bool arg_any = false;
 
-STATIC_DESTRUCTOR_REGISTER(arg_interfaces, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_interfaces, hashmap_free_free_keyp);
 STATIC_DESTRUCTOR_REGISTER(arg_ignore, strv_freep);
 
 static int help(void) {
@@ -32,8 +37,12 @@ static int help(void) {
                "  -h --help                 Show this help\n"
                "     --version              Print version string\n"
                "  -q --quiet                Do not show status information\n"
-               "  -i --interface=INTERFACE  Block until at least these interfaces have appeared\n"
+               "  -i --interface=INTERFACE[:OPERSTATE]\n"
+               "                            Block until at least these interfaces have appeared\n"
                "     --ignore=INTERFACE     Don't take these interfaces into account\n"
+               "  -o --operational-state=OPERSTATE\n"
+               "                            Required operational state\n"
+               "     --any                  Wait until at least one of the interfaces is online\n"
                "     --timeout=SECS         Maximum time to wait for network connectivity\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
@@ -43,21 +52,70 @@ static int help(void) {
         return 0;
 }
 
+static int parse_interface_with_operstate(const char *str) {
+        _cleanup_free_ char *ifname = NULL;
+        LinkOperationalState s;
+        const char *p;
+        int r;
+
+        assert(str);
+
+        p = strchr(str, ':');
+        if (p) {
+                if (isempty(p + 1))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Operational state is empty.");
+
+                s = link_operstate_from_string(p + 1);
+                if (s < 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Invalid operational state '%s'", p + 1);
+
+                ifname = strndup(optarg, p - optarg);
+        } else {
+                s = _LINK_OPERSTATE_INVALID;
+                ifname = strdup(str);
+        }
+        if (!ifname)
+                return log_oom();
+
+        if (!ifname_valid(ifname))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Invalid interface name '%s'", ifname);
+
+        r = hashmap_ensure_allocated(&arg_interfaces, &string_hash_ops);
+        if (r < 0)
+                return log_oom();
+
+        r = hashmap_put(arg_interfaces, ifname, INT_TO_PTR(s));
+        if (r < 0)
+                return log_error_errno(r, "Failed to store interface name: %m");
+        if (r == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "Interface name %s is already specified", ifname);
+
+        TAKE_PTR(ifname);
+        return 0;
+}
+
 static int parse_argv(int argc, char *argv[]) {
 
         enum {
                 ARG_VERSION = 0x100,
                 ARG_IGNORE,
+                ARG_ANY,
                 ARG_TIMEOUT,
         };
 
         static const struct option options[] = {
-                { "help",            no_argument,       NULL, 'h'         },
-                { "version",         no_argument,       NULL, ARG_VERSION },
-                { "quiet",           no_argument,       NULL, 'q'         },
-                { "interface",       required_argument, NULL, 'i'         },
-                { "ignore",          required_argument, NULL, ARG_IGNORE  },
-                { "timeout",         required_argument, NULL, ARG_TIMEOUT  },
+                { "help",              no_argument,       NULL, 'h'         },
+                { "version",           no_argument,       NULL, ARG_VERSION },
+                { "quiet",             no_argument,       NULL, 'q'         },
+                { "interface",         required_argument, NULL, 'i'         },
+                { "ignore",            required_argument, NULL, ARG_IGNORE  },
+                { "operational-state", required_argument, NULL, 'o'         },
+                { "any",               no_argument,       NULL, ARG_ANY     },
+                { "timeout",           required_argument, NULL, ARG_TIMEOUT },
                 {}
         };
 
@@ -66,7 +124,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hi:q", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "hi:qo:", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -82,9 +140,9 @@ static int parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case 'i':
-                        if (strv_extend(&arg_interfaces, optarg) < 0)
-                                return log_oom();
-
+                        r = parse_interface_with_operstate(optarg);
+                        if (r < 0)
+                                return r;
                         break;
 
                 case ARG_IGNORE:
@@ -93,11 +151,25 @@ static int parse_argv(int argc, char *argv[]) {
 
                         break;
 
+                case 'o': {
+                        LinkOperationalState s;
+
+                        s = link_operstate_from_string(optarg);
+                        if (s < 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Invalid operational state '%s'", optarg);
+
+                        arg_required_operstate = s;
+                        break;
+                }
+                case ARG_ANY:
+                        arg_any = true;
+                        break;
+
                 case ARG_TIMEOUT:
                         r = parse_sec(optarg, &arg_timeout);
                         if (r < 0)
                                 return r;
-
                         break;
 
                 case '?':
@@ -124,15 +196,15 @@ static int run(int argc, char *argv[]) {
                 return r;
 
         if (arg_quiet)
-                log_set_max_level(LOG_WARNING);
+                log_set_max_level(LOG_ERR);
 
         assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
 
-        r = manager_new(&m, arg_interfaces, arg_ignore, arg_timeout);
+        r = manager_new(&m, arg_interfaces, arg_ignore, arg_required_operstate, arg_any, arg_timeout);
         if (r < 0)
                 return log_error_errno(r, "Could not create manager: %m");
 
-        if (manager_all_configured(m))
+        if (manager_configured(m))
                 goto success;
 
         notify_message = notify_start("READY=1\n"
index be54ba3..31217c7 100644 (file)
@@ -10,6 +10,8 @@ libnspawn_core_sources = files('''
         nspawn-mount.h
         nspawn-network.c
         nspawn-network.h
+        nspawn-oci.c
+        nspawn-oci.h
         nspawn-patch-uid.c
         nspawn-patch-uid.h
         nspawn-register.c
index 97fa092..168125d 100644 (file)
@@ -5,6 +5,7 @@
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "fileio.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "mkdir.h"
 #include "mount-util.h"
@@ -263,7 +264,7 @@ static int mount_legacy_cgroup_hierarchy(
         if (r > 0)
                 return 0;
 
-        mkdir_p(to, 0755);
+        (void) mkdir_p(to, 0755);
 
         /* The superblock mount options of the mount point need to be
          * identical to the hosts', and hence writable... */
index dec53a0..79304d2 100644 (file)
@@ -62,6 +62,7 @@ Files.Volatile,               config_parse_volatile_mode,  0,                 of
 Files.Bind,                   config_parse_bind,           0,                 0
 Files.BindReadOnly,           config_parse_bind,           1,                 0
 Files.TemporaryFileSystem,    config_parse_tmpfs,          0,                 0
+Files.Inaccessible,           config_parse_inaccessible,   0,                 0
 Files.Overlay,                config_parse_overlay,        0,                 0
 Files.OverlayReadOnly,        config_parse_overlay,        1,                 0
 Files.PrivateUsersChown,      config_parse_tristate,       0,                 offsetof(Settings, userns_chown)
index 11dcfbe..35e3faf 100644 (file)
@@ -6,6 +6,7 @@
 #include "alloc-util.h"
 #include "escape.h"
 #include "fd-util.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "label.h"
 #include "mkdir.h"
 #include "path-util.h"
 #include "rm-rf.h"
 #include "set.h"
+#include "sort-util.h"
 #include "stat-util.h"
 #include "string-util.h"
 #include "strv.h"
 #include "tmpfile-util.h"
 #include "user-util.h"
-#include "util.h"
 
 CustomMount* custom_mount_add(CustomMount **l, size_t *n, CustomMountType t) {
         CustomMount *c, *ret;
@@ -65,6 +66,7 @@ void custom_mount_free_all(CustomMount *l, size_t n) {
                 }
 
                 strv_free(m->lower);
+                free(m->type_argument);
         }
 
         free(l);
@@ -116,32 +118,40 @@ int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n) {
         for (i = 0; i < n; i++) {
                 CustomMount *m = l + i;
 
-                if (m->source) {
-                        char *s;
+                /* /proc we mount in the inner child, i.e. when we acquired CLONE_NEWPID. All other mounts we mount
+                 * already in the outer child, so that the mounts are already established before CLONE_NEWPID and in
+                 * particular CLONE_NEWUSER. This also means any custom mounts below /proc also need to be mounted in
+                 * the inner child, not the outer one. Determine this here. */
+                m->in_userns = path_startswith(m->destination, "/proc");
 
-                        s = resolve_source_path(dest, m->source);
-                        if (!s)
-                                return log_oom();
+                if (m->type == CUSTOM_MOUNT_BIND) {
+                        if (m->source) {
+                                char *s;
 
-                        free_and_replace(m->source, s);
-                } else {
-                        /* No source specified? In that case, use a throw-away temporary directory in /var/tmp */
+                                s = resolve_source_path(dest, m->source);
+                                if (!s)
+                                        return log_oom();
 
-                        m->rm_rf_tmpdir = strdup("/var/tmp/nspawn-temp-XXXXXX");
-                        if (!m->rm_rf_tmpdir)
-                                return log_oom();
+                                free_and_replace(m->source, s);
+                        } else {
+                                /* No source specified? In that case, use a throw-away temporary directory in /var/tmp */
 
-                        if (!mkdtemp(m->rm_rf_tmpdir)) {
-                                m->rm_rf_tmpdir = mfree(m->rm_rf_tmpdir);
-                                return log_error_errno(errno, "Failed to acquire temporary directory: %m");
-                        }
+                                m->rm_rf_tmpdir = strdup("/var/tmp/nspawn-temp-XXXXXX");
+                                if (!m->rm_rf_tmpdir)
+                                        return log_oom();
 
-                        m->source = strjoin(m->rm_rf_tmpdir, "/src");
-                        if (!m->source)
-                                return log_oom();
+                                if (!mkdtemp(m->rm_rf_tmpdir)) {
+                                        m->rm_rf_tmpdir = mfree(m->rm_rf_tmpdir);
+                                        return log_error_errno(errno, "Failed to acquire temporary directory: %m");
+                                }
+
+                                m->source = strjoin(m->rm_rf_tmpdir, "/src");
+                                if (!m->source)
+                                        return log_oom();
 
-                        if (mkdir(m->source, 0755) < 0)
-                                return log_error_errno(errno, "Failed to create %s: %m", m->source);
+                                if (mkdir(m->source, 0755) < 0)
+                                        return log_error_errno(errno, "Failed to create %s: %m", m->source);
+                        }
                 }
 
                 if (m->type == CUSTOM_MOUNT_OVERLAY) {
@@ -206,23 +216,24 @@ int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only)
         }
 
         if (isempty(source))
-                source = NULL;
+                source = mfree(source);
         else if (!source_path_is_valid(source))
                 return -EINVAL;
 
         if (!path_is_absolute(destination))
                 return -EINVAL;
+        if (empty_or_root(destination))
+                return -EINVAL;
 
         m = custom_mount_add(l, n, CUSTOM_MOUNT_BIND);
         if (!m)
                 return -ENOMEM;
 
-        m->source = source;
-        m->destination = destination;
+        m->source = TAKE_PTR(source);
+        m->destination = TAKE_PTR(destination);
         m->read_only = read_only;
-        m->options = opts;
+        m->options = TAKE_PTR(opts);
 
-        source = destination = opts = NULL;
         return 0;
 }
 
@@ -251,6 +262,8 @@ int tmpfs_mount_parse(CustomMount **l, size_t *n, const char *s) {
 
         if (!path_is_absolute(path))
                 return -EINVAL;
+        if (empty_or_root(path))
+                return -EINVAL;
 
         m = custom_mount_add(l, n, CUSTOM_MOUNT_TMPFS);
         if (!m)
@@ -302,7 +315,7 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl
                 /* If the upper directory is unspecified, then let's create it automatically as a throw-away directory
                  * in /var/tmp */
                 if (isempty(upper))
-                        upper = NULL;
+                        upper = mfree(upper);
                 else if (!source_path_is_valid(upper))
                         return -EINVAL;
 
@@ -310,6 +323,9 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl
                         return -EINVAL;
         }
 
+        if (empty_or_root(destination))
+                return -EINVAL;
+
         m = custom_mount_add(l, n, CUSTOM_MOUNT_OVERLAY);
         if (!m)
                 return -ENOMEM;
@@ -322,6 +338,29 @@ int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_onl
         return 0;
 }
 
+int inaccessible_mount_parse(CustomMount **l, size_t *n, const char *s) {
+        _cleanup_free_ char *path = NULL;
+        CustomMount *m;
+
+        assert(l);
+        assert(n);
+        assert(s);
+
+        if (!path_is_absolute(s))
+                return -EINVAL;
+
+        path = strdup(s);
+        if (!path)
+                return -ENOMEM;
+
+        m = custom_mount_add(l, n, CUSTOM_MOUNT_INACCESSIBLE);
+        if (!m)
+                return -ENOMEM;
+
+        m->destination = TAKE_PTR(path);
+        return 0;
+}
+
 int tmpfs_patch_options(
                 const char *options,
                 uid_t uid_shift,
@@ -492,9 +531,9 @@ int mount_all(const char *dest,
               uid_t uid_shift,
               const char *selinux_apifs_context) {
 
-#define PROC_INACCESSIBLE(path)                                         \
-        { NULL, (path), NULL, NULL, MS_BIND,                            \
-          MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO|MOUNT_INACCESSIBLE_REG }, /* Bind mount first ... */ \
+#define PROC_INACCESSIBLE_REG(path)                                     \
+        { "/run/systemd/inaccessible/reg", (path), NULL, NULL, MS_BIND, \
+          MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO }, /* Bind mount first ... */ \
         { NULL, (path), NULL, NULL, MS_BIND|MS_RDONLY|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_REMOUNT, \
           MOUNT_IN_USERNS|MOUNT_APPLY_APIVFS_RO } /* Then, make it r/o */
 
@@ -529,11 +568,11 @@ int mount_all(const char *dest,
 
                 /* Make these files inaccessible to container payloads: they potentially leak information about kernel
                  * internals or the host's execution environment to the container */
-                PROC_INACCESSIBLE("/proc/kallsyms"),
-                PROC_INACCESSIBLE("/proc/kcore"),
-                PROC_INACCESSIBLE("/proc/keys"),
-                PROC_INACCESSIBLE("/proc/sysrq-trigger"),
-                PROC_INACCESSIBLE("/proc/timer_list"),
+                PROC_INACCESSIBLE_REG("/proc/kallsyms"),
+                PROC_INACCESSIBLE_REG("/proc/kcore"),
+                PROC_INACCESSIBLE_REG("/proc/keys"),
+                PROC_INACCESSIBLE_REG("/proc/sysrq-trigger"),
+                PROC_INACCESSIBLE_REG("/proc/timer_list"),
 
                 /* Make these directories read-only to container payloads: they show hardware information, and in some
                  * cases contain tunables the container really shouldn't have access to. */
@@ -545,6 +584,9 @@ int mount_all(const char *dest,
                 PROC_READ_ONLY("/proc/irq"),
                 PROC_READ_ONLY("/proc/scsi"),
 
+                { "mqueue",          "/dev/mqueue",     "mqueue", NULL,       MS_NOSUID|MS_NOEXEC|MS_NODEV,
+                  MOUNT_IN_USERNS },
+
                 /* Then we list outer child mounts (i.e. mounts applied *before* entering user namespacing) */
                 { "tmpfs",           "/tmp",            "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
                   MOUNT_FATAL|MOUNT_APPLY_TMPFS_TMP },
@@ -560,8 +602,6 @@ int mount_all(const char *dest,
                   MOUNT_FATAL },
                 { "tmpfs",           "/run",            "tmpfs", "mode=755",  MS_NOSUID|MS_NODEV|MS_STRICTATIME,
                   MOUNT_FATAL },
-                { "mqueue",          "/dev/mqueue",     "mqueue", NULL,       0,
-                  MOUNT_FATAL },
 
 #if HAVE_SELINUX
                 { "/sys/fs/selinux", "/sys/fs/selinux", NULL,    NULL,        MS_BIND,
@@ -571,7 +611,6 @@ int mount_all(const char *dest,
 #endif
         };
 
-        _cleanup_(unlink_and_freep) char *inaccessible = NULL;
         bool use_userns = (mount_settings & MOUNT_USE_USERNS);
         bool netns = (mount_settings & MOUNT_APPLY_APIVFS_NETNS);
         bool ro = (mount_settings & MOUNT_APPLY_APIVFS_RO);
@@ -582,7 +621,7 @@ int mount_all(const char *dest,
 
         for (k = 0; k < ELEMENTSOF(mount_table); k++) {
                 _cleanup_free_ char *where = NULL, *options = NULL;
-                const char *o, *what;
+                const char *o;
                 bool fatal = (mount_table[k].mount_settings & MOUNT_FATAL);
 
                 if (in_userns != (bool)(mount_table[k].mount_settings & MOUNT_IN_USERNS))
@@ -601,33 +640,14 @@ int mount_all(const char *dest,
                 if (r < 0)
                         return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, mount_table[k].where);
 
-                if (mount_table[k].mount_settings & MOUNT_INACCESSIBLE_REG) {
-
-                        if (!inaccessible) {
-                                _cleanup_free_ char *np = NULL;
-
-                                r = tempfn_random_child(NULL, "inaccessible", &np);
-                                if (r < 0)
-                                        return log_error_errno(r, "Failed to generate inaccessible file node path: %m");
-
-                                r = touch_file(np, false, USEC_INFINITY, UID_INVALID, GID_INVALID, 0000);
-                                if (r < 0)
-                                        return log_error_errno(r, "Failed to create inaccessible file node '%s': %m", np);
-
-                                inaccessible = TAKE_PTR(np);
-                        }
-
-                        what = inaccessible;
-                } else
-                        what = mount_table[k].what;
-
-                r = path_is_mount_point(where, NULL, 0);
-                if (r < 0 && r != -ENOENT)
-                        return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
-
                 /* Skip this entry if it is not a remount. */
-                if (what && r > 0)
-                        continue;
+                if (mount_table[k].what) {
+                        r = path_is_mount_point(where, NULL, 0);
+                        if (r < 0 && r != -ENOENT)
+                                return log_error_errno(r, "Failed to detect whether %s is a mount point: %m", where);
+                        if (r > 0)
+                                continue;
+                }
 
                 r = mkdir_userns_p(dest, where, 0755, (use_userns && !in_userns) ? uid_shift : UID_INVALID);
                 if (r < 0 && r != -EEXIST) {
@@ -652,7 +672,7 @@ int mount_all(const char *dest,
                 }
 
                 r = mount_verbose(fatal ? LOG_ERR : LOG_DEBUG,
-                                  what,
+                                  mount_table[k].what,
                                   where,
                                   mount_table[k].type,
                                   mount_table[k].flags,
@@ -665,7 +685,6 @@ int mount_all(const char *dest,
 }
 
 static int mount_bind(const char *dest, CustomMount *m) {
-
         _cleanup_free_ char *where = NULL;
         struct stat source_st, dest_st;
         int r;
@@ -709,7 +728,6 @@ static int mount_bind(const char *dest, CustomMount *m) {
                         r = touch(where);
                 if (r < 0)
                         return log_error_errno(r, "Failed to create mount point %s: %m", where);
-
         }
 
         r = mount_verbose(LOG_ERR, m->source, where, NULL, MS_BIND | MS_REC, m->options);
@@ -717,7 +735,7 @@ static int mount_bind(const char *dest, CustomMount *m) {
                 return r;
 
         if (m->read_only) {
-                r = bind_remount_recursive(where, true, NULL);
+                r = bind_remount_recursive(where, MS_RDONLY, MS_RDONLY, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Read-only bind mount failed: %m");
         }
@@ -771,7 +789,6 @@ static char *joined_and_escaped_lower_dirs(char **lower) {
 }
 
 static int mount_overlay(const char *dest, CustomMount *m) {
-
         _cleanup_free_ char *lower = NULL, *where = NULL, *escaped_source = NULL;
         const char *options;
         int r;
@@ -813,11 +830,61 @@ static int mount_overlay(const char *dest, CustomMount *m) {
         return mount_verbose(LOG_ERR, "overlay", where, "overlay", m->read_only ? MS_RDONLY : 0, options);
 }
 
+static int mount_inaccessible(const char *dest, CustomMount *m) {
+        _cleanup_free_ char *where = NULL;
+        const char *source;
+        struct stat st;
+        int r;
+
+        assert(dest);
+        assert(m);
+
+        r = chase_symlinks_and_stat(m->destination, dest, CHASE_PREFIX_ROOT, &where, &st);
+        if (r < 0) {
+                log_full_errno(m->graceful ? LOG_DEBUG : LOG_ERR, r, "Failed to resolve %s/%s: %m", dest, m->destination);
+                return m->graceful ? 0 : r;
+        }
+
+        assert_se(source = mode_to_inaccessible_node(st.st_mode));
+
+        r = mount_verbose(m->graceful ? LOG_DEBUG : LOG_ERR, source, where, NULL, MS_BIND, NULL);
+        if (r < 0)
+                return m->graceful ? 0 : r;
+
+        r = mount_verbose(m->graceful ? LOG_DEBUG : LOG_ERR, NULL, where, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL);
+        if (r < 0) {
+                umount_verbose(where);
+                return m->graceful ? 0 : r;
+        }
+
+        return 0;
+}
+
+static int mount_arbitrary(const char *dest, CustomMount *m) {
+        _cleanup_free_ char *where = NULL;
+        int r;
+
+        assert(dest);
+        assert(m);
+
+        r = chase_symlinks(m->destination, dest, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &where);
+        if (r < 0)
+                return log_error_errno(r, "Failed to resolve %s/%s: %m", dest, m->destination);
+        if (r == 0) { /* Doesn't exist yet? */
+                r = mkdir_p_label(where, 0755);
+                if (r < 0)
+                        return log_error_errno(r, "Creating mount point for mount %s failed: %m", where);
+        }
+
+        return mount_verbose(LOG_ERR, m->source, where, m->type_argument, 0, m->options);
+}
+
 int mount_custom(
                 const char *dest,
                 CustomMount *mounts, size_t n,
                 bool userns, uid_t uid_shift, uid_t uid_range,
-                const char *selinux_apifs_context) {
+                const char *selinux_apifs_context,
+                bool in_userns) {
 
         size_t i;
         int r;
@@ -827,6 +894,9 @@ int mount_custom(
         for (i = 0; i < n; i++) {
                 CustomMount *m = mounts + i;
 
+                if (m->in_userns != in_userns)
+                        continue;
+
                 switch (m->type) {
 
                 case CUSTOM_MOUNT_BIND:
@@ -841,6 +911,14 @@ int mount_custom(
                         r = mount_overlay(dest, m);
                         break;
 
+                case CUSTOM_MOUNT_INACCESSIBLE:
+                        r = mount_inaccessible(dest, m);
+                        break;
+
+                case CUSTOM_MOUNT_ARBITRARY:
+                        r = mount_arbitrary(dest, m);
+                        break;
+
                 default:
                         assert_not_reached("Unknown custom mount type");
                 }
@@ -852,9 +930,8 @@ int mount_custom(
         return 0;
 }
 
-int setup_volatile_state(
+static int setup_volatile_state(
                 const char *directory,
-                VolatileMode mode,
                 bool userns, uid_t uid_shift, uid_t uid_range,
                 const char *selinux_apifs_context) {
 
@@ -864,13 +941,9 @@ int setup_volatile_state(
 
         assert(directory);
 
-        if (mode != VOLATILE_STATE)
-                return 0;
+        /* --volatile=state means we simply overmount /var with a tmpfs, and the rest read-only. */
 
-        /* --volatile=state means we simply overmount /var
-           with a tmpfs, and the rest read-only. */
-
-        r = bind_remount_recursive(directory, true, NULL);
+        r = bind_remount_recursive(directory, MS_RDONLY, MS_RDONLY, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to remount %s read-only: %m", directory);
 
@@ -889,9 +962,8 @@ int setup_volatile_state(
         return mount_verbose(LOG_ERR, "tmpfs", p, "tmpfs", MS_STRICTATIME, options);
 }
 
-int setup_volatile(
+static int setup_volatile_yes(
                 const char *directory,
-                VolatileMode mode,
                 bool userns, uid_t uid_shift, uid_t uid_range,
                 const char *selinux_apifs_context) {
 
@@ -903,11 +975,8 @@ int setup_volatile(
 
         assert(directory);
 
-        if (mode != VOLATILE_YES)
-                return 0;
-
-        /* --volatile=yes means we mount a tmpfs to the root dir, and
-           the original /usr to use inside it, and that read-only. */
+        /* --volatile=yes means we mount a tmpfs to the root dir, and the original /usr to use inside it, and that
+           read-only. */
 
         if (!mkdtemp(template))
                 return log_error_errno(errno, "Failed to create temporary directory: %m");
@@ -915,7 +984,7 @@ int setup_volatile(
         options = "mode=755";
         r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
         if (r < 0)
-                return log_oom();
+                goto fail;
         if (r > 0)
                 options = buf;
 
@@ -940,7 +1009,7 @@ int setup_volatile(
 
         bind_mounted = true;
 
-        r = bind_remount_recursive(t, true, NULL);
+        r = bind_remount_recursive(t, MS_RDONLY, MS_RDONLY, NULL);
         if (r < 0) {
                 log_error_errno(r, "Failed to remount %s read-only: %m", t);
                 goto fail;
@@ -964,6 +1033,93 @@ fail:
         return r;
 }
 
+static int setup_volatile_overlay(
+                const char *directory,
+                bool userns, uid_t uid_shift, uid_t uid_range,
+                const char *selinux_apifs_context) {
+
+        _cleanup_free_ char *buf = NULL, *escaped_directory = NULL, *escaped_upper = NULL, *escaped_work = NULL;
+        char template[] = "/tmp/nspawn-volatile-XXXXXX";
+        const char *upper, *work, *options;
+        bool tmpfs_mounted = false;
+        int r;
+
+        assert(directory);
+
+        /* --volatile=overlay means we mount an overlayfs to the root dir. */
+
+        if (!mkdtemp(template))
+                return log_error_errno(errno, "Failed to create temporary directory: %m");
+
+        options = "mode=755";
+        r = tmpfs_patch_options(options, uid_shift == 0 ? UID_INVALID : uid_shift, selinux_apifs_context, &buf);
+        if (r < 0)
+                goto finish;
+        if (r > 0)
+                options = buf;
+
+        r = mount_verbose(LOG_ERR, "tmpfs", template, "tmpfs", MS_STRICTATIME, options);
+        if (r < 0)
+                goto finish;
+
+        tmpfs_mounted = true;
+
+        upper = strjoina(template, "/upper");
+        work = strjoina(template, "/work");
+
+        if (mkdir(upper, 0755) < 0) {
+                r = log_error_errno(errno, "Failed to create %s: %m", upper);
+                goto finish;
+        }
+        if (mkdir(work, 0755) < 0) {
+                r = log_error_errno(errno, "Failed to create %s: %m", work);
+                goto finish;
+        }
+
+        /* And now, let's overmount the root dir with an overlayfs that uses the root dir as lower dir. It's kinda nice
+         * that the kernel allows us to do that without going through some mount point rearrangements. */
+
+        escaped_directory = shell_escape(directory, ",:");
+        escaped_upper = shell_escape(upper, ",:");
+        escaped_work = shell_escape(work, ",:");
+        if (!escaped_directory || !escaped_upper || !escaped_work) {
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        options = strjoina("lowerdir=", escaped_directory, ",upperdir=", escaped_upper, ",workdir=", escaped_work);
+        r = mount_verbose(LOG_ERR, "overlay", directory, "overlay", 0, options);
+
+finish:
+        if (tmpfs_mounted)
+                (void) umount_verbose(template);
+
+        (void) rmdir(template);
+        return r;
+}
+
+int setup_volatile_mode(
+                const char *directory,
+                VolatileMode mode,
+                bool userns, uid_t uid_shift, uid_t uid_range,
+                const char *selinux_apifs_context) {
+
+        switch (mode) {
+
+        case VOLATILE_YES:
+                return setup_volatile_yes(directory, userns, uid_shift, uid_range, selinux_apifs_context);
+
+        case VOLATILE_STATE:
+                return setup_volatile_state(directory, userns, uid_shift, uid_range, selinux_apifs_context);
+
+        case VOLATILE_OVERLAY:
+                return setup_volatile_overlay(directory, userns, uid_shift, uid_range, selinux_apifs_context);
+
+        default:
+                return 0;
+        }
+}
+
 /* Expects *pivot_root_new and *pivot_root_old to be initialised to allocated memory or NULL. */
 int pivot_root_parse(char **pivot_root_new, char **pivot_root_old, const char *s) {
         _cleanup_free_ char *root_new = NULL, *root_old = NULL;
index 8051a7d..ff6990c 100644 (file)
@@ -13,14 +13,15 @@ typedef enum MountSettingsMask {
         MOUNT_APPLY_APIVFS_RO    = 1 << 3, /* if set, /proc/sys, and /sys will be mounted read-only, otherwise read-write. */
         MOUNT_APPLY_APIVFS_NETNS = 1 << 4, /* if set, /proc/sys/net will be mounted read-write.
                                                Works only if MOUNT_APPLY_APIVFS_RO is also set. */
-        MOUNT_INACCESSIBLE_REG   = 1 << 5, /* if set, create an inaccessible regular file first and use as bind mount source */
-        MOUNT_APPLY_TMPFS_TMP    = 1 << 6, /* if set, /tmp will be mounted as tmpfs */
+        MOUNT_APPLY_TMPFS_TMP    = 1 << 5, /* if set, /tmp will be mounted as tmpfs */
 } MountSettingsMask;
 
 typedef enum CustomMountType {
         CUSTOM_MOUNT_BIND,
         CUSTOM_MOUNT_TMPFS,
         CUSTOM_MOUNT_OVERLAY,
+        CUSTOM_MOUNT_INACCESSIBLE,
+        CUSTOM_MOUNT_ARBITRARY,
         _CUSTOM_MOUNT_TYPE_MAX,
         _CUSTOM_MOUNT_TYPE_INVALID = -1
 } CustomMountType;
@@ -34,6 +35,9 @@ typedef struct CustomMount {
         char *work_dir;
         char **lower;
         char *rm_rf_tmpdir;
+        char *type_argument; /* only for CUSTOM_MOUNT_ARBITRARY */
+        bool graceful;
+        bool in_userns;
 } CustomMount;
 
 CustomMount* custom_mount_add(CustomMount **l, size_t *n, CustomMountType t);
@@ -43,14 +47,14 @@ int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n);
 int bind_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
 int tmpfs_mount_parse(CustomMount **l, size_t *n, const char *s);
 int overlay_mount_parse(CustomMount **l, size_t *n, const char *s, bool read_only);
+int inaccessible_mount_parse(CustomMount **l, size_t *n, const char *s);
 
 int mount_all(const char *dest, MountSettingsMask mount_settings, uid_t uid_shift, const char *selinux_apifs_context);
 int mount_sysfs(const char *dest, MountSettingsMask mount_settings);
 
-int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
+int mount_custom(const char *dest, CustomMount *mounts, size_t n, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context, bool in_userns);
 
-int setup_volatile(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
-int setup_volatile_state(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
+int setup_volatile_mode(const char *directory, VolatileMode mode, bool userns, uid_t uid_shift, uid_t uid_range, const char *selinux_apifs_context);
 
 int pivot_root_parse(char **pivot_root_new, char **pivot_root_old, const char *s);
 int setup_pivot_root(const char *directory, const char *pivot_root_new, const char *pivot_root_old);
diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c
new file mode 100644 (file)
index 0000000..db8e4d3
--- /dev/null
@@ -0,0 +1,2269 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <linux/oom.h>
+#if HAVE_SECCOMP
+#include <seccomp.h>
+#endif
+
+#include "bus-util.h"
+#include "cap-list.h"
+#include "cpu-set-util.h"
+#include "env-util.h"
+#include "format-util.h"
+#include "fs-util.h"
+#include "hostname-util.h"
+#include "json.h"
+#include "missing_sched.h"
+#include "nspawn-oci.h"
+#include "path-util.h"
+#include "rlimit-util.h"
+#if HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
+#include "stat-util.h"
+#include "stdio-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
+
+/* TODO:
+ * OCI runtime tool implementation
+ * hooks
+ *
+ * Spec issues:
+ *
+ * How is RLIM_INFINITY supposed to be encoded?
+ * configured effective caps is bullshit, as execv() corrupts it anyway
+ * pipes bind mounted is *very* different from pipes newly created, comments regarding bind mount or not are bogus
+ * annotation values structured? or string?
+ * configurable file system namespace path, but then also root path? wtf?
+ * apply sysctl inside of the container? or outside?
+ * how is unlimited pids tasks limit to be encoded?
+ * what are the defaults for caps if not specified?
+ * what are the default uid/gid mappings if one is missing but the other set, or when user ns is on but no namespace configured
+ * the source field of "mounts" is really weird, as it cannot realistically be relative to the bundle, since we never know if that's what the fs wants
+ * spec contradicts itself on the mount "type" field, as the example uses "bind" as type, but it's not listed in /proc/filesystem, and is something made up by /bin/mount
+ * if type of mount is left out, what shall be assumed? "bind"?
+ * readonly mounts is entirely redundant?
+ * should escaping be applied when joining mount options with ","?
+ * devices cgroup support is bogus, "allow" and "deny" on the kernel level is about adding/removing entries, not about access
+ * spec needs to say that "rwm" devices cgroup combination can't be the empty string
+ * cgrouspv1 crap: kernel, kernelTCP, swapiness, disableOOMKiller, swap, devices, leafWeight
+ * general: it shouldn't leak lower level abstractions this obviously
+ * unmanagable cgroups stuff: realtimeRuntime/realtimePeriod
+ * needs to say what happense when some option is not specified, i.e. which defautls apply
+ * no architecture? no personality?
+ * seccomp example and logic is simply broken: there's no constant "SCMP_ACT_ERRNO".
+ * spec should say what to do with unknown props
+ * /bin/mount regarding NFS and FUSE required?
+ * what does terminal=false mean?
+ * sysctl inside or outside? whitelisting?
+ *
+ * Unsupported:
+ *
+ * apparmorProfile
+ * selinuxLabel + mountLabel
+ * hugepageLimits
+ * network
+ * rdma
+ * intelRdt
+ * swappiness, disableOOMKiller, kernel, kernelTCP, leafWeight (because it's dead, cgroupsv2 can't do it and hence systemd neither)
+ *
+ * Non-slice cgroup paths
+ * Propagation that is not slave + shared
+ * more than one uid/gid mapping, mappings with a container base != 0, or non-matching uid/gid mappings
+ * device cgroups access = false items that are not catchall
+ * device cgroups matches where minor is specified, but major isn't. similar where major is specified but char/block is not. also, any match that only has a type set that has less than "rwm" set. also, any entry that has none of rwm set.
+ *
+ */
+
+static int oci_unexpected(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                        "Unexpected OCI element '%s' of type '%s'.", name, json_variant_type_to_string(json_variant_type(v)));
+}
+
+static int oci_unsupported(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                        "Unsupported OCI element '%s' of type '%s'.", name, json_variant_type_to_string(json_variant_type(v)));
+}
+
+static int oci_terminal(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+
+        /* If not specified, or set to true, we'll default to either an interactive or a read-only
+         * console. If specified as false, we'll forcibly move to "pipe" mode though. */
+        s->console_mode = json_variant_boolean(v) ? _CONSOLE_MODE_INVALID : CONSOLE_PIPE;
+        return 0;
+}
+
+static int oci_console_dimension(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) {
+        unsigned *u = userdata;
+        uintmax_t k;
+
+        assert(u);
+
+        k = json_variant_unsigned(variant);
+        if (k == 0)
+                return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "Console size field '%s' is too small.", strna(name));
+        if (k > USHRT_MAX) /* TIOCSWINSZ's struct winsize uses "unsigned short" for width and height */
+                return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "Console size field '%s' is too large.", strna(name));
+
+        *u = (unsigned) k;
+        return 0;
+}
+
+static int oci_console_size(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "height", JSON_VARIANT_UNSIGNED, oci_console_dimension, offsetof(Settings, console_height), JSON_MANDATORY },
+                { "width",  JSON_VARIANT_UNSIGNED, oci_console_dimension, offsetof(Settings, console_width),  JSON_MANDATORY },
+                {}
+        };
+
+        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+}
+
+static int oci_absolute_path(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        char **p = userdata;
+        const char *n;
+
+        assert(p);
+
+        n = json_variant_string(v);
+
+        if (!path_is_absolute(n))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Path in JSON field '%s' is not absolute: %s", strna(name), n);
+
+        return free_and_strdup_warn(p, n);
+}
+
+static int oci_env(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        char ***l = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(l);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                const char *n;
+
+                if (!json_variant_is_string(e))
+                        return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Environment array contains non-string.");
+
+                assert_se(n = json_variant_string(e));
+
+                if (!env_assignment_is_valid(n))
+                        return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Environment assignment not valid: %s", n);
+
+                r = strv_extend(l, n);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        return 0;
+}
+
+static int oci_args(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        _cleanup_strv_free_ char **l = NULL;
+        char ***value = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(value);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                const char *n;
+
+                if (!json_variant_is_string(e))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Argument is not a string.");
+
+                assert_se(n = json_variant_string(e));
+
+                r = strv_extend(&l, n);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        if (strv_isempty(l))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Argument list empty, refusing.");
+
+        if (isempty(l[0]))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Executable name is empty, refusing.");
+
+        return strv_free_and_replace(*value, l);
+}
+
+static int oci_rlimit_type(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        const char *z;
+        int t, *type = userdata;
+
+        assert_se(type);
+
+        z = startswith(json_variant_string(v), "RLIMIT_");
+        if (!z)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "rlimit entry's name does not begin with 'RLIMIT_', refusing: %s",
+                                json_variant_string(v));
+
+        t = rlimit_from_string(z);
+        if (t < 0)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "rlimit name unknown: %s", json_variant_string(v));
+
+        *type = t;
+        return 0;
+}
+
+static int oci_rlimit_value(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        rlim_t z, *value = userdata;
+
+        assert(value);
+
+        if (json_variant_is_negative(v))
+                z = RLIM_INFINITY;
+        else {
+                if (!json_variant_is_unsigned(v))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                        "rlimits limit not unsigned, refusing.");
+
+                z = (rlim_t) json_variant_unsigned(v);
+
+                if ((uintmax_t) z != json_variant_unsigned(v))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "rlimits limit out of range, refusing.");
+        }
+
+        *value = z;
+        return 0;
+}
+
+static int oci_rlimits(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        Settings *s = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+
+                struct rlimit_data {
+                        int type;
+                        rlim_t soft;
+                        rlim_t hard;
+                } data = {
+                        .type = -1,
+                        .soft = RLIM_INFINITY,
+                        .hard = RLIM_INFINITY,
+                };
+
+                static const JsonDispatch table[] = {
+                        { "soft", JSON_VARIANT_NUMBER, oci_rlimit_value, offsetof(struct rlimit_data, soft), JSON_MANDATORY },
+                        { "hard", JSON_VARIANT_NUMBER, oci_rlimit_value, offsetof(struct rlimit_data, hard), JSON_MANDATORY },
+                        { "type", JSON_VARIANT_STRING, oci_rlimit_type,  offsetof(struct rlimit_data, type), JSON_MANDATORY },
+                        {}
+                };
+
+
+                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                if (r < 0)
+                        return r;
+
+                assert(data.type >= 0);
+                assert(data.type < _RLIMIT_MAX);
+
+                if (s->rlimit[data.type])
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "rlimits array contains duplicate entry, refusing.");
+
+                s->rlimit[data.type] = new(struct rlimit, 1);
+                if (!s->rlimit[data.type])
+                        return log_oom();
+
+                *s->rlimit[data.type] = (struct rlimit) {
+                        .rlim_cur = data.soft,
+                        .rlim_max = data.hard,
+                };
+
+        }
+        return 0;
+}
+
+static int oci_capability_array(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        uint64_t *mask = userdata, m = 0;
+        JsonVariant *e;
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                const char *n;
+                int cap;
+
+                if (!json_variant_is_string(e))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Entry in capabilities array is not a string.");
+
+                assert_se(n = json_variant_string(e));
+
+                cap = capability_from_name(n);
+                if (cap < 0)
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Unknown capability: %s", n);
+
+                m |= UINT64_C(1) << cap;
+        }
+
+        if (*mask == (uint64_t) -1)
+                *mask = m;
+        else
+                *mask |= m;
+
+        return 0;
+}
+
+static int oci_capabilities(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "effective",   JSON_VARIANT_ARRAY, oci_capability_array, offsetof(CapabilityQuintet, effective)   },
+                { "bounding",    JSON_VARIANT_ARRAY, oci_capability_array, offsetof(CapabilityQuintet, bounding)    },
+                { "inheritable", JSON_VARIANT_ARRAY, oci_capability_array, offsetof(CapabilityQuintet, inheritable) },
+                { "permitted",   JSON_VARIANT_ARRAY, oci_capability_array, offsetof(CapabilityQuintet, permitted)   },
+                { "ambient",     JSON_VARIANT_ARRAY, oci_capability_array, offsetof(CapabilityQuintet, ambient)     },
+                {}
+        };
+
+        Settings *s = userdata;
+        int r;
+
+        assert(s);
+
+        r = json_dispatch(v, table, oci_unexpected, flags, &s->full_capabilities);
+        if (r < 0)
+                return r;
+
+        if (s->full_capabilities.bounding != (uint64_t) -1) {
+                s->capability = s->full_capabilities.bounding;
+                s->drop_capability = ~s->full_capabilities.bounding;
+        }
+
+        return 0;
+}
+
+static int oci_oom_score_adj(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        intmax_t k;
+
+        assert(s);
+
+        k = json_variant_integer(v);
+        if (k < OOM_SCORE_ADJ_MIN || k > OOM_SCORE_ADJ_MAX)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "oomScoreAdj value out of range: %ji", k);
+
+        s->oom_score_adjust = (int) k;
+        s->oom_score_adjust_set = true;
+
+        return 0;
+}
+
+static int oci_uid_gid(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        uid_t *uid = userdata, u;
+        uintmax_t k;
+
+        assert(uid);
+        assert_cc(sizeof(uid_t) == sizeof(gid_t));
+
+        k = json_variant_unsigned(v);
+        u = (uid_t) k;
+        if ((uintmax_t) u != k)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "UID/GID out of range: %ji", k);
+
+        if (!uid_is_valid(u))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "UID/GID is not valid: " UID_FMT, u);
+
+        *uid = u;
+        return 0;
+}
+
+static int oci_supplementary_gids(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                gid_t gid, *a;
+
+                if (!json_variant_is_unsigned(e))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Supplementary GID entry is not a UID.");
+
+                r = oci_uid_gid(name, e, flags, &gid);
+                if (r < 0)
+                        return r;
+
+                a = reallocarray(s->supplementary_gids, s->n_supplementary_gids + 1, sizeof(gid_t));
+                if (!a)
+                        return log_oom();
+
+                s->supplementary_gids = a;
+                s->supplementary_gids[s->n_supplementary_gids++] = gid;
+        }
+
+        return 0;
+}
+
+static int oci_user(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        static const JsonDispatch table[] = {
+                { "uid",            JSON_VARIANT_UNSIGNED, oci_uid_gid,            offsetof(Settings, uid), JSON_MANDATORY },
+                { "gid",            JSON_VARIANT_UNSIGNED, oci_uid_gid,            offsetof(Settings, gid), JSON_MANDATORY },
+                { "additionalGids", JSON_VARIANT_ARRAY,    oci_supplementary_gids, 0,                       0              },
+                {}
+        };
+
+        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+}
+
+static int oci_process(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "terminal",        JSON_VARIANT_BOOLEAN, oci_terminal,          0,                                     0               },
+                { "consoleSize",     JSON_VARIANT_OBJECT,  oci_console_size,      0,                                     0               },
+                { "cwd",             JSON_VARIANT_STRING,  oci_absolute_path,     offsetof(Settings, working_directory), 0               },
+                { "env",             JSON_VARIANT_ARRAY,   oci_env,               offsetof(Settings, environment),       0               },
+                { "args",            JSON_VARIANT_ARRAY,   oci_args,              offsetof(Settings, parameters),        0               },
+                { "rlimits",         JSON_VARIANT_ARRAY,   oci_rlimits,           0,                                     0               },
+                { "apparmorProfile", JSON_VARIANT_STRING,  oci_unsupported,       0,                                     JSON_PERMISSIVE },
+                { "capabilities",    JSON_VARIANT_OBJECT,  oci_capabilities,      0,                                     0               },
+                { "noNewPrivileges", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(Settings, no_new_privileges), 0               },
+                { "oomScoreAdj",     JSON_VARIANT_INTEGER, oci_oom_score_adj,     0,                                     0               },
+                { "selinuxLabel",    JSON_VARIANT_STRING,  oci_unsupported,       0,                                     JSON_PERMISSIVE },
+                { "user",            JSON_VARIANT_OBJECT,  oci_user,              0,                                     0               },
+                {}
+        };
+
+        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+}
+
+static int oci_root(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "path",     JSON_VARIANT_STRING,  json_dispatch_string,  offsetof(Settings, root)      },
+                { "readonly", JSON_VARIANT_BOOLEAN, json_dispatch_boolean, offsetof(Settings, read_only) },
+                {}
+        };
+
+        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+}
+
+static int oci_hostname(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        const char *n;
+
+        assert(s);
+
+        assert_se(n = json_variant_string(v));
+
+        if (!hostname_is_valid(n, false))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Hostname string is not a valid hostname: %s", n);
+
+        return free_and_strdup_warn(&s->hostname, n);
+}
+
+static bool oci_exclude_mount(const char *path) {
+
+        /* Returns "true" for all mounts we insist to mount on our own, and hence ignore the OCI data. */
+
+        if (PATH_IN_SET(path,
+                        "/dev",
+                        "/dev/mqueue",
+                        "/dev/pts",
+                        "/dev/shm",
+                        "/proc",
+                        "/proc/acpi",
+                        "/proc/apm",
+                        "/proc/asound",
+                        "/proc/bus",
+                        "/proc/fs",
+                        "/proc/irq",
+                        "/proc/kallsyms",
+                        "/proc/kcore",
+                        "/proc/keys",
+                        "/proc/scsi",
+                        "/proc/sys",
+                        "/proc/sys/net",
+                        "/proc/sysrq-trigger",
+                        "/proc/timer_list",
+                        "/run",
+                        "/sys",
+                        "/sys",
+                        "/sys/fs/selinux",
+                        "/tmp"))
+                return true;
+
+        /* Similar, skip the whole /sys/fs/cgroups subtree */
+        if (path_startswith(path, "/sys/fs/cgroup"))
+                return true;
+
+        return false;
+}
+
+typedef struct oci_mount_data {
+        char *destination;
+        char *source;
+        char *type;
+        char **options;
+} oci_mount_data;
+
+static void cleanup_oci_mount_data(oci_mount_data *data) {
+        free(data->destination);
+        free(data->source);
+        strv_free(data->options);
+        free(data->type);
+}
+
+static int oci_mounts(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                static const JsonDispatch table[] = {
+                        { "destination", JSON_VARIANT_STRING, oci_absolute_path,    offsetof(oci_mount_data, destination), JSON_MANDATORY },
+                        { "source",      JSON_VARIANT_STRING, json_dispatch_string, offsetof(oci_mount_data, source),      0              },
+                        { "options",     JSON_VARIANT_ARRAY,  json_dispatch_strv,   offsetof(oci_mount_data, options),     0,             },
+                        { "type",        JSON_VARIANT_STRING, json_dispatch_string, offsetof(oci_mount_data, type),        0              },
+                        {}
+                };
+
+                _cleanup_free_ char *joined_options = NULL;
+                CustomMount *m;
+                _cleanup_(cleanup_oci_mount_data) oci_mount_data data = {};
+
+                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                if (r < 0)
+                        return r;
+
+                if (!path_is_absolute(data.destination))
+                        return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Mount destination not an absolute path: %s", data.destination);
+
+                if (oci_exclude_mount(data.destination))
+                        continue;
+
+                if (data.options) {
+                        joined_options = strv_join(data.options, ",");
+                        if (!joined_options)
+                                return log_oom();
+                }
+
+                if (!data.type || streq(data.type, "bind")) {
+                        if (data.source && !path_is_absolute(data.source)) {
+                                char *joined;
+
+                                joined = path_join(s->bundle, data.source);
+                                if (!joined)
+                                        return log_oom();
+
+                                free_and_replace(data.source, joined);
+                        }
+
+                        data.type = mfree(data.type);
+
+                        m = custom_mount_add(&s->custom_mounts, &s->n_custom_mounts, CUSTOM_MOUNT_BIND);
+                } else
+                        m = custom_mount_add(&s->custom_mounts, &s->n_custom_mounts, CUSTOM_MOUNT_ARBITRARY);
+                if (!m)
+                        return log_oom();
+
+                m->destination = TAKE_PTR(data.destination);
+                m->source = TAKE_PTR(data.source);
+                m->options = TAKE_PTR(joined_options);
+                m->type_argument = TAKE_PTR(data.type);
+        }
+
+        return 0;
+}
+
+static int oci_namespace_type(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        unsigned long *nsflags = userdata;
+        const char *n;
+
+        assert(nsflags);
+        assert_se(n = json_variant_string(v));
+
+        /* We don't use namespace_flags_from_string() here, as the OCI spec uses slightly different names than the
+         * kernel here. */
+        if (streq(n, "pid"))
+                *nsflags = CLONE_NEWPID;
+        else if (streq(n, "network"))
+                *nsflags = CLONE_NEWNET;
+        else if (streq(n, "mount"))
+                *nsflags = CLONE_NEWNS;
+        else if (streq(n, "ipc"))
+                *nsflags = CLONE_NEWIPC;
+        else if (streq(n, "uts"))
+                *nsflags = CLONE_NEWUTS;
+        else if (streq(n, "user"))
+                *nsflags = CLONE_NEWUSER;
+        else if (streq(n, "cgroup"))
+                *nsflags = CLONE_NEWCGROUP;
+        else
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Unknown cgroup type, refusing: %s", n);
+
+        return 0;
+}
+
+static int oci_namespaces(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        unsigned long n = 0;
+        JsonVariant *e;
+        int r;
+
+        assert_se(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+
+                struct namespace_data {
+                        unsigned long type;
+                        char *path;
+                } data = {};
+
+                static const JsonDispatch table[] = {
+                        { "type", JSON_VARIANT_STRING, oci_namespace_type, offsetof(struct namespace_data, type), JSON_MANDATORY },
+                        { "path", JSON_VARIANT_STRING, oci_absolute_path,  offsetof(struct namespace_data, path), 0              },
+                        {}
+                };
+
+                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                if (r < 0) {
+                        free(data.path);
+                        return r;
+                }
+
+                if (data.path) {
+                        if (data.type != CLONE_NEWNET) {
+                                free(data.path);
+                                return json_log(e, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                                "Specifying namespace path for non-network namespace is not supported.");
+                        }
+
+                        if (s->network_namespace_path) {
+                                free(data.path);
+                                return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
+                                                "Network namespace path specified more than once, refusing.");
+                        }
+
+                        free(s->network_namespace_path);
+                        s->network_namespace_path = data.path;
+                }
+
+                if (FLAGS_SET(n, data.type)) {
+                        return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Duplicate namespace specification, refusing.");
+                }
+
+                n |= data.type;
+        }
+
+        if (!FLAGS_SET(n, CLONE_NEWNS))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                "Containers without file system namespace aren't supported.");
+
+        s->private_network = FLAGS_SET(n, CLONE_NEWNET);
+        s->userns_mode = FLAGS_SET(n, CLONE_NEWUSER) ? USER_NAMESPACE_FIXED : USER_NAMESPACE_NO;
+        s->use_cgns = FLAGS_SET(n, CLONE_NEWCGROUP);
+
+        s->clone_ns_flags = n & (CLONE_NEWIPC|CLONE_NEWPID|CLONE_NEWUTS);
+
+        return 0;
+}
+
+static int oci_uid_gid_range(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        uid_t *uid = userdata, u;
+        uintmax_t k;
+
+        assert(uid);
+        assert_cc(sizeof(uid_t) == sizeof(gid_t));
+
+        /* This is very much like oci_uid_gid(), except the checks are a bit different, as this is a UID range rather
+         * than a specific UID, and hence (uid_t) -1 has no special significance. OTOH a range of zero makes no
+         * sense. */
+
+        k = json_variant_unsigned(v);
+        u = (uid_t) k;
+        if ((uintmax_t) u != k)
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "UID/GID out of range: %ji", k);
+        if (u == 0)
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "UID/GID range can't be zero.");
+
+        *uid = u;
+        return 0;
+}
+
+static int oci_uid_gid_mappings(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        struct mapping_data {
+                uid_t host_id;
+                uid_t container_id;
+                uid_t range;
+        } data = {
+                .host_id = UID_INVALID,
+                .container_id = UID_INVALID,
+                .range = 0,
+        };
+
+        static const JsonDispatch table[] = {
+                { "containerID", JSON_VARIANT_UNSIGNED, oci_uid_gid,       offsetof(struct mapping_data, container_id), JSON_MANDATORY },
+                { "hostID",      JSON_VARIANT_UNSIGNED, oci_uid_gid,       offsetof(struct mapping_data, host_id),      JSON_MANDATORY },
+                { "size",        JSON_VARIANT_UNSIGNED, oci_uid_gid_range, offsetof(struct mapping_data, range),        JSON_MANDATORY },
+                {}
+        };
+
+        Settings *s = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(s);
+
+        if (json_variant_elements(v) == 0)
+                return 0;
+
+        if (json_variant_elements(v) > 1)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                "UID/GID mappings with more than one entry are not supported.");
+
+        assert_se(e = json_variant_by_index(v, 0));
+
+        r = json_dispatch(e, table, oci_unexpected, flags, &data);
+        if (r < 0)
+                return r;
+
+        if (data.host_id + data.range < data.host_id ||
+            data.container_id + data.range < data.container_id)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "UID/GID range goes beyond UID/GID validity range, refusing.");
+
+        if (data.container_id != 0)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                "UID/GID mappings with a non-zero container base are not supported.");
+
+        if (data.range < 0x10000)
+                json_log(v, flags|JSON_WARNING, 0,
+                         "UID/GID mapping with less than 65536 UID/GIDS set up, you are looking for trouble.");
+
+        if (s->uid_range != UID_INVALID &&
+            (s->uid_shift != data.host_id || s->uid_range != data.range))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                "Non-matching UID and GID mappings are not supported.");
+
+        s->uid_shift = data.host_id;
+        s->uid_range = data.range;
+
+        return 0;
+}
+
+static int oci_device_type(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        mode_t *mode = userdata;
+        const char *t;
+
+        assert(mode);
+        assert_se(t = json_variant_string(v));
+
+        if (STR_IN_SET(t, "c", "u"))
+                *mode = (*mode & ~S_IFMT) | S_IFCHR;
+        else if (streq(t, "b"))
+                *mode = (*mode & ~S_IFMT) | S_IFBLK;
+        else if (streq(t, "p"))
+                *mode = (*mode & ~S_IFMT) | S_IFIFO;
+        else
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Unknown device type: %s", t);
+
+        return 0;
+}
+
+static int oci_device_major(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        unsigned *u = userdata;
+        uintmax_t k;
+
+        assert_se(u);
+
+        k = json_variant_unsigned(v);
+        if (!DEVICE_MAJOR_VALID(k))
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "Device major %ji out of range.", k);
+
+        *u = (unsigned) k;
+        return 0;
+}
+
+static int oci_device_minor(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        unsigned *u = userdata;
+        uintmax_t k;
+
+        assert_se(u);
+
+        k = json_variant_unsigned(v);
+        if (!DEVICE_MINOR_VALID(k))
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "Device minor %ji out of range.", k);
+
+        *u = (unsigned) k;
+        return 0;
+}
+
+static int oci_device_file_mode(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        mode_t *mode = userdata, m;
+        uintmax_t k;
+
+        assert(mode);
+
+        k = json_variant_unsigned(v);
+        m = (mode_t) k;
+
+        if ((m & ~07777) != 0 || (uintmax_t) m != k)
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "fileMode out of range, refusing.");
+
+        *mode = m;
+        return 0;
+}
+
+static int oci_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+
+                static const JsonDispatch table[] = {
+                        { "type",     JSON_VARIANT_STRING,   oci_device_type,      offsetof(DeviceNode, mode),  JSON_MANDATORY },
+                        { "path",     JSON_VARIANT_STRING,   oci_absolute_path,    offsetof(DeviceNode, path),  JSON_MANDATORY },
+                        { "major",    JSON_VARIANT_UNSIGNED, oci_device_major,     offsetof(DeviceNode, major), 0              },
+                        { "minor",    JSON_VARIANT_UNSIGNED, oci_device_minor,     offsetof(DeviceNode, minor), 0              },
+                        { "fileMode", JSON_VARIANT_UNSIGNED, oci_device_file_mode, offsetof(DeviceNode, mode),  0              },
+                        { "uid",      JSON_VARIANT_UNSIGNED, oci_uid_gid,          offsetof(DeviceNode, uid),   0              },
+                        { "gid",      JSON_VARIANT_UNSIGNED, oci_uid_gid,          offsetof(DeviceNode, gid),   0              },
+                        {}
+                };
+
+                DeviceNode *node, *nodes;
+
+                nodes = reallocarray(s->extra_nodes, s->n_extra_nodes + 1, sizeof(DeviceNode));
+                if (!nodes)
+                        return log_oom();
+
+                s->extra_nodes = nodes;
+
+                node = nodes + s->n_extra_nodes;
+                *node = (DeviceNode) {
+                        .uid = UID_INVALID,
+                        .gid = GID_INVALID,
+                        .major = (unsigned) -1,
+                        .minor = (unsigned) -1,
+                        .mode = 0644,
+                };
+
+                r = json_dispatch(e, table, oci_unexpected, flags, node);
+                if (r < 0)
+                        goto fail_element;
+
+                if (S_ISCHR(node->mode) || S_ISBLK(node->mode)) {
+                        _cleanup_free_ char *path = NULL;
+
+                        if (node->major == (unsigned) -1 || node->minor == (unsigned) -1) {
+                                r = json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
+                                             "Major/minor required when device node is device node");
+                                goto fail_element;
+                        }
+
+                        /* Suppress a couple of implicit device nodes */
+                        r = device_path_make_canonical(node->mode, makedev(node->major, node->minor), &path);
+                        if (r < 0)
+                                json_log(e, flags|JSON_DEBUG, 0, "Failed to resolve device node %u:%u, ignoring: %m", node->major, node->minor);
+                        else {
+                                if (PATH_IN_SET(path,
+                                                "/dev/null",
+                                                "/dev/zero",
+                                                "/dev/full",
+                                                "/dev/random",
+                                                "/dev/urandom",
+                                                "/dev/tty",
+                                                "/dev/net/tun",
+                                                "/dev/ptmx",
+                                                "/dev/pts/ptmx",
+                                                "/dev/console")) {
+
+                                        json_log(e, flags|JSON_DEBUG, 0, "Ignoring devices item for device '%s', as it is implicitly created anyway.", path);
+                                        free(node->path);
+                                        continue;
+                                }
+                        }
+                }
+
+                s->n_extra_nodes++;
+                continue;
+
+        fail_element:
+                free(node->path);
+                return r;
+        }
+
+        return 0;
+}
+
+static int oci_cgroups_path(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        _cleanup_free_ char *slice = NULL, *backwards = NULL;
+        Settings *s = userdata;
+        const char *p;
+        int r;
+
+        assert(s);
+
+        assert_se(p = json_variant_string(v));
+
+        r = cg_path_get_slice(p, &slice);
+        if (r < 0)
+                return json_log(v, flags, r, "Couldn't derive slice unit name from path '%s': %m", p);
+
+        r = cg_slice_to_path(slice, &backwards);
+        if (r < 0)
+                return json_log(v, flags, r, "Couldn't convert slice unit name '%s' back to path: %m", slice);
+
+        if (!path_equal(backwards, p))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Control group path '%s' does not refer to slice unit, refusing.", p);
+
+        free_and_replace(s->slice, slice);
+        return 0;
+}
+
+static int oci_cgroup_device_type(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        mode_t *mode = userdata;
+        const char *n;
+
+        assert_se(n = json_variant_string(v));
+
+        if (streq(n, "c"))
+                *mode = S_IFCHR;
+        else if (streq(n, "b"))
+                *mode = S_IFBLK;
+        else
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Control group device type unknown: %s", n);
+
+        return 0;
+}
+
+struct device_data {
+        bool allow;
+        bool r;
+        bool w;
+        bool m;
+        mode_t type;
+        unsigned major;
+        unsigned minor;
+};
+
+static int oci_cgroup_device_access(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        struct device_data *d = userdata;
+        bool r = false, w = false, m = false;
+        const char *s;
+        size_t i;
+
+        assert_se(s = json_variant_string(v));
+
+        for (i = 0; s[i]; i++)
+                if (s[i] == 'r')
+                        r = true;
+                else if (s[i] == 'w')
+                        w = true;
+                else if (s[i] == 'm')
+                        m = true;
+                else
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Unknown device access character '%c'.", s[i]);
+
+        d->r = r;
+        d->w = w;
+        d->m = m;
+
+        return 0;
+}
+
+static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        _cleanup_free_ struct device_data *list = NULL;
+        Settings *s = userdata;
+        size_t n_list = 0, i;
+        bool noop = false;
+        JsonVariant *e;
+        int r;
+
+        assert(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+
+                struct device_data data = {
+                        .major = (unsigned) -1,
+                        .minor = (unsigned) -1,
+                }, *a;
+
+                static const JsonDispatch table[] = {
+                        { "allow",  JSON_VARIANT_BOOLEAN,  json_dispatch_boolean,    offsetof(struct device_data, allow), JSON_MANDATORY },
+                        { "type",   JSON_VARIANT_STRING,   oci_cgroup_device_type,   offsetof(struct device_data, type),  0              },
+                        { "major",  JSON_VARIANT_UNSIGNED, oci_device_major,         offsetof(struct device_data, major), 0              },
+                        { "minor",  JSON_VARIANT_UNSIGNED, oci_device_minor,         offsetof(struct device_data, minor), 0              },
+                        { "access", JSON_VARIANT_STRING,   oci_cgroup_device_access, 0,                                   0              },
+                        {}
+                };
+
+                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                if (r < 0)
+                        return r;
+
+                if (!data.allow) {
+                        /* The fact that OCI allows 'deny' entries makes really no sense, as 'allow' vs. 'deny' for the
+                         * devices cgroup controller is really not about whitelisting and blacklisting but about adding
+                         * and removing entries from the whitelist. Since we always start out with an empty whitelist
+                         * we hence ignore the whole thing, as removing entries which don't exist make no sense. We'll
+                         * log about this, since this is really borked in the spec, with one exception: the entry
+                         * that's supposed to drop the kernel's default we ignore silently */
+
+                        if (!data.r || !data.w || !data.m || data.type != 0 || data.major != (unsigned) -1 || data.minor != (unsigned) -1)
+                                json_log(v, flags|JSON_WARNING, 0, "Devices cgroup whitelist with arbitrary 'allow' entries not supported, ignoring.");
+
+                        /* We ignore the 'deny' entry as for us that's implied */
+                        continue;
+                }
+
+                if (!data.r && !data.w && !data.m) {
+                        json_log(v, flags|LOG_WARNING, 0, "Device cgroup whitelist entry with no effect found, ignoring.");
+                        continue;
+                }
+
+                if (data.minor != (unsigned) -1 && data.major == (unsigned) -1)
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                        "Device cgroup whitelist entries with minors but no majors not supported.");
+
+                if (data.major != (unsigned) -1 && data.type == 0)
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                        "Device cgroup whitelist entries with majors but no device node type not supported.");
+
+                if (data.type == 0) {
+                        if (data.r && data.w && data.m) /* a catchall whitelist entry means we are looking at a noop */
+                                noop = true;
+                        else
+                                return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                                "Device cgroup whitelist entries with no type not supported.");
+                }
+
+                a = reallocarray(list, n_list + 1, sizeof(struct device_data));
+                if (!a)
+                        return log_oom();
+
+                list = a;
+                list[n_list++] = data;
+        }
+
+        if (noop)
+                return 0;
+
+        r = settings_allocate_properties(s);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_open_container(s->properties, 'r', "sv");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_append(s->properties, "s", "DeviceAllow");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_open_container(s->properties, 'v', "a(ss)");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_open_container(s->properties, 'a', "(ss)");
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        for (i = 0; i < n_list; i++) {
+                _cleanup_free_ char *pattern = NULL;
+                char access[4];
+                size_t n = 0;
+
+                if (list[i].minor == (unsigned) -1) {
+                        const char *t;
+
+                        if (list[i].type == S_IFBLK)
+                                t = "block";
+                        else {
+                                assert(list[i].type == S_IFCHR);
+                                t = "char";
+                        }
+
+                        if (list[i].major == (unsigned) -1) {
+                                pattern = strjoin(t, "-*");
+                                if (!pattern)
+                                        return log_oom();
+                        } else {
+                                if (asprintf(&pattern, "%s-%u", t, list[i].major) < 0)
+                                        return log_oom();
+                        }
+
+                } else {
+                        assert(list[i].major != (unsigned) -1); /* If a minor is specified, then a major also needs to be specified */
+
+                        r = device_path_make_major_minor(list[i].type, makedev(list[i].major, list[i].minor), &pattern);
+                        if (r < 0)
+                                return log_oom();
+                }
+
+                if (list[i].r)
+                        access[n++] = 'r';
+                if (list[i].w)
+                        access[n++] = 'w';
+                if (list[i].m)
+                        access[n++] = 'm';
+                access[n] = 0;
+
+                assert(n > 0);
+
+                r = sd_bus_message_append(s->properties, "(ss)", pattern, access);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        r = sd_bus_message_close_container(s->properties);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_close_container(s->properties);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        r = sd_bus_message_close_container(s->properties);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        return 0;
+}
+
+static int oci_cgroup_memory_limit(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        uint64_t *m = userdata;
+        uintmax_t k;
+
+        assert(m);
+
+        if (json_variant_is_negative(v)) {
+                *m = UINT64_MAX;
+                return 0;
+        }
+
+        if (!json_variant_is_unsigned(v))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Memory limit is not an unsigned integer");
+
+        k = json_variant_unsigned(v);
+        if (k >= UINT64_MAX)
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "Memory limit too large: %ji", k);
+
+        *m = (uint64_t) k;
+        return 0;
+}
+
+static int oci_cgroup_memory(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        struct memory_data {
+                uint64_t limit;
+                uint64_t reservation;
+                uint64_t swap;
+        } data = {
+                .limit = UINT64_MAX,
+                .reservation = UINT64_MAX,
+                .swap = UINT64_MAX,
+        };
+
+        static const JsonDispatch table[] = {
+                { "limit",            JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, limit),       0               },
+                { "reservation",      JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, reservation), 0               },
+                { "swap",             JSON_VARIANT_NUMBER, oci_cgroup_memory_limit, offsetof(struct memory_data, swap),        0               },
+                { "kernel",           JSON_VARIANT_NUMBER, oci_unsupported,         0,                                         JSON_PERMISSIVE },
+                { "kernelTCP",        JSON_VARIANT_NUMBER, oci_unsupported,         0,                                         JSON_PERMISSIVE },
+                { "swapiness",        JSON_VARIANT_NUMBER, oci_unsupported,         0,                                         JSON_PERMISSIVE },
+                { "disableOOMKiller", JSON_VARIANT_NUMBER, oci_unsupported,         0,                                         JSON_PERMISSIVE },
+                {}
+        };
+
+        Settings *s = userdata;
+        int r;
+
+        r = json_dispatch(v, table, oci_unexpected, flags, &data);
+        if (r < 0)
+                return r;
+
+        if (data.swap != UINT64_MAX) {
+                if (data.limit == UINT64_MAX)
+                        json_log(v, flags|LOG_WARNING, 0, "swap limit without memory limit is not supported, ignoring.");
+                else if (data.swap < data.limit)
+                        json_log(v, flags|LOG_WARNING, 0, "swap limit is below memory limit, ignoring.");
+                else {
+                        r = settings_allocate_properties(s);
+                        if (r < 0)
+                                return r;
+
+                        r = sd_bus_message_append(s->properties, "(sv)", "MemorySwapMax", "t", data.swap - data.limit);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+        }
+
+        if (data.limit != UINT64_MAX) {
+                r = settings_allocate_properties(s);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(s->properties, "(sv)", "MemoryMax", "t", data.limit);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        if (data.reservation != UINT64_MAX) {
+                r = settings_allocate_properties(s);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(s->properties, "(sv)", "MemoryLow", "t", data.reservation);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        return 0;
+}
+
+struct cpu_data {
+        uint64_t shares;
+        uint64_t quota;
+        uint64_t period;
+        cpu_set_t *cpuset;
+        unsigned ncpus;
+};
+
+static int oci_cgroup_cpu_shares(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        uint64_t *u = userdata;
+        uintmax_t k;
+
+        assert(u);
+
+        k = json_variant_unsigned(v);
+        if (k < CGROUP_CPU_SHARES_MIN || k > CGROUP_CPU_SHARES_MAX)
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "shares value out of range.");
+
+        *u = (uint64_t) k;
+        return 0;
+}
+
+static int oci_cgroup_cpu_quota(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        uint64_t *u = userdata;
+        uintmax_t k;
+
+        assert(u);
+
+        k = json_variant_unsigned(v);
+        if (k <= 0 || k >= UINT64_MAX)
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "period/quota value out of range.");
+
+        *u = (uint64_t) k;
+        return 0;
+}
+
+static int oci_cgroup_cpu_cpus(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        struct cpu_data *data = userdata;
+        cpu_set_t *set;
+        const char *n;
+        int ncpus;
+
+        assert(data);
+
+        assert_se(n = json_variant_string(v));
+
+        ncpus = parse_cpu_set(n, &set);
+        if (ncpus < 0)
+                return json_log(v, flags, ncpus, "Failed to parse CPU set specification: %s", n);
+
+        CPU_FREE(data->cpuset);
+        data->cpuset = set;
+        data->ncpus = ncpus;
+
+        return 0;
+}
+
+static int oci_cgroup_cpu(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "shares",          JSON_VARIANT_UNSIGNED, oci_cgroup_cpu_shares, offsetof(struct cpu_data, shares), 0 },
+                { "quota",           JSON_VARIANT_UNSIGNED, oci_cgroup_cpu_quota,  offsetof(struct cpu_data, quota),  0 },
+                { "period",          JSON_VARIANT_UNSIGNED, oci_cgroup_cpu_quota,  offsetof(struct cpu_data, period), 0 },
+                { "realtimeRuntime", JSON_VARIANT_UNSIGNED, oci_unsupported,       0,                                 0 },
+                { "realtimePeriod",  JSON_VARIANT_UNSIGNED, oci_unsupported,       0,                                 0 },
+                { "cpus",            JSON_VARIANT_STRING,   oci_cgroup_cpu_cpus,   0,                                 0 },
+                { "mems",            JSON_VARIANT_STRING,   oci_unsupported,       0,                                 0 },
+                {}
+        };
+
+        struct cpu_data data = {
+                .shares = UINT64_MAX,
+                .quota = UINT64_MAX,
+                .period = UINT64_MAX,
+        };
+
+        Settings *s = userdata;
+        int r;
+
+        r = json_dispatch(v, table, oci_unexpected, flags, &data);
+        if (r < 0) {
+                CPU_FREE(data.cpuset);
+                return r;
+        }
+
+        CPU_FREE(s->cpuset);
+        s->cpuset = data.cpuset;
+        s->cpuset_ncpus = data.ncpus;
+
+        if (data.shares != UINT64_MAX) {
+                r = settings_allocate_properties(s);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(s->properties, "(sv)", "CPUShares", "t", data.shares);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        if (data.quota != UINT64_MAX && data.period != UINT64_MAX) {
+                r = settings_allocate_properties(s);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(s->properties, "(sv)", "CPUQuotaPerSecUSec", "t", (uint64_t) (data.quota * USEC_PER_SEC / data.period));
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+        } else if ((data.quota != UINT64_MAX) != (data.period != UINT64_MAX))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "CPU quota and period not used together.");
+
+        return 0;
+}
+
+static int oci_cgroup_block_io_weight(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        uintmax_t k;
+        int r;
+
+        assert(s);
+
+        k = json_variant_unsigned(v);
+        if (k < CGROUP_BLKIO_WEIGHT_MIN || k > CGROUP_BLKIO_WEIGHT_MAX)
+                return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                "Block I/O weight out of range.");
+
+        r = settings_allocate_properties(s);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(s->properties, "(sv)", "BlockIOWeight", "t", (uint64_t) k);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        return 0;
+}
+
+static int oci_cgroup_block_io_weight_device(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                struct device_data {
+                        unsigned major;
+                        unsigned minor;
+                        uintmax_t weight;
+                } data = {
+                        .major = (unsigned) -1,
+                        .minor = (unsigned) -1,
+                        .weight = UINTMAX_MAX,
+                };
+
+                static const JsonDispatch table[] =  {
+                        { "major",      JSON_VARIANT_UNSIGNED, oci_device_major,       offsetof(struct device_data, major),  JSON_MANDATORY  },
+                        { "minor",      JSON_VARIANT_UNSIGNED, oci_device_minor,       offsetof(struct device_data, minor),  JSON_MANDATORY  },
+                        { "weight",     JSON_VARIANT_UNSIGNED, json_dispatch_unsigned, offsetof(struct device_data, weight), 0               },
+                        { "leafWeight", JSON_VARIANT_INTEGER,  oci_unsupported,        0,                                    JSON_PERMISSIVE },
+                        {}
+                };
+
+                _cleanup_free_ char *path = NULL;
+
+                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                if (r < 0)
+                        return r;
+
+                if (data.weight == UINTMAX_MAX)
+                        continue;
+
+                if (data.weight < CGROUP_BLKIO_WEIGHT_MIN || data.weight > CGROUP_BLKIO_WEIGHT_MAX)
+                        return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                        "Block I/O device weight out of range.");
+
+                r = device_path_make_major_minor(S_IFBLK, makedev(data.major, data.minor), &path);
+                if (r < 0)
+                        return json_log(v, flags, r, "Failed to build device path: %m");
+
+                r = settings_allocate_properties(s);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(s->properties, "(sv)", "BlockIODeviceWeight", "a(st)", 1, path, (uint64_t) data.weight);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        return 0;
+}
+
+static int oci_cgroup_block_io_throttle(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        const char *pname;
+        JsonVariant *e;
+        int r;
+
+        assert(s);
+
+        pname = streq(name, "throttleReadBpsDevice")  ? "IOReadBandwidthMax" :
+                streq(name, "throttleWriteBpsDevice") ? "IOWriteBandwidthMax" :
+                streq(name, "throttleReadIOPSDevice") ? "IOReadIOPSMax" :
+                                                        "IOWriteIOPSMax";
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                struct device_data {
+                        unsigned major;
+                        unsigned minor;
+                        uintmax_t rate;
+                } data = {
+                        .major = (unsigned) -1,
+                        .minor = (unsigned) -1,
+                };
+
+                static const JsonDispatch table[] = {
+                        { "major", JSON_VARIANT_UNSIGNED, oci_device_major,       offsetof(struct device_data, major), JSON_MANDATORY },
+                        { "minor", JSON_VARIANT_UNSIGNED, oci_device_minor,       offsetof(struct device_data, minor), JSON_MANDATORY },
+                        { "rate",  JSON_VARIANT_UNSIGNED, json_dispatch_unsigned, offsetof(struct device_data, rate),  JSON_MANDATORY },
+                        {}
+                };
+
+                _cleanup_free_ char *path = NULL;
+
+                r = json_dispatch(e, table, oci_unexpected, flags, &data);
+                if (r < 0)
+                        return r;
+
+                if (data.rate >= UINT64_MAX)
+                        return json_log(v, flags, SYNTHETIC_ERRNO(ERANGE),
+                                        "Block I/O device rate out of range.");
+
+                r = device_path_make_major_minor(S_IFBLK, makedev(data.major, data.minor), &path);
+                if (r < 0)
+                        return json_log(v, flags, r, "Failed to build device path: %m");
+
+                r = settings_allocate_properties(s);
+                if (r < 0)
+                        return r;
+
+                r = sd_bus_message_append(s->properties, "(sv)", pname, "a(st)", 1, path, (uint64_t) data.rate);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
+        return 0;
+}
+
+static int oci_cgroup_block_io(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "weight",                  JSON_VARIANT_UNSIGNED, oci_cgroup_block_io_weight,        0, 0               },
+                { "leafWeight",              JSON_VARIANT_UNSIGNED, oci_unsupported,                   0, JSON_PERMISSIVE },
+                { "weightDevice",            JSON_VARIANT_ARRAY,    oci_cgroup_block_io_weight_device, 0, 0               },
+                { "throttleReadBpsDevice",   JSON_VARIANT_ARRAY,    oci_cgroup_block_io_throttle,      0, 0               },
+                { "throttleWriteBpsDevice",  JSON_VARIANT_ARRAY,    oci_cgroup_block_io_throttle,      0, 0               },
+                { "throttleReadIOPSDevice",  JSON_VARIANT_ARRAY,    oci_cgroup_block_io_throttle,      0, 0               },
+                { "throttleWriteIOPSDevice", JSON_VARIANT_ARRAY,    oci_cgroup_block_io_throttle,      0, 0               },
+                {}
+        };
+
+        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+}
+
+static int oci_cgroup_pids(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "limit", JSON_VARIANT_NUMBER, json_dispatch_variant, 0, JSON_MANDATORY },
+                {}
+        };
+
+        _cleanup_(json_variant_unrefp) JsonVariant *k = NULL;
+        Settings *s = userdata;
+        uint64_t m;
+        int r;
+
+        assert(s);
+
+        r = json_dispatch(v, table, oci_unexpected, flags, &k);
+        if (r < 0)
+                return r;
+
+        if (json_variant_is_negative(k))
+                m = UINT64_MAX;
+        else {
+                if (!json_variant_is_unsigned(k))
+                        return json_log(k, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "pids limit not unsigned integer, refusing.");
+
+                m = (uint64_t) json_variant_unsigned(k);
+
+                if ((uintmax_t) m != json_variant_unsigned(k))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "pids limit out of range, refusing.");
+        }
+
+        r = settings_allocate_properties(s);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_append(s->properties, "(sv)", "TasksMax", "t", m);
+        if (r < 0)
+                return bus_log_create_error(r);
+
+        return 0;
+}
+
+static int oci_resources(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "devices",        JSON_VARIANT_ARRAY,  oci_cgroup_devices,  0, 0 },
+                { "memory",         JSON_VARIANT_OBJECT, oci_cgroup_memory,   0, 0 },
+                { "cpu",            JSON_VARIANT_OBJECT, oci_cgroup_cpu,      0, 0 },
+                { "blockIO",        JSON_VARIANT_OBJECT, oci_cgroup_block_io, 0, 0 },
+                { "hugepageLimits", JSON_VARIANT_ARRAY,  oci_unsupported,     0, 0 },
+                { "network",        JSON_VARIANT_OBJECT, oci_unsupported,     0, 0 },
+                { "pids",           JSON_VARIANT_OBJECT, oci_cgroup_pids,     0, 0 },
+                { "rdma",           JSON_VARIANT_OBJECT, oci_unsupported,     0, 0 },
+                {}
+        };
+
+        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+}
+
+static bool sysctl_key_valid(const char *s) {
+        bool dot = true;
+
+        /* Note that we are a bit stricter here than in systemd-sysctl, as that inherited semantics from the old sysctl
+         * tool, which were really weird (as it swaps / and . in both ways) */
+
+        if (isempty(s))
+                return false;
+
+        for (; *s; s++) {
+
+                if (*s <= ' ' || *s >= 127)
+                        return false;
+                if (*s == '/')
+                        return false;
+                if (*s == '.') {
+
+                        if (dot) /* Don't allow two dots next to each other (or at the beginning) */
+                                return false;
+
+                        dot = true;
+                } else
+                        dot = false;
+        }
+
+        if (dot) /* don't allow a dot at the end */
+                return false;
+
+        return true;
+}
+
+static int oci_sysctl(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        JsonVariant *k, *w;
+        int r;
+
+        assert(s);
+
+        JSON_VARIANT_OBJECT_FOREACH(k, w, v) {
+                const char *n, *m;
+
+                if (!json_variant_is_string(w))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "sysctl parameter is not a string, refusing.");
+
+                assert_se(n = json_variant_string(k));
+                assert_se(m = json_variant_string(w));
+
+                if (sysctl_key_valid(n))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "sysctl key invalid, refusing: %s", n);
+
+                r = strv_extend_strv(&s->sysctl, STRV_MAKE(n, m), false);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        return 0;
+}
+
+#if HAVE_SECCOMP
+static int oci_seccomp_action_from_string(const char *name, uint32_t *ret) {
+
+        static const struct {
+                const char *name;
+                uint32_t action;
+        } table[] = {
+                { "SCMP_ACT_ALLOW", SCMP_ACT_ALLOW        },
+                { "SCMP_ACT_ERRNO", SCMP_ACT_ERRNO(EPERM) }, /* the OCI spec doesn't document the error, but it appears EPERM is supposed to be used */
+                { "SCMP_ACT_KILL",  SCMP_ACT_KILL         },
+#ifdef SCMP_ACT_LOG
+                { "SCMP_ACT_LOG",   SCMP_ACT_LOG          },
+#endif
+                { "SCMP_ACT_TRAP",  SCMP_ACT_TRAP         },
+
+                /* We don't support SCMP_ACT_TRACE because that requires a tracer, and that doesn't really make sense
+                 * here */
+        };
+
+        size_t i;
+
+        for (i = 0; i < ELEMENTSOF(table); i++)
+                if (streq_ptr(name, table[i].name)) {
+                        *ret = table[i].action;
+                        return 0;
+                }
+
+        return -EINVAL;
+}
+
+static int oci_seccomp_arch_from_string(const char *name, uint32_t *ret) {
+
+        static const struct {
+                const char *name;
+                uint32_t arch;
+        } table[] = {
+                { "SCMP_ARCH_AARCH64",     SCMP_ARCH_AARCH64     },
+                { "SCMP_ARCH_ARM",         SCMP_ARCH_ARM         },
+                { "SCMP_ARCH_MIPS",        SCMP_ARCH_MIPS        },
+                { "SCMP_ARCH_MIPS64",      SCMP_ARCH_MIPS64      },
+                { "SCMP_ARCH_MIPS64N32",   SCMP_ARCH_MIPS64N32   },
+                { "SCMP_ARCH_MIPSEL",      SCMP_ARCH_MIPSEL      },
+                { "SCMP_ARCH_MIPSEL64",    SCMP_ARCH_MIPSEL64    },
+                { "SCMP_ARCH_MIPSEL64N32", SCMP_ARCH_MIPSEL64N32 },
+                { "SCMP_ARCH_NATIVE",      SCMP_ARCH_NATIVE      },
+#ifdef SCMP_ARCH_PARISC
+                { "SCMP_ARCH_PARISC",      SCMP_ARCH_PARISC      },
+#endif
+#ifdef SCMP_ARCH_PARISC64
+                { "SCMP_ARCH_PARISC64",    SCMP_ARCH_PARISC64    },
+#endif
+                { "SCMP_ARCH_PPC",         SCMP_ARCH_PPC         },
+                { "SCMP_ARCH_PPC64",       SCMP_ARCH_PPC64       },
+                { "SCMP_ARCH_PPC64LE",     SCMP_ARCH_PPC64LE     },
+                { "SCMP_ARCH_S390",        SCMP_ARCH_S390        },
+                { "SCMP_ARCH_S390X",       SCMP_ARCH_S390X       },
+                { "SCMP_ARCH_X32",         SCMP_ARCH_X32         },
+                { "SCMP_ARCH_X86",         SCMP_ARCH_X86         },
+                { "SCMP_ARCH_X86_64",      SCMP_ARCH_X86_64      },
+        };
+
+        size_t i;
+
+        for (i = 0; i < ELEMENTSOF(table); i++)
+                if (streq_ptr(table[i].name, name)) {
+                        *ret = table[i].arch;
+                        return 0;
+                }
+
+        return -EINVAL;
+}
+
+static int oci_seccomp_compare_from_string(const char *name, enum scmp_compare *ret) {
+
+        static const struct {
+                const char *name;
+                enum scmp_compare op;
+        } table[] = {
+                { "SCMP_CMP_NE",        SCMP_CMP_NE        },
+                { "SCMP_CMP_LT",        SCMP_CMP_LT        },
+                { "SCMP_CMP_LE",        SCMP_CMP_LE        },
+                { "SCMP_CMP_EQ",        SCMP_CMP_EQ        },
+                { "SCMP_CMP_GE",        SCMP_CMP_GE        },
+                { "SCMP_CMP_GT",        SCMP_CMP_GT        },
+                { "SCMP_CMP_MASKED_EQ", SCMP_CMP_MASKED_EQ },
+        };
+
+        size_t i;
+
+        for (i = 0; i < ELEMENTSOF(table); i++)
+                if (streq_ptr(table[i].name, name)) {
+                        *ret = table[i].op;
+                        return 0;
+                }
+
+        return -EINVAL;
+}
+
+static int oci_seccomp_archs(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        scmp_filter_ctx *sc = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(sc);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                uint32_t a;
+
+                if (!json_variant_is_string(e))
+                        return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Architecture entry is not a string");
+
+                r = oci_seccomp_arch_from_string(json_variant_string(e), &a);
+                if (r < 0)
+                        return json_log(e, flags, r, "Unknown architecture: %s", json_variant_string(e));
+
+                r = seccomp_arch_add(sc, a);
+                if (r == -EEXIST)
+                        continue;
+                if (r < 0)
+                        return json_log(e, flags, r, "Failed to add architecture to seccomp filter: %m");
+        }
+
+        return 0;
+}
+
+struct syscall_rule {
+        char **names;
+        uint32_t action;
+        struct scmp_arg_cmp *arguments;
+        size_t n_arguments;
+};
+
+static void syscall_rule_free(struct syscall_rule *rule) {
+        assert(rule);
+
+        strv_free(rule->names);
+        free(rule->arguments);
+};
+
+static int oci_seccomp_action(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        uint32_t *action = userdata;
+        int r;
+
+        assert(action);
+
+        r = oci_seccomp_action_from_string(json_variant_string(v), action);
+        if (r < 0)
+                return json_log(v, flags, r, "Unknown system call action '%s': %m", json_variant_string(v));
+
+        return 0;
+}
+
+static int oci_seccomp_op(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        enum scmp_compare *op = userdata;
+        int r;
+
+        assert(op);
+
+        r = oci_seccomp_compare_from_string(json_variant_string(v), op);
+        if (r < 0)
+                return json_log(v, flags, r, "Unknown seccomp operator '%s': %m", json_variant_string(v));
+
+        return 0;
+}
+
+static int oci_seccomp_args(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        struct syscall_rule *rule = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(rule);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                static const struct JsonDispatch table[] = {
+                        { "index",    JSON_VARIANT_UNSIGNED, json_dispatch_uint32, offsetof(struct scmp_arg_cmp, arg),     JSON_MANDATORY },
+                        { "value",    JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(struct scmp_arg_cmp, datum_a), JSON_MANDATORY },
+                        { "valueTwo", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(struct scmp_arg_cmp, datum_b), 0              },
+                        { "op",       JSON_VARIANT_STRING,   oci_seccomp_op,       offsetof(struct scmp_arg_cmp, op),      JSON_MANDATORY },
+                        {},
+                };
+
+                struct scmp_arg_cmp *a, *p;
+                int expected;
+
+                a = reallocarray(rule->arguments, rule->n_arguments + 1, sizeof(struct syscall_rule));
+                if (!a)
+                        return log_oom();
+
+                rule->arguments = a;
+                p = rule->arguments + rule->n_arguments;
+
+                *p = (struct scmp_arg_cmp) {
+                        .arg = 0,
+                        .datum_a = 0,
+                        .datum_b = 0,
+                        .op = 0,
+                };
+
+                r = json_dispatch(e, table, oci_unexpected, flags, p);
+                if (r < 0)
+                        return r;
+
+                expected = p->op == SCMP_CMP_MASKED_EQ ? 4 : 3;
+                if (r != expected)
+                        json_log(e, flags|JSON_WARNING, 0, "Wrong number of system call arguments for JSON data data, ignoring.");
+
+                /* Note that we are a bit sloppy here and do not insist that SCMP_CMP_MASKED_EQ gets two datum values,
+                 * and the other only one. That's because buildah for example by default calls things with
+                 * SCMP_CMP_MASKED_EQ but only one argument. We use 0 when the value is not specified. */
+
+                rule->n_arguments++;
+        }
+
+        return 0;
+}
+
+static int oci_seccomp_syscalls(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        scmp_filter_ctx *sc = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(sc);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                static const JsonDispatch table[] = {
+                        { "names",  JSON_VARIANT_ARRAY,  json_dispatch_strv, offsetof(struct syscall_rule, names),  JSON_MANDATORY },
+                        { "action", JSON_VARIANT_STRING, oci_seccomp_action, offsetof(struct syscall_rule, action), JSON_MANDATORY },
+                        { "args",   JSON_VARIANT_ARRAY,  oci_seccomp_args,   0,                                     0              },
+                };
+                struct syscall_rule rule = {
+                        .action = (uint32_t) -1,
+                };
+                char **i;
+
+                r = json_dispatch(e, table, oci_unexpected, flags, &rule);
+                if (r < 0)
+                        goto fail_rule;
+
+                if (strv_isempty(rule.names)) {
+                        json_log(e, flags, 0, "System call name list is empty.");
+                        r = -EINVAL;
+                        goto fail_rule;
+                }
+
+                STRV_FOREACH(i, rule.names) {
+                        int nr;
+
+                        nr = seccomp_syscall_resolve_name(*i);
+                        if (nr == __NR_SCMP_ERROR) {
+                                log_debug("Unknown syscall %s, skipping.", *i);
+                                continue;
+                        }
+
+                        r = seccomp_rule_add_array(sc, rule.action, nr, rule.n_arguments, rule.arguments);
+                        if (r < 0)
+                                goto fail_rule;
+                }
+
+                syscall_rule_free(&rule);
+                continue;
+
+        fail_rule:
+                syscall_rule_free(&rule);
+                return r;
+        }
+
+        return 0;
+}
+#endif
+
+static int oci_seccomp(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+#if HAVE_SECCOMP
+        static const JsonDispatch table[] = {
+                { "defaultAction", JSON_VARIANT_STRING, NULL,                 0, JSON_MANDATORY },
+                { "architectures", JSON_VARIANT_ARRAY,  oci_seccomp_archs,    0, 0              },
+                { "syscalls",      JSON_VARIANT_ARRAY,  oci_seccomp_syscalls, 0, 0              },
+                {}
+        };
+
+        _cleanup_(seccomp_releasep) scmp_filter_ctx sc = NULL;
+        Settings *s = userdata;
+        JsonVariant *def;
+        uint32_t d;
+        int r;
+
+        assert(s);
+
+        def = json_variant_by_key(v, "defaultAction");
+        if (!def)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL), "defaultAction element missing.");
+
+        if (!json_variant_is_string(def))
+                return json_log(def, flags, SYNTHETIC_ERRNO(EINVAL), "defaultAction is not a string.");
+
+        r = oci_seccomp_action_from_string(json_variant_string(def), &d);
+        if (r < 0)
+                return json_log(def, flags, r, "Unknown default action: %s", json_variant_string(def));
+
+        sc = seccomp_init(d);
+        if (!sc)
+                return json_log(v, flags, SYNTHETIC_ERRNO(ENOMEM), "Couldn't allocate seccomp object.");
+
+        r = json_dispatch(v, table, oci_unexpected, flags, sc);
+        if (r < 0)
+                return r;
+
+        seccomp_release(s->seccomp);
+        s->seccomp = TAKE_PTR(sc);
+        return 0;
+#else
+        return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP), "libseccomp support not enabled, can't parse seccomp object.");
+#endif
+}
+
+static int oci_rootfs_propagation(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        const char *s;
+
+        s = json_variant_string(v);
+
+        if (streq(s, "shared"))
+                return 0;
+
+        json_log(v, flags|JSON_DEBUG, 0, "Ignoring rootfsPropagation setting '%s'.", s);
+        return 0;
+}
+
+static int oci_masked_paths(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        JsonVariant *e;
+
+        assert(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                _cleanup_free_ char *destination = NULL;
+                CustomMount *m;
+                const char *p;
+
+                if (!json_variant_is_string(e))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Path is not a string, refusing.");
+
+                assert_se(p = json_variant_string(e));
+
+                if (!path_is_absolute(p))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Path is not not absolute, refusing: %s", p);
+
+                if (oci_exclude_mount(p))
+                        continue;
+
+                destination = strdup(p);
+                if (!destination)
+                        return log_oom();
+
+                m = custom_mount_add(&s->custom_mounts, &s->n_custom_mounts, CUSTOM_MOUNT_INACCESSIBLE);
+                if (!m)
+                        return log_oom();
+
+                m->destination = TAKE_PTR(destination);
+
+                /* The spec doesn't say this, but apparently pre-existing implementations are lenient towards
+                 * non-existing paths to mask. Let's hence be too. */
+                m->graceful = true;
+        }
+
+        return 0;
+}
+
+static int oci_readonly_paths(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        JsonVariant *e;
+
+        assert(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+                _cleanup_free_ char *source = NULL, *destination = NULL;
+                CustomMount *m;
+                const char *p;
+
+                if (!json_variant_is_string(e))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Path is not a string, refusing.");
+
+                assert_se(p = json_variant_string(e));
+
+                if (!path_is_absolute(p))
+                        return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Path is not not absolute, refusing: %s", p);
+
+                if (oci_exclude_mount(p))
+                        continue;
+
+                source = strjoin("+", p);
+                if (!source)
+                        return log_oom();
+
+                destination = strdup(p);
+                if (!destination)
+                        return log_oom();
+
+                m = custom_mount_add(&s->custom_mounts, &s->n_custom_mounts, CUSTOM_MOUNT_BIND);
+                if (!m)
+                        return log_oom();
+
+                m->source = TAKE_PTR(source);
+                m->destination = TAKE_PTR(destination);
+                m->read_only = true;
+        }
+
+        return 0;
+}
+
+static int oci_linux(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "namespaces",        JSON_VARIANT_ARRAY,  oci_namespaces,         0, 0               },
+                { "uidMappings",       JSON_VARIANT_ARRAY,  oci_uid_gid_mappings,   0, 0               },
+                { "gidMappings",       JSON_VARIANT_ARRAY,  oci_uid_gid_mappings,   0, 0               },
+                { "devices",           JSON_VARIANT_ARRAY,  oci_devices,            0, 0               },
+                { "cgroupsPath",       JSON_VARIANT_STRING, oci_cgroups_path,       0, 0               },
+                { "resources",         JSON_VARIANT_OBJECT, oci_resources,          0, 0               },
+                { "intelRdt",          JSON_VARIANT_OBJECT, oci_unsupported,        0, JSON_PERMISSIVE },
+                { "sysctl",            JSON_VARIANT_OBJECT, oci_sysctl,             0, 0               },
+                { "seccomp",           JSON_VARIANT_OBJECT, oci_seccomp,            0, 0               },
+                { "rootfsPropagation", JSON_VARIANT_STRING, oci_rootfs_propagation, 0, 0               },
+                { "maskedPaths",       JSON_VARIANT_ARRAY,  oci_masked_paths,       0, 0               },
+                { "readonlyPaths",     JSON_VARIANT_ARRAY,  oci_readonly_paths,     0, 0               },
+                { "mountLabel",        JSON_VARIANT_STRING, oci_unsupported,        0, JSON_PERMISSIVE },
+                {}
+        };
+
+        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+}
+
+static int oci_hook_timeout(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        usec_t *u = userdata;
+        uintmax_t k;
+
+        k = json_variant_unsigned(v);
+        if (k == 0)
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Hook timeout cannot be zero.");
+
+        if (k > (UINT64_MAX-1/USEC_PER_SEC))
+                return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
+                                "Hook timeout too large.");
+
+        *u = k * USEC_PER_SEC;
+        return 0;
+}
+
+static int oci_hooks_array(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        Settings *s = userdata;
+        JsonVariant *e;
+        int r;
+
+        assert(s);
+
+        JSON_VARIANT_ARRAY_FOREACH(e, v) {
+
+                static const JsonDispatch table[] = {
+                        { "path",    JSON_VARIANT_STRING,   oci_absolute_path, offsetof(OciHook, path),    JSON_MANDATORY },
+                        { "args",    JSON_VARIANT_ARRAY,    oci_args,          offsetof(OciHook, args),    0              },
+                        { "env",     JSON_VARIANT_ARRAY,    oci_env,           offsetof(OciHook, env),     0              },
+                        { "timeout", JSON_VARIANT_UNSIGNED, oci_hook_timeout,  offsetof(OciHook, timeout), 0              },
+                        {}
+                };
+
+                OciHook *a, **array, *new_item;
+                size_t *n_array;
+
+                if (streq(name, "prestart")) {
+                        array = &s->oci_hooks_prestart;
+                        n_array = &s->n_oci_hooks_prestart;
+                } else if (streq(name, "poststart")) {
+                        array = &s->oci_hooks_poststart;
+                        n_array = &s->n_oci_hooks_poststart;
+                } else {
+                        assert(streq(name, "poststop"));
+                        array = &s->oci_hooks_poststop;
+                        n_array = &s->n_oci_hooks_poststop;
+                }
+
+                a = reallocarray(*array, *n_array + 1, sizeof(OciHook));
+                if (!a)
+                        return log_oom();
+
+                *array = a;
+                new_item = a + *n_array;
+
+                *new_item = (OciHook) {
+                        .timeout = USEC_INFINITY,
+                };
+
+                r = json_dispatch(e, table, oci_unexpected, flags, userdata);
+                if (r < 0) {
+                        free(new_item->path);
+                        strv_free(new_item->args);
+                        strv_free(new_item->env);
+                        return r;
+                }
+
+                (*n_array) ++;
+        }
+
+        return 0;
+}
+
+static int oci_hooks(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+
+        static const JsonDispatch table[] = {
+                { "prestart",  JSON_VARIANT_OBJECT, oci_hooks_array, 0, 0 },
+                { "poststart", JSON_VARIANT_OBJECT, oci_hooks_array, 0, 0 },
+                { "poststop",  JSON_VARIANT_OBJECT, oci_hooks_array, 0, 0 },
+                {}
+        };
+
+        return json_dispatch(v, table, oci_unexpected, flags, userdata);
+}
+
+static int oci_annotations(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
+        JsonVariant *k, *w;
+
+        JSON_VARIANT_OBJECT_FOREACH(k, w, v) {
+                const char *n;
+
+                assert_se(n = json_variant_string(k));
+
+                if (isempty(n))
+                        return json_log(k, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Annotation with empty key, refusing.");
+
+                if (!json_variant_is_string(w))
+                        return json_log(w, flags, SYNTHETIC_ERRNO(EINVAL),
+                                        "Annotation has non-string value, refusing.");
+
+                json_log(k, flags|JSON_DEBUG, 0, "Ignoring annotation '%s' with value '%s'.", n, json_variant_string(w));
+        }
+
+        return 0;
+}
+
+int oci_load(FILE *f, const char *bundle, Settings **ret) {
+
+        static const JsonDispatch table[] = {
+                { "ociVersion",  JSON_VARIANT_STRING, NULL,            0, JSON_MANDATORY },
+                { "process",     JSON_VARIANT_OBJECT, oci_process,     0, 0 },
+                { "root",        JSON_VARIANT_OBJECT, oci_root,        0, 0 },
+                { "hostname",    JSON_VARIANT_STRING, oci_hostname,    0, 0 },
+                { "mounts",      JSON_VARIANT_ARRAY,  oci_mounts,      0, 0 },
+                { "linux",       JSON_VARIANT_OBJECT, oci_linux,       0, 0 },
+                { "hooks",       JSON_VARIANT_OBJECT, oci_hooks,       0, 0 },
+                { "annotations", JSON_VARIANT_OBJECT, oci_annotations, 0, 0 },
+                {}
+        };
+
+        _cleanup_(json_variant_unrefp) JsonVariant *oci = NULL;
+        _cleanup_(settings_freep) Settings *s = NULL;
+        unsigned line = 0, column = 0;
+        JsonVariant *v;
+        const char *path;
+        int r;
+
+        assert_se(bundle);
+
+        path = strjoina(bundle, "/config.json");
+
+        r = json_parse_file(f, path, &oci, &line, &column);
+        if (r < 0) {
+                if (line != 0 && column != 0)
+                        return log_error_errno(r, "Failed to parse '%s' at %u:%u: %m", path, line, column);
+                else
+                        return log_error_errno(r, "Failed to parse '%s': %m", path);
+        }
+
+        v = json_variant_by_key(oci, "ociVersion");
+        if (!v) {
+                log_error("JSON file '%s' is not an OCI bundle configuration file. Refusing.", path);
+                return -EINVAL;
+        }
+        if (!streq_ptr(json_variant_string(v), "1.0.0")) {
+                log_error("OCI bundle version not supported: %s", strna(json_variant_string(v)));
+                return -EINVAL;
+        }
+
+        // {
+        //         _cleanup_free_ char *formatted = NULL;
+        //         assert_se(json_variant_format(oci, JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR, &formatted) >= 0);
+        //         fputs(formatted, stdout);
+        // }
+
+        s = settings_new();
+        if (!s)
+                return log_oom();
+
+        s->start_mode = START_PID1;
+        s->resolv_conf = RESOLV_CONF_OFF;
+        s->link_journal = LINK_NO;
+        s->timezone = TIMEZONE_OFF;
+
+        s->bundle = strdup(bundle);
+        if (!s->bundle)
+                return log_oom();
+
+        r = json_dispatch(oci, table, oci_unexpected, 0, s);
+        if (r < 0)
+                return r;
+
+        if (s->properties) {
+                r = sd_bus_message_seal(s->properties, 0, 0);
+                if (r < 0)
+                        return log_error_errno(r, "Cannot seal properties bus message: %m");
+        }
+
+        *ret = TAKE_PTR(s);
+        return 0;
+}
diff --git a/src/nspawn/nspawn-oci.h b/src/nspawn/nspawn-oci.h
new file mode 100644 (file)
index 0000000..d23a2f3
--- /dev/null
@@ -0,0 +1,6 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "nspawn-settings.h"
+
+int oci_load(FILE *f, const char *path, Settings **ret);
index db2f546..c2b779c 100644 (file)
@@ -402,7 +402,7 @@ read_only:
 
                 /* When we hit a ready-only subtree we simply skip it, but log about it. */
                 (void) fd_get_path(fd, &name);
-                log_debug("Skippping read-only file or directory %s.", strna(name));
+                log_debug("Skipping read-only file or directory %s.", strna(name));
                 r = changed;
         }
 
index a7cdfc1..8e2c329 100644 (file)
@@ -5,6 +5,7 @@
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "nspawn-register.h"
 #include "special.h"
 #include "stat-util.h"
@@ -111,6 +112,7 @@ int register_machine(
                 unsigned n_mounts,
                 int kill_signal,
                 char **properties,
+                sd_bus_message *properties_message,
                 bool keep_unit,
                 const char *service) {
 
@@ -184,6 +186,12 @@ int register_machine(
                 if (r < 0)
                         return r;
 
+                if (properties_message) {
+                        r = sd_bus_message_copy(m, properties_message, true);
+                        if (r < 0)
+                                return bus_log_create_error(r);
+                }
+
                 r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties);
                 if (r < 0)
                         return r;
@@ -234,7 +242,8 @@ int allocate_scope(
                 CustomMount *mounts,
                 unsigned n_mounts,
                 int kill_signal,
-                char **properties) {
+                char **properties,
+                sd_bus_message *properties_message) {
 
         _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;
@@ -288,6 +297,12 @@ int allocate_scope(
         if (r < 0)
                 return r;
 
+        if (properties_message) {
+                r = sd_bus_message_copy(m, properties_message, true);
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
         r = append_machine_properties(
                         m,
                         mounts,
index 05f5776..65a3ae8 100644 (file)
@@ -7,8 +7,8 @@
 
 #include "nspawn-mount.h"
 
-int register_machine(sd_bus *bus, const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, bool keep_unit, const char *service);
+int register_machine(sd_bus *bus, const char *machine_name, pid_t pid, const char *directory, sd_id128_t uuid, int local_ifindex, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, sd_bus_message *properties_message, bool keep_unit, const char *service);
 int terminate_machine(sd_bus *bus, const char *machine_name);
 
-int allocate_scope(sd_bus *bus, const char *machine_name, pid_t pid, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties);
+int allocate_scope(sd_bus *bus, const char *machine_name, pid_t pid, const char *slice, CustomMount *mounts, unsigned n_mounts, int kill_signal, char **properties, sd_bus_message *properties_message);
 int terminate_scope(sd_bus *bus, const char *machine_name);
index e7ef80f..9b5eb01 100644 (file)
@@ -3,6 +3,7 @@
 #include <errno.h>
 #include <linux/netlink.h>
 #include <sys/capability.h>
+#include <sys/socket.h>
 #include <sys/types.h>
 
 #if HAVE_SECCOMP
index 505e8ca..476cb07 100644 (file)
 #include "user-util.h"
 #include "util.h"
 
+Settings *settings_new(void) {
+        Settings *s;
+
+        s = new(Settings, 1);
+        if (!s)
+                return NULL;
+
+        *s = (Settings) {
+                .start_mode = _START_MODE_INVALID,
+                .personality = PERSONALITY_INVALID,
+
+                .resolv_conf = _RESOLV_CONF_MODE_INVALID,
+                .link_journal = _LINK_JOURNAL_INVALID,
+                .timezone = _TIMEZONE_MODE_INVALID,
+
+                .userns_mode = _USER_NAMESPACE_MODE_INVALID,
+                .userns_chown = -1,
+                .uid_shift = UID_INVALID,
+                .uid_range = UID_INVALID,
+
+                .no_new_privileges = -1,
+
+                .read_only = -1,
+                .volatile_mode = _VOLATILE_MODE_INVALID,
+
+                .private_network = -1,
+                .network_veth = -1,
+
+                .full_capabilities = CAPABILITY_QUINTET_NULL,
+
+                .uid = UID_INVALID,
+                .gid = GID_INVALID,
+
+                .console_mode = _CONSOLE_MODE_INVALID,
+                .console_width = (unsigned) -1,
+                .console_height = (unsigned) -1,
+
+                .clone_ns_flags = (unsigned long) -1,
+                .use_cgns = -1,
+        };
+
+        return s;
+}
+
 int settings_load(FILE *f, const char *path, Settings **ret) {
         _cleanup_(settings_freep) Settings *s = NULL;
         int r;
@@ -24,27 +68,10 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
         assert(path);
         assert(ret);
 
-        s = new0(Settings, 1);
+        s = settings_new();
         if (!s)
                 return -ENOMEM;
 
-        s->start_mode = _START_MODE_INVALID;
-        s->personality = PERSONALITY_INVALID;
-        s->userns_mode = _USER_NAMESPACE_MODE_INVALID;
-        s->resolv_conf = _RESOLV_CONF_MODE_INVALID;
-        s->link_journal = _LINK_JOURNAL_INVALID;
-        s->timezone = _TIMEZONE_MODE_INVALID;
-        s->uid_shift = UID_INVALID;
-        s->uid_range = UID_INVALID;
-        s->no_new_privileges = -1;
-
-        s->read_only = -1;
-        s->volatile_mode = _VOLATILE_MODE_INVALID;
-        s->userns_chown = -1;
-
-        s->private_network = -1;
-        s->network_veth = -1;
-
         r = config_parse(NULL, path, f,
                          "Exec\0"
                          "Network\0"
@@ -66,12 +93,33 @@ int settings_load(FILE *f, const char *path, Settings **ret) {
                 s->userns_mode = USER_NAMESPACE_NO;
 
         *ret = TAKE_PTR(s);
-
         return 0;
 }
 
-Settings* settings_free(Settings *s) {
+static void free_oci_hooks(OciHook *h, size_t n) {
+        size_t i;
+
+        assert(h || n == 0);
+
+        for (i = 0; i < n; i++) {
+                free(h[i].path);
+                strv_free(h[i].args);
+                strv_free(h[i].env);
+        }
+
+        free(h);
+}
+
+void device_node_array_free(DeviceNode *node, size_t n) {
+        size_t i;
+
+        for (i = 0; i < n; i++)
+                free(node[i].path);
+
+        free(node);
+}
 
+Settings* settings_free(Settings *s) {
         if (!s)
                 return NULL;
 
@@ -96,6 +144,27 @@ Settings* settings_free(Settings *s) {
         expose_port_free_all(s->expose_ports);
 
         custom_mount_free_all(s->custom_mounts, s->n_custom_mounts);
+
+        free(s->bundle);
+        free(s->root);
+
+        free_oci_hooks(s->oci_hooks_prestart, s->n_oci_hooks_prestart);
+        free_oci_hooks(s->oci_hooks_poststart, s->n_oci_hooks_poststart);
+        free_oci_hooks(s->oci_hooks_poststop, s->n_oci_hooks_poststop);
+
+        free(s->slice);
+        sd_bus_message_unref(s->properties);
+
+        free(s->supplementary_gids);
+        device_node_array_free(s->extra_nodes, s->n_extra_nodes);
+        free(s->network_namespace_path);
+
+        strv_free(s->sysctl);
+
+#if HAVE_SECCOMP
+        seccomp_release(s->seccomp);
+#endif
+
         return mfree(s);
 }
 
@@ -122,6 +191,26 @@ bool settings_network_veth(Settings *s) {
                 s->network_zone;
 }
 
+int settings_allocate_properties(Settings *s) {
+        _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+        int r;
+
+        assert(s);
+
+        if (s->properties)
+                return 0;
+
+        r = sd_bus_default_system(&bus);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_new(bus, &s->properties, SD_BUS_MESSAGE_METHOD_CALL);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 DEFINE_CONFIG_PARSE_ENUM(config_parse_volatile_mode, volatile_mode, VolatileMode, "Failed to parse volatile mode");
 
 int config_parse_expose_port(
@@ -315,6 +404,34 @@ int config_parse_tmpfs(
         return 0;
 }
 
+int config_parse_inaccessible(
+                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 = inaccessible_mount_parse(&settings->custom_mounts, &settings->n_custom_mounts, rvalue);
+        if (r < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, r, "Invalid inaccessible file system specification %s: %m", rvalue);
+                return 0;
+        }
+
+        return 0;
+}
+
 int config_parse_overlay(
                 const char *unit,
                 const char *filename,
index a63aa32..64910c3 100644 (file)
@@ -4,13 +4,20 @@
 #include <sched.h>
 #include <stdio.h>
 
+#if HAVE_SECCOMP
+#include <seccomp.h>
+#endif
+
+#include "sd-bus.h"
 #include "sd-id128.h"
 
+#include "capability-util.h"
 #include "conf-parser.h"
 #include "macro.h"
 #include "missing_resource.h"
 #include "nspawn-expose-ports.h"
 #include "nspawn-mount.h"
+#include "time-util.h"
 
 typedef enum StartMode {
         START_PID1, /* Run parameters as command line as process 1 */
@@ -60,6 +67,15 @@ typedef enum TimezoneMode {
         _TIMEZONE_MODE_INVALID = -1
 } TimezoneMode;
 
+typedef enum ConsoleMode {
+        CONSOLE_INTERACTIVE,
+        CONSOLE_READ_ONLY,
+        CONSOLE_PASSIVE,
+        CONSOLE_PIPE,
+        _CONSOLE_MODE_MAX,
+        _CONSOLE_MODE_INVALID = -1,
+} ConsoleMode;
+
 typedef enum SettingsMask {
         SETTING_START_MODE        = UINT64_C(1) << 0,
         SETTING_ENVIRONMENT       = UINT64_C(1) << 1,
@@ -86,9 +102,14 @@ typedef enum SettingsMask {
         SETTING_LINK_JOURNAL      = UINT64_C(1) << 22,
         SETTING_TIMEZONE          = UINT64_C(1) << 23,
         SETTING_EPHEMERAL         = UINT64_C(1) << 24,
-        SETTING_RLIMIT_FIRST      = UINT64_C(1) << 25, /* we define one bit per resource limit here */
-        SETTING_RLIMIT_LAST       = UINT64_C(1) << (25 + _RLIMIT_MAX - 1),
-        _SETTINGS_MASK_ALL        = (UINT64_C(1) << (25 + _RLIMIT_MAX)) -1,
+        SETTING_SLICE             = UINT64_C(1) << 25,
+        SETTING_DIRECTORY         = UINT64_C(1) << 26,
+        SETTING_USE_CGNS          = UINT64_C(1) << 27,
+        SETTING_CLONE_NS_FLAGS    = UINT64_C(1) << 28,
+        SETTING_CONSOLE_MODE      = UINT64_C(1) << 29,
+        SETTING_RLIMIT_FIRST      = UINT64_C(1) << 30, /* we define one bit per resource limit here */
+        SETTING_RLIMIT_LAST       = UINT64_C(1) << (30 + _RLIMIT_MAX - 1),
+        _SETTINGS_MASK_ALL        = (UINT64_C(1) << (30 + _RLIMIT_MAX)) -1,
         _SETTING_FORCE_ENUM_WIDTH = UINT64_MAX
 } SettingsMask;
 
@@ -101,6 +122,22 @@ assert_cc(sizeof(SettingsMask) == 8);
 assert_cc(sizeof(SETTING_RLIMIT_FIRST) == 8);
 assert_cc(sizeof(SETTING_RLIMIT_LAST) == 8);
 
+typedef struct DeviceNode {
+        char *path;
+        unsigned major;
+        unsigned minor;
+        mode_t mode;
+        uid_t uid;
+        gid_t gid;
+} DeviceNode;
+
+typedef struct OciHook {
+        char *path;
+        char **args;
+        char **env;
+        usec_t timeout;
+} OciHook;
+
 typedef struct Settings {
         /* [Run] */
         StartMode start_mode;
@@ -150,13 +187,39 @@ typedef struct Settings {
         char **network_ipvlan;
         char **network_veth_extra;
         ExposePort *expose_ports;
+
+        /* Additional fields, that are specific to OCI runtime case */
+        char *bundle;
+        char *root;
+        OciHook *oci_hooks_prestart, *oci_hooks_poststart, *oci_hooks_poststop;
+        size_t n_oci_hooks_prestart, n_oci_hooks_poststart, n_oci_hooks_poststop;
+        char *slice;
+        sd_bus_message *properties;
+        CapabilityQuintet full_capabilities;
+        uid_t uid;
+        gid_t gid;
+        gid_t *supplementary_gids;
+        size_t n_supplementary_gids;
+        unsigned console_width, console_height;
+        ConsoleMode console_mode;
+        DeviceNode *extra_nodes;
+        size_t n_extra_nodes;
+        unsigned long clone_ns_flags;
+        char *network_namespace_path;
+        int use_cgns;
+        char **sysctl;
+#if HAVE_SECCOMP
+        scmp_filter_ctx seccomp;
+#endif
 } Settings;
 
+Settings *settings_new(void);
 int settings_load(FILE *f, const char *path, Settings **ret);
 Settings* settings_free(Settings *s);
 
 bool settings_network_veth(Settings *s);
 bool settings_private_network(Settings *s);
+int settings_allocate_properties(Settings *s);
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(Settings*, settings_free);
 
@@ -170,6 +233,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_pivot_root);
 CONFIG_PARSER_PROTOTYPE(config_parse_bind);
 CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs);
 CONFIG_PARSER_PROTOTYPE(config_parse_overlay);
+CONFIG_PARSER_PROTOTYPE(config_parse_inaccessible);
 CONFIG_PARSER_PROTOTYPE(config_parse_veth_extra);
 CONFIG_PARSER_PROTOTYPE(config_parse_network_zone);
 CONFIG_PARSER_PROTOTYPE(config_parse_boot);
@@ -190,3 +254,5 @@ const char *timezone_mode_to_string(TimezoneMode a) _const_;
 TimezoneMode timezone_mode_from_string(const char *s) _pure_;
 
 int parse_link_journal(const char *s, LinkJournal *ret_mode, bool *ret_try);
+
+void device_node_array_free(DeviceNode *node, size_t n);
index 0026e4e..3c302d6 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
 #include <grp.h>
 #include <sys/types.h>
 #include <unistd.h>
@@ -43,7 +44,7 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
                 if (rearrange_stdio(-1, pipe_fds[1], -1) < 0)
                         _exit(EXIT_FAILURE);
 
-                close_all_fds(NULL, 0);
+                (void) close_all_fds(NULL, 0);
 
                 (void) rlimit_nofile_safe();
 
@@ -59,14 +60,41 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
         return pipe_fds[0];
 }
 
+int change_uid_gid_raw(
+                uid_t uid,
+                gid_t gid,
+                const gid_t *supplementary_gids,
+                size_t n_supplementary_gids) {
+
+        if (!uid_is_valid(uid))
+                uid = 0;
+        if (!gid_is_valid(gid))
+                gid = 0;
+
+        (void) fchown(STDIN_FILENO, uid, gid);
+        (void) fchown(STDOUT_FILENO, uid, gid);
+        (void) fchown(STDERR_FILENO, uid, gid);
+
+        if (setgroups(n_supplementary_gids, supplementary_gids) < 0)
+                return log_error_errno(errno, "Failed to set auxiliary groups: %m");
+
+        if (setresgid(gid, gid, gid) < 0)
+                return log_error_errno(errno, "setresgid() failed: %m");
+
+        if (setresuid(uid, uid, uid) < 0)
+                return log_error_errno(errno, "setresuid() failed: %m");
+
+        return 0;
+}
+
 int change_uid_gid(const char *user, char **_home) {
         char *x, *u, *g, *h;
         const char *word, *state;
-        _cleanup_free_ uid_t *uids = NULL;
+        _cleanup_free_ gid_t *gids = NULL;
         _cleanup_free_ char *home = NULL, *line = NULL;
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_close_ int fd = -1;
-        unsigned n_uids = 0;
+        unsigned n_gids = 0;
         size_t sz = 0, l;
         uid_t uid;
         gid_t gid;
@@ -189,10 +217,10 @@ int change_uid_gid(const char *user, char **_home) {
                 memcpy(c, word, l);
                 c[l] = 0;
 
-                if (!GREEDY_REALLOC(uids, sz, n_uids+1))
+                if (!GREEDY_REALLOC(gids, sz, n_gids+1))
                         return log_oom();
 
-                r = parse_uid(c, &uids[n_uids++]);
+                r = parse_gid(c, &gids[n_gids++]);
                 if (r < 0)
                         return log_error_errno(r, "Failed to parse group data from getent: %m");
         }
@@ -205,18 +233,9 @@ int change_uid_gid(const char *user, char **_home) {
         if (r < 0 && !IN_SET(r, -EEXIST, -ENOTDIR))
                 return log_error_errno(r, "Failed to make home directory: %m");
 
-        (void) fchown(STDIN_FILENO, uid, gid);
-        (void) fchown(STDOUT_FILENO, uid, gid);
-        (void) fchown(STDERR_FILENO, uid, gid);
-
-        if (setgroups(n_uids, uids) < 0)
-                return log_error_errno(errno, "Failed to set auxiliary groups: %m");
-
-        if (setresgid(gid, gid, gid) < 0)
-                return log_error_errno(errno, "setresgid() failed: %m");
-
-        if (setresuid(uid, uid, uid) < 0)
-                return log_error_errno(errno, "setresuid() failed: %m");
+        r = change_uid_gid_raw(uid, gid, gids, n_gids);
+        if (r < 0)
+                return r;
 
         if (_home)
                 *_home = TAKE_PTR(home);
index 0ae47cb..9a2b05e 100644 (file)
@@ -1,4 +1,5 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-int change_uid_gid(const char *user, char **ret);
+int change_uid_gid_raw(uid_t uid, gid_t gid, const gid_t *supplementary_gids, size_t n_supplementary_gids);
+int change_uid_gid(const char *user, char **ret_home);
index 5d17df3..ebf4f0f 100644 (file)
@@ -67,7 +67,7 @@ int stub_pid1(sd_id128_t uuid) {
         reset_all_signal_handlers();
 
         log_close();
-        close_all_fds(NULL, 0);
+        (void) close_all_fds(NULL, 0);
         log_open();
 
         /* Flush out /proc/self/environ, so that we don't leak the environment from the host into the container. Also,
index e0c2d71..3b0ecb1 100644 (file)
 #include "loopback-setup.h"
 #include "machine-image.h"
 #include "macro.h"
+#include "main-func.h"
 #include "missing.h"
 #include "mkdir.h"
 #include "mount-util.h"
 #include "mountpoint-util.h"
+#include "namespace-util.h"
 #include "netlink-util.h"
 #include "nspawn-cgroup.h"
 #include "nspawn-def.h"
 #include "nspawn-expose-ports.h"
 #include "nspawn-mount.h"
 #include "nspawn-network.h"
+#include "nspawn-oci.h"
 #include "nspawn-patch-uid.h"
 #include "nspawn-register.h"
 #include "nspawn-seccomp.h"
 #include "nspawn-settings.h"
 #include "nspawn-setuid.h"
 #include "nspawn-stub-pid1.h"
+#include "nulstr-util.h"
 #include "os-util.h"
 #include "pager.h"
 #include "parse-util.h"
@@ -84,6 +88,9 @@
 #include "raw-clone.h"
 #include "rlimit-util.h"
 #include "rm-rf.h"
+#if HAVE_SECCOMP
+#include "seccomp-util.h"
+#endif
 #include "selinux-util.h"
 #include "signal-util.h"
 #include "socket-util.h"
@@ -92,6 +99,7 @@
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
+#include "sysctl-util.h"
 #include "terminal-util.h"
 #include "tmpfile-util.h"
 #include "umask-util.h"
 
 typedef enum ContainerStatus {
         CONTAINER_TERMINATED,
-        CONTAINER_REBOOTED
+        CONTAINER_REBOOTED,
 } ContainerStatus;
 
 static char *arg_directory = NULL;
@@ -122,12 +130,16 @@ static char *arg_chdir = NULL;
 static char *arg_pivot_root_new = NULL;
 static char *arg_pivot_root_old = NULL;
 static char *arg_user = NULL;
+static uid_t arg_uid = UID_INVALID;
+static gid_t arg_gid = GID_INVALID;
+static gid_t* arg_supplementary_gids = NULL;
+static size_t arg_n_supplementary_gids = 0;
 static sd_id128_t arg_uuid = {};
 static char *arg_machine = NULL;     /* The name used by the host to refer to this */
 static char *arg_hostname = NULL;    /* The name the payload sees by default */
 static const char *arg_selinux_context = NULL;
 static const char *arg_selinux_apifs_context = NULL;
-static const char *arg_slice = NULL;
+static char *arg_slice = NULL;
 static bool arg_private_network = false;
 static bool arg_read_only = false;
 static StartMode arg_start_mode = START_PID1;
@@ -161,6 +173,7 @@ static uint64_t arg_caps_retain =
         (1ULL << CAP_SYS_PTRACE) |
         (1ULL << CAP_SYS_RESOURCE) |
         (1ULL << CAP_SYS_TTY_CONFIG);
+static CapabilityQuintet arg_full_capabilities = CAPABILITY_QUINTET_NULL;
 static CustomMount *arg_custom_mounts = NULL;
 static size_t arg_n_custom_mounts = 0;
 static char **arg_setenv = NULL;
@@ -175,11 +188,14 @@ static char **arg_network_veth_extra = NULL;
 static char *arg_network_bridge = NULL;
 static char *arg_network_zone = NULL;
 static char *arg_network_namespace_path = NULL;
+static PagerFlags arg_pager_flags = 0;
 static unsigned long arg_personality = PERSONALITY_INVALID;
 static char *arg_image = NULL;
+static char *arg_oci_bundle = NULL;
 static VolatileMode arg_volatile_mode = VOLATILE_NO;
 static ExposePort *arg_expose_ports = NULL;
 static char **arg_property = NULL;
+static sd_bus_message *arg_property_message = NULL;
 static UserNamespaceMode arg_userns_mode = USER_NAMESPACE_NO;
 static uid_t arg_uid_shift = UID_INVALID, arg_uid_range = 0x10000U;
 static bool arg_userns_chown = false;
@@ -197,6 +213,9 @@ static void *arg_root_hash = NULL;
 static size_t arg_root_hash_size = 0;
 static char **arg_syscall_whitelist = NULL;
 static char **arg_syscall_blacklist = NULL;
+#if HAVE_SECCOMP
+static scmp_filter_ctx arg_seccomp = NULL;
+#endif
 static struct rlimit *arg_rlimit[_RLIMIT_MAX] = {};
 static bool arg_no_new_privileges = false;
 static int arg_oom_score_adjust = 0;
@@ -205,44 +224,99 @@ static cpu_set_t *arg_cpuset = NULL;
 static unsigned arg_cpuset_ncpus = 0;
 static ResolvConfMode arg_resolv_conf = RESOLV_CONF_AUTO;
 static TimezoneMode arg_timezone = TIMEZONE_AUTO;
+static unsigned arg_console_width = (unsigned) -1, arg_console_height = (unsigned) -1;
+static DeviceNode* arg_extra_nodes = NULL;
+static size_t arg_n_extra_nodes = 0;
+static char **arg_sysctl = NULL;
+static ConsoleMode arg_console_mode = _CONSOLE_MODE_INVALID;
+
+STATIC_DESTRUCTOR_REGISTER(arg_directory, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_template, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_chdir, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_pivot_root_new, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_pivot_root_old, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_user, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_supplementary_gids, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_machine, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_hostname, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_slice, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_setenv, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_network_interfaces, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_network_macvlan, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_network_ipvlan, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_network_veth_extra, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_network_bridge, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_network_zone, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_network_namespace_path, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_oci_bundle, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_property, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_property_message, sd_bus_message_unrefp);
+STATIC_DESTRUCTOR_REGISTER(arg_parameters, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_syscall_whitelist, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_syscall_blacklist, strv_freep);
+#if HAVE_SECCOMP
+STATIC_DESTRUCTOR_REGISTER(arg_seccomp, seccomp_releasep);
+#endif
+STATIC_DESTRUCTOR_REGISTER(arg_cpuset, CPU_FREEp);
+STATIC_DESTRUCTOR_REGISTER(arg_sysctl, strv_freep);
 
 static int help(void) {
         _cleanup_free_ char *link = NULL;
         int r;
 
-        (void) pager_open(false);
+        (void) pager_open(arg_pager_flags);
 
         r = terminal_urlify_man("systemd-nspawn", "1", &link);
         if (r < 0)
                 return log_oom();
 
-        printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
+        printf("%1$s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
                "Spawn a command or OS in a light-weight container.\n\n"
                "  -h --help                 Show this help\n"
                "     --version              Print version string\n"
                "  -q --quiet                Do not show status information\n"
+               "     --no-pager             Do not pipe output into a pager\n"
+               "     --settings=BOOLEAN     Load additional settings from .nspawn file\n\n"
+               "%3$sImage:%4$s\n"
                "  -D --directory=PATH       Root directory for the container\n"
                "     --template=PATH        Initialize root directory from template directory,\n"
                "                            if missing\n"
                "  -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"
-               "     --root-hash=HASH       Specify verity root hash\n"
+               "  -i --image=PATH           Root file system disk image (or device node) for\n"
+               "                            the container\n"
+               "     --oci-bundle=PATH      OCI bundle directory\n"
+               "     --read-only            Mount the root directory read-only\n"
+               "     --volatile[=MODE]      Run the system in volatile mode\n"
+               "     --root-hash=HASH       Specify verity root hash for root disk image\n"
+               "     --pivot-root=PATH[:PATH]\n"
+               "                            Pivot root to given directory in the container\n\n"
+               "%3$sExecution:%4$s\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"
-               "     --pivot-root=PATH[:PATH]\n"
-               "                            Pivot root to given directory in the container\n"
-               "  -u --user=USER            Run the command under specified user or uid\n"
+               "  -E --setenv=NAME=VALUE    Pass an environment variable to PID 1\n"
+               "  -u --user=USER            Run the command under specified user or UID\n"
+               "     --kill-signal=SIGNAL   Select signal to use for shutting down PID 1\n"
+               "     --notify-ready=BOOLEAN Receive notifications from the child init process\n\n"
+               "%3$sSystem Identity:%4$s\n"
                "  -M --machine=NAME         Set the machine name for the container\n"
                "     --hostname=NAME        Override the hostname for the container\n"
-               "     --uuid=UUID            Set a specific machine UUID for the container\n"
+               "     --uuid=UUID            Set a specific machine UUID for the container\n\n"
+               "%3$sProperties:%4$s\n"
                "  -S --slice=SLICE          Place the container in the specified slice\n"
                "     --property=NAME=VALUE  Set scope unit property\n"
+               "     --register=BOOLEAN     Register container as machine\n"
+               "     --keep-unit            Do not register a scope for the machine, reuse\n"
+               "                            the service unit nspawn is running in\n\n"
+               "%3$sUser Namespacing:%4$s\n"
                "  -U --private-users=pick   Run within user namespace, autoselect UID/GID range\n"
                "     --private-users[=UIDBASE[:NUIDS]]\n"
                "                            Similar, but with user configured UID/GID range\n"
-               "     --private-users-chown  Adjust OS tree ownership to private UID/GID range\n"
+               "     --private-users-chown  Adjust OS tree ownership to private UID/GID range\n\n"
+               "%3$sNetworking:%4$s\n"
                "     --private-network      Disable network in container\n"
                "     --network-interface=INTERFACE\n"
                "                            Assign an existing network interface to the\n"
@@ -267,51 +341,54 @@ static int help(void) {
                "                            Set network namespace to the one represented by\n"
                "                            the specified kernel namespace file node\n"
                "  -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n"
-               "                            Expose a container IP port on the host\n"
-               "  -Z --selinux-context=SECLABEL\n"
-               "                            Set the SELinux security context to be used by\n"
-               "                            processes in the container\n"
-               "  -L --selinux-apifs-context=SECLABEL\n"
-               "                            Set the SELinux security context to be used by\n"
-               "                            API/tmpfs file systems in the container\n"
+               "                            Expose a container IP port on the host\n\n"
+               "%3$sSecurity:%4$s\n"
                "     --capability=CAP       In addition to the default, retain specified\n"
                "                            capability\n"
                "     --drop-capability=CAP  Drop the specified capability from the default set\n"
+               "     --no-new-privileges    Set PR_SET_NO_NEW_PRIVS flag for container payload\n"
                "     --system-call-filter=LIST|~LIST\n"
                "                            Permit/prohibit specific system calls\n"
+               "  -Z --selinux-context=SECLABEL\n"
+               "                            Set the SELinux security context to be used by\n"
+               "                            processes in the container\n"
+               "  -L --selinux-apifs-context=SECLABEL\n"
+               "                            Set the SELinux security context to be used by\n"
+               "                            API/tmpfs file systems in the container\n\n"
+               "%3$sResources:%4$s\n"
                "     --rlimit=NAME=LIMIT    Set a resource limit for the payload\n"
                "     --oom-score-adjust=VALUE\n"
                "                            Adjust the OOM score value for the payload\n"
                "     --cpu-affinity=CPUS    Adjust the CPU affinity of the container\n"
-               "     --kill-signal=SIGNAL   Select signal to use for shutting down PID 1\n"
-               "     --link-journal=MODE    Link up guest journal, one of no, auto, guest, \n"
-               "                            host, try-guest, try-host\n"
-               "  -j                        Equivalent to --link-journal=try-guest\n"
+               "     --personality=ARCH     Pick personality for this container\n\n"
+               "%3$sIntegration:%4$s\n"
                "     --resolv-conf=MODE     Select mode of /etc/resolv.conf initialization\n"
                "     --timezone=MODE        Select mode of /etc/localtime initialization\n"
-               "     --read-only            Mount the root directory read-only\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\n"
+               "%3$sMounts:%4$s\n"
                "     --bind=PATH[:PATH[:OPTIONS]]\n"
                "                            Bind mount a file or directory from the host into\n"
                "                            the container\n"
                "     --bind-ro=PATH[:PATH[:OPTIONS]\n"
                "                            Similar, but creates a read-only bind mount\n"
+               "     --inaccessible=PATH    Over-mount file node with inaccessible node to mask\n"
+               "                            it\n"
                "     --tmpfs=PATH:[OPTIONS] Mount an empty tmpfs to the specified directory\n"
                "     --overlay=PATH[:PATH...]:PATH\n"
                "                            Create an overlay mount from the host to \n"
                "                            the container\n"
                "     --overlay-ro=PATH[:PATH...]:PATH\n"
-               "                            Similar, but creates a read-only overlay mount\n"
-               "  -E --setenv=NAME=VALUE    Pass an environment variable to PID 1\n"
-               "     --register=BOOLEAN     Register container as machine\n"
-               "     --keep-unit            Do not register a scope for the machine, reuse\n"
-               "                            the service unit nspawn is running in\n"
-               "     --volatile[=MODE]      Run the system in volatile mode\n"
-               "     --settings=BOOLEAN     Load additional settings from .nspawn file\n"
-               "     --notify-ready=BOOLEAN Receive notifications from the child init process\n"
-               "\nSee the %s for details.\n"
+               "                            Similar, but creates a read-only overlay mount\n\n"
+               "%3$sInput/Output:%4$s\n"
+               "     --console=MODE         Select how stdin/stdout/stderr and /dev/console are\n"
+               "                            set up for the container.\n"
+               "  -P --pipe                 Equivalent to --console=pipe\n"
+               "\nSee the %2$s for details.\n"
                , program_invocation_short_name
                , link
-        );
+               , ansi_underline(), ansi_normal());
 
         return 0;
 }
@@ -399,7 +476,9 @@ static void parse_share_ns_env(const char *name, unsigned long ns_flag) {
                 return;
         if (r < 0)
                 log_warning_errno(r, "Failed to parse %s from environment, defaulting to false.", name);
+
         arg_clone_ns_flags = (arg_clone_ns_flags & ~ns_flag) | (r > 0 ? 0 : ns_flag);
+        arg_settings_mask |= SETTING_CLONE_NS_FLAGS;
 }
 
 static void parse_mount_settings_env(void) {
@@ -444,9 +523,20 @@ static void parse_environment(void) {
 
         /* SYSTEMD_NSPAWN_USE_CGNS=0 can be used to disable CLONE_NEWCGROUP use,
          * even if it is supported. If not supported, it has no effect. */
-        r = getenv_bool("SYSTEMD_NSPAWN_USE_CGNS");
-        if (r == 0 || !cg_ns_supported())
+        if (!cg_ns_supported())
                 arg_use_cgns = false;
+        else {
+                r = getenv_bool("SYSTEMD_NSPAWN_USE_CGNS");
+                if (r < 0) {
+                        if (r != -ENXIO)
+                                log_warning_errno(r, "Failed to parse $SYSTEMD_NSPAWN_USE_CGNS, ignoring: %m");
+
+                        arg_use_cgns = true;
+                } else {
+                        arg_use_cgns = r > 0;
+                        arg_settings_mask |= SETTING_USE_CGNS;
+                }
+        }
 
         e = getenv("SYSTEMD_NSPAWN_CONTAINER_SERVICE");
         if (e)
@@ -469,6 +559,7 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_TMPFS,
                 ARG_OVERLAY,
                 ARG_OVERLAY_RO,
+                ARG_INACCESSIBLE,
                 ARG_SHARE_SYSTEM,
                 ARG_REGISTER,
                 ARG_KEEP_UNIT,
@@ -499,6 +590,10 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_CPU_AFFINITY,
                 ARG_RESOLV_CONF,
                 ARG_TIMEZONE,
+                ARG_CONSOLE,
+                ARG_PIPE,
+                ARG_OCI_BUNDLE,
+                ARG_NO_PAGER,
         };
 
         static const struct option options[] = {
@@ -522,6 +617,7 @@ static int parse_argv(int argc, char *argv[]) {
                 { "tmpfs",                  required_argument, NULL, ARG_TMPFS                  },
                 { "overlay",                required_argument, NULL, ARG_OVERLAY                },
                 { "overlay-ro",             required_argument, NULL, ARG_OVERLAY_RO             },
+                { "inaccessible",           required_argument, NULL, ARG_INACCESSIBLE           },
                 { "machine",                required_argument, NULL, 'M'                        },
                 { "hostname",               required_argument, NULL, ARG_HOSTNAME               },
                 { "slice",                  required_argument, NULL, 'S'                        },
@@ -559,6 +655,10 @@ static int parse_argv(int argc, char *argv[]) {
                 { "cpu-affinity",           required_argument, NULL, ARG_CPU_AFFINITY           },
                 { "resolv-conf",            required_argument, NULL, ARG_RESOLV_CONF            },
                 { "timezone",               required_argument, NULL, ARG_TIMEZONE               },
+                { "console",                required_argument, NULL, ARG_CONSOLE                },
+                { "pipe",                   no_argument,       NULL, ARG_PIPE                   },
+                { "oci-bundle",             required_argument, NULL, ARG_OCI_BUNDLE             },
+                { "no-pager",               no_argument,       NULL, ARG_NO_PAGER               },
                 {}
         };
 
@@ -570,7 +670,7 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nUE:", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "+hD:u:abL:M:jS:Z:qi:xp:nUE:P", options, NULL)) >= 0)
                 switch (c) {
 
                 case 'h':
@@ -583,18 +683,31 @@ static int parse_argv(int argc, char *argv[]) {
                         r = parse_path_argument_and_warn(optarg, false, &arg_directory);
                         if (r < 0)
                                 return r;
+
+                        arg_settings_mask |= SETTING_DIRECTORY;
                         break;
 
                 case ARG_TEMPLATE:
                         r = parse_path_argument_and_warn(optarg, false, &arg_template);
                         if (r < 0)
                                 return r;
+
+                        arg_settings_mask |= SETTING_DIRECTORY;
                         break;
 
                 case 'i':
                         r = parse_path_argument_and_warn(optarg, false, &arg_image);
                         if (r < 0)
                                 return r;
+
+                        arg_settings_mask |= SETTING_DIRECTORY;
+                        break;
+
+                case ARG_OCI_BUNDLE:
+                        r = parse_path_argument_and_warn(optarg, false, &arg_oci_bundle);
+                        if (r < 0)
+                                return r;
+
                         break;
 
                 case 'x':
@@ -702,6 +815,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return r;
 
+                        arg_settings_mask |= SETTING_NETWORK;
                         break;
 
                 case 'b':
@@ -735,7 +849,11 @@ static int parse_argv(int argc, char *argv[]) {
                         break;
 
                 case 'S':
-                        arg_slice = optarg;
+                        r = free_and_strdup(&arg_slice, optarg);
+                        if (r < 0)
+                                return log_oom();
+
+                        arg_settings_mask |= SETTING_SLICE;
                         break;
 
                 case 'M':
@@ -790,7 +908,6 @@ static int parse_argv(int argc, char *argv[]) {
                                 r = extract_first_word(&p, &t, ",", 0);
                                 if (r < 0)
                                         return log_error_errno(r, "Failed to parse capability %s.", t);
-
                                 if (r == 0)
                                         break;
 
@@ -832,10 +949,8 @@ static int parse_argv(int argc, char *argv[]) {
 
                 case ARG_LINK_JOURNAL:
                         r = parse_link_journal(optarg, &arg_link_journal, &arg_link_journal_try);
-                        if (r < 0) {
-                                log_error_errno(r, "Failed to parse link journal mode %s", optarg);
-                                return -EINVAL;
-                        }
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse link journal mode %s", optarg);
 
                         arg_settings_mask |= SETTING_LINK_JOURNAL;
                         break;
@@ -868,6 +983,14 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_settings_mask |= SETTING_CUSTOM_MOUNTS;
                         break;
 
+                case ARG_INACCESSIBLE:
+                        r = inaccessible_mount_parse(&arg_custom_mounts, &arg_n_custom_mounts, optarg);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse --inaccessible= argument %s: %m", optarg);
+
+                        arg_settings_mask |= SETTING_CUSTOM_MOUNTS;
+                        break;
+
                 case 'E': {
                         char **n;
 
@@ -1118,9 +1241,8 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse root hash: %s", optarg);
                         if (l < sizeof(sd_id128_t)) {
-                                log_error("Root hash must be at least 128bit long: %s", optarg);
                                 free(k);
-                                return -EINVAL;
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Root hash must be at least 128bit long: %s", optarg);
                         }
 
                         free(arg_root_hash);
@@ -1250,6 +1372,36 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_settings_mask |= SETTING_TIMEZONE;
                         break;
 
+                case ARG_CONSOLE:
+                        if (streq(optarg, "interactive"))
+                                arg_console_mode = CONSOLE_INTERACTIVE;
+                        else if (streq(optarg, "read-only"))
+                                arg_console_mode = CONSOLE_READ_ONLY;
+                        else if (streq(optarg, "passive"))
+                                arg_console_mode = CONSOLE_PASSIVE;
+                        else if (streq(optarg, "pipe"))
+                                arg_console_mode = CONSOLE_PIPE;
+                        else if (streq(optarg, "help"))
+                                puts("interactive\n"
+                                     "read-only\n"
+                                     "passive\n"
+                                     "pipe");
+                        else
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown console mode: %s", optarg);
+
+                        arg_settings_mask |= SETTING_CONSOLE_MODE;
+                        break;
+
+                case 'P':
+                case ARG_PIPE:
+                        arg_console_mode = CONSOLE_PIPE;
+                        arg_settings_mask |= SETTING_CONSOLE_MODE;
+                        break;
+
+                case ARG_NO_PAGER:
+                        arg_pager_flags |= PAGER_DISABLE;
+                        break;
+
                 case '?':
                         return -EINVAL;
 
@@ -1273,7 +1425,10 @@ static int parse_argv(int argc, char *argv[]) {
                  * --directory=". */
                 arg_directory = TAKE_PTR(arg_template);
 
-        arg_caps_retain = (arg_caps_retain | plus | (arg_private_network ? 1ULL << CAP_NET_ADMIN : 0)) & ~minus;
+        arg_caps_retain = (arg_caps_retain | plus | (arg_private_network ? UINT64_C(1) << CAP_NET_ADMIN : 0)) & ~minus;
+
+        /* Make sure to parse environment before we reset the settings mask below */
+        parse_environment();
 
         /* Load all settings from .nspawn files */
         if (mask_no_settings)
@@ -1308,6 +1463,9 @@ static int verify_arguments(void) {
         if (arg_start_mode == START_BOOT && arg_kill_signal <= 0)
                 arg_kill_signal = SIGRTMIN+3;
 
+        if (arg_volatile_mode != VOLATILE_NO) /* Make sure all file systems contained in the image are mounted read-only if we are in volatile mode */
+                arg_read_only = true;
+
         if (arg_keep_unit && arg_register && cg_pid_get_owner_uid(0, NULL) >= 0)
                 /* Save the user from accidentally registering either user-$SESSION.scope or user@.service.
                  * The latter is not technically a user session, but we don't need to labour the point. */
@@ -1332,19 +1490,27 @@ static int verify_arguments(void) {
                 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--private-users= is not supported, kernel compiled without user namespace support.");
 
         if (arg_userns_chown && arg_read_only)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--read-only and --private-users-chown may not be combined.");
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--read-only and --private-users-chown may not be combined.");
+
+        /* We don't support --private-users-chown together with any of the volatile modes since we couldn't
+         * change the read-only part of the tree (i.e. /usr) anyway, or because it would trigger a massive
+         * copy-up (in case of overlay) making the entire excercise pointless. */
+        if (arg_userns_chown && arg_volatile_mode != VOLATILE_NO)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--volatile= and --private-users-chown may not be combined.");
 
-        /* If --network-namespace-path is given with any other network-related option,
-         * we need to error out, to avoid conflicts between different network options. */
+        /* If --network-namespace-path is given with any other network-related option, we need to error out,
+         * to avoid conflicts between different network options. */
         if (arg_network_namespace_path &&
                 (arg_network_interfaces || arg_network_macvlan ||
                  arg_network_ipvlan || arg_network_veth_extra ||
                  arg_network_bridge || arg_network_zone ||
                  arg_network_veth || arg_private_network))
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--network-namespace-path cannot be combined with other network options.");
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--network-namespace-path= cannot be combined with other network options.");
 
         if (arg_network_bridge && arg_network_zone)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--network-bridge= and --network-zone= may not be combined.");
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--network-bridge= and --network-zone= may not be combined.");
 
         if (arg_userns_mode != USER_NAMESPACE_NO && (arg_mount_settings & MOUNT_APPLY_APIVFS_NETNS) && !arg_private_network)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid namespacing settings. Mounting sysfs with --private-users requires --private-network.");
@@ -1352,9 +1518,6 @@ static int verify_arguments(void) {
         if (arg_userns_mode != USER_NAMESPACE_NO && !(arg_mount_settings & MOUNT_APPLY_APIVFS_RO))
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot combine --private-users with read-write mounts.");
 
-        if (arg_volatile_mode != VOLATILE_NO && arg_read_only)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot combine --read-only with --volatile. Note that --volatile already implies a read-only base hierarchy.");
-
         if (arg_expose_ports && !arg_private_network)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --port= without private networking.");
 
@@ -1420,6 +1583,10 @@ static const char *timezone_from_path(const char *path) {
                         "/usr/share/zoneinfo/");
 }
 
+static bool etc_writable(void) {
+        return !arg_read_only || IN_SET(arg_volatile_mode, VOLATILE_YES, VOLATILE_OVERLAY);
+}
+
 static int setup_timezone(const char *dest) {
         _cleanup_free_ char *p = NULL, *etc = NULL;
         const char *where, *check;
@@ -1431,9 +1598,9 @@ static int setup_timezone(const char *dest) {
         if (IN_SET(arg_timezone, TIMEZONE_AUTO, TIMEZONE_SYMLINK)) {
                 r = readlink_malloc("/etc/localtime", &p);
                 if (r == -ENOENT && arg_timezone == TIMEZONE_AUTO)
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? TIMEZONE_OFF : TIMEZONE_DELETE;
+                        m = etc_writable() ? TIMEZONE_DELETE : TIMEZONE_OFF;
                 else if (r == -EINVAL && arg_timezone == TIMEZONE_AUTO) /* regular file? */
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? TIMEZONE_BIND : TIMEZONE_COPY;
+                        m = etc_writable() ? TIMEZONE_COPY : TIMEZONE_BIND;
                 else if (r < 0) {
                         log_warning_errno(r, "Failed to read host's /etc/localtime symlink, not updating container timezone: %m");
                         /* To handle warning, delete /etc/localtime and replace it with a symbolic link to a time zone data
@@ -1444,7 +1611,7 @@ static int setup_timezone(const char *dest) {
                          */
                         return 0;
                 } else if (arg_timezone == TIMEZONE_AUTO)
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? TIMEZONE_BIND : TIMEZONE_SYMLINK;
+                        m = etc_writable() ? TIMEZONE_SYMLINK : TIMEZONE_BIND;
                 else
                         m = arg_timezone;
         } else
@@ -1529,7 +1696,7 @@ static int setup_timezone(const char *dest) {
 
         case TIMEZONE_COPY:
                 /* If mounting failed, try to copy */
-                r = copy_file_atomic("/etc/localtime", where, 0644, 0, COPY_REFLINK|COPY_REPLACE);
+                r = copy_file_atomic("/etc/localtime", where, 0644, 0, 0, COPY_REFLINK|COPY_REPLACE);
                 if (r < 0) {
                         log_full_errno(IN_SET(r, -EROFS, -EACCES, -EPERM) ? LOG_DEBUG : LOG_WARNING, r,
                                        "Failed to copy /etc/localtime to %s, ignoring: %m", where);
@@ -1606,11 +1773,11 @@ static int setup_resolv_conf(const char *dest) {
                 if (arg_private_network)
                         m = RESOLV_CONF_OFF;
                 else if (have_resolv_conf(STATIC_RESOLV_CONF) > 0 && resolved_listening() > 0)
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? RESOLV_CONF_BIND_STATIC : RESOLV_CONF_COPY_STATIC;
+                        m = etc_writable() ? RESOLV_CONF_COPY_STATIC : RESOLV_CONF_BIND_STATIC;
                 else if (have_resolv_conf("/etc/resolv.conf") > 0)
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? RESOLV_CONF_BIND_HOST : RESOLV_CONF_COPY_HOST;
+                        m = etc_writable() ? RESOLV_CONF_COPY_HOST : RESOLV_CONF_BIND_HOST;
                 else
-                        m = arg_read_only && arg_volatile_mode != VOLATILE_YES ? RESOLV_CONF_OFF : RESOLV_CONF_DELETE;
+                        m = etc_writable() ? RESOLV_CONF_DELETE : RESOLV_CONF_OFF;
         } else
                 m = arg_resolv_conf;
 
@@ -1656,7 +1823,7 @@ static int setup_resolv_conf(const char *dest) {
         }
 
         /* If that didn't work, let's copy the file */
-        r = copy_file(what, where, O_TRUNC|O_NOFOLLOW, 0644, 0, COPY_REFLINK);
+        r = copy_file(what, where, O_TRUNC|O_NOFOLLOW, 0644, 0, 0, COPY_REFLINK);
         if (r < 0) {
                 /* If the file already exists as symlink, let's suppress the warning, under the assumption that
                  * resolved or something similar runs inside and the symlink points there.
@@ -1682,10 +1849,9 @@ static int setup_boot_id(void) {
         const char *to;
         int r;
 
-        /* Generate a new randomized boot ID, so that each boot-up of
-         * the container gets a new one */
+        /* Generate a new randomized boot ID, so that each boot-up of the container gets a new one */
 
-        r = tempfn_random_child(NULL, "proc-sys-kernel-random-boot-id", &path);
+        r = tempfn_random_child("/run", "proc-sys-kernel-random-boot-id", &path);
         if (r < 0)
                 return log_error_errno(r, "Failed to generate random boot ID path: %m");
 
@@ -1717,9 +1883,9 @@ static int copy_devnodes(const char *dest) {
                 "tty\0"
                 "net/tun\0";
 
+        _cleanup_umask_ mode_t u;
         const char *d;
         int r = 0;
-        _cleanup_umask_ mode_t u;
 
         assert(dest);
 
@@ -1799,6 +1965,32 @@ static int copy_devnodes(const char *dest) {
         return r;
 }
 
+static int make_extra_nodes(const char *dest) {
+        _cleanup_umask_ mode_t u;
+        size_t i;
+        int r;
+
+        u = umask(0000);
+
+        for (i = 0; i < arg_n_extra_nodes; i++) {
+                _cleanup_free_ char *path = NULL;
+                DeviceNode *n = arg_extra_nodes + i;
+
+                path = prefix_root(dest, n->path);
+                if (!path)
+                        return log_oom();
+
+                if (mknod(path, n->mode, S_ISCHR(n->mode) || S_ISBLK(n->mode) ? makedev(n->major, n->minor) : 0) < 0)
+                        return log_error_errno(errno, "Failed to create device node '%s': %m", path);
+
+                r = chmod_and_chown(path, n->mode, n->uid, n->gid);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to adjust device node ownership of '%s': %m", path);
+        }
+
+        return 0;
+}
+
 static int setup_pts(const char *dest) {
         _cleanup_free_ char *options = NULL;
         const char *p;
@@ -1855,10 +2047,12 @@ static int setup_dev_console(const char *dest, const char *console) {
         int r;
 
         assert(dest);
-        assert(console);
 
         u = umask(0000);
 
+        if (!console)
+                return 0;
+
         r = chmod_and_chown(console, 0600, arg_uid_shift, arg_uid_shift);
         if (r < 0)
                 return log_error_errno(r, "Failed to correct access mode for TTY: %m");
@@ -1901,19 +2095,18 @@ static int setup_kmsg(int kmsg_socket) {
         _cleanup_free_ char *fifo = NULL;
         _cleanup_close_ int fd = -1;
         _cleanup_umask_ mode_t u;
-        const char *to;
         int r;
 
         assert(kmsg_socket >= 0);
 
         u = umask(0000);
 
-        /* We create the kmsg FIFO as as temporary file in /tmp, but immediately delete it after bind mounting it to
+        /* We create the kmsg FIFO as as temporary file in /run, but immediately delete it after bind mounting it to
          * /proc/kmsg. While FIFOs on the reading side behave very similar to /proc/kmsg, their writing side behaves
          * differently from /dev/kmsg in that writing blocks when nothing is reading. In order to avoid any problems
          * with containers deadlocking due to this we simply make /dev/kmsg unavailable to the container. */
 
-        r = tempfn_random_child(NULL, "proc-kmsg", &fifo);
+        r = tempfn_random_child("/run", "proc-kmsg", &fifo);
         if (r < 0)
                 return log_error_errno(r, "Failed to generate kmsg path: %m");
 
@@ -1921,9 +2114,8 @@ static int setup_kmsg(int kmsg_socket) {
                 return log_error_errno(errno, "mkfifo() for /run/kmsg failed: %m");
 
         from = TAKE_PTR(fifo);
-        to = "/proc/kmsg";
 
-        r = mount_verbose(LOG_ERR, from, to, NULL, MS_BIND, NULL);
+        r = mount_verbose(LOG_ERR, from, "/proc/kmsg", NULL, MS_BIND, NULL);
         if (r < 0)
                 return r;
 
@@ -2096,8 +2288,40 @@ static int setup_journal(const char *directory) {
         return 0;
 }
 
-static int drop_capabilities(void) {
-        return capability_bounding_set_drop(arg_caps_retain, false);
+static int drop_capabilities(uid_t uid) {
+        CapabilityQuintet q;
+
+        /* Let's initialize all five capability sets to something valid. If the quintet was configured via
+         * OCI use that, but fill in missing bits. If it wasn't then derive the quintet in full from
+         * arg_caps_retain. */
+
+        if (capability_quintet_is_set(&arg_full_capabilities)) {
+                q = arg_full_capabilities;
+
+                if (q.bounding == (uint64_t) -1)
+                        q.bounding = uid == 0 ? arg_caps_retain : 0;
+
+                if (q.effective == (uint64_t) -1)
+                        q.effective = uid == 0 ? q.bounding : 0;
+
+                if (q.inheritable == (uint64_t) -1)
+                        q.inheritable = uid == 0 ? q.bounding : 0;
+
+                if (q.permitted == (uint64_t) -1)
+                        q.permitted = uid == 0 ? q.bounding : 0;
+
+                if (q.ambient == (uint64_t) -1 && ambient_capabilities_supported())
+                        q.ambient = 0;
+        } else
+                q = (CapabilityQuintet) {
+                        .bounding = arg_caps_retain,
+                        .effective = uid == 0 ? arg_caps_retain : 0,
+                        .inheritable = uid == 0 ? arg_caps_retain : 0,
+                        .permitted = uid == 0 ? arg_caps_retain : 0,
+                        .ambient = ambient_capabilities_supported() ? 0 : (uint64_t) -1,
+                };
+
+        return capability_quintet_enforce(&q);
 }
 
 static int reset_audit_loginuid(void) {
@@ -2386,10 +2610,8 @@ static int determine_names(void) {
                                 return log_error_errno(r, "Failed to determine current directory: %m");
                 }
 
-                if (!arg_directory && !arg_image) {
-                        log_error("Failed to determine path, please use -D or -i.");
-                        return -EINVAL;
-                }
+                if (!arg_directory && !arg_image)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine path, please use -D or -i.");
         }
 
         if (!arg_machine) {
@@ -2412,10 +2634,8 @@ static int determine_names(void) {
                         return log_oom();
 
                 hostname_cleanup(arg_machine);
-                if (!machine_name_is_valid(arg_machine)) {
-                        log_error("Failed to determine machine name automatically, please use -M.");
-                        return -EINVAL;
-                }
+                if (!machine_name_is_valid(arg_machine))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine machine name automatically, please use -M.");
 
                 if (arg_ephemeral) {
                         char *b;
@@ -2484,6 +2704,75 @@ static int determine_uid_shift(const char *directory) {
         return 0;
 }
 
+static unsigned long effective_clone_ns_flags(void) {
+        unsigned long flags = arg_clone_ns_flags;
+
+        if (arg_private_network)
+                flags |= CLONE_NEWNET;
+        if (arg_use_cgns)
+                flags |= CLONE_NEWCGROUP;
+        if (arg_userns_mode != USER_NAMESPACE_NO)
+                flags |= CLONE_NEWUSER;
+
+        return flags;
+}
+
+static int patch_sysctl(void) {
+
+        /* This table is inspired by runc's sysctl() function */
+        static const struct {
+                const char *key;
+                bool prefix;
+                unsigned long clone_flags;
+        } safe_sysctl[] = {
+                { "kernel.hostname",   false, CLONE_NEWUTS },
+                { "kernel.domainname", false, CLONE_NEWUTS },
+                { "kernel.msgmax",     false, CLONE_NEWIPC },
+                { "kernel.msgmnb",     false, CLONE_NEWIPC },
+                { "kernel.msgmni",     false, CLONE_NEWIPC },
+                { "kernel.sem",        false, CLONE_NEWIPC },
+                { "kernel.shmall",     false, CLONE_NEWIPC },
+                { "kernel.shmmax",     false, CLONE_NEWIPC },
+                { "kernel.shmmni",     false, CLONE_NEWIPC },
+                { "fs.mqueue.",        true,  CLONE_NEWIPC },
+                { "net.",              true,  CLONE_NEWNET },
+        };
+
+        unsigned long flags;
+        char **k, **v;
+        int r;
+
+        flags = effective_clone_ns_flags();
+
+        STRV_FOREACH_PAIR(k, v, arg_sysctl) {
+                bool good = false;
+                size_t i;
+
+                for (i = 0; i < ELEMENTSOF(safe_sysctl); i++) {
+
+                        if (!FLAGS_SET(flags, safe_sysctl[i].clone_flags))
+                                continue;
+
+                        if (safe_sysctl[i].prefix)
+                                good = startswith(*k, safe_sysctl[i].key);
+                        else
+                                good = streq(*k, safe_sysctl[i].key);
+
+                        if (good)
+                                break;
+                }
+
+                if (!good)
+                        return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Refusing to write to sysctl '%s', as it is not safe in the selected namespaces.", *k);
+
+                r = sysctl_write(*k, *v);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to write sysctl '%s': %m", *k);
+        }
+
+        return 0;
+}
+
 static int inner_child(
                 Barrier *barrier,
                 const char *directory,
@@ -2510,7 +2799,7 @@ static int inner_child(
         };
         const char *exec_target;
         _cleanup_strv_free_ char **env_use = NULL;
-        int r;
+        int r, which_failed;
 
         /* This is the "inner" child process, i.e. the one forked off by the "outer" child process, which is the one
          * the container manager itself forked off. At the time of clone() it gained its own CLONE_NEWNS, CLONE_NEWPID,
@@ -2527,6 +2816,8 @@ static int inner_child(
         assert(directory);
         assert(kmsg_socket >= 0);
 
+        log_debug("Inner child is initializing.");
+
         if (arg_userns_mode != USER_NAMESPACE_NO) {
                 /* Tell the parent, that it now can write the UID map. */
                 (void) barrier_place(barrier); /* #1 */
@@ -2596,6 +2887,18 @@ static int inner_child(
                 return r;
         kmsg_socket = safe_close(kmsg_socket);
 
+        r = mount_custom(
+                        "/",
+                        arg_custom_mounts,
+                        arg_n_custom_mounts,
+                        false,
+                        0,
+                        0,
+                        arg_selinux_apifs_context,
+                        true);
+        if (r < 0)
+                return r;
+
         if (setsid() < 0)
                 return log_error_errno(errno, "setsid() failed: %m");
 
@@ -2609,6 +2912,10 @@ static int inner_child(
                 rtnl_socket = safe_close(rtnl_socket);
         }
 
+        r = patch_sysctl();
+        if (r < 0)
+                return r;
+
         if (arg_oom_score_adjust_set) {
                 r = set_oom_score_adjust(arg_oom_score_adjust);
                 if (r < 0)
@@ -2619,10 +2926,6 @@ static int inner_child(
                 if (sched_setaffinity(0, CPU_ALLOC_SIZE(arg_cpuset_ncpus), arg_cpuset) < 0)
                         return log_error_errno(errno, "Failed to set CPU affinity: %m");
 
-        r = drop_capabilities();
-        if (r < 0)
-                return log_error_errno(r, "drop_capabilities() failed: %m");
-
         (void) setup_hostname();
 
         if (arg_personality != PERSONALITY_INVALID) {
@@ -2635,16 +2938,51 @@ static int inner_child(
                         return log_error_errno(r, "personality() failed: %m");
         }
 
+        r = setrlimit_closest_all((const struct rlimit *const*) arg_rlimit, &which_failed);
+        if (r < 0)
+                return log_error_errno(r, "Failed to apply resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed));
+
+#if HAVE_SECCOMP
+        if (arg_seccomp) {
+
+                if (is_seccomp_available()) {
+
+                        r = seccomp_load(arg_seccomp);
+                        if (IN_SET(r, -EPERM, -EACCES))
+                                return log_error_errno(r, "Failed to install seccomp filter: %m");
+                        if (r < 0)
+                                log_debug_errno(r, "Failed to install seccomp filter: %m");
+                }
+        } else
+#endif
+        {
+                r = setup_seccomp(arg_caps_retain, arg_syscall_whitelist, arg_syscall_blacklist);
+                if (r < 0)
+                        return r;
+        }
+
 #if HAVE_SELINUX
         if (arg_selinux_context)
                 if (setexeccon(arg_selinux_context) < 0)
                         return log_error_errno(errno, "setexeccon(\"%s\") failed: %m", arg_selinux_context);
 #endif
 
-        r = change_uid_gid(arg_user, &home);
+        /* Make sure we keep the caps across the uid/gid dropping, so that we can retain some selected caps
+         * if we need to later on. */
+        if (prctl(PR_SET_KEEPCAPS, 1) < 0)
+                return log_error_errno(errno, "Failed to set PR_SET_KEEPCAPS: %m");
+
+        if (uid_is_valid(arg_uid) || gid_is_valid(arg_gid))
+                r = change_uid_gid_raw(arg_uid, arg_gid, arg_supplementary_gids, arg_n_supplementary_gids);
+        else
+                r = change_uid_gid(arg_user, &home);
         if (r < 0)
                 return r;
 
+        r = drop_capabilities(getuid());
+        if (r < 0)
+                return log_error_errno(r, "Dropping capabilities failed: %m");
+
         if (arg_no_new_privileges)
                 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0)
                         return log_error_errno(errno, "Failed to disable new privileges: %m");
@@ -2656,10 +2994,14 @@ static int inner_child(
         if (envp[n_env])
                 n_env++;
 
-        if ((asprintf((char**)(envp + n_env++), "HOME=%s", home ? home: "/root") < 0) ||
-            (asprintf((char**)(envp + n_env++), "USER=%s", arg_user ? arg_user : "root") < 0) ||
-            (asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0))
-                return log_oom();
+        if (home || !uid_is_valid(arg_uid) || arg_uid == 0)
+                if (asprintf((char**)(envp + n_env++), "HOME=%s", home ?: "/root") < 0)
+                        return log_oom();
+
+        if (arg_user || !uid_is_valid(arg_uid) || arg_uid == 0)
+                if (asprintf((char**)(envp + n_env++), "USER=%s", arg_user ?: "root") < 0 ||
+                    asprintf((char**)(envp + n_env++), "LOGNAME=%s", arg_user ? arg_user : "root") < 0)
+                        return log_oom();
 
         assert(!sd_id128_is_null(arg_uuid));
 
@@ -2699,6 +3041,8 @@ static int inner_child(
                         return r;
         }
 
+        log_debug("Inner child completed, invoking payload.");
+
         /* Now, explicitly close the log, so that we then can close all remaining fds. Closing the log explicitly first
          * has the benefit that the logging subsystem knows about it, and is thus ready to be reopened should we need
          * it again. Note that the other fds closed here are at least the locking and barrier fds. */
@@ -2791,7 +3135,6 @@ static int outer_child(
                 const char *directory,
                 const char *console,
                 DissectedImage *dissected_image,
-                bool interactive,
                 bool secondary,
                 int pid_socket,
                 int uuid_socket,
@@ -2804,9 +3147,9 @@ static int outer_child(
                 int netns_fd) {
 
         _cleanup_close_ int fd = -1;
-        int r, which_failed;
         pid_t pid;
         ssize_t l;
+        int r;
 
         /* This is the "outer" child process, i.e the one forked off by the container manager itself. It already has
          * its own CLONE_NEWNS namespace (which was created by the clone()). It still lives in the host's CLONE_NEWPID,
@@ -2815,18 +3158,21 @@ static int outer_child(
 
         assert(barrier);
         assert(directory);
-        assert(console);
         assert(pid_socket >= 0);
         assert(uuid_socket >= 0);
         assert(notify_socket >= 0);
         assert(kmsg_socket >= 0);
 
+        log_debug("Outer child is initializing.");
+
         if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
                 return log_error_errno(errno, "PR_SET_PDEATHSIG failed: %m");
 
-        if (interactive) {
+        if (arg_console_mode != CONSOLE_PIPE) {
                 int terminal;
 
+                assert(console);
+
                 terminal = open_terminal(console, O_RDWR);
                 if (terminal < 0)
                         return log_error_errno(terminal, "Failed to open console: %m");
@@ -2896,6 +3242,30 @@ static int outer_child(
                          "Selected user namespace base " UID_FMT " and range " UID_FMT ".", arg_uid_shift, arg_uid_range);
         }
 
+        if (!dissected_image) {
+                /* Turn directory into bind mount */
+                r = mount_verbose(LOG_ERR, directory, directory, NULL, MS_BIND|MS_REC, NULL);
+                if (r < 0)
+                        return r;
+        }
+
+        r = setup_pivot_root(
+                        directory,
+                        arg_pivot_root_new,
+                        arg_pivot_root_old);
+        if (r < 0)
+                return r;
+
+        r = setup_volatile_mode(
+                        directory,
+                        arg_volatile_mode,
+                        arg_userns_mode != USER_NAMESPACE_NO,
+                        arg_uid_shift,
+                        arg_uid_range,
+                        arg_selinux_context);
+        if (r < 0)
+                return r;
+
         if (dissected_image) {
                 /* Now we know the uid shift, let's now mount everything else that might be in the image. */
                 r = dissected_image_mount(dissected_image, directory, arg_uid_shift,
@@ -2921,38 +3291,6 @@ static int outer_child(
                 unified_cgroup_hierarchy_socket = safe_close(unified_cgroup_hierarchy_socket);
         }
 
-        /* Turn directory into bind mount */
-        r = mount_verbose(LOG_ERR, directory, directory, NULL, MS_BIND|MS_REC, NULL);
-        if (r < 0)
-                return r;
-
-        r = setup_pivot_root(
-                        directory,
-                        arg_pivot_root_new,
-                        arg_pivot_root_old);
-        if (r < 0)
-                return r;
-
-        r = setup_volatile(
-                        directory,
-                        arg_volatile_mode,
-                        arg_userns_mode != USER_NAMESPACE_NO,
-                        arg_uid_shift,
-                        arg_uid_range,
-                        arg_selinux_context);
-        if (r < 0)
-                return r;
-
-        r = setup_volatile_state(
-                        directory,
-                        arg_volatile_mode,
-                        arg_userns_mode != USER_NAMESPACE_NO,
-                        arg_uid_shift,
-                        arg_uid_range,
-                        arg_selinux_context);
-        if (r < 0)
-                return r;
-
         /* Mark everything as shared so our mounts get propagated down. This is
          * required to make new bind mounts available in systemd services
          * inside the containter that create a new mount namespace.
@@ -2971,8 +3309,8 @@ static int outer_child(
         if (r < 0)
                 return r;
 
-        if (arg_read_only) {
-                r = bind_remount_recursive(directory, true, NULL);
+        if (arg_read_only && arg_volatile_mode == VOLATILE_NO) {
+                r = bind_remount_recursive(directory, MS_RDONLY, MS_RDONLY, NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to make tree read-only: %m");
         }
@@ -2988,7 +3326,12 @@ static int outer_child(
         if (r < 0)
                 return r;
 
-        dev_setup(directory, arg_uid_shift, arg_uid_shift);
+        r = make_extra_nodes(directory);
+        if (r < 0)
+                return r;
+
+        (void) dev_setup(directory, arg_uid_shift, arg_uid_shift);
+        (void) make_inaccessible_nodes(directory, arg_uid_shift, arg_uid_shift);
 
         r = setup_pts(directory);
         if (r < 0)
@@ -3006,10 +3349,6 @@ static int outer_child(
         if (r < 0)
                 return r;
 
-        r = setup_seccomp(arg_caps_retain, arg_syscall_whitelist, arg_syscall_blacklist);
-        if (r < 0)
-                return r;
-
         r = setup_timezone(directory);
         if (r < 0)
                 return r;
@@ -3033,7 +3372,8 @@ static int outer_child(
                         arg_userns_mode != USER_NAMESPACE_NO,
                         arg_uid_shift,
                         arg_uid_range,
-                        arg_selinux_apifs_context);
+                        arg_selinux_apifs_context,
+                        false);
         if (r < 0)
                 return r;
 
@@ -3058,10 +3398,6 @@ static int outer_child(
         if (fd < 0)
                 return fd;
 
-        r = setrlimit_closest_all((const struct rlimit *const*) arg_rlimit, &which_failed);
-        if (r < 0)
-                return log_error_errno(r, "Failed to apply resource limit RLIMIT_%s: %m", rlimit_to_string(which_failed));
-
         pid = raw_clone(SIGCHLD|CLONE_NEWNS|
                         arg_clone_ns_flags |
                         (arg_userns_mode != USER_NAMESPACE_NO ? CLONE_NEWUSER : 0));
@@ -3275,11 +3611,11 @@ static int nspawn_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t r
                 return log_oom();
 
         if (strv_find(tags, "READY=1"))
-                sd_notifyf(false, "READY=1\n");
+                (void) sd_notifyf(false, "READY=1\n");
 
         p = strv_find_startswith(tags, "STATUS=");
         if (p)
-                sd_notifyf(false, "STATUS=Container running: %s", p);
+                (void) sd_notifyf(false, "STATUS=Container running: %s", p);
 
         return 0;
 }
@@ -3314,6 +3650,15 @@ static int merge_settings(Settings *settings, const char *path) {
         if ((arg_settings_mask & SETTING_EPHEMERAL) == 0)
                 arg_ephemeral = settings->ephemeral;
 
+        if ((arg_settings_mask & SETTING_DIRECTORY) == 0 &&
+            settings->root) {
+
+                if (!arg_settings_trusted)
+                        log_warning("Ignoring root directory setting, file %s is not trusted.", path);
+                else
+                        free_and_replace(arg_directory, settings->root);
+        }
+
         if ((arg_settings_mask & SETTING_PIVOT_ROOT) == 0 &&
             settings->pivot_root_new) {
                 free_and_replace(arg_pivot_root_new, settings->pivot_root_new);
@@ -3328,16 +3673,36 @@ static int merge_settings(Settings *settings, const char *path) {
             settings->environment)
                 strv_free_and_replace(arg_setenv, settings->environment);
 
-        if ((arg_settings_mask & SETTING_USER) == 0 &&
-            settings->user)
-                free_and_replace(arg_user, settings->user);
+        if ((arg_settings_mask & SETTING_USER) == 0) {
+
+                if (settings->user)
+                        free_and_replace(arg_user, settings->user);
+
+                if (uid_is_valid(settings->uid))
+                        arg_uid = settings->uid;
+                if (gid_is_valid(settings->gid))
+                        arg_gid = settings->gid;
+                if (settings->n_supplementary_gids > 0) {
+                        free_and_replace(arg_supplementary_gids, settings->supplementary_gids);
+                        arg_n_supplementary_gids = settings->n_supplementary_gids;
+                }
+        }
 
         if ((arg_settings_mask & SETTING_CAPABILITY) == 0) {
-                uint64_t plus;
+                uint64_t plus, minus;
+
+                /* Note that we copy both the simple plus/minus caps here, and the full quintet from the
+                 * Settings structure */
 
                 plus = settings->capability;
-                if (settings_private_network(settings))
-                        plus |= (1ULL << CAP_NET_ADMIN);
+                minus = settings->drop_capability;
+
+                if ((arg_settings_mask & SETTING_NETWORK) == 0) {
+                        if (settings_private_network(settings))
+                                plus |= UINT64_C(1) << CAP_NET_ADMIN;
+                        else
+                                minus |= UINT64_C(1) << CAP_NET_ADMIN;
+                }
 
                 if (!arg_settings_trusted && plus != 0) {
                         if (settings->capability != 0)
@@ -3345,7 +3710,15 @@ static int merge_settings(Settings *settings, const char *path) {
                 } else
                         arg_caps_retain |= plus;
 
-                arg_caps_retain &= ~settings->drop_capability;
+                arg_caps_retain &= ~minus;
+
+                /* Copy the full capabilities over too */
+                if (capability_quintet_is_set(&settings->full_capabilities)) {
+                        if (!arg_settings_trusted)
+                                log_warning("Ignoring capabilitiy settings, file %s is not trusted.", path);
+                        else
+                                arg_full_capabilities = settings->full_capabilities;
+                }
         }
 
         if ((arg_settings_mask & SETTING_KILL_SIGNAL) == 0 &&
@@ -3394,7 +3767,8 @@ static int merge_settings(Settings *settings, const char *path) {
              settings->network_interfaces ||
              settings->network_macvlan ||
              settings->network_ipvlan ||
-             settings->network_veth_extra)) {
+             settings->network_veth_extra ||
+             settings->network_namespace_path)) {
 
                 if (!arg_settings_trusted)
                         log_warning("Ignoring network settings, file %s is not trusted.", path);
@@ -3409,6 +3783,8 @@ static int merge_settings(Settings *settings, const char *path) {
 
                         free_and_replace(arg_network_bridge, settings->network_bridge);
                         free_and_replace(arg_network_zone, settings->network_zone);
+
+                        free_and_replace(arg_network_namespace_path, settings->network_namespace_path);
                 }
         }
 
@@ -3441,12 +3817,21 @@ static int merge_settings(Settings *settings, const char *path) {
 
         if ((arg_settings_mask & SETTING_SYSCALL_FILTER) == 0) {
 
-                if (!arg_settings_trusted && !strv_isempty(arg_syscall_whitelist))
+                if (!arg_settings_trusted && !strv_isempty(settings->syscall_whitelist))
                         log_warning("Ignoring SystemCallFilter= settings, file %s is not trusted.", path);
                 else {
                         strv_free_and_replace(arg_syscall_whitelist, settings->syscall_whitelist);
                         strv_free_and_replace(arg_syscall_blacklist, settings->syscall_blacklist);
                 }
+
+#if HAVE_SECCOMP
+                if (!arg_settings_trusted && settings->seccomp)
+                        log_warning("Ignoring SECCOMP filter, file %s is not trusted.", path);
+                else {
+                        seccomp_release(arg_seccomp);
+                        arg_seccomp = TAKE_PTR(settings->seccomp);
+                }
+#endif
         }
 
         for (rl = 0; rl < _RLIMIT_MAX; rl ++) {
@@ -3515,6 +3900,55 @@ static int merge_settings(Settings *settings, const char *path) {
             settings->timezone != _TIMEZONE_MODE_INVALID)
                 arg_timezone = settings->timezone;
 
+        if ((arg_settings_mask & SETTING_SLICE) == 0 &&
+            settings->slice) {
+
+                if (!arg_settings_trusted)
+                        log_warning("Ignoring slice setting, file '%s' is not trusted.", path);
+                else
+                        free_and_replace(arg_slice, settings->slice);
+        }
+
+        if ((arg_settings_mask & SETTING_USE_CGNS) == 0 &&
+            settings->use_cgns >= 0) {
+
+                if (!arg_settings_trusted)
+                        log_warning("Ignoring cgroup namespace setting, file '%s' is not trusted.", path);
+                else
+                        arg_use_cgns = settings->use_cgns;
+        }
+
+        if ((arg_settings_mask & SETTING_CLONE_NS_FLAGS) == 0 &&
+            settings->clone_ns_flags != (unsigned long) -1) {
+
+                if (!arg_settings_trusted)
+                        log_warning("Ignoring namespace setting, file '%s' is not trusted.", path);
+                else
+                        arg_clone_ns_flags = settings->clone_ns_flags;
+        }
+
+        if ((arg_settings_mask & SETTING_CONSOLE_MODE) == 0 &&
+            settings->console_mode >= 0) {
+
+                if (!arg_settings_trusted)
+                        log_warning("Ignoring console mode setting, file '%s' is not trusted.", path);
+                else
+                        arg_console_mode = settings->console_mode;
+        }
+
+        /* The following properties can only be set through the OCI settings logic, not from the command line, hence we
+         * don't consult arg_settings_mask for them. */
+
+        sd_bus_message_unref(arg_property_message);
+        arg_property_message = TAKE_PTR(settings->properties);
+
+        arg_console_width = settings->console_width;
+        arg_console_height = settings->console_height;
+
+        device_node_array_free(arg_extra_nodes, arg_n_extra_nodes);
+        arg_extra_nodes = TAKE_PTR(settings->extra_nodes);
+        arg_n_extra_nodes = settings->n_extra_nodes;
+
         return 0;
 }
 
@@ -3525,6 +3959,9 @@ static int load_settings(void) {
         const char *fn, *i;
         int r;
 
+        if (arg_oci_bundle)
+                return 0;
+
         /* If all settings are masked, there's no point in looking for
          * the settings file */
         if ((arg_settings_mask & _SETTINGS_MASK_ALL) == _SETTINGS_MASK_ALL)
@@ -3592,10 +4029,27 @@ static int load_settings(void) {
         return merge_settings(settings, p);
 }
 
-static int run(int master,
+static int load_oci_bundle(void) {
+        _cleanup_(settings_freep) Settings *settings = NULL;
+        int r;
+
+        if (!arg_oci_bundle)
+                return 0;
+
+        /* By default let's trust OCI bundles */
+        if (arg_settings_trusted < 0)
+                arg_settings_trusted = true;
+
+        r = oci_load(NULL, arg_oci_bundle, &settings);
+        if (r < 0)
+                return r;
+
+        return merge_settings(settings, arg_oci_bundle);
+}
+
+static int run_container(int master,
                const char* console,
                DissectedImage *dissected_image,
-               bool interactive,
                bool secondary,
                FDSet *fds,
                char veth_name[IFNAMSIZ], bool *veth_created,
@@ -3626,7 +4080,6 @@ static int run(int master,
         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
         ContainerStatus container_status = 0;
-        char last_char = 0;
         int ifi = 0, r;
         ssize_t l;
         sigset_t mask_chld;
@@ -3695,10 +4148,9 @@ static int run(int master,
                         log_debug_errno(r, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does.", arg_network_namespace_path);
                 else if (r < 0)
                         return log_error_errno(r, "Failed to check %s fs type: %m", arg_network_namespace_path);
-                else if (r == 0) {
-                        log_error("Path %s doesn't refer to a network namespace, refusing.", arg_network_namespace_path);
-                        return -EINVAL;
-                }
+                else if (r == 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "Path %s doesn't refer to a network namespace, refusing.", arg_network_namespace_path);
         }
 
         *pid = raw_clone(SIGCHLD|CLONE_NEWNS);
@@ -3728,7 +4180,6 @@ static int run(int master,
                                 arg_directory,
                                 console,
                                 dissected_image,
-                                interactive,
                                 secondary,
                                 pid_socket_pair[1],
                                 uuid_socket_pair[1],
@@ -3747,7 +4198,7 @@ static int run(int master,
 
         barrier_set_role(&barrier, BARRIER_PARENT);
 
-        fds = fdset_free(fds);
+        fdset_close(fds);
 
         kmsg_socket_pair[1] = safe_close(kmsg_socket_pair[1]);
         rtnl_socket_pair[1] = safe_close(rtnl_socket_pair[1]);
@@ -3762,10 +4213,8 @@ static int run(int master,
                 l = recv(uid_shift_socket_pair[0], &arg_uid_shift, sizeof arg_uid_shift, 0);
                 if (l < 0)
                         return log_error_errno(errno, "Failed to read UID shift: %m");
-                if (l != sizeof arg_uid_shift) {
-                        log_error("Short read while reading UID shift.");
-                        return -EIO;
-                }
+                if (l != sizeof arg_uid_shift)
+                        return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading UID shift.");
 
                 if (arg_userns_mode == USER_NAMESPACE_PICK) {
                         /* If we are supposed to pick the UID shift, let's try to use the shift read from the
@@ -3779,10 +4228,8 @@ static int run(int master,
                         l = send(uid_shift_socket_pair[0], &arg_uid_shift, sizeof arg_uid_shift, MSG_NOSIGNAL);
                         if (l < 0)
                                 return log_error_errno(errno, "Failed to send UID shift: %m");
-                        if (l != sizeof arg_uid_shift) {
-                                log_error("Short write while writing UID shift.");
-                                return -EIO;
-                        }
+                        if (l != sizeof arg_uid_shift)
+                                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short write while writing UID shift.");
                 }
         }
 
@@ -3791,11 +4238,9 @@ static int run(int master,
                 l = recv(unified_cgroup_hierarchy_socket_pair[0], &arg_unified_cgroup_hierarchy, sizeof(arg_unified_cgroup_hierarchy), 0);
                 if (l < 0)
                         return log_error_errno(errno, "Failed to read cgroup mode: %m");
-                if (l != sizeof(arg_unified_cgroup_hierarchy)) {
-                        log_error("Short read while reading cgroup mode (%zu bytes).%s",
-                                  l, l == 0 ? " The child is most likely dead." : "");
-                        return -EIO;
-                }
+                if (l != sizeof(arg_unified_cgroup_hierarchy))
+                        return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading cgroup mode (%zu bytes).%s",
+                                               l, l == 0 ? " The child is most likely dead." : "");
         }
 
         /* Wait for the outer child. */
@@ -3809,19 +4254,15 @@ static int run(int master,
         l = recv(pid_socket_pair[0], pid, sizeof *pid, 0);
         if (l < 0)
                 return log_error_errno(errno, "Failed to read inner child PID: %m");
-        if (l != sizeof *pid) {
-                log_error("Short read while reading inner child PID.");
-                return -EIO;
-        }
+        if (l != sizeof *pid)
+                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading inner child PID.");
 
         /* We also retrieve container UUID in case it was generated by outer child */
         l = recv(uuid_socket_pair[0], &arg_uuid, sizeof arg_uuid, 0);
         if (l < 0)
                 return log_error_errno(errno, "Failed to read container machine ID: %m");
-        if (l != sizeof(arg_uuid)) {
-                log_error("Short read while reading container machined ID.");
-                return -EIO;
-        }
+        if (l != sizeof(arg_uuid))
+                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading container machined ID.");
 
         /* We also retrieve the socket used for notifications generated by outer child */
         notify_socket = receive_one_fd(notify_socket_pair[0], 0);
@@ -3832,10 +4273,8 @@ static int run(int master,
         log_debug("Init process invoked as PID "PID_FMT, *pid);
 
         if (arg_userns_mode != USER_NAMESPACE_NO) {
-                if (!barrier_place_and_sync(&barrier)) { /* #1 */
-                        log_error("Child died too early.");
-                        return -ESRCH;
-                }
+                if (!barrier_place_and_sync(&barrier)) /* #1 */
+                        return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Child died too early.");
 
                 r = setup_uid_map(*pid);
                 if (r < 0)
@@ -3847,10 +4286,8 @@ static int run(int master,
         if (arg_private_network) {
                 if (!arg_network_namespace_path) {
                         /* Wait until the child has unshared its network namespace. */
-                        if (!barrier_place_and_sync(&barrier)) { /* #3 */
-                                log_error("Child died too early");
-                                return -ESRCH;
-                        }
+                        if (!barrier_place_and_sync(&barrier)) /* #3 */
+                                return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Child died too early");
                 }
 
                 r = move_network_interfaces(*pid, arg_network_interfaces);
@@ -3940,6 +4377,7 @@ static int run(int master,
                                 arg_custom_mounts, arg_n_custom_mounts,
                                 arg_kill_signal,
                                 arg_property,
+                                arg_property_message,
                                 arg_keep_unit,
                                 arg_container_service_name);
                 if (r < 0)
@@ -3953,18 +4391,19 @@ static int run(int master,
                                 arg_slice,
                                 arg_custom_mounts, arg_n_custom_mounts,
                                 arg_kill_signal,
-                                arg_property);
+                                arg_property,
+                                arg_property_message);
                 if (r < 0)
                         return r;
 
         } else if (arg_slice || arg_property)
                 log_notice("Machine and scope registration turned off, --slice= and --property= settings will have no effect.");
 
-        r = sync_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift);
+        r = create_subcgroup(*pid, arg_keep_unit, arg_unified_cgroup_hierarchy);
         if (r < 0)
                 return r;
 
-        r = create_subcgroup(*pid, arg_keep_unit, arg_unified_cgroup_hierarchy);
+        r = sync_cgroup(*pid, arg_unified_cgroup_hierarchy, arg_uid_shift);
         if (r < 0)
                 return r;
 
@@ -4004,18 +4443,16 @@ static int run(int master,
                 return r;
 
         /* Let the child know that we are ready and wait that the child is completely ready now. */
-        if (!barrier_place_and_sync(&barrier)) { /* #5 */
-                log_error("Child died too early.");
-                return -ESRCH;
-        }
+        if (!barrier_place_and_sync(&barrier)) /* #5 */
+                return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "Child died too early.");
 
         /* At this point we have made use of the UID we picked, and thus nss-mymachines
          * will make them appear in getpwuid(), thus we can release the /etc/passwd lock. */
         etc_passwd_lock = safe_close(etc_passwd_lock);
 
-        sd_notifyf(false,
-                   "STATUS=Container running.\n"
-                   "X_NSPAWN_LEADER_PID=" PID_FMT, *pid);
+        (void) sd_notifyf(false,
+                          "STATUS=Container running.\n"
+                          "X_NSPAWN_LEADER_PID=" PID_FMT, *pid);
         if (!arg_notify_ready)
                 (void) sd_notify(false, "READY=1\n");
 
@@ -4042,22 +4479,32 @@ static int run(int master,
 
         rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]);
 
-        r = pty_forward_new(event, master,
-                            PTY_FORWARD_IGNORE_VHANGUP | (interactive ? 0 : PTY_FORWARD_READ_ONLY),
-                            &forward);
-        if (r < 0)
-                return log_error_errno(r, "Failed to create PTY forwarder: %m");
+        if (IN_SET(arg_console_mode, CONSOLE_INTERACTIVE, CONSOLE_READ_ONLY)) {
+                assert(master >= 0);
+
+                r = pty_forward_new(event, master,
+                                    PTY_FORWARD_IGNORE_VHANGUP | (arg_console_mode == CONSOLE_READ_ONLY ? PTY_FORWARD_READ_ONLY : 0),
+                                    &forward);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to create PTY forwarder: %m");
+
+                if (arg_console_width != (unsigned) -1 || arg_console_height != (unsigned) -1)
+                        (void) pty_forward_set_width_height(forward, arg_console_width, arg_console_height);
+        }
 
         r = sd_event_loop(event);
         if (r < 0)
                 return log_error_errno(r, "Failed to run event loop: %m");
 
-        pty_forward_get_last_char(forward, &last_char);
+        if (forward) {
+                char last_char = 0;
 
-        forward = pty_forward_free(forward);
+                (void) pty_forward_get_last_char(forward, &last_char);
+                forward = pty_forward_free(forward);
 
-        if (!arg_quiet && last_char != '\n')
-                putc('\n', stdout);
+                if (!arg_quiet && last_char != '\n')
+                        putc('\n', stdout);
+        }
 
         /* Kill if it is not dead yet anyway */
         if (bus) {
@@ -4171,7 +4618,7 @@ static int initialize_rlimits(void) {
         return 0;
 }
 
-int main(int argc, char *argv[]) {
+static int run(int argc, char *argv[]) {
         _cleanup_free_ char *console = NULL;
         _cleanup_close_ int master = -1;
         _cleanup_fdset_free_ FDSet *fds = NULL;
@@ -4181,7 +4628,7 @@ int main(int argc, char *argv[]) {
         pid_t pid = 0;
         union in_addr_union exposed = {};
         _cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
-        bool interactive, veth_created = false, remove_tmprootdir = false;
+        bool veth_created = false, remove_tmprootdir = false;
         char tmprootdir[] = "/tmp/nspawn-root-XXXXXX";
         _cleanup_(loop_device_unrefp) LoopDevice *loop = NULL;
         _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL;
@@ -4190,10 +4637,6 @@ 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;
@@ -4206,6 +4649,10 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
+        r = load_oci_bundle();
+        if (r < 0)
+                goto finish;
+
         r = determine_names();
         if (r < 0)
                 goto finish;
@@ -4214,8 +4661,6 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
-        parse_environment();
-
         r = cg_unified_flush();
         if (r < 0) {
                 log_error_errno(r, "Failed to determine whether the unified cgroups hierarchy is used: %m");
@@ -4398,7 +4843,7 @@ int main(int argc, char *argv[]) {
                                 goto finish;
                         }
 
-                        r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL, COPY_REFLINK);
+                        r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL, FS_NOCOW_FL, COPY_REFLINK|COPY_CRTIME);
                         if (r < 0) {
                                 r = log_error_errno(r, "Failed to copy image file: %m");
                                 goto finish;
@@ -4481,31 +4926,37 @@ int main(int argc, char *argv[]) {
         if (r < 0)
                 goto finish;
 
-        interactive =
-                isatty(STDIN_FILENO) > 0 &&
-                isatty(STDOUT_FILENO) > 0;
+        if (arg_console_mode < 0)
+                arg_console_mode =
+                        isatty(STDIN_FILENO) > 0 &&
+                        isatty(STDOUT_FILENO) > 0 ? CONSOLE_INTERACTIVE : CONSOLE_READ_ONLY;
 
-        master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
-        if (master < 0) {
-                r = log_error_errno(errno, "Failed to acquire pseudo tty: %m");
-                goto finish;
-        }
+        if (arg_console_mode == CONSOLE_PIPE) /* if we pass STDERR on to the container, don't add our own logs into it too */
+                arg_quiet = true;
 
-        r = ptsname_malloc(master, &console);
-        if (r < 0) {
-                r = log_error_errno(r, "Failed to determine tty name: %m");
-                goto finish;
-        }
+        if (arg_console_mode != CONSOLE_PIPE) {
+                master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NONBLOCK);
+                if (master < 0) {
+                        r = log_error_errno(errno, "Failed to acquire pseudo tty: %m");
+                        goto finish;
+                }
 
-        if (arg_selinux_apifs_context) {
-                r = mac_selinux_apply(console, arg_selinux_apifs_context);
-                if (r < 0)
+                r = ptsname_malloc(master, &console);
+                if (r < 0) {
+                        r = log_error_errno(r, "Failed to determine tty name: %m");
                         goto finish;
-        }
+                }
 
-        if (unlockpt(master) < 0) {
-                r = log_error_errno(errno, "Failed to unlock tty: %m");
-                goto finish;
+                if (arg_selinux_apifs_context) {
+                        r = mac_selinux_apply(console, arg_selinux_apifs_context);
+                        if (r < 0)
+                                goto finish;
+                }
+
+                if (unlockpt(master) < 0) {
+                        r = log_error_errno(errno, "Failed to unlock tty: %m");
+                        goto finish;
+                }
         }
 
         if (!arg_quiet)
@@ -4520,22 +4971,22 @@ int main(int argc, char *argv[]) {
         }
 
         for (;;) {
-                r = run(master,
-                        console,
-                        dissected_image,
-                        interactive, secondary,
-                        fds,
-                        veth_name, &veth_created,
-                        &exposed,
-                        &pid, &ret);
+                r = run_container(master,
+                                  console,
+                                  dissected_image,
+                                  secondary,
+                                  fds,
+                                  veth_name, &veth_created,
+                                  &exposed,
+                                  &pid, &ret);
                 if (r <= 0)
                         break;
         }
 
 finish:
-        sd_notify(false,
-                  r == 0 && ret == EXIT_FORCE_RESTART ? "STOPPING=1\nSTATUS=Restarting..." :
-                                                        "STOPPING=1\nSTATUS=Terminating...");
+        (void) sd_notify(false,
+                         r == 0 && ret == EXIT_FORCE_RESTART ? "STOPPING=1\nSTATUS=Restarting..." :
+                                                               "STOPPING=1\nSTATUS=Terminating...");
 
         if (pid > 0)
                 (void) kill(pid, SIGKILL);
@@ -4582,32 +5033,15 @@ finish:
                 (void) remove_veth_links(veth_name, arg_network_veth_extra);
         (void) remove_bridge(arg_network_zone);
 
-        free(arg_directory);
-        free(arg_template);
-        free(arg_image);
-        free(arg_machine);
-        free(arg_hostname);
-        free(arg_user);
-        free(arg_pivot_root_new);
-        free(arg_pivot_root_old);
-        free(arg_chdir);
-        strv_free(arg_setenv);
-        free(arg_network_bridge);
-        strv_free(arg_network_interfaces);
-        strv_free(arg_network_macvlan);
-        strv_free(arg_network_ipvlan);
-        strv_free(arg_network_veth_extra);
-        strv_free(arg_parameters);
-        free(arg_network_zone);
-        free(arg_network_namespace_path);
-        strv_free(arg_property);
         custom_mount_free_all(arg_custom_mounts, arg_n_custom_mounts);
         expose_port_free_all(arg_expose_ports);
-        free(arg_root_hash);
         rlimit_free_all(arg_rlimit);
-        strv_free(arg_syscall_whitelist);
-        strv_free(arg_syscall_blacklist);
-        arg_cpuset = cpu_set_mfree(arg_cpuset);
+        device_node_array_free(arg_extra_nodes, arg_n_extra_nodes);
 
-        return r < 0 ? EXIT_FAILURE : ret;
+        if (r < 0)
+                return r;
+
+        return ret;
 }
+
+DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run);
index e491351..90de140 100644 (file)
@@ -8,13 +8,13 @@
 #include <string.h>
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "hostname-util.h"
 #include "local-addresses.h"
 #include "macro.h"
 #include "nss-util.h"
 #include "signal-util.h"
 #include "string-util.h"
-#include "util.h"
 
 /* We use 127.0.0.2 as IPv4 address. This has the advantage over
  * 127.0.0.1 that it can be translated back to the local hostname. For
@@ -64,10 +64,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
         } else if (is_gateway_hostname(name)) {
 
                 n_addresses = local_gateways(NULL, 0, AF_UNSPEC, &addresses);
-                if (n_addresses <= 0) {
-                        *h_errnop = HOST_NOT_FOUND;
-                        return NSS_STATUS_NOTFOUND;
-                }
+                if (n_addresses <= 0)
+                        goto not_found;
 
                 canonical = "_gateway";
 
@@ -81,10 +79,8 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
                 }
 
                 /* We respond to our local host name, our hostname suffixed with a single dot. */
-                if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
-                        *h_errnop = HOST_NOT_FOUND;
-                        return NSS_STATUS_NOTFOUND;
-                }
+                if (!streq(name, hn) && !streq_ptr(startswith(name, hn), "."))
+                        goto not_found;
 
                 n_addresses = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
                 if (n_addresses < 0)
@@ -164,6 +160,10 @@ enum nss_status _nss_myhostname_gethostbyname4_r(
         h_errno = 0;
 
         return NSS_STATUS_SUCCESS;
+
+not_found:
+        *h_errnop = HOST_NOT_FOUND;
+        return NSS_STATUS_NOTFOUND;
 }
 
 static enum nss_status fill_in_hostent(
@@ -339,10 +339,8 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
         } else if (is_gateway_hostname(name)) {
 
                 n_addresses = local_gateways(NULL, 0, af, &addresses);
-                if (n_addresses <= 0) {
-                        *h_errnop = HOST_NOT_FOUND;
-                        return NSS_STATUS_NOTFOUND;
-                }
+                if (n_addresses <= 0)
+                        goto not_found;
 
                 canonical = "_gateway";
 
@@ -355,10 +353,8 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
                         return NSS_STATUS_TRYAGAIN;
                 }
 
-                if (!streq(name, hn) && !streq_ptr(startswith(name, hn), ".")) {
-                        *h_errnop = HOST_NOT_FOUND;
-                        return NSS_STATUS_NOTFOUND;
-                }
+                if (!streq(name, hn) && !streq_ptr(startswith(name, hn), "."))
+                        goto not_found;
 
                 n_addresses = local_addresses(NULL, 0, af, &addresses);
                 if (n_addresses < 0)
@@ -381,6 +377,10 @@ enum nss_status _nss_myhostname_gethostbyname3_r(
                         errnop, h_errnop,
                         ttlp,
                         canonp);
+
+not_found:
+        *h_errnop = HOST_NOT_FOUND;
+        return NSS_STATUS_NOTFOUND;
 }
 
 enum nss_status _nss_myhostname_gethostbyaddr2_r(
index 486a658..0e76c43 100644 (file)
@@ -9,14 +9,16 @@
 #include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "env-util.h"
+#include "errno-util.h"
+#include "format-util.h"
 #include "hostname-util.h"
 #include "in-addr-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "nss-util.h"
 #include "signal-util.h"
 #include "string-util.h"
 #include "user-util.h"
-#include "util.h"
 
 NSS_GETHOSTBYNAME_PROTOTYPES(mymachines);
 NSS_GETPW_PROTOTYPES(mymachines);
@@ -230,7 +232,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r(
 fail:
         UNPROTECT_ERRNO;
         *errnop = -r;
-        *h_errnop = NO_DATA;
+        *h_errnop = NO_RECOVERY;
         return NSS_STATUS_UNAVAIL;
 }
 
@@ -401,7 +403,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r(
 fail:
         UNPROTECT_ERRNO;
         *errnop = -r;
-        *h_errnop = NO_DATA;
+        *h_errnop = NO_RECOVERY;
         return NSS_STATUS_UNAVAIL;
 }
 
index 8370fed..ac5fff5 100644 (file)
@@ -5,17 +5,19 @@
 #include <nss.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "sd-bus.h"
 
 #include "bus-common-errors.h"
+#include "errno-util.h"
 #include "in-addr-util.h"
 #include "macro.h"
 #include "nss-util.h"
 #include "resolved-def.h"
-#include "string-util.h"
-#include "util.h"
 #include "signal-util.h"
+#include "string-util.h"
 
 NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
 NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
@@ -24,7 +26,9 @@ static bool bus_error_shall_fallback(sd_bus_error *e) {
         return sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN) ||
                sd_bus_error_has_name(e, SD_BUS_ERROR_NAME_HAS_NO_OWNER) ||
                sd_bus_error_has_name(e, SD_BUS_ERROR_NO_REPLY) ||
-               sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED);
+               sd_bus_error_has_name(e, SD_BUS_ERROR_ACCESS_DENIED) ||
+               sd_bus_error_has_name(e, SD_BUS_ERROR_DISCONNECTED) ||
+               sd_bus_error_has_name(e, SD_BUS_ERROR_TIMEOUT);
 }
 
 static int count_addresses(sd_bus_message *m, int af, const char **canonical) {
@@ -116,7 +120,6 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         struct gaih_addrtuple *r_tuple, *r_tuple_first = NULL;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
-        enum nss_status ret = NSS_STATUS_UNAVAIL;
         const char *canonical = NULL;
         size_t l, ms, idx;
         char *r_name;
@@ -160,8 +163,7 @@ enum nss_status _nss_resolve_gethostbyname4_r(
 
         r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
         if (r < 0) {
-                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
-                    !bus_error_shall_fallback(&error))
+                if (!bus_error_shall_fallback(&error))
                         goto not_found;
 
                 /* Return NSS_STATUS_UNAVAIL when communication with systemd-resolved fails,
@@ -271,7 +273,7 @@ fail:
         UNPROTECT_ERRNO;
         *errnop = -r;
         *h_errnop = NO_RECOVERY;
-        return ret;
+        return NSS_STATUS_UNAVAIL;
 
 not_found:
         *h_errnop = HOST_NOT_FOUND;
@@ -291,7 +293,6 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         char *r_name, *r_aliases, *r_addr, *r_addr_list;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
-        enum nss_status ret = NSS_STATUS_UNAVAIL;
         size_t l, idx, ms, alen;
         const char *canonical;
         int c, r, i = 0;
@@ -342,8 +343,7 @@ enum nss_status _nss_resolve_gethostbyname3_r(
 
         r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
         if (r < 0) {
-                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
-                    !bus_error_shall_fallback(&error))
+                if (!bus_error_shall_fallback(&error))
                         goto not_found;
 
                 goto fail;
@@ -461,7 +461,7 @@ fail:
         UNPROTECT_ERRNO;
         *errnop = -r;
         *h_errnop = NO_RECOVERY;
-        return ret;
+        return NSS_STATUS_UNAVAIL;
 
 not_found:
         *h_errnop = HOST_NOT_FOUND;
@@ -480,7 +480,6 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         char *r_name, *r_aliases, *r_addr, *r_addr_list;
         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
-        enum nss_status ret = NSS_STATUS_UNAVAIL;
         unsigned c = 0, i = 0;
         size_t ms = 0, idx;
         const char *n;
@@ -503,10 +502,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         }
 
         if (len != FAMILY_ADDRESS_SIZE(af)) {
-                UNPROTECT_ERRNO;
-                *errnop = EINVAL;
-                *h_errnop = NO_RECOVERY;
-                return NSS_STATUS_UNAVAIL;
+                r = -EINVAL;
+                goto fail;
         }
 
         if (avoid_deadlock()) {
@@ -546,8 +543,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
 
         r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
         if (r < 0) {
-                if (sd_bus_error_has_name(&error, _BUS_ERROR_DNS "NXDOMAIN") ||
-                    !bus_error_shall_fallback(&error))
+                if (!bus_error_shall_fallback(&error))
                         goto not_found;
 
                 goto fail;
@@ -572,7 +568,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
 
         r = sd_bus_message_rewind(reply, false);
         if (r < 0)
-                return r;
+                goto fail;
 
         if (c <= 0)
                 goto not_found;
@@ -646,7 +642,7 @@ fail:
         UNPROTECT_ERRNO;
         *errnop = -r;
         *h_errnop = NO_RECOVERY;
-        return ret;
+        return NSS_STATUS_UNAVAIL;
 
 not_found:
         *h_errnop = HOST_NOT_FOUND;
index f8db27a..8beae06 100644 (file)
@@ -10,6 +10,7 @@
 #include "dirent-util.h"
 #include "env-util.h"
 #include "fd-util.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "list.h"
 #include "macro.h"
index 29f9101..ce86f96 100644 (file)
@@ -26,6 +26,7 @@
 #include "pretty-print.h"
 #include "stat-util.h"
 #include "strv.h"
+#include "util.h"
 
 static const char *arg_target = NULL;
 static bool arg_dry_run = false;
index 4c20a88..31d41af 100644 (file)
@@ -47,7 +47,7 @@
 
                 <allow send_destination="org.freedesktop.portable1"
                        send_interface="org.freedesktop.portable1.Manager"
-                       send_member="GetImageUnitFiles"/>
+                       send_member="GetImageMetadata"/>
 
                 <allow send_destination="org.freedesktop.portable1"
                        send_interface="org.freedesktop.portable1.Manager"
 
                 <allow send_destination="org.freedesktop.portable1"
                        send_interface="org.freedesktop.portable1.Image"
-                       send_member="GetUnitFiles"/>
+                       send_member="GetMetadata"/>
 
                 <allow send_destination="org.freedesktop.portable1"
                        send_interface="org.freedesktop.portable1.Image"
-                       send_member="GetImageState"/>
+                       send_member="GetState"/>
 
                 <allow send_destination="org.freedesktop.portable1"
                        send_interface="org.freedesktop.portable1.Image"
index 01fd1a9..9b6cc21 100644 (file)
@@ -17,6 +17,7 @@
 #include "loop-util.h"
 #include "machine-image.h"
 #include "mkdir.h"
+#include "nulstr-util.h"
 #include "os-util.h"
 #include "path-lookup.h"
 #include "portable.h"
@@ -24,6 +25,7 @@
 #include "set.h"
 #include "signal-util.h"
 #include "socket-util.h"
+#include "sort-util.h"
 #include "string-table.h"
 #include "strv.h"
 #include "tmpfile-util.h"
@@ -784,7 +786,7 @@ static int install_profile_dropin(
 
         if (flags & PORTABLE_PREFER_COPY) {
 
-                r = copy_file_atomic(from, dropin, 0644, 0, COPY_REFLINK);
+                r = copy_file_atomic(from, dropin, 0644, 0, 0, COPY_REFLINK);
                 if (r < 0)
                         return log_debug_errno(r, "Failed to copy %s %s %s: %m", from, special_glyph(SPECIAL_GLYPH_ARROW), dropin);
 
index 3cbdb0b..89168c3 100644 (file)
@@ -359,8 +359,8 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("ListImages", NULL, "a(ssbtttso)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetImageOSRelease", "s", "a{ss}", method_get_image_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetImageState", "s", "s", method_get_image_state, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetImageMetadata", "sas", "saya{say}", method_get_image_metadata, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("GetImageState", "s", "s", method_get_image_state, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("AttachImage", "sassbs", "a(sss)", method_attach_image, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("DetachImage", "sb", "a(sss)", method_detach_image, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
index 3605598..fd2b7c9 100644 (file)
@@ -1,5 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-label.h"
@@ -523,7 +528,7 @@ const sd_bus_vtable image_vtable[] = {
         SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
         SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
         SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
-        SD_BUS_METHOD("GetMedatadata", "as", "saya{say}", bus_image_method_get_metadata, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("GetMetadata", "as", "saya{say}", bus_image_method_get_metadata, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetState", NULL, "s", bus_image_method_get_state, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Attach", "assbs", "a(sss)", bus_image_method_attach, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Detach", "b", "a(sss)", bus_image_method_detach, SD_BUS_VTABLE_UNPRIVILEGED),
index 49a359f..5464360 100644 (file)
@@ -1,5 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include "sd-bus.h"
 #include "sd-daemon.h"
 
index 90f542a..4e83fc8 100644 (file)
@@ -4,6 +4,8 @@
 #include <stdbool.h>
 #include <stdio.h>
 #include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "main-func.h"
index 0c5f329..71c2dba 100644 (file)
@@ -51,7 +51,7 @@ static int run(int argc, char *argv[]) {
         if (buf_size < POOL_SIZE_MIN)
                 buf_size = POOL_SIZE_MIN;
 
-        r = mkdir_parents_label(RANDOM_SEED, 0755);
+        r = mkdir_parents(RANDOM_SEED, 0755);
         if (r < 0)
                 return log_error_errno(r, "Failed to create directory " RANDOM_SEED_DIR ": %m");
 
index 0bac355..0df29aa 100644 (file)
@@ -47,6 +47,31 @@ static int track_pid(Hashmap **h, const char *path, pid_t pid) {
         return 0;
 }
 
+static int do_remount(const char *path, bool force_rw, Hashmap **pids) {
+        pid_t pid;
+        int r;
+
+        log_debug("Remounting %s...", path);
+
+        r = safe_fork(force_rw ? "(remount-rw)" : "(remount)",
+                      FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
+        if (r < 0)
+                return r;
+        if (r == 0) {
+                /* Child */
+                execv(MOUNT_PATH,
+                      STRV_MAKE(MOUNT_PATH,
+                                path,
+                                "-o",
+                                force_rw ? "remount,rw" : "remount"));
+                log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
+                _exit(EXIT_FAILURE);
+        }
+
+        /* Parent */
+        return track_pid(pids, path, pid);
+}
+
 static int run(int argc, char *argv[]) {
         _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
         _cleanup_endmntent_ FILE *f = NULL;
@@ -66,36 +91,20 @@ static int run(int argc, char *argv[]) {
         if (!f) {
                 if (errno != ENOENT)
                         return log_error_errno(errno, "Failed to open /etc/fstab: %m");
-        } else {
+        } else
                 while ((me = getmntent(f))) {
-                        pid_t pid;
-
-                        /* Remount the root fs, /usr and all API VFS */
+                        /* Remount the root fs, /usr, and all API VFSs */
                         if (!mount_point_is_api(me->mnt_dir) &&
                             !PATH_IN_SET(me->mnt_dir, "/", "/usr"))
                                 continue;
 
-                        log_debug("Remounting %s...", me->mnt_dir);
-
                         if (path_equal(me->mnt_dir, "/"))
                                 has_root = true;
 
-                        r = safe_fork("(remount)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
-                        if (r < 0)
-                                return r;
-                        if (r == 0) {
-                                /* Child */
-                                execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, me->mnt_dir, "-o", "remount"));
-                                log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
-                                _exit(EXIT_FAILURE);
-                        }
-
-                        /* Parent */
-                        r = track_pid(&pids, me->mnt_dir, pid);
+                        r = do_remount(me->mnt_dir, false, &pids);
                         if (r < 0)
                                 return r;
                 }
-        }
 
         if (!has_root) {
                 /* The $SYSTEMD_REMOUNT_ROOT_RW environment variable is set by systemd-gpt-auto-generator to tell us
@@ -103,27 +112,14 @@ static int run(int argc, char *argv[]) {
                  * which takes precedence. */
 
                 r = getenv_bool("SYSTEMD_REMOUNT_ROOT_RW");
-                if (r > 0) {
-                        pid_t pid;
-
-                        log_debug("Remounting / writable...");
+                if (r < 0 && r != -ENXIO)
+                        log_warning_errno(r, "Failed to parse $SYSTEMD_REMOUNT_ROOT_RW, ignoring: %m");
 
-                        r = safe_fork("(remount-rw)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &pid);
-                        if (r < 0)
-                                return r;
-                        if (r == 0) {
-                                /* Child */
-                                execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, "/", "-o", "remount,rw"));
-                                log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
-                                _exit(EXIT_FAILURE);
-                        }
-
-                        r = track_pid(&pids, "/", pid);
+                if (r > 0) {
+                        r = do_remount("/", true, &pids);
                         if (r < 0)
                                 return r;
-
-                } else if (r < 0 && r != -ENXIO)
-                        log_warning_errno(r, "Failed to parse $SYSTEMD_REMOUNT_ROOT_RW, ignoring: %m");
+                }
         }
 
         r = 0;
index ee7a0ea..f8f6c2d 100644 (file)
@@ -11,6 +11,7 @@
 #include "fileio.h"
 #include "log.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "socket-util.h"
 #include "string-util.h"
 #include "util.h"
index 4d533f8..1d2fc71 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <getopt.h>
+#include <locale.h>
 #include <net/if.h>
 
 #include "sd-bus.h"
@@ -118,10 +119,8 @@ int ifname_mangle(const char *s) {
                 }
         }
 
-        if (arg_ifindex > 0 && arg_ifindex != ifi) {
-                log_error("Specified multiple different interfaces. Refusing.");
-                return -EINVAL;
-        }
+        if (arg_ifindex > 0 && arg_ifindex != ifi)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified multiple different interfaces. Refusing.");
 
         arg_ifindex = ifi;
         free_and_replace(arg_ifname, iface);
index 5b547ba..4fc281e 100644 (file)
@@ -4,12 +4,13 @@
 #include "bus-common-errors.h"
 #include "bus-util.h"
 #include "dns-domain.h"
+#include "memory-util.h"
 #include "missing_capability.h"
 #include "resolved-bus.h"
 #include "resolved-def.h"
 #include "resolved-dns-synthesize.h"
-#include "resolved-dnssd.h"
 #include "resolved-dnssd-bus.h"
+#include "resolved-dnssd.h"
 #include "resolved-link-bus.h"
 #include "user-util.h"
 #include "utf8.h"
index d7252d3..0ee7340 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <stdio.h>
+
 #include "alloc-util.h"
 #include "dns-domain.h"
 #include "resolved-dns-answer.h"
@@ -87,40 +89,33 @@ int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFl
                 if (a->items[i].ifindex != ifindex)
                         continue;
 
-                r = dns_resource_record_equal(a->items[i].rr, rr);
+                r = dns_resource_key_equal(a->items[i].rr->key, rr->key);
                 if (r < 0)
                         return r;
-                if (r > 0) {
-                        /* Don't mix contradicting TTLs (see below) */
-                        if ((rr->ttl == 0) != (a->items[i].rr->ttl == 0))
-                                return -EINVAL;
-
-                        /* 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;
-                        }
+                if (r == 0)
+                        continue;
 
-                        a->items[i].flags |= flags;
-                        return 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;
 
-                r = dns_resource_key_equal(a->items[i].rr->key, rr->key);
+                r = dns_resource_record_payload_equal(a->items[i].rr, rr);
                 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 (r == 0)
+                        continue;
+
+                /* 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;
         }
 
         return dns_answer_add_raw(a, rr, ifindex, flags);
index 14acc4e..a5ded5a 100644 (file)
 #include "fileio.h"
 #include "gcrypt-util.h"
 #include "hexdecoct.h"
+#include "memory-util.h"
 #include "resolved-dns-dnssec.h"
 #include "resolved-dns-packet.h"
+#include "sort-util.h"
 #include "string-table.h"
 
 #define VERIFY_RRS_MAX 256
@@ -1797,22 +1799,14 @@ static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) {
         return dns_name_between(dns_resource_key_name(rr->key), name, rr->nsec.next_domain_name);
 }
 
-static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) {
-        _cleanup_free_ char *wc = NULL;
-        const char *common_suffix, *signer;
-        int r;
+static int dnssec_nsec_generate_wildcard(DnsResourceRecord *rr, const char *name, char **wc) {
+        const char *common_suffix1, *common_suffix2, *signer;
+        int r, labels1, labels2;
 
         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...
-         */
+        /* Generates "Wildcard at the Closest Encloser" for the given name and NSEC RR. */
 
         r = dns_resource_record_signer(rr, &signer);
         if (r < 0)
@@ -1822,23 +1816,31 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name)
         if (r <= 0)
                 return r;
 
-        r = dns_name_endswith(name, dns_resource_key_name(rr->key));
+        r = dns_name_common_suffix(name, dns_resource_key_name(rr->key), &common_suffix1);
         if (r < 0)
                 return r;
-        if (r > 0)  /* If the name we are interested in is a child of the NSEC RR, then append the asterisk to the NSEC
-                     * RR's name. */
-                r = dns_name_concat("*", dns_resource_key_name(rr->key), 0, &wc);
-        else {
-                r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix);
-                if (r < 0)
-                        return r;
 
-                r = dns_name_concat("*", common_suffix, 0, &wc);
-        }
+        r = dns_name_common_suffix(name, rr->nsec.next_domain_name, &common_suffix2);
+        if (r < 0)
+                return r;
+
+        labels1 = dns_name_count_labels(common_suffix1);
+        if (labels1 < 0)
+            return labels1;
+
+        labels2 = dns_name_count_labels(common_suffix2);
+        if (labels2 < 0)
+            return labels2;
+
+        if (labels1 > labels2)
+                r = dns_name_concat("*", common_suffix1, 0, wc);
+        else
+                r = dns_name_concat("*", common_suffix2, 0, wc);
+
         if (r < 0)
                 return r;
 
-        return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name);
+        return 0;
 }
 
 int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
@@ -1942,14 +1944,30 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
                         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 (covering_rr) {
+                _cleanup_free_ char *wc = NULL;
+                r = dnssec_nsec_generate_wildcard(covering_rr, name, &wc);
                 if (r < 0)
                         return r;
-                if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) {
-                        wildcard_rr = rr;
-                        wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
+
+                DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) {
+
+                        if (rr->key->class != key->class)
+                                continue;
+
+                        if (rr->key->type != DNS_TYPE_NSEC)
+                                continue;
+
+                        /* Check if this NSEC RR proves the nonexistence of the wildcard */
+                        r = dnssec_nsec_covers(rr, wc);
+                        if (r < 0)
+                                return r;
+                        if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) {
+                                wildcard_rr = rr;
+                                wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
+                        }
                 }
         }
 
index 572271b..a4959cd 100644 (file)
@@ -6,7 +6,9 @@
 
 #include "alloc-util.h"
 #include "dns-domain.h"
+#include "memory-util.h"
 #include "resolved-dns-packet.h"
+#include "set.h"
 #include "string-table.h"
 #include "strv.h"
 #include "unaligned.h"
@@ -2133,6 +2135,17 @@ static int dns_packet_extract_question(DnsPacket *p, DnsQuestion **ret_question)
                 if (!question)
                         return -ENOMEM;
 
+                _cleanup_set_free_ Set *keys = NULL; /* references to keys are kept by Question */
+
+                keys = set_new(&dns_resource_key_hash_ops);
+                if (!keys)
+                        return log_oom();
+
+                r = set_reserve(keys, n * 2); /* Higher multipliers give slightly higher efficiency through
+                                               * hash collisions, but the gains quickly drop of after 2. */
+                if (r < 0)
+                        return r;
+
                 for (i = 0; i < n; i++) {
                         _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
                         bool cache_flush;
@@ -2147,7 +2160,14 @@ static int dns_packet_extract_question(DnsPacket *p, DnsQuestion **ret_question)
                         if (!dns_type_is_valid_query(key->type))
                                 return -EBADMSG;
 
-                        r = dns_question_add(question, key);
+                        r = set_put(keys, key);
+                        if (r < 0)
+                                return r;
+                        if (r == 0)
+                                /* Already in the Question, let's skip */
+                                continue;
+
+                        r = dns_question_add_raw(question, key);
                         if (r < 0)
                                 return r;
                 }
@@ -2239,7 +2259,7 @@ static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) {
                                          * 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.");
+                                        log_debug("OPT RR contains RFC6975 data, ignoring.");
                                         bad_opt = true;
                                         continue;
                                 }
index 008860b..56614c4 100644 (file)
@@ -119,12 +119,12 @@ static inline uint16_t DNS_PACKET_PAYLOAD_SIZE_MAX(DnsPacket *p) {
 
         /* Returns the advertised maximum size for replies, or the DNS default if there's nothing defined. */
 
+        if (p->ipproto == IPPROTO_TCP) /* we ignore EDNS(0) size data on TCP, like everybody else */
+                return DNS_PACKET_SIZE_MAX;
+
         if (p->opt)
                 return MAX(DNS_PACKET_UNICAST_SIZE_MAX, p->opt->key->class);
 
-        if (p->ipproto == IPPROTO_TCP)
-                return DNS_PACKET_SIZE_MAX;
-
         return DNS_PACKET_UNICAST_SIZE_MAX;
 }
 
index 535ef4e..4a41921 100644 (file)
@@ -387,10 +387,8 @@ DnsQuery *dns_query_free(DnsQuery *q) {
 
         if (q->request_dns_stream) {
                 /* Detach the stream from our query, in case something else keeps a reference to it. */
-                q->request_dns_stream->complete = NULL;
-                q->request_dns_stream->on_packet = NULL;
-                q->request_dns_stream->query = NULL;
-                dns_stream_unref(q->request_dns_stream);
+                (void) set_remove(q->request_dns_stream->queries, q);
+                q->request_dns_stream = dns_stream_unref(q->request_dns_stream);
         }
 
         free(q->request_address_string);
index 1ed9171..60cd34b 100644 (file)
@@ -32,8 +32,20 @@ static DnsQuestion *dns_question_free(DnsQuestion *q) {
 
 DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsQuestion, dns_question, dns_question_free);
 
+int dns_question_add_raw(DnsQuestion *q, DnsResourceKey *key) {
+        /* Insert without checking for duplicates. */
+
+        assert(key);
+        assert(q);
+
+        if (q->n_keys >= q->n_allocated)
+                return -ENOSPC;
+
+        q->keys[q->n_keys++] = dns_resource_key_ref(key);
+        return 0;
+}
+
 int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
-        size_t i;
         int r;
 
         assert(key);
@@ -41,7 +53,7 @@ int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
         if (!q)
                 return -ENOSPC;
 
-        for (i = 0; i < q->n_keys; i++) {
+        for (size_t i = 0; i < q->n_keys; i++) {
                 r = dns_resource_key_equal(q->keys[i], key);
                 if (r < 0)
                         return r;
@@ -49,11 +61,7 @@ int dns_question_add(DnsQuestion *q, DnsResourceKey *key) {
                         return 0;
         }
 
-        if (q->n_keys >= q->n_allocated)
-                return -ENOSPC;
-
-        q->keys[q->n_keys++] = dns_resource_key_ref(key);
-        return 0;
+        return dns_question_add_raw(q, key);
 }
 
 int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain) {
index f513bf0..0803f49 100644 (file)
@@ -22,6 +22,7 @@ int dns_question_new_address(DnsQuestion **ret, int family, const char *name, bo
 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_raw(DnsQuestion *q, DnsResourceKey *key);
 int dns_question_add(DnsQuestion *q, DnsResourceKey *key);
 
 int dns_question_matches_rr(DnsQuestion *q, DnsResourceRecord *rr, const char *search_domain);
index a1dffb0..4cbb972 100644 (file)
@@ -557,18 +557,10 @@ int dns_resource_record_new_address(DnsResourceRecord **ret, int family, const u
         ((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 dns_resource_record_payload_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;
+        /* Check if a and b are the same, but don't look at their keys */
 
         if (a->unparseable != b->unparseable)
                 return 0;
@@ -692,6 +684,22 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor
         }
 }
 
+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;
+
+        return dns_resource_record_payload_equal(a, b);
+}
+
 static char* format_location(uint32_t latitude, uint32_t longitude, uint32_t altitude,
                              uint8_t size, uint8_t horiz_pre, uint8_t vert_pre) {
         char *s;
@@ -954,7 +962,6 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
         case DNS_TYPE_DNSKEY: {
                 _cleanup_free_ char *alg = NULL;
                 char *ss;
-                int n;
                 uint16_t key_tag;
 
                 key_tag = dnssec_keytag(rr, true);
@@ -963,16 +970,15 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
                 if (r < 0)
                         return NULL;
 
-                r = asprintf(&s, "%s %u %u %s %n",
+                r = asprintf(&s, "%s %u %u %s",
                              k,
                              rr->dnskey.flags,
                              rr->dnskey.protocol,
-                             alg,
-                             &n);
+                             alg);
                 if (r < 0)
                         return NULL;
 
-                r = base64_append(&s, n,
+                r = base64_append(&s, r,
                                   rr->dnskey.key, rr->dnskey.key_size,
                                   8, columns());
                 if (r < 0)
@@ -998,7 +1004,6 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
                 _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);
 
@@ -1017,7 +1022,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
                 /* TYPE?? follows
                  * http://tools.ietf.org/html/rfc3597#section-5 */
 
-                r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s %n",
+                r = asprintf(&s, "%s %s%.*u %s %u %u %s %s %u %s",
                              k,
                              type ?: "TYPE",
                              type ? 0 : 1, type ? 0u : (unsigned) rr->rrsig.type_covered,
@@ -1027,12 +1032,11 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
                              expiration,
                              inception,
                              rr->rrsig.key_tag,
-                             rr->rrsig.signer,
-                             &n);
+                             rr->rrsig.signer);
                 if (r < 0)
                         return NULL;
 
-                r = base64_append(&s, n,
+                r = base64_append(&s, r,
                                   rr->rrsig.signature, rr->rrsig.signature_size,
                                   8, columns());
                 if (r < 0)
@@ -1138,15 +1142,11 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) {
         }
 
         case DNS_TYPE_OPENPGPKEY: {
-                int n;
-
-                r = asprintf(&s, "%s %n",
-                             k,
-                             &n);
+                r = asprintf(&s, "%s", k);
                 if (r < 0)
                         return NULL;
 
-                r = base64_append(&s, n,
+                r = base64_append(&s, r,
                                   rr->generic.data, rr->generic.data_size,
                                   8, columns());
                 if (r < 0)
index e02fa2d..291447f 100644 (file)
@@ -9,6 +9,7 @@
 #include "in-addr-util.h"
 #include "list.h"
 #include "string-util.h"
+#include "time-util.h"
 
 typedef struct DnsResourceKey DnsResourceKey;
 typedef struct DnsResourceRecord DnsResourceRecord;
@@ -308,6 +309,8 @@ 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_payload_equal(const DnsResourceRecord *a, const DnsResourceRecord *b);
+
 const char* dns_resource_record_to_string(DnsResourceRecord *rr);
 DnsResourceRecord *dns_resource_record_copy(DnsResourceRecord *rr);
 DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref);
index aee339a..cb7b186 100644 (file)
@@ -11,6 +11,8 @@
 #define DNS_STREAM_TIMEOUT_USEC (10 * USEC_PER_SEC)
 #define DNS_STREAMS_MAX 128
 
+#define DNS_QUERIES_PER_STREAM 32
+
 static void dns_stream_stop(DnsStream *s) {
         assert(s);
 
@@ -36,12 +38,16 @@ static int dns_stream_update_io(DnsStream *s) {
                 s->n_written = 0;
                 f |= EPOLLOUT;
         }
-        if (!s->read_packet || s->n_read < sizeof(s->read_size) + s->read_packet->size)
+
+        /* Let's read a packet if we haven't queued any yet. Except if we already hit a limit of parallel
+         * queries for this connection. */
+        if ((!s->read_packet || s->n_read < sizeof(s->read_size) + s->read_packet->size) &&
+                set_size(s->queries) < DNS_QUERIES_PER_STREAM)
                 f |= EPOLLIN;
 
 #if ENABLE_DNS_OVER_TLS
         /* For handshake and clean closing purposes, TLS can override requested events */
-        if (s->dnstls_events)
+        if (s->dnstls_events != 0)
                 f = s->dnstls_events;
 #endif
 
@@ -52,6 +58,10 @@ static int dns_stream_complete(DnsStream *s, int error) {
         _cleanup_(dns_stream_unrefp) _unused_ DnsStream *ref = dns_stream_ref(s); /* Protect stream while we process it */
 
         assert(s);
+        assert(error >= 0);
+
+        /* Error is > 0 when the connection failed for some reason in the network stack. It's == 0 if we sent
+         * and receieved exactly one packet each (in the LLMNR client case). */
 
 #if ENABLE_DNS_OVER_TLS
         if (s->encrypted) {
@@ -281,6 +291,7 @@ static int on_stream_timeout(sd_event_source *es, usec_t usec, void *userdata) {
 
 static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *userdata) {
         _cleanup_(dns_stream_unrefp) DnsStream *s = dns_stream_ref(userdata); /* Protect stream while we process it */
+        bool progressed = false;
         int r;
 
         assert(s);
@@ -324,8 +335,10 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
                 if (ss < 0) {
                         if (!IN_SET(-ss, EINTR, EAGAIN))
                                 return dns_stream_complete(s, -ss);
-                } else
+                } else {
+                        progressed = true;
                         s->n_written += ss;
+                }
 
                 /* Are we done? If so, disable the event source for EPOLLOUT */
                 if (s->n_written >= sizeof(s->write_size) + s->write_packet->size) {
@@ -348,8 +361,10 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
                                         return dns_stream_complete(s, -ss);
                         } else if (ss == 0)
                                 return dns_stream_complete(s, ECONNRESET);
-                        else
+                        else {
+                                progressed = true;
                                 s->n_read += ss;
+                        }
                 }
 
                 if (s->n_read >= sizeof(s->read_size)) {
@@ -420,10 +435,21 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use
                 }
         }
 
-        if ((s->write_packet && s->n_written >= sizeof(s->write_size) + s->write_packet->size) &&
+        /* Call "complete" callback if finished reading and writing one packet, and there's nothing else left
+         * to write. */
+        if (s->type == DNS_STREAM_LLMNR_SEND &&
+            (s->write_packet && s->n_written >= sizeof(s->write_size) + s->write_packet->size) &&
+            ordered_set_isempty(s->write_queue) &&
             (s->read_packet && s->n_read >= sizeof(s->read_size) + s->read_packet->size))
                 return dns_stream_complete(s, 0);
 
+        /* If we did something, let's restart the timeout event source */
+        if (progressed && s->timeout_event_source) {
+                r = sd_event_source_set_time(s->timeout_event_source, now(clock_boottime_or_monotonic()) + DNS_STREAM_TIMEOUT_USEC);
+                if (r < 0)
+                        log_warning_errno(errno, "Couldn't restart TCP connection timeout, ignoring: %m");
+        }
+
         return 0;
 }
 
@@ -437,7 +463,7 @@ static DnsStream *dns_stream_free(DnsStream *s) {
 
         if (s->manager) {
                 LIST_REMOVE(streams, s->manager->dns_streams, s);
-                s->manager->n_dns_streams--;
+                s->manager->n_dns_streams[s->type]--;
         }
 
 #if ENABLE_DNS_OVER_TLS
@@ -462,6 +488,7 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsStream, dns_stream, dns_stream_free);
 int dns_stream_new(
                 Manager *m,
                 DnsStream **ret,
+                DnsStreamType type,
                 DnsProtocol protocol,
                 int fd,
                 const union sockaddr_union *tfo_address) {
@@ -471,9 +498,13 @@ int dns_stream_new(
 
         assert(m);
         assert(ret);
+        assert(type >= 0);
+        assert(type < _DNS_STREAM_TYPE_MAX);
+        assert(protocol >= 0);
+        assert(protocol < _DNS_PROTOCOL_MAX);
         assert(fd >= 0);
 
-        if (m->n_dns_streams > DNS_STREAMS_MAX)
+        if (m->n_dns_streams[type] > DNS_STREAMS_MAX)
                 return -EBUSY;
 
         s = new(DnsStream, 1);
@@ -508,7 +539,7 @@ int dns_stream_new(
         (void) sd_event_source_set_description(s->timeout_event_source, "dns-stream-timeout");
 
         LIST_PREPEND(streams, m->dns_streams, s);
-        m->n_dns_streams++;
+        m->n_dns_streams[type]++;
         s->manager = m;
 
         s->fd = fd;
index f18fc91..780051b 100644 (file)
@@ -5,6 +5,15 @@
 
 typedef struct DnsStream DnsStream;
 
+typedef enum DnsStreamType {
+        DNS_STREAM_LOOKUP,        /* Outgoing connection to a classic DNS server */
+        DNS_STREAM_LLMNR_SEND,    /* Outgoing LLMNR TCP lookup */
+        DNS_STREAM_LLMNR_RECV,    /* Incoming LLMNR TCP lookup */
+        DNS_STREAM_STUB,          /* Incoming DNS stub connection */
+        _DNS_STREAM_TYPE_MAX,
+        _DNS_STREAM_TYPE_INVALID = -1,
+} DnsStreamType;
+
 #include "resolved-dns-packet.h"
 #include "resolved-dns-transaction.h"
 #include "resolved-manager.h"
@@ -25,6 +34,7 @@ struct DnsStream {
         Manager *manager;
         unsigned n_ref;
 
+        DnsStreamType type;
         DnsProtocol protocol;
 
         int fd;
@@ -58,7 +68,7 @@ struct DnsStream {
 
         LIST_HEAD(DnsTransaction, transactions); /* when used by the transaction logic */
         DnsServer *server;                       /* when used by the transaction logic */
-        DnsQuery *query;                         /* when used by the DNS stub logic */
+        Set *queries;                            /* when used by the DNS stub logic */
 
         /* used when DNS-over-TLS is enabled */
         bool encrypted:1;
@@ -66,7 +76,7 @@ struct DnsStream {
         LIST_FIELDS(DnsStream, streams);
 };
 
-int dns_stream_new(Manager *m, DnsStream **s, DnsProtocol protocol, int fd, const union sockaddr_union *tfo_address);
+int dns_stream_new(Manager *m, DnsStream **s, DnsStreamType type, DnsProtocol protocol, int fd, const union sockaddr_union *tfo_address);
 #if ENABLE_DNS_OVER_TLS
 int dns_stream_connect_tls(DnsStream *s, void *tls_session);
 #endif
index a00716c..ce994a7 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include "errno-util.h"
 #include "fd-util.h"
 #include "missing_network.h"
 #include "resolved-dns-stub.h"
@@ -91,7 +92,14 @@ static int dns_stub_finish_reply_packet(
 
         assert(p);
 
-        if (!add_opt) {
+        if (add_opt) {
+                r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, rcode, NULL);
+                if (r == -EMSGSIZE) /* Hit the size limit? then indicate truncation */
+                        tc = true;
+                else if (r < 0)
+                        return r;
+
+        } else {
                 /* If the client can't to EDNS0, don't do DO either */
                 edns0_do = false;
 
@@ -117,23 +125,9 @@ static int dns_stub_finish_reply_packet(
                                                               0  /* cd */,
                                                               rcode));
 
-        if (add_opt) {
-                r = dns_packet_append_opt(p, ADVERTISE_DATAGRAM_SIZE_MAX, edns0_do, rcode, NULL);
-                if (r < 0)
-                        return r;
-        }
-
         return 0;
 }
 
-static void dns_stub_detach_stream(DnsStream *s) {
-        assert(s);
-
-        s->complete = NULL;
-        s->on_packet = NULL;
-        s->query = NULL;
-}
-
 static int dns_stub_send(Manager *m, DnsStream *s, DnsPacket *p, DnsPacket *reply) {
         int r;
 
@@ -197,17 +191,19 @@ static void dns_stub_query_complete(DnsQuery *q) {
                         break;
                 }
 
-                r = dns_query_process_cname(q);
-                if (r == -ELOOP) {
-                        (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false);
-                        break;
-                }
-                if (r < 0) {
-                        log_debug_errno(r, "Failed to process CNAME: %m");
-                        break;
+                if (!truncated) {
+                        r = dns_query_process_cname(q);
+                        if (r == -ELOOP) {
+                                (void) dns_stub_send_failure(q->manager, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false);
+                                break;
+                        }
+                        if (r < 0) {
+                                log_debug_errno(r, "Failed to process CNAME: %m");
+                                break;
+                        }
+                        if (r == DNS_QUERY_RESTARTED)
+                                return;
                 }
-                if (r == DNS_QUERY_RESTARTED)
-                        return;
 
                 r = dns_stub_finish_reply_packet(
                                 q->reply_dns_packet,
@@ -257,27 +253,27 @@ static void dns_stub_query_complete(DnsQuery *q) {
                 assert_not_reached("Impossible state");
         }
 
-        /* If there's a packet to write set, let's leave the stream around */
-        if (q->request_dns_stream && DNS_STREAM_QUEUED(q->request_dns_stream)) {
-
-                /* Detach the stream from our query (make it an orphan), but do not drop the reference to it. The
-                 * default completion action of the stream will drop the reference. */
-
-                dns_stub_detach_stream(q->request_dns_stream);
-                q->request_dns_stream = NULL;
-        }
-
         dns_query_free(q);
 }
 
 static int dns_stub_stream_complete(DnsStream *s, int error) {
         assert(s);
 
-        log_debug_errno(error, "DNS TCP connection terminated, destroying query: %m");
+        log_debug_errno(error, "DNS TCP connection terminated, destroying queries: %m");
+
+        for (;;) {
+                DnsQuery *q;
+
+                q = set_first(s->queries);
+                if (!q)
+                        break;
 
-        assert(s->query);
-        dns_query_free(s->query);
+                dns_query_free(q);
+        }
 
+        /* This drops the implicit ref we keep around since it was allocated, as incoming stub connections
+         * should be kept as long as the client wants to. */
+        dns_stream_unref(s);
         return 0;
 }
 
@@ -289,8 +285,6 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) {
         assert(p);
         assert(p->protocol == DNS_PROTOCOL_DNS);
 
-        /* Takes ownership of the *s stream object */
-
         if (in_addr_is_localhost(p->family, &p->sender) <= 0 ||
             in_addr_is_localhost(p->family, &p->destination) <= 0) {
                 log_error("Got packet on unexpected IP range, refusing.");
@@ -351,9 +345,19 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) {
         q->complete = dns_stub_query_complete;
 
         if (s) {
-                s->on_packet = NULL;
-                s->complete = dns_stub_stream_complete;
-                s->query = q;
+                /* Remember which queries belong to this stream, so that we can cancel them when the stream
+                 * is disconnected early */
+
+                r = set_ensure_allocated(&s->queries, &trivial_hash_ops);
+                if (r < 0) {
+                        log_oom();
+                        goto fail;
+                }
+
+                if (set_put(s->queries, q) < 0) {
+                        log_oom();
+                        goto fail;
+                }
         }
 
         r = dns_query_go(q);
@@ -367,9 +371,6 @@ static void dns_stub_process_query(Manager *m, DnsStream *s, DnsPacket *p) {
         return;
 
 fail:
-        if (s && DNS_STREAM_QUEUED(s))
-                dns_stub_detach_stream(s);
-
         dns_query_free(q);
 }
 
@@ -421,8 +422,9 @@ static int manager_dns_stub_udp_fd(Manager *m) {
                 return r;
 
         /* Make sure no traffic from outside the local host can leak to onto this socket */
-        if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, "lo", 3) < 0)
-                return -errno;
+        r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
+        if (r < 0)
+                return r;
 
         if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
                 return -errno;
@@ -451,10 +453,6 @@ static int on_dns_stub_stream_packet(DnsStream *s) {
         } else
                 log_debug("Invalid DNS stub TCP packet, ignoring.");
 
-        /* Drop the reference to the stream. Either a query was created and added its own reference to the stream now,
-         * or that didn't happen in which case we want to free the stream */
-        dns_stream_unref(s);
-
         return 0;
 }
 
@@ -465,22 +463,22 @@ static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void
 
         cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
         if (cfd < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
+                if (ERRNO_IS_ACCEPT_AGAIN(errno))
                         return 0;
 
                 return -errno;
         }
 
-        r = dns_stream_new(m, &stream, DNS_PROTOCOL_DNS, cfd, NULL);
+        r = dns_stream_new(m, &stream, DNS_STREAM_STUB, DNS_PROTOCOL_DNS, cfd, NULL);
         if (r < 0) {
                 safe_close(cfd);
                 return r;
         }
 
         stream->on_packet = on_dns_stub_stream_packet;
+        stream->complete = dns_stub_stream_complete;
 
-        /* We let the reference to the stream dangling here, it will either be dropped by the default "complete" action
-         * of the stream, or by our packet callback, or when the manager is shut down. */
+        /* We let the reference to the stream dangle here, it will be dropped later by the complete callback. */
 
         return 0;
 }
@@ -518,8 +516,9 @@ static int manager_dns_stub_tcp_fd(Manager *m) {
                 return r;
 
         /* Make sure no traffic from outside the local host can leak to onto this socket */
-        if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, "lo", 3) < 0)
-                return -errno;
+        r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX);
+        if (r < 0)
+                return r;
 
         if (bind(fd, &sa.sa, sizeof(sa.in)) < 0)
                 return -errno;
index 4a2d2cc..9cac91f 100644 (file)
@@ -6,6 +6,7 @@
 #include "alloc-util.h"
 #include "dns-domain.h"
 #include "errno-list.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "random-util.h"
 #include "resolved-dns-cache.h"
@@ -540,12 +541,8 @@ static int on_stream_packet(DnsStream *s) {
         if (t)
                 return dns_transaction_on_stream_packet(t, p);
 
-        /* Ignore incorrect transaction id as transaction can have been canceled */
-        if (dns_packet_validate_reply(p) <= 0) {
-                log_debug("Invalid TCP reply packet.");
-                on_stream_complete(s, 0);
-        }
-
+        /* Ignore incorrect transaction id as an old transaction can have been canceled. */
+        log_debug("Received unexpected TCP reply packet with id %" PRIu16 ", ignoring.", DNS_PACKET_ID(p));
         return 0;
 }
 
@@ -554,9 +551,10 @@ static uint16_t dns_port_for_feature_level(DnsServerFeatureLevel level) {
 }
 
 static int dns_transaction_emit_tcp(DnsTransaction *t) {
-        _cleanup_close_ int fd = -1;
         _cleanup_(dns_stream_unrefp) DnsStream *s = NULL;
+        _cleanup_close_ int fd = -1;
         union sockaddr_union sa;
+        DnsStreamType type;
         int r;
 
         assert(t);
@@ -582,6 +580,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
                 else
                         fd = dns_scope_socket_tcp(t->scope, AF_UNSPEC, NULL, t->server, dns_port_for_feature_level(t->current_feature_level), &sa);
 
+                type = DNS_STREAM_LOOKUP;
                 break;
 
         case DNS_PROTOCOL_LLMNR:
@@ -607,6 +606,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
                         fd = dns_scope_socket_tcp(t->scope, family, &address, NULL, LLMNR_PORT, &sa);
                 }
 
+                type = DNS_STREAM_LLMNR_SEND;
                 break;
 
         default:
@@ -617,7 +617,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
                 if (fd < 0)
                         return fd;
 
-                r = dns_stream_new(t->scope->manager, &s, t->scope->protocol, fd, &sa);
+                r = dns_stream_new(t->scope->manager, &s, type, t->scope->protocol, fd, &sa);
                 if (r < 0)
                         return r;
 
@@ -636,8 +636,8 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) {
 
                 if (t->server) {
                         dns_server_unref_stream(t->server);
-                        t->server->stream = dns_stream_ref(s);
                         s->server = dns_server_ref(t->server);
+                        t->server->stream = dns_stream_ref(s);
                 }
 
                 s->complete = on_stream_complete;
index c5ec93b..d25b5f9 100644 (file)
@@ -9,10 +9,12 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "hexdecoct.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
-#include "resolved-dns-trust-anchor.h"
 #include "resolved-dns-dnssec.h"
+#include "resolved-dns-trust-anchor.h"
 #include "set.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "strv.h"
 
index b8e6a7a..0e6fa1d 100644 (file)
@@ -1,21 +1,15 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "conf-files.h"
 #include "conf-parser.h"
+#include "def.h"
 #include "resolved-dnssd.h"
 #include "resolved-dns-rr.h"
 #include "resolved-manager.h"
 #include "specifier.h"
 #include "strv.h"
 
-const char* const dnssd_service_dirs[] = {
-        "/etc/systemd/dnssd",
-        "/run/systemd/dnssd",
-        "/usr/lib/systemd/dnssd",
-#if HAVE_SPLIT_USR
-        "/lib/systemd/dnssd",
-#endif
-    NULL
-};
+#define DNSSD_SERVICE_DIRS ((const char* const*) CONF_PATHS_STRV("systemd/dnssd"))
 
 DnssdTxtData *dnssd_txtdata_free(DnssdTxtData *txt_data) {
         if (!txt_data)
@@ -92,7 +86,7 @@ static int dnssd_service_load(Manager *manager, const char *filename) {
 
         dropin_dirname = strjoina(service->name, ".dnssd.d");
 
-        r = config_parse_many(filename, dnssd_service_dirs, dropin_dirname,
+        r = config_parse_many(filename, DNSSD_SERVICE_DIRS, dropin_dirname,
                               "Service\0",
                               config_item_perf_lookup, resolved_dnssd_gperf_lookup,
                               false, service);
@@ -195,7 +189,7 @@ int dnssd_load(Manager *manager) {
         if (manager->mdns_support != RESOLVE_SUPPORT_YES)
                 return 0;
 
-        r = conf_files_list_strv(&files, ".dnssd", NULL, 0, dnssd_service_dirs);
+        r = conf_files_list_strv(&files, ".dnssd", NULL, 0, DNSSD_SERVICE_DIRS);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate .dnssd files: %m");
 
index ee21222..6a23d2b 100644 (file)
@@ -1,5 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "fd-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
index dfa55c5..61e5034 100644 (file)
@@ -3,6 +3,7 @@
 #include <netinet/in.h>
 #include <resolv.h>
 
+#include "errno-util.h"
 #include "fd-util.h"
 #include "resolved-llmnr.h"
 #include "resolved-manager.h"
@@ -289,19 +290,21 @@ static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *u
 
         cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
         if (cfd < 0) {
-                if (IN_SET(errno, EAGAIN, EINTR))
+                if (ERRNO_IS_ACCEPT_AGAIN(errno))
                         return 0;
 
                 return -errno;
         }
 
-        r = dns_stream_new(m, &stream, DNS_PROTOCOL_LLMNR, cfd, NULL);
+        r = dns_stream_new(m, &stream, DNS_STREAM_LLMNR_RECV, DNS_PROTOCOL_LLMNR, cfd, NULL);
         if (r < 0) {
                 safe_close(cfd);
                 return r;
         }
 
         stream->on_packet = on_llmnr_stream_packet;
+        /* We don't configure a "complete" handler here, we rely on the default handler than simply drops the
+         * reference to the stream, thus freeing it */
         return 0;
 }
 
index b3d35c8..9b8239b 100644 (file)
@@ -1,9 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
 #include <netinet/in.h>
 #include <poll.h>
 #include <stdio_ext.h>
 #include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #if HAVE_LIBIDN2
 #include <idn2.h>
index 06c76f6..72171f8 100644 (file)
@@ -54,7 +54,7 @@ struct Manager {
         unsigned n_dns_queries;
 
         LIST_HEAD(DnsStream, dns_streams);
-        unsigned n_dns_streams;
+        unsigned n_dns_streams[_DNS_STREAM_TYPE_MAX];
 
         /* Unicast dns */
         LIST_HEAD(DnsServer, dns_servers);
index 89c2497..67080cb 100644 (file)
@@ -8,6 +8,7 @@
 #include "fd-util.h"
 #include "resolved-manager.h"
 #include "resolved-mdns.h"
+#include "sort-util.h"
 
 #define CLEAR_CACHE_FLUSH(x) (~MDNS_RR_CACHE_FLUSH & (x))
 
index 5205071..0435791 100644 (file)
@@ -2,6 +2,9 @@
 
 #include <resolv.h>
 #include <stdio_ext.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "dns-domain.h"
index 0845b2c..2ca9fbd 100644 (file)
@@ -1,5 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "sd-daemon.h"
 #include "sd-event.h"
 
index dbff889..ca35900 100644 (file)
@@ -10,6 +10,7 @@
 #include "log.h"
 #include "resolved-etc-hosts.h"
 #include "strv.h"
+#include "tests.h"
 #include "tmpfile-util.h"
 
 static void test_parse_etc_hosts_system(void) {
@@ -137,9 +138,7 @@ static void test_parse_file(const char *fname) {
 }
 
 int main(int argc, char **argv) {
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         if (argc == 1) {
                 test_parse_etc_hosts_system();
index 22ae26c..c9a511b 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "log.h"
 #include "resolved-dns-packet.h"
+#include "tests.h"
 
 static void test_dns_packet_new(void) {
         size_t i;
@@ -23,10 +24,7 @@ static void test_dns_packet_new(void) {
 }
 
 int main(int argc, char **argv) {
-
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_dns_packet_new();
 
index ac21dc0..16610cd 100644 (file)
@@ -1,7 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
 #include <linux/rfkill.h>
 #include <poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "sd-daemon.h"
 #include "sd-device.h"
@@ -147,8 +151,8 @@ static int load_state(Context *c, const struct rfkill_event *event) {
                 return r;
 
         r = read_one_line_file(state_file, &value);
-        if (r == -ENOENT) {
-                /* No state file? Then save the current state */
+        if (IN_SET(r, -ENOENT, 0)) {
+                /* No state file or it's truncated? Then save the current state */
 
                 r = write_string_file(state_file, one_zero(event->soft), WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC);
                 if (r < 0)
index a5dfac0..7d6c110 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <unistd.h>
+
 #include "alloc-util.h"
 #include "escape.h"
 #include "fd-util.h"
index e9e3128..56aa9aa 100644 (file)
@@ -2,6 +2,9 @@
 
 #include <getopt.h>
 #include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "sd-bus.h"
 #include "sd-event.h"
@@ -10,6 +13,7 @@
 #include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "calendarspec.h"
 #include "env-util.h"
 #include "fd-util.h"
@@ -56,7 +60,7 @@ static enum {
 static char **arg_path_property = NULL;
 static char **arg_socket_property = NULL;
 static char **arg_timer_property = NULL;
-static bool with_timer = false;
+static bool arg_with_timer = false;
 static bool arg_quiet = false;
 static bool arg_aggressive_gc = false;
 static char *arg_working_directory = NULL;
@@ -120,6 +124,8 @@ static int help(void) {
                "     --on-unit-active=SECONDS     Run SECONDS after the last activation\n"
                "     --on-unit-inactive=SECONDS   Run SECONDS after the last deactivation\n"
                "     --on-calendar=SPEC           Realtime timer\n"
+               "     --on-timezone-change         Run when the timezone changes\n"
+               "     --on-clock-change            Run when the realtime clock jumps\n"
                "     --timer-property=NAME=VALUE  Set timer unit property\n"
                "\nSee the %s for details.\n"
                , program_invocation_short_name
@@ -166,6 +172,8 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_ON_UNIT_ACTIVE,
                 ARG_ON_UNIT_INACTIVE,
                 ARG_ON_CALENDAR,
+                ARG_ON_TIMEZONE_CHANGE,
+                ARG_ON_CLOCK_CHANGE,
                 ARG_TIMER_PROPERTY,
                 ARG_PATH_PROPERTY,
                 ARG_SOCKET_PROPERTY,
@@ -206,6 +214,8 @@ static int parse_argv(int argc, char *argv[]) {
                 { "on-unit-active",    required_argument, NULL, ARG_ON_UNIT_ACTIVE    },
                 { "on-unit-inactive",  required_argument, NULL, ARG_ON_UNIT_INACTIVE  },
                 { "on-calendar",       required_argument, NULL, ARG_ON_CALENDAR       },
+                { "on-timezone-change",no_argument,       NULL, ARG_ON_TIMEZONE_CHANGE},
+                { "on-clock-change",   no_argument,       NULL, ARG_ON_CLOCK_CHANGE   },
                 { "timer-property",    required_argument, NULL, ARG_TIMER_PROPERTY    },
                 { "path-property",     required_argument, NULL, ARG_PATH_PROPERTY     },
                 { "socket-property",   required_argument, NULL, ARG_SOCKET_PROPERTY   },
@@ -335,7 +345,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return r;
 
-                        with_timer = true;
+                        arg_with_timer = true;
                         break;
 
                 case ARG_ON_BOOT:
@@ -343,7 +353,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return r;
 
-                        with_timer = true;
+                        arg_with_timer = true;
                         break;
 
                 case ARG_ON_STARTUP:
@@ -351,7 +361,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return r;
 
-                        with_timer = true;
+                        arg_with_timer = true;
                         break;
 
                 case ARG_ON_UNIT_ACTIVE:
@@ -359,7 +369,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return r;
 
-                        with_timer = true;
+                        arg_with_timer = true;
                         break;
 
                 case ARG_ON_UNIT_INACTIVE:
@@ -367,7 +377,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return r;
 
-                        with_timer = true;
+                        arg_with_timer = true;
                         break;
 
                 case ARG_ON_CALENDAR:
@@ -375,7 +385,23 @@ static int parse_argv(int argc, char *argv[]) {
                         if (r < 0)
                                 return r;
 
-                        with_timer = true;
+                        arg_with_timer = true;
+                        break;
+
+                case ARG_ON_TIMEZONE_CHANGE:
+                        r = add_timer_property("OnTimezoneChange", "yes");
+                        if (r < 0)
+                                return r;
+
+                        arg_with_timer = true;
+                        break;
+
+                case ARG_ON_CLOCK_CHANGE:
+                        r = add_timer_property("OnClockChange", "yes");
+                        if (r < 0)
+                                return r;
+
+                        arg_with_timer = true;
                         break;
 
                 case ARG_TIMER_PROPERTY:
@@ -383,7 +409,7 @@ static int parse_argv(int argc, char *argv[]) {
                         if (strv_extend(&arg_timer_property, optarg) < 0)
                                 return log_oom();
 
-                        with_timer = with_timer ||
+                        arg_with_timer = arg_with_timer ||
                                 STARTSWITH_SET(optarg,
                                                "OnActiveSec=",
                                                "OnBootSec=",
@@ -451,10 +477,10 @@ static int parse_argv(int argc, char *argv[]) {
                         assert_not_reached("Unhandled option");
                 }
 
-        with_trigger = !!arg_path_property || !!arg_socket_property || with_timer;
+        with_trigger = !!arg_path_property || !!arg_socket_property || arg_with_timer;
 
         /* currently, only single trigger (path, socket, timer) unit can be created simultaneously */
-        if ((int) !!arg_path_property + (int) !!arg_socket_property + (int) with_timer > 1)
+        if ((int) !!arg_path_property + (int) !!arg_socket_property + (int) arg_with_timer > 1)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Only single trigger (path, socket, timer) unit can be created.");
 
@@ -550,7 +576,7 @@ static int parse_argv(int argc, char *argv[]) {
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Path, socket or timer options are not supported in --scope mode.");
 
-        if (arg_timer_property && !with_timer)
+        if (arg_timer_property && !arg_with_timer)
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "--timer-property= has no effect without any other timer options.");
 
@@ -1642,7 +1668,7 @@ static int run(int argc, char* argv[]) {
                 r = start_transient_trigger(bus, ".path");
         else if (arg_socket_property)
                 r = start_transient_trigger(bus, ".socket");
-        else if (with_timer)
+        else if (arg_with_timer)
                 r = start_transient_trigger(bus, ".timer");
         else
                 r = start_transient_service(bus, &retval);
index 9633514..1ccb4f8 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <errno.h>
 #include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "acl-util.h"
 #include "alloc-util.h"
index 072bf72..ab0c346 100644 (file)
@@ -31,6 +31,7 @@
 #include "io-util.h"
 #include "log.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "mkdir.h"
 #include "process-util.h"
@@ -44,7 +45,6 @@
 #include "tmpfile-util.h"
 #include "umask-util.h"
 #include "utf8.h"
-#include "util.h"
 
 #define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
 
@@ -77,13 +77,18 @@ static int retrieve_key(key_serial_t serial, char ***ret) {
                 n = keyctl(KEYCTL_READ, (unsigned long) serial, (unsigned long) p, (unsigned long) m, 0);
                 if (n < 0)
                         return -errno;
-
                 if (n < m)
                         break;
 
                 explicit_bzero_safe(p, n);
-                free(p);
+
+                if (m > LONG_MAX / 2) /* overflow check */
+                        return -ENOMEM;
                 m *= 2;
+                if ((long) (size_t) m != m) /* make sure that this still fits if converted to size_t */
+                        return -ENOMEM;
+
+                free(p);
         }
 
         l = strv_parse_nulstr(p, n);
@@ -306,9 +311,9 @@ int ask_password_tty(
         };
 
         for (;;) {
+                _cleanup_(erase_char) char c;
                 int sleep_for = -1, k;
                 ssize_t n;
-                char c;
 
                 if (until > 0) {
                         usec_t y;
@@ -385,13 +390,13 @@ int ask_password_tty(
                                 if (!(flags & ASK_PASSWORD_SILENT))
                                         backspace_chars(ttyfd, 1);
 
-                                /* Remove a full UTF-8 codepoint from the end. For that, figure out where the last one
-                                 * begins */
+                                /* Remove a full UTF-8 codepoint from the end. For that, figure out where the
+                                 * last one begins */
                                 q = 0;
                                 for (;;) {
                                         size_t z;
 
-                                        z = utf8_encoded_valid_unichar(passphrase + q);
+                                        z = utf8_encoded_valid_unichar(passphrase + q, (size_t) -1);
                                         if (z == 0) {
                                                 q = (size_t) -1; /* Invalid UTF8! */
                                                 break;
@@ -410,8 +415,8 @@ int ask_password_tty(
 
                                 flags |= ASK_PASSWORD_SILENT;
 
-                                /* There are two ways to enter silent mode. Either by pressing backspace as first key
-                                 * (and only as first key), or ... */
+                                /* There are two ways to enter silent mode. Either by pressing backspace as
+                                 * first key (and only as first key), or ... */
 
                                 if (ttyfd >= 0)
                                         (void) loop_write(ttyfd, "(no echo) ", 10, false);
@@ -440,18 +445,18 @@ int ask_password_tty(
 
                         if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) {
                                 /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */
-                                n = utf8_encoded_valid_unichar(passphrase + codepoint);
+                                n = utf8_encoded_valid_unichar(passphrase + codepoint, (size_t) -1);
                                 if (n >= 0) {
+                                        if (flags & ASK_PASSWORD_ECHO)
+                                                (void) loop_write(ttyfd, passphrase + codepoint, n, false);
+                                        else
+                                                (void) loop_write(ttyfd, "*", 1, false);
                                         codepoint = p;
-                                        (void) loop_write(ttyfd, (flags & ASK_PASSWORD_ECHO) ? &c : "*", 1, false);
                                 }
                         }
 
                         dirty = true;
                 }
-
-                /* Let's forget this char, just to not keep needlessly copies of key material around */
-                c = 'x';
         }
 
         x = strndup(passphrase, p);
index 89d7a7d..657407d 100644 (file)
 #include "fd-util.h"
 #include "log.h"
 #include "macro.h"
+#include "nulstr-util.h"
+#include "path-util.h"
 #include "string-util.h"
 #include "umask-util.h"
 #include "user-util.h"
-#include "util.h"
 
 typedef struct BaseFilesystem {
         const char *dir;
@@ -45,8 +46,8 @@ static const BaseFilesystem table[] = {
 
 int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
         _cleanup_close_ int fd = -1;
-        int r = 0;
         size_t i;
+        int r;
 
         fd = open(root, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
         if (fd < 0)
@@ -68,7 +69,7 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
                                 if (table[i].exists) {
                                         _cleanup_free_ char *p = NULL;
 
-                                        p = strjoin(s, "/", table[i].exists);
+                                        p = path_join(s, table[i].exists);
                                         if (!p)
                                                 return log_oom();
 
@@ -83,9 +84,15 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
                         if (!target)
                                 continue;
 
-                        r = symlinkat(target, fd, table[i].dir);
-                        if (r < 0 && errno != EEXIST)
-                                return log_error_errno(errno, "Failed to create symlink at %s/%s: %m", root, table[i].dir);
+                        if (symlinkat(target, fd, table[i].dir) < 0) {
+                                log_full_errno(IN_SET(errno, EEXIST, EROFS) || table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno,
+                                               "Failed to create symlink at %s/%s: %m", root, table[i].dir);
+
+                                if (IN_SET(errno, EEXIST, EROFS) || table[i].ignore_failure)
+                                        continue;
+
+                                return -errno;
+                        }
 
                         if (uid_is_valid(uid) || gid_is_valid(gid)) {
                                 if (fchownat(fd, table[i].dir, uid, gid, AT_SYMLINK_NOFOLLOW) < 0)
@@ -97,14 +104,14 @@ int base_filesystem_create(const char *root, uid_t uid, gid_t gid) {
 
                 RUN_WITH_UMASK(0000)
                         r = mkdirat(fd, table[i].dir, table[i].mode);
-                if (r < 0 && errno != EEXIST) {
-                        log_full_errno(table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno,
+                if (r < 0) {
+                        log_full_errno(IN_SET(errno, EEXIST, EROFS) || table[i].ignore_failure ? LOG_DEBUG : LOG_ERR, errno,
                                        "Failed to create directory at %s/%s: %m", root, table[i].dir);
 
-                        if (!table[i].ignore_failure)
-                                return -errno;
+                        if (IN_SET(errno, EEXIST, EROFS) || table[i].ignore_failure)
+                                continue;
 
-                        continue;
+                        return -errno;
                 }
 
                 if (uid != UID_INVALID || gid != UID_INVALID) {
index a4cd645..a956a42 100644 (file)
@@ -10,6 +10,7 @@
 #include "bitmap.h"
 #include "hashmap.h"
 #include "macro.h"
+#include "memory-util.h"
 
 struct Bitmap {
         uint64_t *bitmaps;
index 7e276f1..9a0dc29 100644 (file)
@@ -2,7 +2,9 @@
 
 #include <stdio.h>
 #include <linux/magic.h>
+#include <unistd.h>
 
+#include "sd-device.h"
 #include "sd-id128.h"
 
 #include "alloc-util.h"
 #include "conf-files.h"
 #include "def.h"
 #include "device-nodes.h"
+#include "dirent-util.h"
 #include "efivars.h"
+#include "env-file.h"
 #include "env-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "parse-util.h"
 #include "path-util.h"
+#include "pe-header.h"
+#include "sort-util.h"
 #include "stat-util.h"
+#include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
+#include "unaligned.h"
+#include "util.h"
 #include "virt.h"
 
 static void boot_entry_free(BootEntry *entry) {
@@ -27,6 +36,7 @@ static void boot_entry_free(BootEntry *entry) {
 
         free(entry->id);
         free(entry->path);
+        free(entry->root);
         free(entry->title);
         free(entry->show_title);
         free(entry->version);
@@ -39,31 +49,44 @@ static void boot_entry_free(BootEntry *entry) {
         free(entry->device_tree);
 }
 
-static int boot_entry_load(const char *path, BootEntry *entry) {
-        _cleanup_(boot_entry_free) BootEntry tmp = {};
+static int boot_entry_load(
+                const char *root,
+                const char *path,
+                BootEntry *entry) {
+
+        _cleanup_(boot_entry_free) BootEntry tmp = {
+                .type = BOOT_ENTRY_CONF,
+        };
+
         _cleanup_fclose_ FILE *f = NULL;
         unsigned line = 1;
         char *b, *c;
         int r;
 
+        assert(root);
         assert(path);
         assert(entry);
 
         c = endswith_no_case(path, ".conf");
-        if (!c) {
-                log_error("Invalid loader entry filename: %s", path);
-                return -EINVAL;
-        }
+        if (!c)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry file suffix: %s", path);
 
         b = basename(path);
         tmp.id = strndup(b, c - b);
         if (!tmp.id)
                 return log_oom();
 
+        if (!efi_loader_entry_name_valid(tmp.id))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry filename: %s", path);
+
         tmp.path = strdup(path);
         if (!tmp.path)
                 return log_oom();
 
+        tmp.root = strdup(root);
+        if (!tmp.root)
+                return log_oom();
+
         f = fopen(path, "re");
         if (!f)
                 return log_error_errno(errno, "Failed to open \"%s\": %m", path);
@@ -115,7 +138,7 @@ static int boot_entry_load(const char *path, BootEntry *entry) {
                 else if (streq(field, "devicetree"))
                         r = free_and_strdup(&tmp.device_tree, p);
                 else {
-                        log_notice("%s:%u: Unknown line \"%s\"", path, line, field);
+                        log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field);
                         continue;
                 }
                 if (r < 0)
@@ -137,6 +160,7 @@ void boot_config_free(BootConfig *config) {
         free(config->editor);
         free(config->auto_entries);
         free(config->auto_firmware);
+        free(config->console_mode);
 
         free(config->entry_oneshot);
         free(config->entry_default);
@@ -203,7 +227,7 @@ static int boot_loader_read_conf(const char *path, BootConfig *config) {
                 else if (streq(field, "console-mode"))
                         r = free_and_strdup(&config->console_mode, p);
                 else {
-                        log_notice("%s:%u: Unknown line \"%s\"", path, line, field);
+                        log_notice("%s:%u: Unknown line \"%s\", ignoring.", path, line, field);
                         continue;
                 }
                 if (r < 0)
@@ -217,36 +241,275 @@ static int boot_entry_compare(const BootEntry *a, const BootEntry *b) {
         return str_verscmp(a->id, b->id);
 }
 
-static int boot_entries_find(const char *dir, BootEntry **ret_entries, size_t *ret_n_entries) {
+static int boot_entries_find(
+                const char *root,
+                const char *dir,
+                BootEntry **entries,
+                size_t *n_entries) {
+
         _cleanup_strv_free_ char **files = NULL;
+        size_t n_allocated = *n_entries;
         char **f;
         int r;
-        BootEntry *array = NULL;
-        size_t n_allocated = 0, n = 0;
 
+        assert(root);
         assert(dir);
-        assert(ret_entries);
-        assert(ret_n_entries);
+        assert(entries);
+        assert(n_entries);
 
         r = conf_files_list(&files, ".conf", NULL, 0, dir, NULL);
         if (r < 0)
                 return log_error_errno(r, "Failed to list files in \"%s\": %m", dir);
 
         STRV_FOREACH(f, files) {
-                if (!GREEDY_REALLOC0(array, n_allocated, n + 1))
+                if (!GREEDY_REALLOC0(*entries, n_allocated, *n_entries + 1))
                         return log_oom();
 
-                r = boot_entry_load(*f, array + n);
+                r = boot_entry_load(root, *f, *entries + *n_entries);
                 if (r < 0)
                         continue;
 
-                n++;
+                (*n_entries) ++;
+        }
+
+        return 0;
+}
+
+static int boot_entry_load_unified(
+                const char *root,
+                const char *path,
+                const char *osrelease,
+                const char *cmdline,
+                BootEntry *ret) {
+
+        _cleanup_free_ char *os_pretty_name = NULL, *os_id = NULL, *version_id = NULL, *build_id = NULL;
+        _cleanup_(boot_entry_free) BootEntry tmp = {
+                .type = BOOT_ENTRY_UNIFIED,
+        };
+        _cleanup_fclose_ FILE *f = NULL;
+        const char *k;
+        int r;
+
+        assert(root);
+        assert(path);
+        assert(osrelease);
+
+        k = path_startswith(path, root);
+        if (!k)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Path is not below root: %s", path);
+
+        f = fmemopen((void*) osrelease, strlen(osrelease), "r");
+        if (!f)
+                return log_error_errno(errno, "Failed to open os-release buffer: %m");
+
+        r = parse_env_file(f, "os-release",
+                           "PRETTY_NAME", &os_pretty_name,
+                           "ID", &os_id,
+                           "VERSION_ID", &version_id,
+                           "BUILD_ID", &build_id);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse os-release data from unified kernel image %s: %m", path);
+
+        if (!os_pretty_name || !os_id || !(version_id || build_id))
+                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Missing fields in os-release data from unified kernel image %s, refusing.", path);
+
+        tmp.id = strjoin(os_id, "-", version_id ?: build_id);
+        if (!tmp.id)
+                return log_oom();
+
+        if (!efi_loader_entry_name_valid(tmp.id))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid loader entry: %s", tmp.id);
+
+        tmp.path = strdup(path);
+        if (!tmp.path)
+                return log_oom();
+
+        tmp.root = strdup(root);
+        if (!tmp.root)
+                return log_oom();
+
+        tmp.kernel = strdup(skip_leading_chars(k, "/"));
+        if (!tmp.kernel)
+                return log_oom();
+
+        tmp.options = strv_new(skip_leading_chars(cmdline, WHITESPACE));
+        if (!tmp.options)
+                return log_oom();
+
+        delete_trailing_chars(tmp.options[0], WHITESPACE);
+
+        tmp.title = TAKE_PTR(os_pretty_name);
+
+        *ret = tmp;
+        tmp = (BootEntry) {};
+        return 0;
+}
+
+/* Maximum PE section we are willing to load (Note that sections we are not interested in may be larger, but
+ * the ones we do care about and we are willing to load into memory have this size limit.) */
+#define PE_SECTION_SIZE_MAX (4U*1024U*1024U)
+
+static int find_sections(
+                int fd,
+                char **ret_osrelease,
+                char **ret_cmdline) {
+
+        _cleanup_free_ struct PeSectionHeader *sections = NULL;
+        _cleanup_free_ char *osrelease = NULL, *cmdline = NULL;
+        size_t i, n_sections;
+        struct DosFileHeader dos;
+        struct PeHeader pe;
+        uint64_t start;
+        ssize_t n;
+
+        n = pread(fd, &dos, sizeof(dos), 0);
+        if (n < 0)
+                return log_error_errno(errno, "Failed read DOS header: %m");
+        if (n != sizeof(dos))
+                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading DOS header, refusing.");
+
+        if (dos.Magic[0] != 'M' || dos.Magic[1] != 'Z')
+                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "DOS executable magic missing, refusing.");
+
+        start = unaligned_read_le32(&dos.ExeHeader);
+        n = pread(fd, &pe, sizeof(pe), start);
+        if (n < 0)
+                return log_error_errno(errno, "Failed to read PE header: %m");
+        if (n != sizeof(pe))
+                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading PE header, refusing.");
+
+        if (pe.Magic[0] != 'P' || pe.Magic[1] != 'E' || pe.Magic[2] != 0 || pe.Magic[3] != 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "PE executable magic missing, refusing.");
+
+        n_sections = unaligned_read_le16(&pe.FileHeader.NumberOfSections);
+        if (n_sections > 96)
+                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "PE header has too many sections, refusing.");
+
+        sections = new(struct PeSectionHeader, n_sections);
+        if (!sections)
+                return log_oom();
+
+        n = pread(fd, sections,
+                  n_sections * sizeof(struct PeSectionHeader),
+                  start + sizeof(pe) + unaligned_read_le16(&pe.FileHeader.SizeOfOptionalHeader));
+        if (n < 0)
+                return log_error_errno(errno, "Failed to read section data: %m");
+        if ((size_t) n != n_sections * sizeof(struct PeSectionHeader))
+                return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading sections, refusing.");
+
+        for (i = 0; i < n_sections; i++) {
+                _cleanup_free_ char *k = NULL;
+                uint32_t offset, size;
+                char **b;
+
+                if (strneq((char*) sections[i].Name, ".osrel", sizeof(sections[i].Name)))
+                        b = &osrelease;
+                else if (strneq((char*) sections[i].Name, ".cmdline", sizeof(sections[i].Name)))
+                        b = &cmdline;
+                else
+                        continue;
+
+                if (*b)
+                        return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Duplicate section %s, refusing.", sections[i].Name);
+
+                offset = unaligned_read_le32(&sections[i].PointerToRawData);
+                size = unaligned_read_le32(&sections[i].VirtualSize);
+
+                if (size > PE_SECTION_SIZE_MAX)
+                        return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Section %s too large, refusing.", sections[i].Name);
+
+                k = new(char, size+1);
+                if (!k)
+                        return log_oom();
+
+                n = pread(fd, k, size, offset);
+                if (n < 0)
+                        return log_error_errno(errno, "Failed to read section payload: %m");
+                if ((size_t) n != size)
+                        return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read while reading section payload, refusing:");
+
+                /* Allow one trailing NUL byte, but nothing more. */
+                if (size > 0 && memchr(k, 0, size - 1))
+                        return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Section contains embedded NUL byte: %m");
+
+                k[size] = 0;
+                *b = TAKE_PTR(k);
         }
 
-        typesafe_qsort(array, n, boot_entry_compare);
+        if (!osrelease)
+                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "Image lacks .osrel section, refusing.");
 
-        *ret_entries = array;
-        *ret_n_entries = n;
+        if (ret_osrelease)
+                *ret_osrelease = TAKE_PTR(osrelease);
+        if (ret_cmdline)
+                *ret_cmdline = TAKE_PTR(cmdline);
+
+        return 0;
+}
+
+static int boot_entries_find_unified(
+                const char *root,
+                const char *dir,
+                BootEntry **entries,
+                size_t *n_entries) {
+
+        _cleanup_(closedirp) DIR *d = NULL;
+        size_t n_allocated = *n_entries;
+        struct dirent *de;
+        int r;
+
+        assert(root);
+        assert(dir);
+        assert(entries);
+        assert(n_entries);
+
+        d = opendir(dir);
+        if (!d) {
+                if (errno == ENOENT)
+                        return 0;
+
+                return log_error_errno(errno, "Failed to open %s: %m", dir);
+        }
+
+        FOREACH_DIRENT(de, d, return log_error_errno(errno, "Failed to read %s: %m", dir)) {
+                _cleanup_free_ char *j = NULL, *osrelease = NULL, *cmdline = NULL;
+                _cleanup_close_ int fd = -1;
+
+                if (!dirent_is_file(de))
+                        continue;
+
+                if (!endswith_no_case(de->d_name, ".efi"))
+                        continue;
+
+                if (!GREEDY_REALLOC0(*entries, n_allocated, *n_entries + 1))
+                        return log_oom();
+
+                fd = openat(dirfd(d), de->d_name, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+                if (fd < 0) {
+                        log_warning_errno(errno, "Failed to open %s/%s, ignoring: %m", dir, de->d_name);
+                        continue;
+                }
+
+                r = fd_verify_regular(fd);
+                if (r < 0) {
+                        log_warning_errno(r, "File %s/%s is not regular, ignoring: %m", dir, de->d_name);
+                        continue;
+                }
+
+                r = find_sections(fd, &osrelease, &cmdline);
+                if (r < 0)
+                        continue;
+
+                j = path_join(dir, de->d_name);
+                if (!j)
+                        return log_oom();
+
+                r = boot_entry_load_unified(root, j, osrelease, cmdline, *entries + *n_entries);
+                if (r < 0)
+                        continue;
+
+                (*n_entries) ++;
+        }
 
         return 0;
 }
@@ -325,6 +588,12 @@ static int boot_entries_select_default(const BootConfig *config) {
         int i;
 
         assert(config);
+        assert(config->entries || config->n_entries == 0);
+
+        if (config->n_entries == 0) {
+                log_debug("Found no default boot entry :(");
+                return -1; /* -1 means "no default" */
+        }
 
         if (config->entry_oneshot)
                 for (i = config->n_entries - 1; i >= 0; i--)
@@ -350,30 +619,50 @@ static int boot_entries_select_default(const BootConfig *config) {
                                 return i;
                         }
 
-        if (config->n_entries > 0)
-                log_debug("Found default: last entry \"%s\"", config->entries[config->n_entries - 1].id);
-        else
-                log_debug("Found no default boot entry :(");
-
-        return config->n_entries - 1; /* -1 means "no default" */
+        log_debug("Found default: last entry \"%s\"", config->entries[config->n_entries - 1].id);
+        return config->n_entries - 1;
 }
 
-int boot_entries_load_config(const char *esp_path, BootConfig *config) {
+int boot_entries_load_config(
+                const char *esp_path,
+                const char *xbootldr_path,
+                BootConfig *config) {
+
         const char *p;
         int r;
 
-        assert(esp_path);
         assert(config);
 
-        p = strjoina(esp_path, "/loader/loader.conf");
-        r = boot_loader_read_conf(p, config);
-        if (r < 0)
-                return r;
+        if (esp_path) {
+                p = strjoina(esp_path, "/loader/loader.conf");
+                r = boot_loader_read_conf(p, config);
+                if (r < 0)
+                        return r;
 
-        p = strjoina(esp_path, "/loader/entries");
-        r = boot_entries_find(p, &config->entries, &config->n_entries);
-        if (r < 0)
-                return r;
+                p = strjoina(esp_path, "/loader/entries");
+                r = boot_entries_find(esp_path, p, &config->entries, &config->n_entries);
+                if (r < 0)
+                        return r;
+
+                p = strjoina(esp_path, "/EFI/Linux/");
+                r = boot_entries_find_unified(esp_path, p, &config->entries, &config->n_entries);
+                if (r < 0)
+                        return r;
+        }
+
+        if (xbootldr_path) {
+                p = strjoina(xbootldr_path, "/loader/entries");
+                r = boot_entries_find(xbootldr_path, p, &config->entries, &config->n_entries);
+                if (r < 0)
+                        return r;
+
+                p = strjoina(xbootldr_path, "/EFI/Linux/");
+                r = boot_entries_find_unified(xbootldr_path, p, &config->entries, &config->n_entries);
+                if (r < 0)
+                        return r;
+        }
+
+        typesafe_qsort(config->entries, config->n_entries, boot_entry_compare);
 
         r = boot_entries_uniquify(config->entries, config->n_entries);
         if (r < 0)
@@ -381,101 +670,153 @@ int boot_entries_load_config(const char *esp_path, BootConfig *config) {
 
         if (is_efi_boot()) {
                 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", &config->entry_oneshot);
-                if (r < 0 && r != -ENOENT)
-                        return log_error_errno(r, "Failed to read EFI var \"LoaderEntryOneShot\": %m");
+                if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) {
+                        log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryOneShot\": %m");
+                        if (r == -ENOMEM)
+                                return r;
+                }
 
                 r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryDefault", &config->entry_default);
-                if (r < 0 && r != -ENOENT)
-                        return log_error_errno(r, "Failed to read EFI var \"LoaderEntryDefault\": %m");
+                if (r < 0 && !IN_SET(r, -ENOENT, -ENODATA)) {
+                        log_warning_errno(r, "Failed to read EFI variable \"LoaderEntryDefault\": %m");
+                        if (r == -ENOMEM)
+                                return r;
+                }
         }
 
         config->default_entry = boot_entries_select_default(config);
         return 0;
 }
 
-/********************************************************************************/
+int boot_entries_load_config_auto(
+                const char *override_esp_path,
+                const char *override_xbootldr_path,
+                BootConfig *config) {
 
-static int verify_esp(
-                const char *p,
-                bool searching,
-                bool unprivileged_mode,
-                uint32_t *ret_part,
-                uint64_t *ret_pstart,
-                uint64_t *ret_psize,
-                sd_id128_t *ret_uuid) {
-#if HAVE_BLKID
-        _cleanup_(blkid_free_probep) blkid_probe b = NULL;
-        _cleanup_free_ char *node = NULL;
-        const char *v;
-#endif
-        uint64_t pstart = 0, psize = 0;
-        struct stat st, st2;
-        const char *t2;
-        struct statfs sfs;
-        sd_id128_t uuid = SD_ID128_NULL;
-        uint32_t part = 0;
-        bool relax_checks;
+        _cleanup_free_ char *esp_where = NULL, *xbootldr_where = NULL;
         int r;
 
-        assert(p);
+        assert(config);
 
-        relax_checks = getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0;
+        /* This function is similar to boot_entries_load_config(), however we automatically search for the
+         * ESP and the XBOOTLDR partition unless it is explicitly specified. Also, if the user did not pass
+         * an ESP or XBOOTLDR path directly, let's see if /run/boot-loader-entries/ exists. If so, let's
+         * read data from there, as if it was an ESP (i.e. loading both entries and loader.conf data from
+         * it). This allows other boot loaders to pass boot loader entry information to our tools if they
+         * want to. */
 
-        /* Non-root user can only check the status, so if an error occured in the following, it does not cause any
-         * issues. Let's also, silence the error messages. */
+        if (!override_esp_path && !override_xbootldr_path) {
+                if (access("/run/boot-loader-entries/", F_OK) >= 0)
+                        return boot_entries_load_config("/run/boot-loader-entries/", NULL, config);
 
-        if (!relax_checks) {
-                if (statfs(p, &sfs) < 0) {
-                        /* If we are searching for the mount point, don't generate a log message if we can't find the path */
-                        if (errno == ENOENT && searching)
-                                return -ENOENT;
+                if (errno != ENOENT)
+                        return log_error_errno(errno,
+                                               "Failed to determine whether /run/boot-loader-entries/ exists: %m");
+        }
 
-                        return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
-                                              "Failed to check file system type of \"%s\": %m", p);
-                }
+        r = find_esp_and_warn(override_esp_path, false, &esp_where, NULL, NULL, NULL, NULL);
+        if (r < 0) /* we don't log about ENOKEY here, but propagate it, leaving it to the caller to log */
+                return r;
 
-                if (!F_TYPE_EQUAL(sfs.f_type, MSDOS_SUPER_MAGIC)) {
-                        if (searching)
-                                return -EADDRNOTAVAIL;
+        r = find_xbootldr_and_warn(override_xbootldr_path, false, &xbootldr_where, NULL);
+        if (r < 0 && r != -ENOKEY)
+                return r; /* It's fine if the XBOOTLDR partition doesn't exist, hence we ignore ENOKEY here */
 
-                        log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
-                        return -ENODEV;
-                }
-        }
+        return boot_entries_load_config(esp_where, xbootldr_where, config);
+}
 
-        if (stat(p, &st) < 0)
-                return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
-                                      "Failed to determine block device node of \"%s\": %m", p);
+int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) {
 
-        if (major(st.st_dev) == 0) {
-                log_error("Block device node of %p is invalid.", p);
-                return -ENODEV;
-        }
+        static const char * const title_table[] = {
+                /* Pretty names for a few well-known automatically discovered entries. */
+                "auto-osx",                      "macOS",
+                "auto-windows",                  "Windows Boot Manager",
+                "auto-efi-shell",                "EFI Shell",
+                "auto-efi-default",              "EFI Default Loader",
+                "auto-reboot-to-firmware-setup", "Reboot Into Firmware Interface",
+        };
+
+        _cleanup_strv_free_ char **found_by_loader = NULL;
+        size_t n_allocated;
+        char **i;
+        int r;
+
+        assert(config);
 
-        t2 = strjoina(p, "/..");
-        r = stat(t2, &st2);
+        /* Let's add the entries discovered by the boot loader to the end of our list, unless they are
+         * already included there. */
+
+        r = efi_loader_get_entries(&found_by_loader);
+        if (IN_SET(r, -ENOENT, -EOPNOTSUPP))
+                return log_debug_errno(r, "Boot loader reported no entries.");
         if (r < 0)
-                return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
-                                      "Failed to determine block device node of parent of \"%s\": %m", p);
+                return log_error_errno(r, "Failed to determine entries reported by boot loader: %m");
+
+        n_allocated = config->n_entries;
+
+        STRV_FOREACH(i, found_by_loader) {
+                _cleanup_free_ char *c = NULL, *t = NULL;
+                char **a, **b;
+
+                if (boot_config_has_entry(config, *i))
+                        continue;
+
+                if (only_auto && !startswith(*i, "auto-"))
+                        continue;
 
-        if (st.st_dev == st2.st_dev) {
-                log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p);
-                return -ENODEV;
+                c = strdup(*i);
+                if (!c)
+                        return log_oom();
+
+                STRV_FOREACH_PAIR(a, b, (char**) title_table)
+                        if (streq(*a, *i)) {
+                                t = strdup(*b);
+                                if (!t)
+                                        return log_oom();
+                                break;
+                        }
+
+                if (!GREEDY_REALLOC0(config->entries, n_allocated, config->n_entries + 1))
+                        return log_oom();
+
+                config->entries[config->n_entries++] = (BootEntry) {
+                        .type = BOOT_ENTRY_LOADER,
+                        .id = TAKE_PTR(c),
+                        .title = TAKE_PTR(t),
+                };
         }
 
-        /* In a container we don't have access to block devices, skip this part of the verification, we trust the
-         * container manager set everything up correctly on its own. Also skip the following verification for non-root user. */
-        if (detect_container() > 0 || unprivileged_mode || relax_checks)
-                goto finish;
+        return 0;
+}
+
+/********************************************************************************/
+
+static int verify_esp_blkid(
+                dev_t devid,
+                bool searching,
+                uint32_t *ret_part,
+                uint64_t *ret_pstart,
+                uint64_t *ret_psize,
+                sd_id128_t *ret_uuid) {
+
+        sd_id128_t uuid = SD_ID128_NULL;
+        uint64_t pstart = 0, psize = 0;
+        uint32_t part = 0;
 
 #if HAVE_BLKID
-        r = device_path_make_major_minor(S_IFBLK, st.st_dev, &node);
+        _cleanup_(blkid_free_probep) blkid_probe b = NULL;
+        _cleanup_free_ char *node = NULL;
+        const char *v;
+        int r;
+
+        r = device_path_make_major_minor(S_IFBLK, devid, &node);
         if (r < 0)
                 return log_error_errno(r, "Failed to format major/minor device path: %m");
+
         errno = 0;
         b = blkid_new_probe_from_filename(node);
         if (!b)
-                return log_error_errno(errno ?: ENOMEM, "Failed to open file system \"%s\": %m", p);
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
 
         blkid_probe_enable_superblocks(b, 1);
         blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
@@ -484,56 +825,52 @@ static int verify_esp(
 
         errno = 0;
         r = blkid_do_safeprobe(b);
-        if (r == -2) {
-                log_error("File system \"%s\" is ambiguous.", p);
-                return -ENODEV;
-        } else if (r == 1) {
-                log_error("File system \"%s\" does not contain a label.", p);
-                return -ENODEV;
-        } else if (r != 0)
-                return log_error_errno(errno ?: EIO, "Failed to probe file system \"%s\": %m", p);
+        if (r == -2)
+                return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
+        else if (r == 1)
+                return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" does not contain a label.", node);
+        else if (r != 0)
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
 
         errno = 0;
         r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
         if (r != 0)
-                return log_error_errno(errno ?: EIO, "Failed to probe file system type \"%s\": %m", p);
-        if (!streq(v, "vfat")) {
-                log_error("File system \"%s\" is not FAT.", p);
-                return -ENODEV;
-        }
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system type of \"%s\": %m", node);
+        if (!streq(v, "vfat"))
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                      "File system \"%s\" is not FAT.", node);
 
         errno = 0;
         r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
         if (r != 0)
-                return log_error_errno(errno ?: EIO, "Failed to probe partition scheme \"%s\": %m", p);
-        if (!streq(v, "gpt")) {
-                log_error("File system \"%s\" is not on a GPT partition table.", p);
-                return -ENODEV;
-        }
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition scheme of \"%s\": %m", node);
+        if (!streq(v, "gpt"))
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                      "File system \"%s\" is not on a GPT partition table.", node);
 
         errno = 0;
         r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
         if (r != 0)
-                return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID \"%s\": %m", p);
-        if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
-                log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p);
-                return -ENODEV;
-        }
+                return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID of \"%s\": %m", node);
+        if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"))
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                       SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                       "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
 
         errno = 0;
         r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
         if (r != 0)
-                return log_error_errno(errno ?: EIO, "Failed to probe partition entry UUID \"%s\": %m", p);
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition entry UUID of \"%s\": %m", node);
         r = sd_id128_from_string(v, &uuid);
-        if (r < 0) {
-                log_error("Partition \"%s\" has invalid UUID \"%s\".", p, v);
-                return -EIO;
-        }
+        if (r < 0)
+                return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
 
         errno = 0;
         r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
         if (r != 0)
-                return log_error_errno(errno ?: EIO, "Failed to probe partition number \"%s\": m", p);
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition number of \"%s\": m", node);
         r = safe_atou32(v, &part);
         if (r < 0)
                 return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
@@ -541,7 +878,7 @@ static int verify_esp(
         errno = 0;
         r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
         if (r != 0)
-                return log_error_errno(errno ?: EIO, "Failed to probe partition offset \"%s\": %m", p);
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition offset of \"%s\": %m", node);
         r = safe_atou64(v, &pstart);
         if (r < 0)
                 return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
@@ -549,13 +886,12 @@ static int verify_esp(
         errno = 0;
         r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
         if (r != 0)
-                return log_error_errno(errno ?: EIO, "Failed to probe partition size \"%s\": %m", p);
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition size of \"%s\": %m", node);
         r = safe_atou64(v, &psize);
         if (r < 0)
                 return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
 #endif
 
-finish:
         if (ret_part)
                 *ret_part = part;
         if (ret_pstart)
@@ -568,6 +904,234 @@ finish:
         return 0;
 }
 
+static int verify_esp_udev(
+                dev_t devid,
+                bool searching,
+                uint32_t *ret_part,
+                uint64_t *ret_pstart,
+                uint64_t *ret_psize,
+                sd_id128_t *ret_uuid) {
+
+        _cleanup_(sd_device_unrefp) sd_device *d = NULL;
+        _cleanup_free_ char *node = NULL;
+        sd_id128_t uuid = SD_ID128_NULL;
+        uint64_t pstart = 0, psize = 0;
+        uint32_t part = 0;
+        const char *v;
+        int r;
+
+        r = device_path_make_major_minor(S_IFBLK, devid, &node);
+        if (r < 0)
+                return log_error_errno(r, "Failed to format major/minor device path: %m");
+
+        r = sd_device_new_from_devnum(&d, 'b', devid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device from device number: %m");
+
+        r = sd_device_get_property_value(d, "ID_FS_TYPE", &v);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device property: %m");
+        if (!streq(v, "vfat"))
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                      "File system \"%s\" is not FAT.", node );
+
+        r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device property: %m");
+        if (!streq(v, "gpt"))
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                      "File system \"%s\" is not on a GPT partition table.", node);
+
+        r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device property: %m");
+        if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"))
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                       SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                       "File system \"%s\" has wrong type for an EFI System Partition (ESP).", node);
+
+        r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device property: %m");
+        r = sd_id128_from_string(v, &uuid);
+        if (r < 0)
+                return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
+
+        r = sd_device_get_property_value(d, "ID_PART_ENTRY_NUMBER", &v);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device property: %m");
+        r = safe_atou32(v, &part);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
+
+        r = sd_device_get_property_value(d, "ID_PART_ENTRY_OFFSET", &v);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device property: %m");
+        r = safe_atou64(v, &pstart);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
+
+        r = sd_device_get_property_value(d, "ID_PART_ENTRY_SIZE", &v);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device property: %m");
+        r = safe_atou64(v, &psize);
+        if (r < 0)
+                return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
+
+        if (ret_part)
+                *ret_part = part;
+        if (ret_pstart)
+                *ret_pstart = pstart;
+        if (ret_psize)
+                *ret_psize = psize;
+        if (ret_uuid)
+                *ret_uuid = uuid;
+
+        return 0;
+}
+
+static int verify_fsroot_dir(
+                const char *path,
+                bool searching,
+                bool unprivileged_mode,
+                dev_t *ret_dev) {
+
+        struct stat st, st2;
+        const char *t2, *trigger;
+        int r;
+
+        assert(path);
+        assert(ret_dev);
+
+        /* So, the ESP and XBOOTLDR partition are commonly located on an autofs mount. stat() on the
+         * directory won't trigger it, if it is not mounted yet. Let's hence explicitly trigger it here,
+         * before stat()ing */
+        trigger = strjoina(path, "/trigger"); /* Filename doesn't matter... */
+        (void) access(trigger, F_OK);
+
+        if (stat(path, &st) < 0)
+                return log_full_errno((searching && errno == ENOENT) ||
+                                      (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
+                                      "Failed to determine block device node of \"%s\": %m", path);
+
+        if (major(st.st_dev) == 0)
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                      "Block device node of \"%s\" is invalid.", path);
+
+        t2 = strjoina(path, "/..");
+        if (stat(t2, &st2) < 0) {
+                if (errno != EACCES)
+                        r = -errno;
+                else {
+                        _cleanup_free_ char *parent = NULL;
+
+                        /* If going via ".." didn't work due to EACCESS, then let's determine the parent path
+                         * directly instead. It's not as good, due to symlinks and such, but we can't do
+                         * anything better here. */
+
+                        parent = dirname_malloc(path);
+                        if (!parent)
+                                return log_oom();
+
+                        if (stat(parent, &st2) < 0)
+                                r = -errno;
+                        else
+                                r = 0;
+                }
+
+                if (r < 0)
+                        return log_full_errno(unprivileged_mode && r == -EACCES ? LOG_DEBUG : LOG_ERR, r,
+                                              "Failed to determine block device node of parent of \"%s\": %m", path);
+        }
+
+        if (st.st_dev == st2.st_dev)
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                      "Directory \"%s\" is not the root of the file system.", path);
+
+        if (ret_dev)
+                *ret_dev = st.st_dev;
+
+        return 0;
+}
+
+static int verify_esp(
+                const char *p,
+                bool searching,
+                bool unprivileged_mode,
+                uint32_t *ret_part,
+                uint64_t *ret_pstart,
+                uint64_t *ret_psize,
+                sd_id128_t *ret_uuid) {
+
+        bool relax_checks;
+        dev_t devid;
+        int r;
+
+        assert(p);
+
+        /* This logs about all errors, except:
+         *
+         *  -ENOENT        → if 'searching' is set, and the dir doesn't exist
+         *  -EADDRNOTAVAIL → if 'searching' is set, and the dir doesn't look like an ESP
+         *  -EACESS        → if 'unprivileged_mode' is set, and we have trouble acessing the thing
+         */
+
+        relax_checks = getenv_bool("SYSTEMD_RELAX_ESP_CHECKS") > 0;
+
+        /* Non-root user can only check the status, so if an error occured in the following, it does not cause any
+         * issues. Let's also, silence the error messages. */
+
+        if (!relax_checks) {
+                struct statfs sfs;
+
+                if (statfs(p, &sfs) < 0)
+                        /* If we are searching for the mount point, don't generate a log message if we can't find the path */
+                        return log_full_errno((searching && errno == ENOENT) ||
+                                              (unprivileged_mode && errno == EACCES) ? LOG_DEBUG : LOG_ERR, errno,
+                                              "Failed to check file system type of \"%s\": %m", p);
+
+                if (!F_TYPE_EQUAL(sfs.f_type, MSDOS_SUPER_MAGIC))
+                        return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                              SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV),
+                                              "File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
+        }
+
+        r = verify_fsroot_dir(p, searching, unprivileged_mode, &devid);
+        if (r < 0)
+                return r;
+
+        /* In a container we don't have access to block devices, skip this part of the verification, we trust
+         * the container manager set everything up correctly on its own. */
+        if (detect_container() > 0 || relax_checks)
+                goto finish;
+
+        /* If we are unprivileged we ask udev for the metadata about the partition. If we are privileged we
+         * use blkid instead. Why? Because this code is called from 'bootctl' which is pretty much an
+         * emergency recovery tool that should also work when udev isn't up (i.e. from the emergency shell),
+         * however blkid can't work if we have no privileges to access block devices directly, which is why
+         * we use udev in that case. */
+        if (unprivileged_mode)
+                return verify_esp_udev(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
+        else
+                return verify_esp_blkid(devid, searching, ret_part, ret_pstart, ret_psize, ret_uuid);
+
+finish:
+        if (ret_part)
+                *ret_part = 0;
+        if (ret_pstart)
+                *ret_pstart = 0;
+        if (ret_psize)
+                *ret_psize = 0;
+        if (ret_uuid)
+                *ret_uuid = SD_ID128_NULL;
+
+        return 0;
+}
+
 int find_esp_and_warn(
                 const char *path,
                 bool unprivileged_mode,
@@ -631,35 +1195,234 @@ found:
         return 0;
 }
 
-int find_default_boot_entry(
-                const char *esp_path,
-                char **esp_where,
-                BootConfig *config,
-                const BootEntry **e) {
+static int verify_xbootldr_blkid(
+                dev_t devid,
+                bool searching,
+                sd_id128_t *ret_uuid) {
+
+        sd_id128_t uuid = SD_ID128_NULL;
 
-        _cleanup_free_ char *where = NULL;
+#if HAVE_BLKID
+        _cleanup_(blkid_free_probep) blkid_probe b = NULL;
+        _cleanup_free_ char *node = NULL;
+        const char *v;
         int r;
 
-        assert(config);
-        assert(e);
+        r = device_path_make_major_minor(S_IFBLK, devid, &node);
+        if (r < 0)
+                return log_error_errno(r, "Failed to format major/minor device path: %m");
+        errno = 0;
+        b = blkid_new_probe_from_filename(node);
+        if (!b)
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(ENOMEM), "Failed to open file system \"%s\": %m", node);
+
+        blkid_probe_enable_partitions(b, 1);
+        blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
+
+        errno = 0;
+        r = blkid_do_safeprobe(b);
+        if (r == -2)
+                return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" is ambiguous.", node);
+        else if (r == 1)
+                return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "File system \"%s\" does not contain a label.", node);
+        else if (r != 0)
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe file system \"%s\": %m", node);
+
+        errno = 0;
+        r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
+        if (r != 0)
+                return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition scheme of \"%s\": %m", node);
+        if (streq(v, "gpt")) {
+
+                errno = 0;
+                r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
+                if (r != 0)
+                        return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition type UUID of \"%s\": %m", node);
+                if (!streq(v, "bc13c2ff-59e6-4262-a352-b275fd6f7172"))
+                        return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                              searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
+                                              "File system \"%s\" has wrong type for extended boot loader partition.", node);
+
+                errno = 0;
+                r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
+                if (r != 0)
+                        return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition entry UUID of \"%s\": %m", node);
+                r = sd_id128_from_string(v, &uuid);
+                if (r < 0)
+                        return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
+
+        } else if (streq(v, "dos")) {
+
+                errno = 0;
+                r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
+                if (r != 0)
+                        return log_error_errno(errno ?: SYNTHETIC_ERRNO(EIO), "Failed to probe partition type UUID of \"%s\": %m", node);
+                if (!streq(v, "0xea"))
+                        return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                              searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
+                                              "File system \"%s\" has wrong type for extended boot loader partition.", node);
+
+        } else
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
+                                      "File system \"%s\" is not on a GPT or DOS partition table.", node);
+#endif
+
+        if (ret_uuid)
+                *ret_uuid = uuid;
+
+        return 0;
+}
+
+static int verify_xbootldr_udev(
+                dev_t devid,
+                bool searching,
+                sd_id128_t *ret_uuid) {
+
+        _cleanup_(sd_device_unrefp) sd_device *d = NULL;
+        _cleanup_free_ char *node = NULL;
+        sd_id128_t uuid = SD_ID128_NULL;
+        const char *v;
+        int r;
 
-        r = find_esp_and_warn(esp_path, false, &where, NULL, NULL, NULL, NULL);
+        r = device_path_make_major_minor(S_IFBLK, devid, &node);
         if (r < 0)
-                return r;
+                return log_error_errno(r, "Failed to format major/minor device path: %m");
 
-        r = boot_entries_load_config(where, config);
+        r = sd_device_new_from_devnum(&d, 'b', devid);
         if (r < 0)
-                return log_error_errno(r, "Failed to load bootspec config from \"%s/loader\": %m", where);
+                return log_error_errno(r, "Failed to get device from device number: %m");
+
+        r = sd_device_get_property_value(d, "ID_PART_ENTRY_SCHEME", &v);
+        if (r < 0)
+                return log_error_errno(r, "Failed to get device property: %m");
+
+        if (streq(v, "gpt")) {
+
+                r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get device property: %m");
+                if (!streq(v, "bc13c2ff-59e6-4262-a352-b275fd6f7172"))
+                        return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                              searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
+                                              "File system \"%s\" has wrong type for extended boot loader partition.", node);
 
-        if (config->default_entry < 0)
-                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
-                                       "No entry suitable as default, refusing to guess.");
+                r = sd_device_get_property_value(d, "ID_PART_ENTRY_UUID", &v);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get device property: %m");
+                r = sd_id128_from_string(v, &uuid);
+                if (r < 0)
+                        return log_error_errno(r, "Partition \"%s\" has invalid UUID \"%s\".", node, v);
 
-        *e = &config->entries[config->default_entry];
-        log_debug("Found default boot entry in file \"%s\"", (*e)->path);
+        } else if (streq(v, "dos")) {
 
-        if (esp_where)
-                *esp_where = TAKE_PTR(where);
+                r = sd_device_get_property_value(d, "ID_PART_ENTRY_TYPE", &v);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to get device property: %m");
+                if (!streq(v, "0xea"))
+                        return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                              searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
+                                              "File system \"%s\" has wrong type for extended boot loader partition.", node);
+        } else
+                return log_full_errno(searching ? LOG_DEBUG : LOG_ERR,
+                                      searching ? SYNTHETIC_ERRNO(EADDRNOTAVAIL) : SYNTHETIC_ERRNO(ENODEV),
+                                      "File system \"%s\" is not on a GPT or DOS partition table.", node);
+
+        if (ret_uuid)
+                *ret_uuid = uuid;
 
         return 0;
 }
+
+static int verify_xbootldr(
+                const char *p,
+                bool searching,
+                bool unprivileged_mode,
+                sd_id128_t *ret_uuid) {
+
+        bool relax_checks;
+        dev_t devid;
+        int r;
+
+        assert(p);
+
+        relax_checks = getenv_bool("SYSTEMD_RELAX_XBOOTLDR_CHECKS") > 0;
+
+        r = verify_fsroot_dir(p, searching, unprivileged_mode, &devid);
+        if (r < 0)
+                return r;
+
+        if (detect_container() > 0 || relax_checks)
+                goto finish;
+
+        if (unprivileged_mode)
+                return verify_xbootldr_udev(devid, searching, ret_uuid);
+        else
+                return verify_xbootldr_blkid(devid, searching, ret_uuid);
+
+finish:
+        if (ret_uuid)
+                *ret_uuid = SD_ID128_NULL;
+
+        return 0;
+}
+
+int find_xbootldr_and_warn(
+                const char *path,
+                bool unprivileged_mode,
+                char **ret_path,
+                sd_id128_t *ret_uuid) {
+
+        int r;
+
+        /* Similar to find_esp_and_warn(), but finds the XBOOTLDR partition. Returns the same errors. */
+
+        if (path) {
+                r = verify_xbootldr(path, false, unprivileged_mode, ret_uuid);
+                if (r < 0)
+                        return r;
+
+                goto found;
+        }
+
+        path = getenv("SYSTEMD_XBOOTLDR_PATH");
+        if (path) {
+                if (!path_is_valid(path) || !path_is_absolute(path))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "$SYSTEMD_XBOOTLDR_PATH does not refer to absolute path, refusing to use it: %s",
+                                               path);
+
+                goto found;
+        }
+
+        r = verify_xbootldr("/boot", true, unprivileged_mode, ret_uuid);
+        if (r >= 0) {
+                path = "/boot";
+                goto found;
+        }
+        if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
+                return r;
+
+        return -ENOKEY;
+
+found:
+        if (ret_path) {
+                char *c;
+
+                c = strdup(path);
+                if (!c)
+                        return log_oom();
+
+                *ret_path = c;
+        }
+
+        return 0;
+}
+
+static const char* const boot_entry_type_table[_BOOT_ENTRY_MAX] = {
+        [BOOT_ENTRY_CONF] = "conf",
+        [BOOT_ENTRY_UNIFIED] = "unified",
+        [BOOT_ENTRY_LOADER] = "loader",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(boot_entry_type, BootEntryType);
index ed57621..45e1fc3 100644 (file)
@@ -8,9 +8,21 @@
 
 #include "sd-id128.h"
 
+#include "string-util.h"
+
+typedef enum BootEntryType {
+        BOOT_ENTRY_CONF,     /* Type #1 entries: *.conf files */
+        BOOT_ENTRY_UNIFIED,  /* Type #2 entries: *.efi files */
+        BOOT_ENTRY_LOADER,   /* Additional entries augmented from LoaderEntries EFI var */
+        _BOOT_ENTRY_MAX,
+        _BOOT_ENTRY_INVALID = -1,
+} BootEntryType;
+
 typedef struct BootEntry {
+        BootEntryType type;
         char *id;       /* This is the file basename without extension */
-        char *path;     /* This is the full path to the file */
+        char *path;     /* This is the full path to the drop-in file */
+        char *root;     /* The root path in which the drop-in was found, i.e. to which 'kernel', 'efi' and 'initrd' are relative */
         char *title;
         char *show_title;
         char *version;
@@ -39,13 +51,34 @@ typedef struct BootConfig {
         ssize_t default_entry;
 } BootConfig;
 
+static inline bool boot_config_has_entry(BootConfig *config, const char *id) {
+        size_t j;
+
+        for (j = 0; j < config->n_entries; j++)
+                if (streq(config->entries[j].id, id))
+                        return true;
+
+        return false;
+}
+
+static inline BootEntry* boot_config_default_entry(BootConfig *config) {
+        if (config->default_entry < 0)
+                return NULL;
+
+        return config->entries + config->default_entry;
+}
+
 void boot_config_free(BootConfig *config);
-int boot_entries_load_config(const char *esp_path, BootConfig *config);
+int boot_entries_load_config(const char *esp_path, const char *xbootldr_path, BootConfig *config);
+int boot_entries_load_config_auto(const char *override_esp_path, const char *override_xbootldr_path, BootConfig *config);
+int boot_entries_augment_from_loader(BootConfig *config, bool only_auto);
 
 static inline const char* boot_entry_title(const BootEntry *entry) {
         return entry->show_title ?: entry->title ?: entry->id;
 }
 
 int find_esp_and_warn(const char *path, bool unprivileged_mode, char **ret_path, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid);
+int find_xbootldr_and_warn(const char *path, bool unprivileged_mode, char **ret_path,sd_id128_t *ret_uuid);
 
-int find_default_boot_entry(const char *esp_path, char **esp_where, BootConfig *config, const BootEntry **e);
+const char* boot_entry_type_to_string(BootEntryType t) _const_;
+BootEntryType boot_entry_type_from_string(const char *s) _pure_;
index 2c61e04..40bc964 100644 (file)
@@ -9,9 +9,9 @@
 #include "bpf-program.h"
 #include "fd-util.h"
 #include "log.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "path-util.h"
-#include "util.h"
 
 int bpf_program_new(uint32_t prog_type, BPFProgram **ret) {
         _cleanup_(bpf_program_unrefp) BPFProgram *p = NULL;
diff --git a/src/shared/bus-unit-procs.c b/src/shared/bus-unit-procs.c
new file mode 100644 (file)
index 0000000..23c5a12
--- /dev/null
@@ -0,0 +1,411 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "bus-unit-procs.h"
+#include "hashmap.h"
+#include "list.h"
+#include "locale-util.h"
+#include "macro.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "sort-util.h"
+#include "string-util.h"
+#include "terminal-util.h"
+
+struct CGroupInfo {
+        char *cgroup_path;
+        bool is_const; /* If false, cgroup_path should be free()'d */
+
+        Hashmap *pids; /* PID → process name */
+        bool done;
+
+        struct CGroupInfo *parent;
+        LIST_FIELDS(struct CGroupInfo, siblings);
+        LIST_HEAD(struct CGroupInfo, children);
+        size_t n_children;
+};
+
+static int add_cgroup(Hashmap *cgroups, const char *path, bool is_const, struct CGroupInfo **ret) {
+        struct CGroupInfo *parent = NULL, *cg;
+        int r;
+
+        assert(cgroups);
+        assert(ret);
+
+        if (empty_or_root(path))
+                path = "/";
+
+        cg = hashmap_get(cgroups, path);
+        if (cg) {
+                *ret = cg;
+                return 0;
+        }
+
+        if (!empty_or_root(path)) {
+                const char *e, *pp;
+
+                e = strrchr(path, '/');
+                if (!e)
+                        return -EINVAL;
+
+                pp = strndupa(path, e - path);
+                if (!pp)
+                        return -ENOMEM;
+
+                r = add_cgroup(cgroups, pp, false, &parent);
+                if (r < 0)
+                        return r;
+        }
+
+        cg = new0(struct CGroupInfo, 1);
+        if (!cg)
+                return -ENOMEM;
+
+        if (is_const)
+                cg->cgroup_path = (char*) path;
+        else {
+                cg->cgroup_path = strdup(path);
+                if (!cg->cgroup_path) {
+                        free(cg);
+                        return -ENOMEM;
+                }
+        }
+
+        cg->is_const = is_const;
+        cg->parent = parent;
+
+        r = hashmap_put(cgroups, cg->cgroup_path, cg);
+        if (r < 0) {
+                if (!is_const)
+                        free(cg->cgroup_path);
+                free(cg);
+                return r;
+        }
+
+        if (parent) {
+                LIST_PREPEND(siblings, parent->children, cg);
+                parent->n_children++;
+        }
+
+        *ret = cg;
+        return 1;
+}
+
+static int add_process(
+                Hashmap *cgroups,
+                const char *path,
+                pid_t pid,
+                const char *name) {
+
+        struct CGroupInfo *cg;
+        int r;
+
+        assert(cgroups);
+        assert(name);
+        assert(pid > 0);
+
+        r = add_cgroup(cgroups, path, true, &cg);
+        if (r < 0)
+                return r;
+
+        r = hashmap_ensure_allocated(&cg->pids, &trivial_hash_ops);
+        if (r < 0)
+                return r;
+
+        return hashmap_put(cg->pids, PID_TO_PTR(pid), (void*) name);
+}
+
+static void remove_cgroup(Hashmap *cgroups, struct CGroupInfo *cg) {
+        assert(cgroups);
+        assert(cg);
+
+        while (cg->children)
+                remove_cgroup(cgroups, cg->children);
+
+        hashmap_remove(cgroups, cg->cgroup_path);
+
+        if (!cg->is_const)
+                free(cg->cgroup_path);
+
+        hashmap_free(cg->pids);
+
+        if (cg->parent)
+                LIST_REMOVE(siblings, cg->parent->children, cg);
+
+        free(cg);
+}
+
+static int cgroup_info_compare_func(struct CGroupInfo * const *a, struct CGroupInfo * const *b) {
+        return strcmp((*a)->cgroup_path, (*b)->cgroup_path);
+}
+
+static int dump_processes(
+                Hashmap *cgroups,
+                const char *cgroup_path,
+                const char *prefix,
+                unsigned n_columns,
+                OutputFlags flags) {
+
+        struct CGroupInfo *cg;
+        int r;
+
+        assert(prefix);
+
+        if (empty_or_root(cgroup_path))
+                cgroup_path = "/";
+
+        cg = hashmap_get(cgroups, cgroup_path);
+        if (!cg)
+                return 0;
+
+        if (!hashmap_isempty(cg->pids)) {
+                const char *name;
+                size_t n = 0, i;
+                pid_t *pids;
+                void *pidp;
+                Iterator j;
+                int width;
+
+                /* Order processes by their PID */
+                pids = newa(pid_t, hashmap_size(cg->pids));
+
+                HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j)
+                        pids[n++] = PTR_TO_PID(pidp);
+
+                assert(n == hashmap_size(cg->pids));
+                typesafe_qsort(pids, n, pid_compare_func);
+
+                width = DECIMAL_STR_WIDTH(pids[n-1]);
+
+                for (i = 0; i < n; i++) {
+                        _cleanup_free_ char *e = NULL;
+                        const char *special;
+                        bool more;
+
+                        name = hashmap_get(cg->pids, PID_TO_PTR(pids[i]));
+                        assert(name);
+
+                        if (n_columns != 0) {
+                                unsigned k;
+
+                                k = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
+
+                                e = ellipsize(name, k, 100);
+                                if (e)
+                                        name = e;
+                        }
+
+                        more = i+1 < n || cg->children;
+                        special = special_glyph(more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT);
+
+                        fprintf(stdout, "%s%s%*"PID_PRI" %s\n",
+                                prefix,
+                                special,
+                                width, pids[i],
+                                name);
+                }
+        }
+
+        if (cg->children) {
+                struct CGroupInfo **children, *child;
+                size_t n = 0, i;
+
+                /* Order subcgroups by their name */
+                children = newa(struct CGroupInfo*, cg->n_children);
+                LIST_FOREACH(siblings, child, cg->children)
+                        children[n++] = child;
+                assert(n == cg->n_children);
+                typesafe_qsort(children, n, cgroup_info_compare_func);
+
+                if (n_columns != 0)
+                        n_columns = MAX(LESS_BY(n_columns, 2U), 20U);
+
+                for (i = 0; i < n; i++) {
+                        _cleanup_free_ char *pp = NULL;
+                        const char *name, *special;
+                        bool more;
+
+                        child = children[i];
+
+                        name = strrchr(child->cgroup_path, '/');
+                        if (!name)
+                                return -EINVAL;
+                        name++;
+
+                        more = i+1 < n;
+                        special = special_glyph(more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT);
+
+                        fputs(prefix, stdout);
+                        fputs(special, stdout);
+                        fputs(name, stdout);
+                        fputc('\n', stdout);
+
+                        special = special_glyph(more ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE);
+
+                        pp = strappend(prefix, special);
+                        if (!pp)
+                                return -ENOMEM;
+
+                        r = dump_processes(cgroups, child->cgroup_path, pp, n_columns, flags);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        cg->done = true;
+        return 0;
+}
+
+static int dump_extra_processes(
+                Hashmap *cgroups,
+                const char *prefix,
+                unsigned n_columns,
+                OutputFlags flags) {
+
+        _cleanup_free_ pid_t *pids = NULL;
+        _cleanup_hashmap_free_ Hashmap *names = NULL;
+        struct CGroupInfo *cg;
+        size_t n_allocated = 0, n = 0, k;
+        Iterator i;
+        int width, r;
+
+        /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
+         * combined, sorted, linear list. */
+
+        HASHMAP_FOREACH(cg, cgroups, i) {
+                const char *name;
+                void *pidp;
+                Iterator j;
+
+                if (cg->done)
+                        continue;
+
+                if (hashmap_isempty(cg->pids))
+                        continue;
+
+                r = hashmap_ensure_allocated(&names, &trivial_hash_ops);
+                if (r < 0)
+                        return r;
+
+                if (!GREEDY_REALLOC(pids, n_allocated, n + hashmap_size(cg->pids)))
+                        return -ENOMEM;
+
+                HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j) {
+                        pids[n++] = PTR_TO_PID(pidp);
+
+                        r = hashmap_put(names, pidp, (void*) name);
+                        if (r < 0)
+                                return r;
+                }
+        }
+
+        if (n == 0)
+                return 0;
+
+        typesafe_qsort(pids, n, pid_compare_func);
+        width = DECIMAL_STR_WIDTH(pids[n-1]);
+
+        for (k = 0; k < n; k++) {
+                _cleanup_free_ char *e = NULL;
+                const char *name;
+
+                name = hashmap_get(names, PID_TO_PTR(pids[k]));
+                assert(name);
+
+                if (n_columns != 0) {
+                        unsigned z;
+
+                        z = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
+
+                        e = ellipsize(name, z, 100);
+                        if (e)
+                                name = e;
+                }
+
+                fprintf(stdout, "%s%s %*" PID_PRI " %s\n",
+                        prefix,
+                        special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET),
+                        width, pids[k],
+                        name);
+        }
+
+        return 0;
+}
+
+int unit_show_processes(
+                sd_bus *bus,
+                const char *unit,
+                const char *cgroup_path,
+                const char *prefix,
+                unsigned n_columns,
+                OutputFlags flags,
+                sd_bus_error *error) {
+
+        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+        Hashmap *cgroups = NULL;
+        struct CGroupInfo *cg;
+        int r;
+
+        assert(bus);
+        assert(unit);
+
+        if (flags & OUTPUT_FULL_WIDTH)
+                n_columns = 0;
+        else if (n_columns <= 0)
+                n_columns = columns();
+
+        prefix = strempty(prefix);
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "GetUnitProcesses",
+                        error,
+                        &reply,
+                        "s",
+                        unit);
+        if (r < 0)
+                return r;
+
+        cgroups = hashmap_new(&path_hash_ops);
+        if (!cgroups)
+                return -ENOMEM;
+
+        r = sd_bus_message_enter_container(reply, 'a', "(sus)");
+        if (r < 0)
+                goto finish;
+
+        for (;;) {
+                const char *path = NULL, *name = NULL;
+                uint32_t pid;
+
+                r = sd_bus_message_read(reply, "(sus)", &path, &pid, &name);
+                if (r < 0)
+                        goto finish;
+                if (r == 0)
+                        break;
+
+                r = add_process(cgroups, path, pid, name);
+                if (r < 0)
+                        goto finish;
+        }
+
+        r = sd_bus_message_exit_container(reply);
+        if (r < 0)
+                goto finish;
+
+        r = dump_processes(cgroups, cgroup_path, prefix, n_columns, flags);
+        if (r < 0)
+                goto finish;
+
+        r = dump_extra_processes(cgroups, prefix, n_columns, flags);
+
+finish:
+        while ((cg = hashmap_first(cgroups)))
+               remove_cgroup(cgroups, cg);
+
+        hashmap_free(cgroups);
+
+        return r;
+}
diff --git a/src/shared/bus-unit-procs.h b/src/shared/bus-unit-procs.h
new file mode 100644 (file)
index 0000000..1cb5ca6
--- /dev/null
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "sd-bus.h"
+
+#include "output-mode.h"
+
+int unit_show_processes(sd_bus *bus, const char *unit, const char *cgroup_path, const char *prefix, unsigned n_columns, OutputFlags flags, sd_bus_error *error);
index 9a8051d..b42a9e5 100644 (file)
@@ -1,39 +1,36 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "alloc-util.h"
-#include "bus-internal.h"
+#include "bus-error.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
 #include "cap-list.h"
 #include "cgroup-util.h"
 #include "condition.h"
 #include "cpu-set-util.h"
-#include "env-util.h"
-#include "errno-list.h"
 #include "escape.h"
-#include "hashmap.h"
 #include "hexdecoct.h"
 #include "hostname-util.h"
 #include "in-addr-util.h"
 #include "ip-protocol-list.h"
-#include "list.h"
 #include "locale-util.h"
+#include "log.h"
 #include "missing_fs.h"
 #include "mountpoint-util.h"
 #include "nsflags.h"
 #include "parse-util.h"
-#include "path-util.h"
 #include "process-util.h"
 #include "rlimit-util.h"
 #include "securebits-util.h"
 #include "signal-util.h"
+#include "socket-util.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "syslog-util.h"
 #include "terminal-util.h"
 #include "unit-def.h"
 #include "user-util.h"
 #include "utf8.h"
-#include "util.h"
 
 int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
         assert(message);
@@ -464,6 +461,20 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
                 return 1;
         }
 
+        if (streq(field, "CPUQuotaPeriodSec")) {
+                usec_t u = USEC_INFINITY;
+
+                r = parse_sec_def_infinity(eq, &u);
+                if (r < 0)
+                        return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
+
+                r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
+                if (r < 0)
+                        return bus_log_create_error(r);
+
+                return 1;
+        }
+
         if (streq(field, "DeviceAllow")) {
 
                 if (isempty(eq))
@@ -730,17 +741,17 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
                        "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
                        "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
                        "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
-                       "RuntimeDirectoryPreserve", "Personality", "KeyringMode"))
+                       "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
 
                 return bus_append_string(m, field, eq);
 
         if (STR_IN_SET(field,
-                       "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
-                       "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
-                       "PrivateMounts", "NoNewPrivileges", "SyslogLevelPrefix",
-                       "MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
-                       "ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups",
-                       "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality"))
+                       "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
+                       "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
+                       "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
+                       "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
+                       "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
+                       "ProtectHostname", "RestrictSUIDSGID"))
 
                 return bus_append_parse_boolean(m, field, eq);
 
@@ -1488,7 +1499,8 @@ static int bus_append_socket_property(sd_bus_message *m, const char *field, cons
 static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
         int r;
 
-        if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent"))
+        if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent",
+                       "OnTimezoneChange", "OnClockChange"))
 
                 return bus_append_parse_boolean(m, field, eq);
 
@@ -1758,327 +1770,6 @@ int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char
         return 0;
 }
 
-typedef struct BusWaitForJobs {
-        sd_bus *bus;
-        Set *jobs;
-
-        char *name;
-        char *result;
-
-        sd_bus_slot *slot_job_removed;
-        sd_bus_slot *slot_disconnected;
-} BusWaitForJobs;
-
-static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        assert(m);
-
-        log_error("Warning! D-Bus connection terminated.");
-        sd_bus_close(sd_bus_message_get_bus(m));
-
-        return 0;
-}
-
-static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
-        const char *path, *unit, *result;
-        BusWaitForJobs *d = userdata;
-        uint32_t id;
-        char *found;
-        int r;
-
-        assert(m);
-        assert(d);
-
-        r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
-        if (r < 0) {
-                bus_log_parse_error(r);
-                return 0;
-        }
-
-        found = set_remove(d->jobs, (char*) path);
-        if (!found)
-                return 0;
-
-        free(found);
-
-        if (!isempty(result))
-                d->result = strdup(result);
-
-        if (!isempty(unit))
-                d->name = strdup(unit);
-
-        return 0;
-}
-
-void bus_wait_for_jobs_free(BusWaitForJobs *d) {
-        if (!d)
-                return;
-
-        set_free_free(d->jobs);
-
-        sd_bus_slot_unref(d->slot_disconnected);
-        sd_bus_slot_unref(d->slot_job_removed);
-
-        sd_bus_unref(d->bus);
-
-        free(d->name);
-        free(d->result);
-
-        free(d);
-}
-
-int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
-        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
-        int r;
-
-        assert(bus);
-        assert(ret);
-
-        d = new0(BusWaitForJobs, 1);
-        if (!d)
-                return -ENOMEM;
-
-        d->bus = sd_bus_ref(bus);
-
-        /* When we are a bus client we match by sender. Direct
-         * connections OTOH have no initialized sender field, and
-         * hence we ignore the sender then */
-        r = sd_bus_match_signal_async(
-                        bus,
-                        &d->slot_job_removed,
-                        bus->bus_client ? "org.freedesktop.systemd1" : NULL,
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "JobRemoved",
-                        match_job_removed, NULL, d);
-        if (r < 0)
-                return r;
-
-        r = sd_bus_match_signal_async(
-                        bus,
-                        &d->slot_disconnected,
-                        "org.freedesktop.DBus.Local",
-                        NULL,
-                        "org.freedesktop.DBus.Local",
-                        "Disconnected",
-                        match_disconnected, NULL, d);
-        if (r < 0)
-                return r;
-
-        *ret = TAKE_PTR(d);
-
-        return 0;
-}
-
-static int bus_process_wait(sd_bus *bus) {
-        int r;
-
-        for (;;) {
-                r = sd_bus_process(bus, NULL);
-                if (r < 0)
-                        return r;
-                if (r > 0)
-                        return 0;
-
-                r = sd_bus_wait(bus, (uint64_t) -1);
-                if (r < 0)
-                        return r;
-        }
-}
-
-static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
-        _cleanup_free_ char *dbus_path = NULL;
-
-        assert(d);
-        assert(d->name);
-        assert(result);
-
-        if (!endswith(d->name, ".service"))
-                return -EINVAL;
-
-        dbus_path = unit_dbus_path_from_name(d->name);
-        if (!dbus_path)
-                return -ENOMEM;
-
-        return sd_bus_get_property_string(d->bus,
-                                          "org.freedesktop.systemd1",
-                                          dbus_path,
-                                          "org.freedesktop.systemd1.Service",
-                                          "Result",
-                                          NULL,
-                                          result);
-}
-
-static const struct {
-        const char *result, *explanation;
-} explanations [] = {
-        { "resources",   "of unavailable resources or another system error" },
-        { "protocol",    "the service did not take the steps required by its unit configuration" },
-        { "timeout",     "a timeout was exceeded" },
-        { "exit-code",   "the control process exited with error code" },
-        { "signal",      "a fatal signal was delivered to the control process" },
-        { "core-dump",   "a fatal signal was delivered causing the control process to dump core" },
-        { "watchdog",    "the service failed to send watchdog ping" },
-        { "start-limit", "start of the service was attempted too often" }
-};
-
-static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
-        _cleanup_free_ char *service_shell_quoted = NULL;
-        const char *systemctl = "systemctl", *journalctl = "journalctl";
-
-        assert(service);
-
-        service_shell_quoted = shell_maybe_quote(service, ESCAPE_BACKSLASH);
-
-        if (!strv_isempty((char**) extra_args)) {
-                _cleanup_free_ char *t;
-
-                t = strv_join((char**) extra_args, " ");
-                systemctl = strjoina("systemctl ", t ? : "<args>");
-                journalctl = strjoina("journalctl ", t ? : "<args>");
-        }
-
-        if (!isempty(result)) {
-                unsigned i;
-
-                for (i = 0; i < ELEMENTSOF(explanations); ++i)
-                        if (streq(result, explanations[i].result))
-                                break;
-
-                if (i < ELEMENTSOF(explanations)) {
-                        log_error("Job for %s failed because %s.\n"
-                                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
-                                  service,
-                                  explanations[i].explanation,
-                                  systemctl,
-                                  service_shell_quoted ?: "<service>",
-                                  journalctl);
-                        goto finish;
-                }
-        }
-
-        log_error("Job for %s failed.\n"
-                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
-                  service,
-                  systemctl,
-                  service_shell_quoted ?: "<service>",
-                  journalctl);
-
-finish:
-        /* For some results maybe additional explanation is required */
-        if (streq_ptr(result, "start-limit"))
-                log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
-                         "followed by \"%1$s start %2$s\" again.",
-                         systemctl,
-                         service_shell_quoted ?: "<service>");
-}
-
-static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
-        assert(d->result);
-
-        if (!quiet) {
-                if (streq(d->result, "canceled"))
-                        log_error("Job for %s canceled.", strna(d->name));
-                else if (streq(d->result, "timeout"))
-                        log_error("Job for %s timed out.", strna(d->name));
-                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("%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"))
-                        log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
-                else if (streq(d->result, "collected"))
-                        log_error("Queued job for %s was garbage collected.", strna(d->name));
-                else if (streq(d->result, "once"))
-                        log_error("Unit %s was started already once and can't be started again.", strna(d->name));
-                else if (!STR_IN_SET(d->result, "done", "skipped")) {
-                        if (d->name) {
-                                _cleanup_free_ char *result = NULL;
-                                int q;
-
-                                q = bus_job_get_service_result(d, &result);
-                                if (q < 0)
-                                        log_debug_errno(q, "Failed to get Result property of unit %s: %m", d->name);
-
-                                log_job_error_with_service_result(d->name, result, extra_args);
-                        } else
-                                log_error("Job failed. See \"journalctl -xe\" for details.");
-                }
-        }
-
-        if (STR_IN_SET(d->result, "canceled", "collected"))
-                return -ECANCELED;
-        else if (streq(d->result, "timeout"))
-                return -ETIME;
-        else if (streq(d->result, "dependency"))
-                return -EIO;
-        else if (streq(d->result, "invalid"))
-                return -ENOEXEC;
-        else if (streq(d->result, "assert"))
-                return -EPROTO;
-        else if (streq(d->result, "unsupported"))
-                return -EOPNOTSUPP;
-        else if (streq(d->result, "once"))
-                return -ESTALE;
-        else if (STR_IN_SET(d->result, "done", "skipped"))
-                return 0;
-
-        return log_debug_errno(SYNTHETIC_ERRNO(EIO),
-                               "Unexpected job result, assuming server side newer than us: %s", d->result);
-}
-
-int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
-        int r = 0;
-
-        assert(d);
-
-        while (!set_isempty(d->jobs)) {
-                int q;
-
-                q = bus_process_wait(d->bus);
-                if (q < 0)
-                        return log_error_errno(q, "Failed to wait for response: %m");
-
-                if (d->result) {
-                        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)
-                                r = q;
-
-                        log_debug_errno(q, "Got result %s/%m for job %s", strna(d->result), strna(d->name));
-                }
-
-                d->name = mfree(d->name);
-                d->result = mfree(d->result);
-        }
-
-        return r;
-}
-
-int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
-        int r;
-
-        assert(d);
-
-        r = set_ensure_allocated(&d->jobs, &string_hash_ops);
-        if (r < 0)
-                return r;
-
-        return set_put_strdup(d->jobs, path);
-}
-
-int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
-        int r;
-
-        r = bus_wait_for_jobs_add(d, path);
-        if (r < 0)
-                return log_oom();
-
-        return bus_wait_for_jobs(d, quiet, NULL);
-}
-
 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
         const char *type, *path, *source;
         int r;
@@ -2117,409 +1808,6 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un
         return 0;
 }
 
-struct CGroupInfo {
-        char *cgroup_path;
-        bool is_const; /* If false, cgroup_path should be free()'d */
-
-        Hashmap *pids; /* PID → process name */
-        bool done;
-
-        struct CGroupInfo *parent;
-        LIST_FIELDS(struct CGroupInfo, siblings);
-        LIST_HEAD(struct CGroupInfo, children);
-        size_t n_children;
-};
-
-static bool IS_ROOT(const char *p) {
-        return isempty(p) || streq(p, "/");
-}
-
-static int add_cgroup(Hashmap *cgroups, const char *path, bool is_const, struct CGroupInfo **ret) {
-        struct CGroupInfo *parent = NULL, *cg;
-        int r;
-
-        assert(cgroups);
-        assert(ret);
-
-        if (IS_ROOT(path))
-                path = "/";
-
-        cg = hashmap_get(cgroups, path);
-        if (cg) {
-                *ret = cg;
-                return 0;
-        }
-
-        if (!IS_ROOT(path)) {
-                const char *e, *pp;
-
-                e = strrchr(path, '/');
-                if (!e)
-                        return -EINVAL;
-
-                pp = strndupa(path, e - path);
-                if (!pp)
-                        return -ENOMEM;
-
-                r = add_cgroup(cgroups, pp, false, &parent);
-                if (r < 0)
-                        return r;
-        }
-
-        cg = new0(struct CGroupInfo, 1);
-        if (!cg)
-                return -ENOMEM;
-
-        if (is_const)
-                cg->cgroup_path = (char*) path;
-        else {
-                cg->cgroup_path = strdup(path);
-                if (!cg->cgroup_path) {
-                        free(cg);
-                        return -ENOMEM;
-                }
-        }
-
-        cg->is_const = is_const;
-        cg->parent = parent;
-
-        r = hashmap_put(cgroups, cg->cgroup_path, cg);
-        if (r < 0) {
-                if (!is_const)
-                        free(cg->cgroup_path);
-                free(cg);
-                return r;
-        }
-
-        if (parent) {
-                LIST_PREPEND(siblings, parent->children, cg);
-                parent->n_children++;
-        }
-
-        *ret = cg;
-        return 1;
-}
-
-static int add_process(
-                Hashmap *cgroups,
-                const char *path,
-                pid_t pid,
-                const char *name) {
-
-        struct CGroupInfo *cg;
-        int r;
-
-        assert(cgroups);
-        assert(name);
-        assert(pid > 0);
-
-        r = add_cgroup(cgroups, path, true, &cg);
-        if (r < 0)
-                return r;
-
-        r = hashmap_ensure_allocated(&cg->pids, &trivial_hash_ops);
-        if (r < 0)
-                return r;
-
-        return hashmap_put(cg->pids, PID_TO_PTR(pid), (void*) name);
-}
-
-static void remove_cgroup(Hashmap *cgroups, struct CGroupInfo *cg) {
-        assert(cgroups);
-        assert(cg);
-
-        while (cg->children)
-                remove_cgroup(cgroups, cg->children);
-
-        hashmap_remove(cgroups, cg->cgroup_path);
-
-        if (!cg->is_const)
-                free(cg->cgroup_path);
-
-        hashmap_free(cg->pids);
-
-        if (cg->parent)
-                LIST_REMOVE(siblings, cg->parent->children, cg);
-
-        free(cg);
-}
-
-static int cgroup_info_compare_func(struct CGroupInfo * const *a, struct CGroupInfo * const *b) {
-        return strcmp((*a)->cgroup_path, (*b)->cgroup_path);
-}
-
-static int dump_processes(
-                Hashmap *cgroups,
-                const char *cgroup_path,
-                const char *prefix,
-                unsigned n_columns,
-                OutputFlags flags) {
-
-        struct CGroupInfo *cg;
-        int r;
-
-        assert(prefix);
-
-        if (IS_ROOT(cgroup_path))
-                cgroup_path = "/";
-
-        cg = hashmap_get(cgroups, cgroup_path);
-        if (!cg)
-                return 0;
-
-        if (!hashmap_isempty(cg->pids)) {
-                const char *name;
-                size_t n = 0, i;
-                pid_t *pids;
-                void *pidp;
-                Iterator j;
-                int width;
-
-                /* Order processes by their PID */
-                pids = newa(pid_t, hashmap_size(cg->pids));
-
-                HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j)
-                        pids[n++] = PTR_TO_PID(pidp);
-
-                assert(n == hashmap_size(cg->pids));
-                typesafe_qsort(pids, n, pid_compare_func);
-
-                width = DECIMAL_STR_WIDTH(pids[n-1]);
-
-                for (i = 0; i < n; i++) {
-                        _cleanup_free_ char *e = NULL;
-                        const char *special;
-                        bool more;
-
-                        name = hashmap_get(cg->pids, PID_TO_PTR(pids[i]));
-                        assert(name);
-
-                        if (n_columns != 0) {
-                                unsigned k;
-
-                                k = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
-
-                                e = ellipsize(name, k, 100);
-                                if (e)
-                                        name = e;
-                        }
-
-                        more = i+1 < n || cg->children;
-                        special = special_glyph(more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT);
-
-                        fprintf(stdout, "%s%s%*"PID_PRI" %s\n",
-                                prefix,
-                                special,
-                                width, pids[i],
-                                name);
-                }
-        }
-
-        if (cg->children) {
-                struct CGroupInfo **children, *child;
-                size_t n = 0, i;
-
-                /* Order subcgroups by their name */
-                children = newa(struct CGroupInfo*, cg->n_children);
-                LIST_FOREACH(siblings, child, cg->children)
-                        children[n++] = child;
-                assert(n == cg->n_children);
-                typesafe_qsort(children, n, cgroup_info_compare_func);
-
-                if (n_columns != 0)
-                        n_columns = MAX(LESS_BY(n_columns, 2U), 20U);
-
-                for (i = 0; i < n; i++) {
-                        _cleanup_free_ char *pp = NULL;
-                        const char *name, *special;
-                        bool more;
-
-                        child = children[i];
-
-                        name = strrchr(child->cgroup_path, '/');
-                        if (!name)
-                                return -EINVAL;
-                        name++;
-
-                        more = i+1 < n;
-                        special = special_glyph(more ? SPECIAL_GLYPH_TREE_BRANCH : SPECIAL_GLYPH_TREE_RIGHT);
-
-                        fputs(prefix, stdout);
-                        fputs(special, stdout);
-                        fputs(name, stdout);
-                        fputc('\n', stdout);
-
-                        special = special_glyph(more ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE);
-
-                        pp = strappend(prefix, special);
-                        if (!pp)
-                                return -ENOMEM;
-
-                        r = dump_processes(cgroups, child->cgroup_path, pp, n_columns, flags);
-                        if (r < 0)
-                                return r;
-                }
-        }
-
-        cg->done = true;
-        return 0;
-}
-
-static int dump_extra_processes(
-                Hashmap *cgroups,
-                const char *prefix,
-                unsigned n_columns,
-                OutputFlags flags) {
-
-        _cleanup_free_ pid_t *pids = NULL;
-        _cleanup_hashmap_free_ Hashmap *names = NULL;
-        struct CGroupInfo *cg;
-        size_t n_allocated = 0, n = 0, k;
-        Iterator i;
-        int width, r;
-
-        /* Prints the extra processes, i.e. those that are in cgroups we haven't displayed yet. We show them as
-         * combined, sorted, linear list. */
-
-        HASHMAP_FOREACH(cg, cgroups, i) {
-                const char *name;
-                void *pidp;
-                Iterator j;
-
-                if (cg->done)
-                        continue;
-
-                if (hashmap_isempty(cg->pids))
-                        continue;
-
-                r = hashmap_ensure_allocated(&names, &trivial_hash_ops);
-                if (r < 0)
-                        return r;
-
-                if (!GREEDY_REALLOC(pids, n_allocated, n + hashmap_size(cg->pids)))
-                        return -ENOMEM;
-
-                HASHMAP_FOREACH_KEY(name, pidp, cg->pids, j) {
-                        pids[n++] = PTR_TO_PID(pidp);
-
-                        r = hashmap_put(names, pidp, (void*) name);
-                        if (r < 0)
-                                return r;
-                }
-        }
-
-        if (n == 0)
-                return 0;
-
-        typesafe_qsort(pids, n, pid_compare_func);
-        width = DECIMAL_STR_WIDTH(pids[n-1]);
-
-        for (k = 0; k < n; k++) {
-                _cleanup_free_ char *e = NULL;
-                const char *name;
-
-                name = hashmap_get(names, PID_TO_PTR(pids[k]));
-                assert(name);
-
-                if (n_columns != 0) {
-                        unsigned z;
-
-                        z = MAX(LESS_BY(n_columns, 2U + width + 1U), 20U);
-
-                        e = ellipsize(name, z, 100);
-                        if (e)
-                                name = e;
-                }
-
-                fprintf(stdout, "%s%s %*" PID_PRI " %s\n",
-                        prefix,
-                        special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET),
-                        width, pids[k],
-                        name);
-        }
-
-        return 0;
-}
-
-int unit_show_processes(
-                sd_bus *bus,
-                const char *unit,
-                const char *cgroup_path,
-                const char *prefix,
-                unsigned n_columns,
-                OutputFlags flags,
-                sd_bus_error *error) {
-
-        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
-        Hashmap *cgroups = NULL;
-        struct CGroupInfo *cg;
-        int r;
-
-        assert(bus);
-        assert(unit);
-
-        if (flags & OUTPUT_FULL_WIDTH)
-                n_columns = 0;
-        else if (n_columns <= 0)
-                n_columns = columns();
-
-        prefix = strempty(prefix);
-
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        "GetUnitProcesses",
-                        error,
-                        &reply,
-                        "s",
-                        unit);
-        if (r < 0)
-                return r;
-
-        cgroups = hashmap_new(&path_hash_ops);
-        if (!cgroups)
-                return -ENOMEM;
-
-        r = sd_bus_message_enter_container(reply, 'a', "(sus)");
-        if (r < 0)
-                goto finish;
-
-        for (;;) {
-                const char *path = NULL, *name = NULL;
-                uint32_t pid;
-
-                r = sd_bus_message_read(reply, "(sus)", &path, &pid, &name);
-                if (r < 0)
-                        goto finish;
-                if (r == 0)
-                        break;
-
-                r = add_process(cgroups, path, pid, name);
-                if (r < 0)
-                        goto finish;
-        }
-
-        r = sd_bus_message_exit_container(reply);
-        if (r < 0)
-                goto finish;
-
-        r = dump_processes(cgroups, cgroup_path, prefix, n_columns, flags);
-        if (r < 0)
-                goto finish;
-
-        r = dump_extra_processes(cgroups, prefix, n_columns, flags);
-
-finish:
-        while ((cg = hashmap_first(cgroups)))
-               remove_cgroup(cgroups, cg);
-
-        hashmap_free(cgroups);
-
-        return r;
-}
-
 int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_free_ char *path = NULL;
index 4fc94b0..a0b496f 100644 (file)
@@ -1,9 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-#include "install.h"
-#include "output-mode.h"
 #include "sd-bus.h"
+
+#include "install.h"
 #include "unit-def.h"
 
 typedef struct UnitInfo {
@@ -25,18 +25,6 @@ int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u);
 int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment);
 int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l);
 
-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, const char* const* 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);
-
 int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes);
 
-int unit_show_processes(sd_bus *bus, const char *unit, const char *cgroup_path, const char *prefix, unsigned n_columns, OutputFlags flags, sd_bus_error *error);
-
 int unit_load_state(sd_bus *bus, const char *name, char **load_state);
index a489651..b35b362 100644 (file)
@@ -410,14 +410,14 @@ int bus_verify_polkit_async(
                 if (sd_bus_message_is_method_error(q->reply, NULL)) {
                         const sd_bus_error *e;
 
-                        /* Copy error from polkit reply */
                         e = sd_bus_message_get_error(q->reply);
-                        sd_bus_error_copy(error, e);
 
                         /* Treat no PK available as access denied */
                         if (sd_bus_error_has_name(e, SD_BUS_ERROR_SERVICE_UNKNOWN))
                                 return -EACCES;
 
+                        /* Copy error from polkit reply */
+                        sd_bus_error_copy(error, e);
                         return -sd_bus_error_get_errno(e);
                 }
 
@@ -668,7 +668,21 @@ int bus_connect_user_systemd(sd_bus **_bus) {
         return 0;
 }
 
-int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) {
+int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *value) {
+        assert(name);
+
+        if (expected_value && !streq_ptr(expected_value, value))
+                return 0;
+
+        if (only_value)
+                puts(value);
+        else
+                printf("%s=%s\n", name, value);
+
+        return 0;
+}
+
+int bus_print_property_valuef(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) {
         va_list ap;
         int r;
 
@@ -731,7 +745,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                         /* This property has a single value, so we need to take
                          * care not to print a new line, everything else is OK. */
                         good = !strchr(s, '\n');
-                        bus_print_property_value(name, expected_value, value, "%s", good ? s : "[unprintable]");
+                        bus_print_property_value(name, expected_value, value, good ? s : "[unprintable]");
                 }
 
                 return 1;
@@ -747,7 +761,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                 if (expected_value && parse_boolean(expected_value) != b)
                         return 1;
 
-                bus_print_property_value(name, NULL, value, "%s", yes_no(b));
+                bus_print_property_value(name, NULL, value, yes_no(b));
                 return 1;
         }
 
@@ -768,13 +782,13 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
 
                         t = format_timestamp(timestamp, sizeof(timestamp), u);
                         if (t || all)
-                                bus_print_property_value(name, expected_value, value, "%s", strempty(t));
+                                bus_print_property_value(name, expected_value, value, strempty(t));
 
                 } else if (strstr(name, "USec")) {
                         char timespan[FORMAT_TIMESPAN_MAX];
 
                         (void) format_timespan(timespan, sizeof(timespan), u, 0);
-                        bus_print_property_value(name, expected_value, value, "%s", timespan);
+                        bus_print_property_value(name, expected_value, value, timespan);
 
                 } else if (streq(name, "RestrictNamespaces")) {
                         _cleanup_free_ char *s = NULL;
@@ -782,7 +796,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
 
                         if ((u & NAMESPACE_FLAGS_ALL) == 0)
                                 result = "yes";
-                        else if ((u & NAMESPACE_FLAGS_ALL) == NAMESPACE_FLAGS_ALL)
+                        else if (FLAGS_SET(u, NAMESPACE_FLAGS_ALL))
                                 result = "no";
                         else {
                                 r = namespace_flags_to_string(u, &s);
@@ -792,7 +806,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                                 result = s;
                         }
 
-                        bus_print_property_value(name, expected_value, value, "%s", result);
+                        bus_print_property_value(name, expected_value, value, result);
 
                 } else if (streq(name, "MountFlags")) {
                         const char *result;
@@ -801,7 +815,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                         if (!result)
                                 return -EINVAL;
 
-                        bus_print_property_value(name, expected_value, value, "%s", result);
+                        bus_print_property_value(name, expected_value, value, result);
 
                 } else if (STR_IN_SET(name, "CapabilityBoundingSet", "AmbientCapabilities")) {
                         _cleanup_free_ char *s = NULL;
@@ -810,7 +824,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                         if (r < 0)
                                 return r;
 
-                        bus_print_property_value(name, expected_value, value, "%s", s);
+                        bus_print_property_value(name, expected_value, value, s);
 
                 } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) ||
                            (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) ||
@@ -818,16 +832,18 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                            (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) ||
                            (endswith(name, "NSec") && u == (uint64_t) -1))
 
-                        bus_print_property_value(name, expected_value, value, "%s", "[not set]");
+                        bus_print_property_value(name, expected_value, value, "[not set]");
 
                 else if ((STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
                          (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
                          (startswith(name, "Limit") && u == (uint64_t) -1) ||
                          (startswith(name, "DefaultLimit") && u == (uint64_t) -1))
 
-                        bus_print_property_value(name, expected_value, value, "%s", "infinity");
+                        bus_print_property_value(name, expected_value, value, "infinity");
+                else if (STR_IN_SET(name, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u == (uint64_t) -1)
+                        bus_print_property_value(name, expected_value, value, "[no data]");
                 else
-                        bus_print_property_value(name, expected_value, value, "%"PRIu64, u);
+                        bus_print_property_valuef(name, expected_value, value, "%"PRIu64, u);
 
                 return 1;
         }
@@ -839,7 +855,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                 if (r < 0)
                         return r;
 
-                bus_print_property_value(name, expected_value, value, "%"PRIi64, i);
+                bus_print_property_valuef(name, expected_value, value, "%"PRIi64, i);
                 return 1;
         }
 
@@ -851,20 +867,20 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                         return r;
 
                 if (strstr(name, "UMask") || strstr(name, "Mode"))
-                        bus_print_property_value(name, expected_value, value, "%04o", u);
+                        bus_print_property_valuef(name, expected_value, value, "%04o", u);
 
                 else if (streq(name, "UID")) {
                         if (u == UID_INVALID)
-                                bus_print_property_value(name, expected_value, value, "%s", "[not set]");
+                                bus_print_property_value(name, expected_value, value, "[not set]");
                         else
-                                bus_print_property_value(name, expected_value, value, "%"PRIu32, u);
+                                bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
                 } else if (streq(name, "GID")) {
                         if (u == GID_INVALID)
-                                bus_print_property_value(name, expected_value, value, "%s", "[not set]");
+                                bus_print_property_value(name, expected_value, value, "[not set]");
                         else
-                                bus_print_property_value(name, expected_value, value, "%"PRIu32, u);
+                                bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
                 } else
-                        bus_print_property_value(name, expected_value, value, "%"PRIu32, u);
+                        bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
 
                 return 1;
         }
@@ -876,7 +892,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                 if (r < 0)
                         return r;
 
-                bus_print_property_value(name, expected_value, value, "%"PRIi32, i);
+                bus_print_property_valuef(name, expected_value, value, "%"PRIi32, i);
                 return 1;
         }
 
@@ -887,7 +903,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
                 if (r < 0)
                         return r;
 
-                bus_print_property_value(name, expected_value, value, "%g", d);
+                bus_print_property_valuef(name, expected_value, value, "%g", d);
                 return 1;
         }
 
index a79546c..00d948d 100644 (file)
@@ -12,6 +12,7 @@
 #include "hashmap.h"
 #include "macro.h"
 #include "string-util.h"
+#include "time-util.h"
 
 typedef enum BusTransport {
         BUS_TRANSPORT_LOCAL,
@@ -64,7 +65,8 @@ int bus_connect_transport_systemd(BusTransport transport, const char *host, bool
 
 typedef int (*bus_message_print_t) (const char *name, const char *expected_value, sd_bus_message *m, bool value, bool all);
 
-int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) _printf_(4,5);
+int bus_print_property_value(const char *name, const char *expected_value, bool only_value, const char *value);
+int bus_print_property_valuef(const char *name, const char *expected_value, bool only_value, const char *fmt, ...) _printf_(4,5);
 int bus_message_print_all_properties(sd_bus_message *m, bus_message_print_t func, char **filter, bool value, bool all, Set **found_properties);
 int bus_print_all_properties(sd_bus *bus, const char *dest, const char *path, bus_message_print_t func, char **filter, bool value, bool all, Set **found_properties);
 
diff --git a/src/shared/bus-wait-for-jobs.c b/src/shared/bus-wait-for-jobs.c
new file mode 100644 (file)
index 0000000..4e6b862
--- /dev/null
@@ -0,0 +1,337 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "bus-wait-for-jobs.h"
+#include "set.h"
+#include "bus-util.h"
+#include "bus-internal.h"
+#include "unit-def.h"
+#include "escape.h"
+#include "strv.h"
+
+typedef struct BusWaitForJobs {
+        sd_bus *bus;
+
+        /* The set of jobs to wait for, as bus object paths */
+        Set *jobs;
+
+        /* The unit name and job result of the last Job message */
+        char *name;
+        char *result;
+
+        sd_bus_slot *slot_job_removed;
+        sd_bus_slot *slot_disconnected;
+} BusWaitForJobs;
+
+static int match_disconnected(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        assert(m);
+
+        log_error("Warning! D-Bus connection terminated.");
+        sd_bus_close(sd_bus_message_get_bus(m));
+
+        return 0;
+}
+
+static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+        const char *path, *unit, *result;
+        BusWaitForJobs *d = userdata;
+        uint32_t id;
+        char *found;
+        int r;
+
+        assert(m);
+        assert(d);
+
+        r = sd_bus_message_read(m, "uoss", &id, &path, &unit, &result);
+        if (r < 0) {
+                bus_log_parse_error(r);
+                return 0;
+        }
+
+        found = set_remove(d->jobs, (char*) path);
+        if (!found)
+                return 0;
+
+        free(found);
+
+        (void) free_and_strdup(&d->result, empty_to_null(result));
+
+        (void) free_and_strdup(&d->name, empty_to_null(unit));
+
+        return 0;
+}
+
+void bus_wait_for_jobs_free(BusWaitForJobs *d) {
+        if (!d)
+                return;
+
+        set_free_free(d->jobs);
+
+        sd_bus_slot_unref(d->slot_disconnected);
+        sd_bus_slot_unref(d->slot_job_removed);
+
+        sd_bus_unref(d->bus);
+
+        free(d->name);
+        free(d->result);
+
+        free(d);
+}
+
+int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) {
+        _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *d = NULL;
+        int r;
+
+        assert(bus);
+        assert(ret);
+
+        d = new(BusWaitForJobs, 1);
+        if (!d)
+                return -ENOMEM;
+
+        *d = (BusWaitForJobs) {
+                .bus = sd_bus_ref(bus),
+        };
+
+        /* When we are a bus client we match by sender. Direct
+         * connections OTOH have no initialized sender field, and
+         * hence we ignore the sender then */
+        r = sd_bus_match_signal_async(
+                        bus,
+                        &d->slot_job_removed,
+                        bus->bus_client ? "org.freedesktop.systemd1" : NULL,
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "JobRemoved",
+                        match_job_removed, NULL, d);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_match_signal_async(
+                        bus,
+                        &d->slot_disconnected,
+                        "org.freedesktop.DBus.Local",
+                        NULL,
+                        "org.freedesktop.DBus.Local",
+                        "Disconnected",
+                        match_disconnected, NULL, d);
+        if (r < 0)
+                return r;
+
+        *ret = TAKE_PTR(d);
+
+        return 0;
+}
+
+static int bus_process_wait(sd_bus *bus) {
+        int r;
+
+        for (;;) {
+                r = sd_bus_process(bus, NULL);
+                if (r < 0)
+                        return r;
+                if (r > 0)
+                        return 0;
+
+                r = sd_bus_wait(bus, (uint64_t) -1);
+                if (r < 0)
+                        return r;
+        }
+}
+
+static int bus_job_get_service_result(BusWaitForJobs *d, char **result) {
+        _cleanup_free_ char *dbus_path = NULL;
+
+        assert(d);
+        assert(d->name);
+        assert(result);
+
+        if (!endswith(d->name, ".service"))
+                return -EINVAL;
+
+        dbus_path = unit_dbus_path_from_name(d->name);
+        if (!dbus_path)
+                return -ENOMEM;
+
+        return sd_bus_get_property_string(d->bus,
+                                          "org.freedesktop.systemd1",
+                                          dbus_path,
+                                          "org.freedesktop.systemd1.Service",
+                                          "Result",
+                                          NULL,
+                                          result);
+}
+
+static void log_job_error_with_service_result(const char* service, const char *result, const char* const* extra_args) {
+        _cleanup_free_ char *service_shell_quoted = NULL;
+        const char *systemctl = "systemctl", *journalctl = "journalctl";
+
+        static const struct {
+                const char *result, *explanation;
+        } explanations[] = {
+                { "resources",   "of unavailable resources or another system error" },
+                { "protocol",    "the service did not take the steps required by its unit configuration" },
+                { "timeout",     "a timeout was exceeded" },
+                { "exit-code",   "the control process exited with error code" },
+                { "signal",      "a fatal signal was delivered to the control process" },
+                { "core-dump",   "a fatal signal was delivered causing the control process to dump core" },
+                { "watchdog",    "the service failed to send watchdog ping" },
+                { "start-limit", "start of the service was attempted too often" }
+        };
+
+        assert(service);
+
+        service_shell_quoted = shell_maybe_quote(service, ESCAPE_BACKSLASH);
+
+        if (!strv_isempty((char**) extra_args)) {
+                _cleanup_free_ char *t;
+
+                t = strv_join((char**) extra_args, " ");
+                systemctl = strjoina("systemctl ", t ? : "<args>");
+                journalctl = strjoina("journalctl ", t ? : "<args>");
+        }
+
+        if (!isempty(result)) {
+                size_t i;
+
+                for (i = 0; i < ELEMENTSOF(explanations); ++i)
+                        if (streq(result, explanations[i].result))
+                                break;
+
+                if (i < ELEMENTSOF(explanations)) {
+                        log_error("Job for %s failed because %s.\n"
+                                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
+                                  service,
+                                  explanations[i].explanation,
+                                  systemctl,
+                                  service_shell_quoted ?: "<service>",
+                                  journalctl);
+                        goto finish;
+                }
+        }
+
+        log_error("Job for %s failed.\n"
+                  "See \"%s status %s\" and \"%s -xe\" for details.\n",
+                  service,
+                  systemctl,
+                  service_shell_quoted ?: "<service>",
+                  journalctl);
+
+finish:
+        /* For some results maybe additional explanation is required */
+        if (streq_ptr(result, "start-limit"))
+                log_info("To force a start use \"%1$s reset-failed %2$s\"\n"
+                         "followed by \"%1$s start %2$s\" again.",
+                         systemctl,
+                         service_shell_quoted ?: "<service>");
+}
+
+static int check_wait_response(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
+        assert(d);
+        assert(d->name);
+        assert(d->result);
+
+        if (!quiet) {
+                if (streq(d->result, "canceled"))
+                        log_error("Job for %s canceled.", strna(d->name));
+                else if (streq(d->result, "timeout"))
+                        log_error("Job for %s timed out.", strna(d->name));
+                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("%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"))
+                        log_error("Operation on or unit type of %s not supported on this system.", strna(d->name));
+                else if (streq(d->result, "collected"))
+                        log_error("Queued job for %s was garbage collected.", strna(d->name));
+                else if (streq(d->result, "once"))
+                        log_error("Unit %s was started already once and can't be started again.", strna(d->name));
+                else if (!STR_IN_SET(d->result, "done", "skipped")) {
+
+                        if (d->name && endswith(d->name, ".service")) {
+                                _cleanup_free_ char *result = NULL;
+                                int q;
+
+                                q = bus_job_get_service_result(d, &result);
+                                if (q < 0)
+                                        log_debug_errno(q, "Failed to get Result property of unit %s: %m", d->name);
+
+                                log_job_error_with_service_result(d->name, result, extra_args);
+                        } else
+                                log_error("Job failed. See \"journalctl -xe\" for details.");
+                }
+        }
+
+        if (STR_IN_SET(d->result, "canceled", "collected"))
+                return -ECANCELED;
+        else if (streq(d->result, "timeout"))
+                return -ETIME;
+        else if (streq(d->result, "dependency"))
+                return -EIO;
+        else if (streq(d->result, "invalid"))
+                return -ENOEXEC;
+        else if (streq(d->result, "assert"))
+                return -EPROTO;
+        else if (streq(d->result, "unsupported"))
+                return -EOPNOTSUPP;
+        else if (streq(d->result, "once"))
+                return -ESTALE;
+        else if (STR_IN_SET(d->result, "done", "skipped"))
+                return 0;
+
+        return log_debug_errno(SYNTHETIC_ERRNO(EIO),
+                               "Unexpected job result, assuming server side newer than us: %s", d->result);
+}
+
+int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args) {
+        int r = 0;
+
+        assert(d);
+
+        while (!set_isempty(d->jobs)) {
+                int q;
+
+                q = bus_process_wait(d->bus);
+                if (q < 0)
+                        return log_error_errno(q, "Failed to wait for response: %m");
+
+                if (d->name && d->result) {
+                        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)
+                                r = q;
+
+                        log_debug_errno(q, "Got result %s/%m for job %s", d->result, d->name);
+                }
+
+                d->name = mfree(d->name);
+                d->result = mfree(d->result);
+        }
+
+        return r;
+}
+
+int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path) {
+        int r;
+
+        assert(d);
+
+        r = set_ensure_allocated(&d->jobs, &string_hash_ops);
+        if (r < 0)
+                return r;
+
+        return set_put_strdup(d->jobs, path);
+}
+
+int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet) {
+        int r;
+
+        r = bus_wait_for_jobs_add(d, path);
+        if (r < 0)
+                return log_oom();
+
+        return bus_wait_for_jobs(d, quiet, NULL);
+}
diff --git a/src/shared/bus-wait-for-jobs.h b/src/shared/bus-wait-for-jobs.h
new file mode 100644 (file)
index 0000000..8f21eb9
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "sd-bus.h"
+#include "macro.h"
+
+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, const char* const* 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);
index dafc09e..d83e796 100644 (file)
 
 #include "alloc-util.h"
 #include "calendarspec.h"
+#include "errno-util.h"
 #include "fileio.h"
 #include "macro.h"
 #include "parse-util.h"
 #include "process-util.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "time-util.h"
 
@@ -31,7 +33,7 @@
  * linked compenents anyway. */
 #define CALENDARSPEC_COMPONENTS_MAX 240
 
-static void free_chain(CalendarComponent *c) {
+static void chain_free(CalendarComponent *c) {
         CalendarComponent *n;
 
         while (c) {
@@ -41,17 +43,19 @@ static void free_chain(CalendarComponent *c) {
         }
 }
 
+DEFINE_TRIVIAL_CLEANUP_FUNC(CalendarComponent*, chain_free);
+
 CalendarSpec* calendar_spec_free(CalendarSpec *c) {
 
         if (!c)
                 return NULL;
 
-        free_chain(c->year);
-        free_chain(c->month);
-        free_chain(c->day);
-        free_chain(c->hour);
-        free_chain(c->minute);
-        free_chain(c->microsecond);
+        chain_free(c->year);
+        chain_free(c->month);
+        chain_free(c->day);
+        chain_free(c->hour);
+        chain_free(c->minute);
+        chain_free(c->microsecond);
         free(c->timezone);
 
         return mfree(c);
@@ -549,14 +553,16 @@ static int const_chain(int value, CalendarComponent **c) {
 
         assert(c);
 
-        cc = new0(CalendarComponent, 1);
+        cc = new(CalendarComponent, 1);
         if (!cc)
                 return -ENOMEM;
 
-        cc->start = value;
-        cc->stop = -1;
-        cc->repeat = 0;
-        cc->next = *c;
+        *cc = (CalendarComponent) {
+                .start = value,
+                .stop = -1,
+                .repeat = 0,
+                .next = *c,
+        };
 
         *c = cc;
 
@@ -564,13 +570,18 @@ static int const_chain(int value, CalendarComponent **c) {
 }
 
 static int calendarspec_from_time_t(CalendarSpec *c, time_t time) {
+        _cleanup_(chain_freep) CalendarComponent
+                *year = NULL, *month = NULL, *day = NULL,
+                *hour = NULL, *minute = NULL, *us = NULL;
         struct tm tm;
-        CalendarComponent *year = NULL, *month = NULL, *day = NULL, *hour = NULL, *minute = NULL, *us = NULL;
         int r;
 
         if (!gmtime_r(&time, &tm))
                 return -ERANGE;
 
+        if (tm.tm_year > INT_MAX - 1900)
+                return -ERANGE;
+
         r = const_chain(tm.tm_year + 1900, &year);
         if (r < 0)
                 return r;
@@ -596,12 +607,12 @@ static int calendarspec_from_time_t(CalendarSpec *c, time_t time) {
                 return r;
 
         c->utc = true;
-        c->year = year;
-        c->month = month;
-        c->day = day;
-        c->hour = hour;
-        c->minute = minute;
-        c->microsecond = us;
+        c->year = TAKE_PTR(year);
+        c->month = TAKE_PTR(month);
+        c->day = TAKE_PTR(day);
+        c->hour = TAKE_PTR(hour);
+        c->minute = TAKE_PTR(minute);
+        c->microsecond = TAKE_PTR(us);
         return 0;
 }
 
@@ -642,14 +653,16 @@ static int prepend_component(const char **p, bool usec, unsigned nesting, Calend
         if (!IN_SET(*e, 0, ' ', ',', '-', '~', ':'))
                 return -EINVAL;
 
-        cc = new0(CalendarComponent, 1);
+        cc = new(CalendarComponent, 1);
         if (!cc)
                 return -ENOMEM;
 
-        cc->start = start;
-        cc->stop = stop;
-        cc->repeat = repeat;
-        cc->next = *c;
+        *cc = (CalendarComponent) {
+                .start = start,
+                .stop = stop,
+                .repeat = repeat,
+                .next = *c,
+        };
 
         *p = e;
         *c = cc;
@@ -663,8 +676,8 @@ static int prepend_component(const char **p, bool usec, unsigned nesting, Calend
 }
 
 static int parse_chain(const char **p, bool usec, CalendarComponent **c) {
+        _cleanup_(chain_freep) CalendarComponent *cc = NULL;
         const char *t;
-        CalendarComponent *cc = NULL;
         int r;
 
         assert(p);
@@ -686,20 +699,18 @@ static int parse_chain(const char **p, bool usec, CalendarComponent **c) {
         }
 
         r = prepend_component(&t, usec, 0, &cc);
-        if (r < 0) {
-                free_chain(cc);
+        if (r < 0)
                 return r;
-        }
 
         *p = t;
-        *c = cc;
+        *c = TAKE_PTR(cc);
         return 0;
 }
 
 static int parse_date(const char **p, CalendarSpec *c) {
+        _cleanup_(chain_freep) CalendarComponent *first = NULL, *second = NULL, *third = NULL;
         const char *t;
         int r;
-        CalendarComponent *first, *second, *third;
 
         assert(p);
         assert(*p);
@@ -736,70 +747,51 @@ static int parse_date(const char **p, CalendarSpec *c) {
                 return r;
 
         /* Already the end? A ':' as separator? In that case this was a time, not a date */
-        if (IN_SET(*t, 0, ':')) {
-                free_chain(first);
+        if (IN_SET(*t, 0, ':'))
                 return 0;
-        }
 
         if (*t == '~')
                 c->end_of_month = true;
-        else if (*t != '-') {
-                free_chain(first);
+        else if (*t != '-')
                 return -EINVAL;
-        }
 
         t++;
         r = parse_chain(&t, false, &second);
-        if (r < 0) {
-                free_chain(first);
+        if (r < 0)
                 return r;
-        }
 
         /* Got two parts, hence it's month and day */
         if (IN_SET(*t, 0, ' ')) {
                 *p = t + strspn(t, " ");
-                c->month = first;
-                c->day = second;
+                c->month = TAKE_PTR(first);
+                c->day = TAKE_PTR(second);
                 return 0;
-        } else if (c->end_of_month) {
-                free_chain(first);
-                free_chain(second);
+        } else if (c->end_of_month)
                 return -EINVAL;
-        }
 
         if (*t == '~')
                 c->end_of_month = true;
-        else if (*t != '-') {
-                free_chain(first);
-                free_chain(second);
+        else if (*t != '-')
                 return -EINVAL;
-        }
 
         t++;
         r = parse_chain(&t, false, &third);
-        if (r < 0) {
-                free_chain(first);
-                free_chain(second);
+        if (r < 0)
                 return r;
-        }
 
-        /* Got three parts, hence it is year, month and day */
-        if (IN_SET(*t, 0, ' ')) {
-                *p = t + strspn(t, " ");
-                c->year = first;
-                c->month = second;
-                c->day = third;
-                return 0;
-        }
+        if (!IN_SET(*t, 0, ' '))
+                return -EINVAL;
 
-        free_chain(first);
-        free_chain(second);
-        free_chain(third);
-        return -EINVAL;
+        /* Got three parts, hence it is year, month and day */
+        *p = t + strspn(t, " ");
+        c->year = TAKE_PTR(first);
+        c->month = TAKE_PTR(second);
+        c->day = TAKE_PTR(third);
+        return 0;
 }
 
 static int parse_calendar_time(const char **p, CalendarSpec *c) {
-        CalendarComponent *h = NULL, *m = NULL, *s = NULL;
+        _cleanup_(chain_freep) CalendarComponent *h = NULL, *m = NULL, *s = NULL;
         const char *t;
         int r;
 
@@ -815,86 +807,81 @@ static int parse_calendar_time(const char **p, CalendarSpec *c) {
 
         r = parse_chain(&t, false, &h);
         if (r < 0)
-                goto fail;
+                return r;
 
-        if (*t != ':') {
-                r = -EINVAL;
-                goto fail;
-        }
+        if (*t != ':')
+                return -EINVAL;
 
         t++;
         r = parse_chain(&t, false, &m);
         if (r < 0)
-                goto fail;
+                return r;
 
         /* Already at the end? Then it's hours and minutes, and seconds are 0 */
         if (*t == 0)
                 goto null_second;
 
-        if (*t != ':') {
-                r = -EINVAL;
-                goto fail;
-        }
+        if (*t != ':')
+                return -EINVAL;
 
         t++;
         r = parse_chain(&t, true, &s);
         if (r < 0)
-                goto fail;
+                return r;
 
         /* At the end? Then it's hours, minutes and seconds */
         if (*t == 0)
                 goto finish;
 
-        r = -EINVAL;
-        goto fail;
+        return -EINVAL;
 
 null_hour:
         r = const_chain(0, &h);
         if (r < 0)
-                goto fail;
+                return r;
 
         r = const_chain(0, &m);
         if (r < 0)
-                goto fail;
+                return r;
 
 null_second:
         r = const_chain(0, &s);
         if (r < 0)
-                goto fail;
+                return r;
 
 finish:
         *p = t;
-        c->hour = h;
-        c->minute = m;
-        c->microsecond = s;
+        c->hour = TAKE_PTR(h);
+        c->minute = TAKE_PTR(m);
+        c->microsecond = TAKE_PTR(s);
 
         return 0;
-
-fail:
-        free_chain(h);
-        free_chain(m);
-        free_chain(s);
-        return r;
 }
 
 int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
         const char *utc;
         _cleanup_(calendar_spec_freep) CalendarSpec *c = NULL;
+        _cleanup_free_ char *p_tmp = NULL;
         int r;
 
         assert(p);
         assert(spec);
 
-        c = new0(CalendarSpec, 1);
+        c = new(CalendarSpec, 1);
         if (!c)
                 return -ENOMEM;
-        c->dst = -1;
-        c->timezone = NULL;
+
+        *c = (CalendarSpec) {
+                .dst = -1,
+                .timezone = NULL,
+        };
 
         utc = endswith_no_case(p, " UTC");
         if (utc) {
                 c->utc = true;
-                p = strndupa(p, utc - p);
+                p = p_tmp = strndup(p, utc - p);
+                if (!p)
+                        return -ENOMEM;
         } else {
                 const char *e = NULL;
                 int j;
@@ -919,7 +906,10 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
 
                 /* Found one of the two timezones specified? */
                 if (IN_SET(j, 0, 1)) {
-                        p = strndupa(p, e - p - 1);
+                        p = p_tmp = strndup(p, e - p - 1);
+                        if (!p)
+                                return -ENOMEM;
+
                         c->dst = j;
                 } else {
                         const char *last_space;
@@ -930,7 +920,9 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) {
                                 if (!c->timezone)
                                         return -ENOMEM;
 
-                                p = strndupa(p, last_space - p);
+                                p = p_tmp = strndup(p, last_space - p);
+                                if (!p)
+                                        return -ENOMEM;
                         }
                 }
         }
index 61df751..91a2439 100644 (file)
@@ -20,6 +20,7 @@
 #include "output-mode.h"
 #include "path-util.h"
 #include "process-util.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "terminal-util.h"
 #include "unit-name.h"
index b0e7036..1b77c07 100644 (file)
 
 #include "alloc-util.h"
 #include "clock-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "macro.h"
 #include "string-util.h"
-#include "util.h"
 
 int clock_get_hwclock(struct tm *tm) {
         _cleanup_close_ int fd = -1;
index fb77966..d1ac9de 100644 (file)
 #include "cgroup-util.h"
 #include "condition.h"
 #include "efivars.h"
+#include "env-file.h"
 #include "extract-word.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "glob-util.h"
 #include "hostname-util.h"
 #include "ima-util.h"
+#include "limits-util.h"
 #include "list.h"
 #include "macro.h"
 #include "mountpoint-util.h"
-#include "env-file.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "proc-cmdline.h"
 
 Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
         Condition *c;
-        int r;
 
         assert(type >= 0);
         assert(type < _CONDITION_TYPE_MAX);
         assert((!parameter) == (type == CONDITION_NULL));
 
-        c = new0(Condition, 1);
+        c = new(Condition, 1);
         if (!c)
                 return NULL;
 
-        c->type = type;
-        c->trigger = trigger;
-        c->negate = negate;
+        *c = (Condition) {
+                .type = type,
+                .trigger = trigger,
+                .negate = negate,
+        };
 
-        r = free_and_strdup(&c->parameter, parameter);
-        if (r < 0) {
-                return mfree(c);
+        if (parameter) {
+                c->parameter = strdup(parameter);
+                if (!c->parameter)
+                        return mfree(c);
         }
 
         return c;
@@ -77,13 +80,17 @@ void condition_free(Condition *c) {
         free(c);
 }
 
-Condition* condition_free_list(Condition *first) {
+Condition* condition_free_list_type(Condition *head, ConditionType type) {
         Condition *c, *n;
 
-        LIST_FOREACH_SAFE(conditions, c, n, first)
-                condition_free(c);
+        LIST_FOREACH_SAFE(conditions, c, n, head)
+                if (type < 0 || c->type == type) {
+                        LIST_REMOVE(conditions, head, c);
+                        condition_free(c);
+                }
 
-        return NULL;
+        assert(type >= 0 || !head);
+        return head;
 }
 
 static int condition_test_kernel_command_line(Condition *c) {
@@ -128,70 +135,144 @@ static int condition_test_kernel_command_line(Condition *c) {
         return false;
 }
 
-static int condition_test_kernel_version(Condition *c) {
-        enum {
-                /* Listed in order of checking. Note that some comparators are prefixes of others, hence the longest
-                 * should be listed first. */
-                LOWER_OR_EQUAL,
-                GREATER_OR_EQUAL,
-                LOWER,
-                GREATER,
-                EQUAL,
-                _ORDER_MAX,
-        };
+typedef enum {
+        /* Listed in order of checking. Note that some comparators are prefixes of others, hence the longest
+         * should be listed first. */
+        ORDER_LOWER_OR_EQUAL,
+        ORDER_GREATER_OR_EQUAL,
+        ORDER_LOWER,
+        ORDER_GREATER,
+        ORDER_EQUAL,
+        ORDER_UNEQUAL,
+        _ORDER_MAX,
+        _ORDER_INVALID = -1
+} OrderOperator;
+
+static OrderOperator parse_order(const char **s) {
 
         static const char *const prefix[_ORDER_MAX] = {
-                [LOWER_OR_EQUAL] = "<=",
-                [GREATER_OR_EQUAL] = ">=",
-                [LOWER] = "<",
-                [GREATER] = ">",
-                [EQUAL] = "=",
+                [ORDER_LOWER_OR_EQUAL] = "<=",
+                [ORDER_GREATER_OR_EQUAL] = ">=",
+                [ORDER_LOWER] = "<",
+                [ORDER_GREATER] = ">",
+                [ORDER_EQUAL] = "=",
+                [ORDER_UNEQUAL] = "!=",
         };
-        const char *p = NULL;
-        struct utsname u;
-        size_t i;
-        int k;
 
-        assert(c);
-        assert(c->parameter);
-        assert(c->type == CONDITION_KERNEL_VERSION);
-
-        assert_se(uname(&u) >= 0);
+        OrderOperator i;
 
         for (i = 0; i < _ORDER_MAX; i++) {
-                p = startswith(c->parameter, prefix[i]);
-                if (p)
-                        break;
+                const char *e;
+
+                e = startswith(*s, prefix[i]);
+                if (e) {
+                        *s = e;
+                        return i;
+                }
         }
 
-        /* No prefix? Then treat as glob string */
-        if (!p)
-                return fnmatch(skip_leading_chars(c->parameter, NULL), u.release, 0) == 0;
+        return _ORDER_INVALID;
+}
 
-        k = str_verscmp(u.release, skip_leading_chars(p, NULL));
+static bool test_order(int k, OrderOperator p) {
 
-        switch (i) {
+        switch (p) {
 
-        case LOWER:
+        case ORDER_LOWER:
                 return k < 0;
 
-        case LOWER_OR_EQUAL:
+        case ORDER_LOWER_OR_EQUAL:
                 return k <= 0;
 
-        case EQUAL:
+        case ORDER_EQUAL:
                 return k == 0;
 
-        case GREATER_OR_EQUAL:
+        case ORDER_UNEQUAL:
+                return k != 0;
+
+        case ORDER_GREATER_OR_EQUAL:
                 return k >= 0;
 
-        case GREATER:
+        case ORDER_GREATER:
                 return k > 0;
 
         default:
-                assert_not_reached("Can't compare");
+                assert_not_reached("unknown order");
+
         }
 }
 
+static int condition_test_kernel_version(Condition *c) {
+        OrderOperator order;
+        struct utsname u;
+        const char *p;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_KERNEL_VERSION);
+
+        assert_se(uname(&u) >= 0);
+
+        p = c->parameter;
+        order = parse_order(&p);
+
+        /* No prefix? Then treat as glob string */
+        if (order < 0)
+                return fnmatch(skip_leading_chars(c->parameter, NULL), u.release, 0) == 0;
+
+        return test_order(str_verscmp(u.release, skip_leading_chars(p, NULL)), order);
+}
+
+static int condition_test_memory(Condition *c) {
+        OrderOperator order;
+        uint64_t m, k;
+        const char *p;
+        int r;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_MEMORY);
+
+        m = physical_memory();
+
+        p = c->parameter;
+        order = parse_order(&p);
+        if (order < 0)
+                order = ORDER_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */
+
+        r = safe_atou64(p, &k);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to parse size: %m");
+
+        return test_order(CMP(m, k), order);
+}
+
+static int condition_test_cpus(Condition *c) {
+        OrderOperator order;
+        const char *p;
+        unsigned k;
+        int r, n;
+
+        assert(c);
+        assert(c->parameter);
+        assert(c->type == CONDITION_CPUS);
+
+        n = cpus_in_affinity_mask();
+        if (n < 0)
+                return log_debug_errno(n, "Failed to determine CPUs in affinity mask: %m");
+
+        p = c->parameter;
+        order = parse_order(&p);
+        if (order < 0)
+                order = ORDER_GREATER_OR_EQUAL; /* default to >= check, if nothing is specified. */
+
+        r = safe_atou(p, &k);
+        if (r < 0)
+                return log_debug_errno(r, "Failed to parse number of CPUs: %m");
+
+        return test_order(CMP((unsigned) n, k), order);
+}
+
 static int condition_test_user(Condition *c) {
         uid_t id;
         int r;
@@ -625,6 +706,8 @@ int condition_test(Condition *c) {
                 [CONDITION_GROUP] = condition_test_group,
                 [CONDITION_CONTROL_GROUP_CONTROLLER] = condition_test_control_group_controller,
                 [CONDITION_NULL] = condition_test_null,
+                [CONDITION_CPUS] = condition_test_cpus,
+                [CONDITION_MEMORY] = condition_test_memory,
         };
 
         int r, b;
@@ -644,6 +727,52 @@ int condition_test(Condition *c) {
         return b;
 }
 
+bool condition_test_list(Condition *first, const char *(*to_string)(ConditionType t), condition_test_logger_t logger, void *userdata) {
+        Condition *c;
+        int triggered = -1;
+
+        assert(!!logger == !!to_string);
+
+        /* If the condition list is empty, then it is true */
+        if (!first)
+                return true;
+
+        /* Otherwise, if all of the non-trigger conditions apply and
+         * if any of the trigger conditions apply (unless there are
+         * none) we return true */
+        LIST_FOREACH(conditions, c, first) {
+                int r;
+
+                r = condition_test(c);
+
+                if (logger) {
+                        if (r < 0)
+                                logger(userdata, LOG_WARNING, r, __FILE__, __LINE__, __func__,
+                                       "Couldn't determine result for %s=%s%s%s, assuming failed: %m",
+                                       to_string(c->type),
+                                       c->trigger ? "|" : "",
+                                       c->negate ? "!" : "",
+                                       c->parameter);
+                        else
+                                logger(userdata, LOG_DEBUG, 0, __FILE__, __LINE__, __func__,
+                                       "%s=%s%s%s %s.",
+                                       to_string(c->type),
+                                       c->trigger ? "|" : "",
+                                       c->negate ? "!" : "",
+                                       c->parameter,
+                                       condition_result_to_string(c->result));
+                }
+
+                if (!c->trigger && r <= 0)
+                        return false;
+
+                if (c->trigger && triggered <= 0)
+                        triggered = r > 0;
+        }
+
+        return triggered != 0;
+}
+
 void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t)) {
         assert(c);
         assert(f);
@@ -690,7 +819,9 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_USER] = "ConditionUser",
         [CONDITION_GROUP] = "ConditionGroup",
         [CONDITION_CONTROL_GROUP_CONTROLLER] = "ConditionControlGroupController",
-        [CONDITION_NULL] = "ConditionNull"
+        [CONDITION_NULL] = "ConditionNull",
+        [CONDITION_CPUS] = "ConditionCPUs",
+        [CONDITION_MEMORY] = "ConditionMemory",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
@@ -718,7 +849,9 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = {
         [CONDITION_USER] = "AssertUser",
         [CONDITION_GROUP] = "AssertGroup",
         [CONDITION_CONTROL_GROUP_CONTROLLER] = "AssertControlGroupController",
-        [CONDITION_NULL] = "AssertNull"
+        [CONDITION_NULL] = "AssertNull",
+        [CONDITION_CPUS] = "AssertCPUs",
+        [CONDITION_MEMORY] = "AssertMemory",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType);
index e69fc36..84322e7 100644 (file)
@@ -16,6 +16,8 @@ typedef enum ConditionType {
         CONDITION_SECURITY,
         CONDITION_CAPABILITY,
         CONDITION_AC_POWER,
+        CONDITION_MEMORY,
+        CONDITION_CPUS,
 
         CONDITION_NEEDS_UPDATE,
         CONDITION_FIRST_BOOT,
@@ -65,9 +67,14 @@ typedef struct Condition {
 
 Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate);
 void condition_free(Condition *c);
-Condition* condition_free_list(Condition *c);
+Condition* condition_free_list_type(Condition *first, ConditionType type);
+static inline Condition* condition_free_list(Condition *first) {
+        return condition_free_list_type(first, _CONDITION_TYPE_INVALID);
+}
 
 int condition_test(Condition *c);
+typedef int (*condition_test_logger_t)(void *userdata, int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(7, 8);
+bool condition_test_list(Condition *first, const char *(*to_string)(ConditionType t), condition_test_logger_t logger, void *userdata);
 
 void condition_dump(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t));
 void condition_dump_list(Condition *c, FILE *f, const char *prefix, const char *(*to_string)(ConditionType t));
index b80c147..2df09ed 100644 (file)
@@ -19,6 +19,7 @@
 #include "log.h"
 #include "macro.h"
 #include "missing.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -506,6 +507,7 @@ DEFINE_PARSER(unsigned, unsigned, safe_atou);
 DEFINE_PARSER(double, double, safe_atod);
 DEFINE_PARSER(nsec, nsec_t, parse_nsec);
 DEFINE_PARSER(sec, usec_t, parse_sec);
+DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity);
 DEFINE_PARSER(mode, mode_t, parse_mode);
 
 int config_parse_iec_size(const char* unit,
index 865db42..17b4bdf 100644 (file)
@@ -127,6 +127,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_string);
 CONFIG_PARSER_PROTOTYPE(config_parse_path);
 CONFIG_PARSER_PROTOTYPE(config_parse_strv);
 CONFIG_PARSER_PROTOTYPE(config_parse_sec);
+CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_infinity);
 CONFIG_PARSER_PROTOTYPE(config_parse_nsec);
 CONFIG_PARSER_PROTOTYPE(config_parse_mode);
 CONFIG_PARSER_PROTOTYPE(config_parse_warn_compat);
index 8c86714..bdc2d04 100644 (file)
 #define CRYPT_LUKS NULL
 #endif
 
+#ifndef CRYPT_ACTIVATE_SAME_CPU_CRYPT
+#define CRYPT_ACTIVATE_SAME_CPU_CRYPT (1 << 6)
+#endif
+
+#ifndef CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS
+#define CRYPT_ACTIVATE_SUBMIT_FROM_CRYPT_CPUS (1 << 7)
+#endif
+
 DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, crypt_free);
 
 void cryptsetup_log_glue(int level, const char *msg, void *usrptr);
index b545c2a..12e80e4 100644 (file)
@@ -8,10 +8,10 @@
 #include "dev-setup.h"
 #include "label.h"
 #include "log.h"
+#include "nulstr-util.h"
 #include "path-util.h"
 #include "umask-util.h"
 #include "user-util.h"
-#include "util.h"
 
 int dev_setup(const char *prefix, uid_t uid, gid_t gid) {
         static const char symlinks[] =
index df0c584..ac2f7ce 100644 (file)
@@ -30,6 +30,7 @@
 #include "missing.h"
 #include "mount-util.h"
 #include "mountpoint-util.h"
+#include "nulstr-util.h"
 #include "os-util.h"
 #include "path-util.h"
 #include "process-util.h"
@@ -344,10 +345,8 @@ int dissect_image(
 
         errno = 0;
         r = blkid_do_safeprobe(b);
-        if (IN_SET(r, -2, 1)) {
-                log_debug("Failed to identify any partition table.");
-                return -ENOPKG;
-        }
+        if (IN_SET(r, -2, 1))
+                return log_debug_errno(SYNTHETIC_ERRNO(ENOPKG), "Failed to identify any partition table.");
         if (r != 0)
                 return -errno ?: -EIO;
 
@@ -498,6 +497,14 @@ int dissect_image(
 
                                 designator = PARTITION_ESP;
                                 fstype = "vfat";
+
+                        } else if (sd_id128_equal(type_id, GPT_XBOOTLDR)) {
+
+                                if (pflags & GPT_FLAG_NO_AUTO)
+                                        continue;
+
+                                designator = PARTITION_XBOOTLDR;
+                                rw = !(pflags & GPT_FLAG_READ_ONLY);
                         }
 #ifdef GPT_ROOT_NATIVE
                         else if (sd_id128_equal(type_id, GPT_ROOT_NATIVE)) {
@@ -613,21 +620,53 @@ int dissect_image(
 
                 } else if (is_mbr) {
 
-                        if (pflags != 0x80) /* Bootable flag */
-                                continue;
+                        switch (blkid_partition_get_type(pp)) {
 
-                        if (blkid_partition_get_type(pp) != 0x83) /* Linux partition */
-                                continue;
+                        case 0x83: /* Linux partition */
+
+                                if (pflags != 0x80) /* Bootable flag */
+                                        continue;
+
+                                if (generic_node)
+                                        multiple_generic = true;
+                                else {
+                                        generic_nr = nr;
+                                        generic_rw = true;
+                                        generic_node = strdup(node);
+                                        if (!generic_node)
+                                                return -ENOMEM;
+                                }
+
+                                break;
+
+                        case 0xEA: { /* Boot Loader Spec extended $BOOT partition */
+                                _cleanup_free_ char *n = NULL;
+                                sd_id128_t id = SD_ID128_NULL;
+                                const char *sid;
+
+                                /* First one wins */
+                                if (m->partitions[PARTITION_XBOOTLDR].found)
+                                        continue;
+
+                                sid = blkid_partition_get_uuid(pp);
+                                if (sid)
+                                        (void) sd_id128_from_string(sid, &id);
 
-                        if (generic_node)
-                                multiple_generic = true;
-                        else {
-                                generic_nr = nr;
-                                generic_rw = true;
-                                generic_node = strdup(node);
-                                if (!generic_node)
+                                n = strdup(node);
+                                if (!n)
                                         return -ENOMEM;
-                        }
+
+                                m->partitions[PARTITION_XBOOTLDR] = (DissectedPartition) {
+                                        .found = true,
+                                        .partno = nr,
+                                        .rw = true,
+                                        .architecture = _ARCHITECTURE_INVALID,
+                                        .node = TAKE_PTR(n),
+                                        .uuid = id,
+                                };
+
+                                break;
+                        }}
                 }
         }
 
@@ -820,11 +859,15 @@ static int mount_partition(
                         return -ENOMEM;
         }
 
-        return mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
+        r = mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
+        if (r < 0)
+                return r;
+
+        return 1;
 }
 
 int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
-        int r;
+        int r, boot_mounted;
 
         assert(m);
         assert(where);
@@ -857,21 +900,26 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift,
         if (r < 0)
                 return r;
 
+        boot_mounted = mount_partition(m->partitions + PARTITION_XBOOTLDR, where, "/boot", uid_shift, flags);
+        if (boot_mounted < 0)
+                return boot_mounted;
+
         if (m->partitions[PARTITION_ESP].found) {
-                const char *mp;
+                /* Mount the ESP to /efi if it exists. If it doesn't exist, use /boot instead, but only if it
+                 * exists and is empty, and we didn't already mount the XBOOTLDR partition into it. */
 
-                /* Mount the ESP to /efi if it exists and is empty. If it doesn't exist, use /boot instead. */
+                r = chase_symlinks("/efi", where, CHASE_PREFIX_ROOT, NULL);
+                if (r >= 0) {
+                        r = mount_partition(m->partitions + PARTITION_ESP, where, "/efi", uid_shift, flags);
+                        if (r < 0)
+                                return r;
 
-                FOREACH_STRING(mp, "/efi", "/boot") {
+                } else if (boot_mounted <= 0) {
                         _cleanup_free_ char *p = NULL;
 
-                        r = chase_symlinks(mp, where, CHASE_PREFIX_ROOT, &p);
-                        if (r < 0)
-                                continue;
-
-                        r = dir_is_empty(p);
-                        if (r > 0) {
-                                r = mount_partition(m->partitions + PARTITION_ESP, where, mp, uid_shift, flags);
+                        r = chase_symlinks("/boot", where, CHASE_PREFIX_ROOT, &p);
+                        if (r >= 0 && dir_is_empty(p) > 0) {
+                                r = mount_partition(m->partitions + PARTITION_ESP, where, "/boot", uid_shift, flags);
                                 if (r < 0)
                                         return r;
                         }
@@ -1500,6 +1548,7 @@ static const char *const partition_designator_table[] = {
         [PARTITION_HOME] = "home",
         [PARTITION_SRV] = "srv",
         [PARTITION_ESP] = "esp",
+        [PARTITION_XBOOTLDR] = "xbootldr",
         [PARTITION_SWAP] = "swap",
         [PARTITION_ROOT_VERITY] = "root-verity",
         [PARTITION_ROOT_SECONDARY_VERITY] = "root-secondary-verity",
index f50b40e..ded43f3 100644 (file)
@@ -29,6 +29,7 @@ enum  {
         PARTITION_HOME,
         PARTITION_SRV,
         PARTITION_ESP,
+        PARTITION_XBOOTLDR,
         PARTITION_SWAP,
         PARTITION_ROOT_VERITY, /* verity data for the PARTITION_ROOT partition */
         PARTITION_ROOT_SECONDARY_VERITY, /* verity data for the PARTITION_ROOT_SECONDARY partition */
index 26f905b..4f32163 100644 (file)
 #include "io-util.h"
 #include "macro.h"
 #include "parse-util.h"
+#include "sort-util.h"
 #include "stdio-util.h"
 #include "strv.h"
 #include "time-util.h"
 #include "utf8.h"
-#include "util.h"
 #include "virt.h"
 
 #if ENABLE_EFI
@@ -223,7 +223,7 @@ int efi_get_variable(
         if (fstat(fd, &st) < 0)
                 return -errno;
         if (st.st_size < 4)
-                return -EIO;
+                return -ENODATA;
         if (st.st_size > 4*1024*1024 + 4)
                 return -E2BIG;
 
@@ -789,16 +789,6 @@ int efi_loader_get_device_part_uuid(sd_id128_t *u) {
         return 0;
 }
 
-bool efi_loader_entry_name_valid(const char *s) {
-        if (isempty(s))
-                return false;
-
-        if (strlen(s) > FILENAME_MAX) /* Make sure entry names fit in filenames */
-                return false;
-
-        return in_charset(s, ALPHANUMERICAL "-");
-}
-
 int efi_loader_get_entries(char ***ret) {
         _cleanup_free_ char16_t *entries = NULL;
         _cleanup_strv_free_ char **l = NULL;
@@ -903,6 +893,16 @@ int efi_loader_get_features(uint64_t *ret) {
 
 #endif
 
+bool efi_loader_entry_name_valid(const char *s) {
+        if (isempty(s))
+                return false;
+
+        if (strlen(s) > FILENAME_MAX) /* Make sure entry names fit in filenames */
+                return false;
+
+        return in_charset(s, ALPHANUMERICAL "-_.");
+}
+
 char *efi_tilt_backslashes(char *s) {
         char *p;
 
index 92670c8..d8f18aa 100644 (file)
@@ -50,8 +50,6 @@ int efi_loader_get_boot_usec(usec_t *firmware, usec_t *loader);
 
 int efi_loader_get_entries(char ***ret);
 
-bool efi_loader_entry_name_valid(const char *s);
-
 int efi_loader_get_features(uint64_t *ret);
 
 #else
@@ -138,4 +136,6 @@ static inline int efi_loader_get_features(uint64_t *ret) {
 
 #endif
 
+bool efi_loader_entry_name_valid(const char *s);
+
 char *efi_tilt_backslashes(char *s);
index 17a278a..2867f08 100644 (file)
@@ -78,24 +78,28 @@ static int do_execute(
                 void* const callback_args[_STDOUT_CONSUME_MAX],
                 int output_fd,
                 char *argv[],
-                char *envp[]) {
+                char *envp[],
+                ExecDirFlags flags) {
 
         _cleanup_hashmap_free_free_ Hashmap *pids = NULL;
         _cleanup_strv_free_ char **paths = NULL;
         char **path, **e;
         int r;
+        bool parallel_execution;
 
         /* We fork this all off from a child process so that we can somewhat cleanly make
          * use of SIGALRM to set a time limit.
          *
-         * If callbacks is nonnull, execution is serial. Otherwise, we default to parallel.
+         * We attempt to perform parallel execution if configured by the user, however
+         * if `callbacks` is nonnull, execution must be serial.
          */
+        parallel_execution = FLAGS_SET(flags, EXEC_DIR_PARALLEL) && !callbacks;
 
         r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char* const*) directories);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate executables: %m");
 
-        if (!callbacks) {
+        if (parallel_execution) {
                 pids = hashmap_new(NULL);
                 if (!pids)
                         return log_oom();
@@ -130,23 +134,28 @@ static int do_execute(
                 if (r <= 0)
                         continue;
 
-                if (pids) {
+                if (parallel_execution) {
                         r = hashmap_put(pids, PID_TO_PTR(pid), t);
                         if (r < 0)
                                 return log_oom();
                         t = NULL;
                 } else {
                         r = wait_for_terminate_and_check(t, pid, WAIT_LOG);
-                        if (r < 0)
-                                continue;
-
-                        if (lseek(fd, 0, SEEK_SET) < 0)
-                                return log_error_errno(errno, "Failed to seek on serialization fd: %m");
-
-                        r = callbacks[STDOUT_GENERATE](fd, callback_args[STDOUT_GENERATE]);
-                        fd = -1;
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to process output from %s: %m", *path);
+                        if (FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS)) {
+                                if (r < 0)
+                                        continue;
+                        } else if (r > 0)
+                                return r;
+
+                        if (callbacks) {
+                                if (lseek(fd, 0, SEEK_SET) < 0)
+                                        return log_error_errno(errno, "Failed to seek on serialization fd: %m");
+
+                                r = callbacks[STDOUT_GENERATE](fd, callback_args[STDOUT_GENERATE]);
+                                fd = -1;
+                                if (r < 0)
+                                        return log_error_errno(r, "Failed to process output from %s: %m", *path);
+                        }
                 }
         }
 
@@ -166,7 +175,9 @@ static int do_execute(
                 t = hashmap_remove(pids, PID_TO_PTR(pid));
                 assert(t);
 
-                (void) wait_for_terminate_and_check(t, pid, WAIT_LOG);
+                r = wait_for_terminate_and_check(t, pid, WAIT_LOG);
+                if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0)
+                        return r;
         }
 
         return 0;
@@ -178,12 +189,14 @@ int execute_directories(
                 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
                 void* const callback_args[_STDOUT_CONSUME_MAX],
                 char *argv[],
-                char *envp[]) {
+                char *envp[],
+                ExecDirFlags flags) {
 
         char **dirs = (char**) directories;
         _cleanup_close_ int fd = -1;
         char *name;
         int r;
+        pid_t executor_pid;
 
         assert(!strv_isempty(dirs));
 
@@ -205,14 +218,20 @@ int execute_directories(
          * them to finish. Optionally a timeout is applied. If a file with the same name
          * exists in more than one directory, the earliest one wins. */
 
-        r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL);
+        r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &executor_pid);
         if (r < 0)
                 return r;
         if (r == 0) {
-                r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv, envp);
-                _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+                r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv, envp, flags);
+                _exit(r < 0 ? EXIT_FAILURE : r);
         }
 
+        r = wait_for_terminate_and_check("(sd-executor)", executor_pid, 0);
+        if (r < 0)
+                return r;
+        if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0)
+                return r;
+
         if (!callbacks)
                 return 0;
 
index 6ac3c90..5b75a40 100644 (file)
@@ -14,12 +14,19 @@ enum {
         _STDOUT_CONSUME_MAX,
 };
 
+typedef enum {
+        EXEC_DIR_NONE          = 0,      /* No execdir flags */
+        EXEC_DIR_PARALLEL      = 1 << 0, /* Execute scripts in parallel, if possible */
+        EXEC_DIR_IGNORE_ERRORS = 1 << 1, /* Ignore non-zero exit status of scripts */
+} ExecDirFlags;
+
 int execute_directories(
                 const char* const* directories,
                 usec_t timeout,
                 gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX],
                 void* const callback_args[_STDOUT_CONSUME_MAX],
                 char *argv[],
-                char *envp[]);
+                char *envp[],
+                ExecDirFlags flags);
 
 extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
index 5d27732..ae65286 100644 (file)
@@ -48,25 +48,25 @@ int fdset_new_array(FDSet **ret, const int *fds, size_t n_fds) {
         return 0;
 }
 
-FDSet* fdset_free(FDSet *s) {
+void fdset_close(FDSet *s) {
         void *p;
 
         while ((p = set_steal_first(MAKE_SET(s)))) {
-                /* Valgrind's fd might have ended up in this set here,
-                 * due to fdset_new_fill(). We'll ignore all failures
-                 * here, so that the EBADFD that valgrind will return
-                 * us on close() doesn't influence us */
-
-                /* When reloading duplicates of the private bus
-                 * connection fds and suchlike are closed here, which
-                 * has no effect at all, since they are only
-                 * duplicates. So don't be surprised about these log
-                 * messages. */
-
-                log_debug("Closing left-over fd %i", PTR_TO_FD(p));
-                close_nointr(PTR_TO_FD(p));
+                /* Valgrind's fd might have ended up in this set here, due to fdset_new_fill(). We'll ignore
+                 * all failures here, so that the EBADFD that valgrind will return us on close() doesn't
+                 * influence us */
+
+                /* When reloading duplicates of the private bus connection fds and suchlike are closed here,
+                 * which has no effect at all, since they are only duplicates. So don't be surprised about
+                 * these log messages. */
+
+                log_debug("Closing set fd %i", PTR_TO_FD(p));
+                (void) close_nointr(PTR_TO_FD(p));
         }
+}
 
+FDSet* fdset_free(FDSet *s) {
+        fdset_close(s);
         set_free(MAKE_SET(s));
         return NULL;
 }
index d31062b..bdf1377 100644 (file)
@@ -33,6 +33,8 @@ int fdset_iterate(FDSet *s, Iterator *i);
 
 int fdset_steal_first(FDSet *fds);
 
+void fdset_close(FDSet *fds);
+
 #define FDSET_FOREACH(fd, fds, i) \
         for ((i) = ITERATOR_FIRST, (fd) = fdset_iterate((fds), &(i)); (fd) >= 0; (fd) = fdset_iterate((fds), &(i)))
 
index 7d52980..a5c0a99 100644 (file)
@@ -8,9 +8,11 @@
 #include "fileio.h"
 #include "format-table.h"
 #include "gunicode.h"
+#include "memory-util.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "pretty-print.h"
+#include "sort-util.h"
 #include "string-util.h"
 #include "terminal-util.h"
 #include "time-util.h"
index 6fd9866..118d591 100644 (file)
 #include "fstab-util.h"
 #include "macro.h"
 #include "mount-util.h"
+#include "nulstr-util.h"
 #include "parse-util.h"
 #include "path-util.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 int fstab_has_fstype(const char *fstype) {
         _cleanup_endmntent_ FILE *f = NULL;
index 9820f78..0862256 100644 (file)
@@ -20,14 +20,12 @@ static inline bool fstab_test_option(const char *opts, const char *names) {
 int fstab_find_pri(const char *options, int *ret);
 
 static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no) {
-        int r;
         const char *opt;
 
         /* If first name given is last, return 1.
          * If second name given is last or neither is found, return 0. */
 
-        r = fstab_filter_options(opts, yes_no, &opt, NULL, NULL);
-        assert(r >= 0);
+        assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL) >= 0);
 
         return opt == yes_no;
 }
index 0adaaf2..ed7f037 100644 (file)
@@ -55,13 +55,14 @@ int generator_open_unit_file(
         return 0;
 }
 
-int generator_add_symlink(const char *root, const char *dst, const char *dep_type, const char *src) {
-        /* Adds a symlink from <dst>.<dep_type>.d/ to ../<src> */
+int generator_add_symlink(const char *dir, const char *dst, const char *dep_type, const char *src) {
+        /* Adds a symlink from <dst>.<dep_type>/ to <src> (if src is absolute)
+         * or ../<src> (otherwise). */
 
         const char *from, *to;
 
-        from = strjoina("../", src);
-        to = strjoina(root, "/", dst, ".", dep_type, "/", src);
+        from = path_is_absolute(src) ? src : strjoina("../", src);
+        to = strjoina(dir, "/", dst, ".", dep_type, "/", basename(src));
 
         mkdir_parents_label(to, 0755);
         if (symlink(from, to) < 0)
@@ -85,7 +86,7 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
         if (!escaped2)
                 return log_oom();
 
-        unit = strjoina(dir, "/systemd-fsck-root.service");
+        unit = strjoina(dir, "/"SPECIAL_FSCK_ROOT_SERVICE);
         log_debug("Creating %s", unit);
 
         r = unit_name_from_path(what, ".device", &device);
@@ -157,10 +158,10 @@ int generator_write_fsck_deps(
         if (path_equal(where, "/")) {
                 const char *lnk;
 
-                lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/systemd-fsck-root.service");
+                lnk = strjoina(dir, "/" SPECIAL_LOCAL_FS_TARGET ".wants/"SPECIAL_FSCK_ROOT_SERVICE);
 
                 mkdir_parents(lnk, 0755);
-                if (symlink(SYSTEM_DATA_UNIT_PATH "/systemd-fsck-root.service", lnk) < 0)
+                if (symlink(SYSTEM_DATA_UNIT_PATH "/"SPECIAL_FSCK_ROOT_SERVICE, lnk) < 0)
                         return log_error_errno(errno, "Failed to create symlink %s: %m", lnk);
 
         } else {
@@ -172,7 +173,7 @@ int generator_write_fsck_deps(
                         if (r < 0)
                                 return r;
 
-                        fsck = "systemd-fsck-root.service";
+                        fsck = SPECIAL_FSCK_ROOT_SERVICE;
                 } else {
                         r = unit_name_from_path_instance("systemd-fsck", what, ".service", &_fsck);
                         if (r < 0)
@@ -390,7 +391,7 @@ int generator_hook_up_mkfs(
                                        "Cannot format partition %s, filesystem type is not specified",
                                        node);
 
-        r = unit_name_from_path_instance("systemd-mkfs", node, ".service", &unit);
+        r = unit_name_from_path_instance("systemd-makefs", node, ".service", &unit);
         if (r < 0)
                 return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
                                        node);
@@ -416,7 +417,7 @@ int generator_hook_up_mkfs(
                 "# Automatically generated by %s\n\n"
                 "[Unit]\n"
                 "Description=Make File System on %%f\n"
-                "Documentation=man:systemd-mkfs@.service(8)\n"
+                "Documentation=man:systemd-makefs@.service(8)\n"
                 "DefaultDependencies=no\n"
                 "BindsTo=%%i.device\n"
                 "Conflicts=shutdown.target\n"
@@ -498,6 +499,12 @@ int generator_hook_up_growfs(
         return generator_add_symlink(dir, where_unit, "wants", unit);
 }
 
+int generator_enable_remount_fs_service(const char *dir) {
+        /* Pull in systemd-remount-fs.service */
+        return generator_add_symlink(dir, SPECIAL_LOCAL_FS_TARGET, "wants",
+                                     SYSTEM_DATA_UNIT_PATH "/" SPECIAL_REMOUNT_FS_SERVICE);
+}
+
 void log_setup_generator(void) {
         log_set_prohibit_ipc(true);
         log_setup_service();
index 5a1c1e3..fa002a9 100644 (file)
@@ -11,7 +11,7 @@ int generator_open_unit_file(
         const char *name,
         FILE **file);
 
-int generator_add_symlink(const char *root, const char *dst, const char *dep_type, const char *src);
+int generator_add_symlink(const char *dir, const char *dst, const char *dep_type, const char *src);
 
 int generator_write_fsck_deps(
         FILE *f,
@@ -50,6 +50,8 @@ int generator_hook_up_growfs(
         const char *where,
         const char *target);
 
+int generator_enable_remount_fs_service(const char *dir);
+
 void log_setup_generator(void);
 
 /* Similar to DEFINE_MAIN_FUNCTION, but initializes logging and assigns positional arguments. */
index fd953fa..31e01bd 100644 (file)
@@ -15,6 +15,7 @@
 #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_XBOOTLDR    SD_ID128_MAKE(bc,13,c2,ff,59,e6,42,62,a3,52,b2,75,fd,6f,71,72)
 #define GPT_SWAP        SD_ID128_MAKE(06,57,fd,6d,a4,ab,43,c4,84,e5,09,33,c8,4b,4f,4f)
 #define GPT_HOME        SD_ID128_MAKE(93,3a,c7,e1,2e,b4,4f,13,b8,44,0e,14,e2,ae,f9,15)
 #define GPT_SRV         SD_ID128_MAKE(3b,8f,84,25,20,e0,4f,3b,90,7f,1a,25,a7,6f,98,e8)
index bcd6c0c..dad6c1c 100644 (file)
@@ -8,10 +8,10 @@
 #include "import-util.h"
 #include "log.h"
 #include "macro.h"
+#include "nulstr-util.h"
 #include "path-util.h"
 #include "string-table.h"
 #include "string-util.h"
-#include "util.h"
 
 int import_url_last_component(const char *url, char **ret) {
         const char *e, *p;
index 8629304..ca52d17 100644 (file)
@@ -15,6 +15,7 @@
 #include "alloc-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
+#include "def.h"
 #include "dirent-util.h"
 #include "extract-word.h"
 #include "fd-util.h"
@@ -116,7 +117,7 @@ bool unit_type_may_template(UnitType type) {
                       UNIT_PATH);
 }
 
-static const char *unit_file_type_table[_UNIT_FILE_TYPE_MAX] = {
+static const char *const unit_file_type_table[_UNIT_FILE_TYPE_MAX] = {
         [UNIT_FILE_TYPE_REGULAR] = "regular",
         [UNIT_FILE_TYPE_SYMLINK] = "symlink",
         [UNIT_FILE_TYPE_MASKED] = "masked",
@@ -2796,7 +2797,7 @@ static int split_pattern_into_name_and_instances(const char *pattern, char **out
         assert(out_instances);
         assert(out_unit_name);
 
-        r = extract_first_word(&pattern, &unit_name, NULL, 0);
+        r = extract_first_word(&pattern, &unit_name, NULL, EXTRACT_RETAIN_ESCAPE);
         if (r < 0)
                 return r;
 
@@ -2820,6 +2821,24 @@ static int split_pattern_into_name_and_instances(const char *pattern, char **out
         return 0;
 }
 
+static int presets_find_config(UnitFileScope scope, const char *root_dir, char ***files) {
+        static const char* const system_dirs[] = {CONF_PATHS("systemd/system-preset"), NULL};
+        static const char* const user_dirs[] = {CONF_PATHS_USR("systemd/user-preset"), NULL};
+        const char* const* dirs;
+
+        assert(scope >= 0);
+        assert(scope < _UNIT_FILE_SCOPE_MAX);
+
+        if (scope == UNIT_FILE_SYSTEM)
+                dirs = system_dirs;
+        else if (IN_SET(scope, UNIT_FILE_GLOBAL, UNIT_FILE_USER))
+                dirs = user_dirs;
+        else
+                assert_not_reached("Invalid unit file scope");
+
+        return conf_files_list_strv(files, ".preset", root_dir, 0, dirs);
+}
+
 static int read_presets(UnitFileScope scope, const char *root_dir, Presets *presets) {
         _cleanup_(presets_freep) Presets ps = {};
         size_t n_allocated = 0;
@@ -2831,33 +2850,7 @@ static int read_presets(UnitFileScope scope, const char *root_dir, Presets *pres
         assert(scope < _UNIT_FILE_SCOPE_MAX);
         assert(presets);
 
-        switch (scope) {
-        case UNIT_FILE_SYSTEM:
-                r = conf_files_list(&files, ".preset", root_dir, 0,
-                                    "/etc/systemd/system-preset",
-                                    "/run/systemd/system-preset",
-                                    "/usr/local/lib/systemd/system-preset",
-                                    "/usr/lib/systemd/system-preset",
-#if HAVE_SPLIT_USR
-                                    "/lib/systemd/system-preset",
-#endif
-                                    NULL);
-                break;
-
-        case UNIT_FILE_GLOBAL:
-        case UNIT_FILE_USER:
-                r = conf_files_list(&files, ".preset", root_dir, 0,
-                                    "/etc/systemd/user-preset",
-                                    "/run/systemd/user-preset",
-                                    "/usr/local/lib/systemd/user-preset",
-                                    "/usr/lib/systemd/user-preset",
-                                    NULL);
-                break;
-
-        default:
-                assert_not_reached("Invalid unit file scope");
-        }
-
+        r = presets_find_config(scope, root_dir, &files);
         if (r < 0)
                 return r;
 
index 3786ff1..db003a4 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
+#include <locale.h>
 #include <math.h>
 #include <stdarg.h>
 #include <stdio_ext.h>
@@ -11,6 +12,7 @@
 #include "sd-messages.h"
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "float.h"
@@ -18,6 +20,7 @@
 #include "json-internal.h"
 #include "json.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
@@ -1756,7 +1759,6 @@ static void inc_lines_columns(unsigned *line, unsigned *column, const char *s, s
         assert(s || n == 0);
 
         while (n > 0) {
-
                 if (*s == '\n') {
                         (*line)++;
                         *column = 1;
@@ -1765,7 +1767,7 @@ static void inc_lines_columns(unsigned *line, unsigned *column, const char *s, s
                 else {
                         int w;
 
-                        w = utf8_encoded_valid_unichar(s);
+                        w = utf8_encoded_valid_unichar(s, n);
                         if (w < 0) /* count invalid unichars as normal characters */
                                 w = 1;
                         else if ((size_t) w > n) /* never read more than the specified number of characters */
@@ -1930,7 +1932,7 @@ static int json_parse_string(const char **p, char **ret) {
                         continue;
                 }
 
-                len = utf8_encoded_valid_unichar(c);
+                len = utf8_encoded_valid_unichar(c, (size_t) -1);
                 if (len < 0)
                         return len;
 
@@ -3109,8 +3111,6 @@ finish:
 
         free(stack);
 
-        va_end(ap);
-
         return r;
 }
 
@@ -3167,7 +3167,7 @@ int json_log_internal(
                                 "CONFIG_FILE=%s", source,
                                 "CONFIG_LINE=%u", source_line,
                                 "CONFIG_COLUMN=%u", source_column,
-                                LOG_MESSAGE("%s:%u: %s", source, line, buffer),
+                                LOG_MESSAGE("%s:%u:%u: %s", source, source_line, source_column, buffer),
                                 NULL);
         else
                 return log_struct_internal(
@@ -3297,10 +3297,8 @@ int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFl
         assert(variant);
         assert(b);
 
-        if (!json_variant_is_boolean(variant)) {
-                json_log(variant, flags, 0, "JSON field '%s' is not a boolean.", strna(name));
-                return -EINVAL;
-        }
+        if (!json_variant_is_boolean(variant))
+                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name));
 
         *b = json_variant_boolean(variant);
         return 0;
@@ -3312,10 +3310,8 @@ int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchF
         assert(variant);
         assert(b);
 
-        if (!json_variant_is_boolean(variant)) {
-                json_log(variant, flags, 0, "JSON field '%s' is not a boolean.", strna(name));
-                return -EINVAL;
-        }
+        if (!json_variant_is_boolean(variant))
+                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a boolean.", strna(name));
 
         *b = json_variant_boolean(variant);
         return 0;
@@ -3327,10 +3323,8 @@ int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFl
         assert(variant);
         assert(i);
 
-        if (!json_variant_is_integer(variant)) {
-                json_log(variant, flags, 0, "JSON field '%s' is not an integer.", strna(name));
-                return -EINVAL;
-        }
+        if (!json_variant_is_integer(variant))
+                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
 
         *i = json_variant_integer(variant);
         return 0;
@@ -3342,10 +3336,8 @@ int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchF
         assert(variant);
         assert(u);
 
-        if (!json_variant_is_unsigned(variant)) {
-                json_log(variant, flags, 0, "JSON field '%s' is not an unsigned integer.", strna(name));
-                return -EINVAL;
-        }
+        if (!json_variant_is_unsigned(variant))
+                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an unsigned integer.", strna(name));
 
         *u = json_variant_unsigned(variant);
         return 0;
@@ -3357,15 +3349,11 @@ int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFla
         assert(variant);
         assert(u);
 
-        if (!json_variant_is_unsigned(variant)) {
-                json_log(variant, flags, 0, "JSON field '%s' is not an unsigned integer.", strna(name));
-                return -EINVAL;
-        }
+        if (!json_variant_is_unsigned(variant))
+                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an unsigned integer.", strna(name));
 
-        if (json_variant_unsigned(variant) > UINT32_MAX) {
-                json_log(variant, flags, 0, "JSON field '%s' out of bounds.", strna(name));
-                return -ERANGE;
-        }
+        if (json_variant_unsigned(variant) > UINT32_MAX)
+                return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' out of bounds.", strna(name));
 
         *u = (uint32_t) json_variant_unsigned(variant);
         return 0;
@@ -3377,15 +3365,11 @@ int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlag
         assert(variant);
         assert(i);
 
-        if (!json_variant_is_integer(variant)) {
-                json_log(variant, flags, 0, "JSON field '%s' is not an integer.", strna(name));
-                return -EINVAL;
-        }
+        if (!json_variant_is_integer(variant))
+                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
 
-        if (json_variant_integer(variant) < INT32_MIN || json_variant_integer(variant) > INT32_MAX) {
-                json_log(variant, flags, 0, "JSON field '%s' out of bounds.", strna(name));
-                return -ERANGE;
-        }
+        if (json_variant_integer(variant) < INT32_MIN || json_variant_integer(variant) > INT32_MAX)
+                return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' out of bounds.", strna(name));
 
         *i = (int32_t) json_variant_integer(variant);
         return 0;
@@ -3403,10 +3387,8 @@ int json_dispatch_string(const char *name, JsonVariant *variant, JsonDispatchFla
                 return 0;
         }
 
-        if (!json_variant_is_string(variant)) {
-                json_log(variant, flags, 0, "JSON field '%s' is not a string.", strna(name));
-                return -EINVAL;
-        }
+        if (!json_variant_is_string(variant))
+                return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name));
 
         r = free_and_strdup(s, json_variant_string(variant));
         if (r < 0)
@@ -3429,20 +3411,16 @@ int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags
                 return 0;
         }
 
-        if (!json_variant_is_array(variant)) {
-                json_log(variant, 0, flags, "JSON field '%s' is not an array.", strna(name));
-                return -EINVAL;
-        }
+        if (!json_variant_is_array(variant))
+                return json_log(variant, SYNTHETIC_ERRNO(EINVAL), flags, "JSON field '%s' is not an array.", strna(name));
 
         for (i = 0; i < json_variant_elements(variant); i++) {
                 JsonVariant *e;
 
                 assert_se(e = json_variant_by_index(variant, i));
 
-                if (!json_variant_is_string(e)) {
-                        json_log(e, 0, flags, "JSON array element is not a string.");
-                        return -EINVAL;
-                }
+                if (!json_variant_is_string(e))
+                        return json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "JSON array element is not a string.");
 
                 r = strv_extend(&l, json_variant_string(e));
                 if (r < 0)
index f8e035c..e5532c5 100644 (file)
@@ -4,10 +4,11 @@
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdint.h>
+#include <stdio.h>
 
 #include "macro.h"
 #include "string-util.h"
-#include "util.h"
+#include "log.h"
 
 /*
   In case you wonder why we have our own JSON implementation, here are a couple of reasons why this implementation has
@@ -264,12 +265,12 @@ static inline int json_dispatch_level(JsonDispatchFlags flags) {
 
 int json_log_internal(JsonVariant *variant, int level, int error, const char *file, int line, const char *func, const char *format, ...)  _printf_(7, 8);
 
-#define json_log(variant, flags, error, ...)                       \
+#define json_log(variant, flags, error, ...)                            \
         ({                                                              \
-                int _level = json_dispatch_level(flags), _e = (error);    \
+                int _level = json_dispatch_level(flags), _e = (error);  \
                 (log_get_max_level() >= LOG_PRI(_level))                \
                         ? json_log_internal(variant, _level, _e, __FILE__, __LINE__, __func__, __VA_ARGS__) \
-                        : -abs(_e);                                     \
+                        : -ERRNO_VALUE(_e);                             \
         })
 
 #define JSON_VARIANT_STRING_CONST(x) _JSON_VARIANT_STRING_CONST(UNIQ, (x))
diff --git a/src/shared/libmount-util.h b/src/shared/libmount-util.h
new file mode 100644 (file)
index 0000000..7d94468
--- /dev/null
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+/* This needs to be after sys/mount.h */
+#include <libmount.h>
+
+#include "macro.h"
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter);
diff --git a/src/shared/log-link.h b/src/shared/log-link.h
new file mode 100644 (file)
index 0000000..99efc0c
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "log.h"
+
+/*
+ * The following macros append INTERFACE= to the message.
+ * The macros require a struct named 'Link' which contains 'char *ifname':
+ *
+ *         typedef struct Link {
+ *                 char *ifname;
+ *         } Link;
+ *
+ * See, network/networkd-link.h for example.
+ */
+
+#define log_link_full(link, level, error, ...)                          \
+        ({                                                              \
+                const Link *_l = (link);                                \
+                (_l && _l->ifname) ? log_object_internal(level, error, __FILE__, __LINE__, __func__, "INTERFACE=", _l->ifname, NULL, NULL, ##__VA_ARGS__) : \
+                        log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
+        })                                                              \
+
+#define log_link_debug(link, ...)   log_link_full(link, LOG_DEBUG, 0, ##__VA_ARGS__)
+#define log_link_info(link, ...)    log_link_full(link, LOG_INFO, 0, ##__VA_ARGS__)
+#define log_link_notice(link, ...)  log_link_full(link, LOG_NOTICE, 0, ##__VA_ARGS__)
+#define log_link_warning(link, ...) log_link_full(link, LOG_WARNING, 0, ##__VA_ARGS__)
+#define log_link_error(link, ...)   log_link_full(link, LOG_ERR, 0, ##__VA_ARGS__)
+
+#define log_link_debug_errno(link, error, ...)   log_link_full(link, LOG_DEBUG, error, ##__VA_ARGS__)
+#define log_link_info_errno(link, error, ...)    log_link_full(link, LOG_INFO, error, ##__VA_ARGS__)
+#define log_link_notice_errno(link, error, ...)  log_link_full(link, LOG_NOTICE, error, ##__VA_ARGS__)
+#define log_link_warning_errno(link, error, ...) log_link_full(link, LOG_WARNING, error, ##__VA_ARGS__)
+#define log_link_error_errno(link, error, ...)   log_link_full(link, LOG_ERR, error, ##__VA_ARGS__)
+
+#define LOG_LINK_MESSAGE(link, fmt, ...) "MESSAGE=%s: " fmt, (link)->ifname, ##__VA_ARGS__
+#define LOG_LINK_INTERFACE(link) "INTERFACE=%s", (link)->ifname
index 15ef0f1..5fb736f 100644 (file)
@@ -25,6 +25,7 @@
 #include "log.h"
 #include "logs-show.h"
 #include "macro.h"
+#include "namespace-util.h"
 #include "output-mode.h"
 #include "parse-util.h"
 #include "process-util.h"
index af06ab2..4ad1127 100644 (file)
@@ -31,6 +31,7 @@
 #include "machine-image.h"
 #include "macro.h"
 #include "mkdir.h"
+#include "nulstr-util.h"
 #include "os-util.h"
 #include "path-util.h"
 #include "rm-rf.h"
@@ -39,7 +40,6 @@
 #include "strv.h"
 #include "time-util.h"
 #include "utf8.h"
-#include "util.h"
 #include "xattr-util.h"
 
 static const char* const image_search_path[_IMAGE_CLASS_MAX] = {
@@ -808,7 +808,7 @@ static int clone_auxiliary_file(const char *path, const char *new_name, const ch
         if (!rs)
                 return -ENOMEM;
 
-        return copy_file_atomic(path, rs, 0664, 0, COPY_REFLINK);
+        return copy_file_atomic(path, rs, 0664, 0, 0, COPY_REFLINK);
 }
 
 int image_clone(Image *i, const char *new_name, bool read_only) {
@@ -870,7 +870,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
         case IMAGE_RAW:
                 new_path = strjoina("/var/lib/machines/", new_name, ".raw");
 
-                r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, COPY_REFLINK);
+                r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, FS_NOCOW_FL, COPY_REFLINK|COPY_CRTIME);
                 break;
 
         case IMAGE_BLOCK:
@@ -1032,7 +1032,7 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
         }
 
         if (p) {
-                mkdir_p("/run/systemd/nspawn/locks", 0700);
+                (void) mkdir_p("/run/systemd/nspawn/locks", 0700);
 
                 r = make_lock_file(p, operation, global);
                 if (r < 0) {
@@ -1169,8 +1169,6 @@ int image_read_metadata(Image *i) {
 }
 
 int image_name_lock(const char *name, int operation, LockFile *ret) {
-        const char *p;
-
         assert(name);
         assert(ret);
 
@@ -1187,9 +1185,8 @@ int image_name_lock(const char *name, int operation, LockFile *ret) {
         if (streq(name, ".host"))
                 return -EBUSY;
 
-        mkdir_p("/run/systemd/nspawn/locks", 0700);
-        p = strjoina("/run/systemd/nspawn/locks/name-", name);
-
+        const char *p = strjoina("/run/systemd/nspawn/locks/name-", name);
+        (void) mkdir_p("/run/systemd/nspawn/locks", 0700);
         return make_lock_file(p, operation, ret);
 }
 
index 3c182e8..1b77316 100644 (file)
@@ -8,17 +8,19 @@
 #include "spawn-ask-password-agent.h"
 #include "spawn-polkit-agent.h"
 #include "static-destruct.h"
+#include "util.h"
 
 #define _DEFINE_MAIN_FUNCTION(intro, impl, ret)                         \
         int main(int argc, char *argv[]) {                              \
                 int r;                                                  \
+                save_argc_argv(argc, argv);                             \
                 intro;                                                  \
                 r = impl;                                               \
-                static_destruct();                                      \
                 ask_password_agent_close();                             \
                 polkit_agent_close();                                   \
-                mac_selinux_finish();                                   \
                 pager_close();                                          \
+                mac_selinux_finish();                                   \
+                static_destruct();                                      \
                 return ret;                                             \
         }
 
index f22b02d..15466bc 100644 (file)
@@ -21,10 +21,14 @@ shared_sources = files('''
         bootspec.h
         bpf-program.c
         bpf-program.h
+        bus-unit-procs.c
+        bus-unit-procs.h
         bus-unit-util.c
         bus-unit-util.h
         bus-util.c
         bus-util.h
+        bus-wait-for-jobs.c
+        bus-wait-for-jobs.h
         calendarspec.c
         calendarspec.h
         cgroup-show.c
@@ -91,6 +95,7 @@ shared_sources = files('''
         json-internal.h
         json.c
         json.h
+        libmount-util.h
         linux/auto_dev-ioctl.h
         linux/bpf.h
         linux/bpf_common.h
@@ -100,6 +105,7 @@ shared_sources = files('''
         linux/netdevice.h
         lockfile-util.c
         lockfile-util.h
+        log-link.h
         logs-show.c
         logs-show.h
         loop-util.c
@@ -124,6 +130,7 @@ shared_sources = files('''
         pager.h
         path-lookup.c
         path-lookup.h
+        pe-header.h
         pretty-print.c
         pretty-print.h
         ptyfwd.c
index 9fa995f..9987b6f 100644 (file)
@@ -29,8 +29,8 @@
 #include "strv.h"
 
 int umount_recursive(const char *prefix, int flags) {
-        bool again;
         int n = 0, r;
+        bool again;
 
         /* Try to umount everything recursively below a
          * directory. Also, take care of stacked mounts, and keep
@@ -73,9 +73,9 @@ int umount_recursive(const char *prefix, int flags) {
                                 continue;
                         }
 
-                        r = cunescape(path, UNESCAPE_RELAX, &p);
-                        if (r < 0)
-                                return r;
+                        k = cunescape(path, UNESCAPE_RELAX, &p);
+                        if (k < 0)
+                                return k;
 
                         if (!path_startswith(p, prefix))
                                 continue;
@@ -95,7 +95,7 @@ int umount_recursive(const char *prefix, int flags) {
 
         } while (again);
 
-        return r ? r : n;
+        return r < 0 ? r : n;
 }
 
 static int get_mount_flags(const char *path, unsigned long *flags) {
@@ -107,10 +107,15 @@ static int get_mount_flags(const char *path, unsigned long *flags) {
         return 0;
 }
 
-/* Use this function only if do you have direct access to /proc/self/mountinfo
- * and need the caller to open it for you. This is the case when /proc is
- * masked or not mounted. Otherwise, use bind_remount_recursive. */
-int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **blacklist, FILE *proc_self_mountinfo) {
+/* Use this function only if you do not have direct access to /proc/self/mountinfo but the caller can open it
+ * for you. This is the case when /proc is masked or not mounted. Otherwise, use bind_remount_recursive. */
+int bind_remount_recursive_with_mountinfo(
+                const char *prefix,
+                unsigned long new_flags,
+                unsigned long flags_mask,
+                char **blacklist,
+                FILE *proc_self_mountinfo) {
+
         _cleanup_set_free_free_ Set *done = NULL;
         _cleanup_free_ char *cleaned = NULL;
         int r;
@@ -245,16 +250,12 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl
                         (void) get_mount_flags(cleaned, &orig_flags);
                         orig_flags &= ~MS_RDONLY;
 
-                        if (mount(NULL, cleaned, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
+                        if (mount(NULL, cleaned, NULL, (orig_flags & ~flags_mask)|MS_BIND|MS_REMOUNT|new_flags, NULL) < 0)
                                 return -errno;
 
                         log_debug("Made top-level directory %s a mount point.", prefix);
 
-                        x = strdup(cleaned);
-                        if (!x)
-                                return -ENOMEM;
-
-                        r = set_consume(done, x);
+                        r = set_put_strdup(done, cleaned);
                         if (r < 0)
                                 return r;
                 }
@@ -291,7 +292,7 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl
                         (void) get_mount_flags(x, &orig_flags);
                         orig_flags &= ~MS_RDONLY;
 
-                        if (mount(NULL, x, NULL, orig_flags|MS_BIND|MS_REMOUNT|(ro ? MS_RDONLY : 0), NULL) < 0)
+                        if (mount(NULL, x, NULL, (orig_flags & ~flags_mask)|MS_BIND|MS_REMOUNT|new_flags, NULL) < 0)
                                 return -errno;
 
                         log_debug("Remounted %s read-only.", x);
@@ -299,7 +300,7 @@ int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **bl
         }
 }
 
-int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
+int bind_remount_recursive(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **blacklist) {
         _cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
 
         proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
@@ -308,7 +309,7 @@ int bind_remount_recursive(const char *prefix, bool ro, char **blacklist) {
 
         (void) __fsetlocking(proc_self_mountinfo, FSETLOCKING_BYCALLER);
 
-        return bind_remount_recursive_with_mountinfo(prefix, ro, blacklist, proc_self_mountinfo);
+        return bind_remount_recursive_with_mountinfo(prefix, new_flags, flags_mask, blacklist, proc_self_mountinfo);
 }
 
 int mount_move_root(const char *path) {
index 00df1b0..8649fca 100644 (file)
@@ -8,8 +8,8 @@
 
 int repeat_unmount(const char *path, int flags);
 int umount_recursive(const char *target, int flags);
-int bind_remount_recursive(const char *prefix, bool ro, char **blacklist);
-int bind_remount_recursive_with_mountinfo(const char *prefix, bool ro, char **blacklist, FILE *proc_self_mountinfo);
+int bind_remount_recursive(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **blacklist);
+int bind_remount_recursive_with_mountinfo(const char *prefix, unsigned long new_flags, unsigned long flags_mask, char **blacklist, FILE *proc_self_mountinfo);
 
 int mount_move_root(const char *path);
 
index bf2597e..2abb0f6 100644 (file)
@@ -24,6 +24,7 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
+#include "util.h"
 
 static pid_t pager_pid = 0;
 
diff --git a/src/shared/pe-header.h b/src/shared/pe-header.h
new file mode 100644 (file)
index 0000000..a362917
--- /dev/null
@@ -0,0 +1,59 @@
+#pragma once
+
+#include <inttypes.h>
+
+#include "macro.h"
+#include "sparse-endian.h"
+
+struct DosFileHeader {
+        uint8_t Magic[2];
+        le16_t LastSize;
+        le16_t nBlocks;
+        le16_t nReloc;
+        le16_t HdrSize;
+        le16_t MinAlloc;
+        le16_t MaxAlloc;
+        le16_t ss;
+        le16_t sp;
+        le16_t Checksum;
+        le16_t ip;
+        le16_t cs;
+        le16_t RelocPos;
+        le16_t nOverlay;
+        le16_t reserved[4];
+        le16_t OEMId;
+        le16_t OEMInfo;
+        le16_t reserved2[10];
+        le32_t ExeHeader;
+} _packed_;
+
+#define PE_HEADER_MACHINE_I386 0x014cU
+#define PE_HEADER_MACHINE_X64  0x8664U
+
+struct PeFileHeader {
+        le16_t Machine;
+        le16_t NumberOfSections;
+        le32_t TimeDateStamp;
+        le32_t PointerToSymbolTable;
+        le32_t NumberOfSymbols;
+        le16_t SizeOfOptionalHeader;
+        le16_t Characteristics;
+} _packed_;
+
+struct PeHeader {
+        uint8_t Magic[4];
+        struct PeFileHeader FileHeader;
+} _packed_;
+
+struct PeSectionHeader {
+        uint8_t Name[8];
+        le32_t VirtualSize;
+        le32_t VirtualAddress;
+        le32_t SizeOfRawData;
+        le32_t PointerToRawData;
+        le32_t PointerToRelocations;
+        le32_t PointerToLinenumbers;
+        le16_t NumberOfRelocations;
+        le16_t NumberOfLinenumbers;
+        le32_t Characteristics;
+ } _packed_;
index de6274a..c602e03 100644 (file)
@@ -213,33 +213,91 @@ void print_separator(void) {
                 fputs("\n\n", stdout);
 }
 
+static int guess_type(const char **name, bool *is_usr, bool *is_collection, const char **extension) {
+        /* Try to figure out if name is like tmpfiles.d/ or systemd/system-presets/,
+         * i.e. a collection of directories without a main config file. */
+
+        _cleanup_free_ char *n = NULL;
+        bool usr = false, coll = false;
+        const char *ext = ".conf";
+
+        if (path_equal(*name, "environment.d"))
+                /* Special case: we need to include /etc/environment in the search path, even
+                 * though the whole concept is called environment.d. */
+                *name = "environment";
+
+        n = strdup(*name);
+        if (!n)
+                return log_oom();
+
+        delete_trailing_chars(n, "/");
+
+        if (endswith(n, ".d"))
+                coll = true;
+
+        if (path_equal(n, "environment"))
+                usr = true;
+
+        if (path_equal(n, "udev/hwdb.d"))
+                ext = ".hwdb";
+
+        if (path_equal(n, "udev/rules.d"))
+                ext = ".rules";
+
+        if (path_equal(n, "kernel/install.d"))
+                ext = ".install";
+
+        if (PATH_IN_SET(n, "systemd/system-preset", "systemd/user-preset")) {
+                coll = true;
+                ext = ".preset";
+        }
+
+        if (path_equal(n, "systemd/user-preset"))
+                usr = true;
+
+        *is_usr = usr;
+        *is_collection = coll;
+        *extension = ext;
+        return 0;
+}
+
 int conf_files_cat(const char *root, const char *name) {
         _cleanup_strv_free_ char **dirs = NULL, **files = NULL;
         _cleanup_free_ char *path = NULL;
-        const char *dir;
+        char **dir;
+        bool is_usr, is_collection;
+        const char *extension;
         char **t;
         int r;
 
-        NULSTR_FOREACH(dir, CONF_PATHS_NULSTR("")) {
-                assert(endswith(dir, "/"));
-                r = strv_extendf(&dirs, "%s%s.d", dir, name);
+        r = guess_type(&name, &is_usr, &is_collection, &extension);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(dir, is_usr ? CONF_PATHS_USR_STRV("") : CONF_PATHS_STRV("")) {
+                assert(endswith(*dir, "/"));
+                r = strv_extendf(&dirs, "%s%s%s", *dir, name,
+                                 is_collection ? "" : ".d");
                 if (r < 0)
                         return log_error_errno(r, "Failed to build directory list: %m");
         }
 
-        r = conf_files_list_strv(&files, ".conf", root, 0, (const char* const*) dirs);
+        r = conf_files_list_strv(&files, extension, root, 0, (const char* const*) dirs);
         if (r < 0)
                 return log_error_errno(r, "Failed to query file list: %m");
 
-        path = path_join(root, "/etc", name);
-        if (!path)
-                return log_oom();
+        if (!is_collection) {
+                path = path_join(root, "/etc", name);
+                if (!path)
+                        return log_oom();
+        }
 
         if (DEBUG_LOGGING) {
                 log_debug("Looking for configuration in:");
-                log_debug("   %s", path);
+                if (path)
+                        log_debug("   %s", path);
                 STRV_FOREACH(t, dirs)
-                        log_debug("   %s/*.conf", *t);
+                        log_debug("   %s/*%s", *t, extension);
         }
 
         /* show */
index ca40159..08569e8 100644 (file)
 #include "umask-util.h"
 #include "virt.h"
 
-int update_reboot_parameter_and_warn(const char *parameter) {
+int update_reboot_parameter_and_warn(const char *parameter, bool keep) {
         int r;
 
         if (isempty(parameter)) {
+                if (keep)
+                        return 0;
+
                 if (unlink("/run/systemd/reboot-param") < 0) {
                         if (errno == ENOENT)
                                 return 0;
@@ -36,6 +39,18 @@ int update_reboot_parameter_and_warn(const char *parameter) {
         return 0;
 }
 
+int read_reboot_parameter(char **parameter) {
+        int r;
+
+        assert(parameter);
+
+        r = read_one_line_file("/run/systemd/reboot-param", parameter);
+        if (r < 0 && r != -ENOENT)
+                return log_debug_errno(r, "Failed to read /run/systemd/reboot-param: %m");
+
+        return 0;
+}
+
 int reboot_with_parameter(RebootFlags flags) {
         int r;
 
index d459333..7bddc91 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
-int update_reboot_parameter_and_warn(const char *parameter);
+int update_reboot_parameter_and_warn(const char *parameter, bool keep);
 
 typedef enum RebootFlags {
         REBOOT_LOG      = 1 << 0, /* log about what we are going to do and all errors */
@@ -9,4 +9,5 @@ typedef enum RebootFlags {
         REBOOT_FALLBACK = 1 << 2, /* fallback to plain reboot() if argument-based reboot doesn't work, isn't configured or doesn't apply otherwise */
 } RebootFlags;
 
+int read_reboot_parameter(char **parameter);
 int reboot_with_parameter(RebootFlags flags);
index cc58b3c..8ed09fd 100644 (file)
@@ -1,24 +1,26 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
+#include <fcntl.h>
 #include <linux/seccomp.h>
 #include <seccomp.h>
 #include <stddef.h>
 #include <sys/mman.h>
 #include <sys/prctl.h>
 #include <sys/shm.h>
+#include <sys/stat.h>
 
 #include "af-list.h"
 #include "alloc-util.h"
+#include "errno-list.h"
 #include "macro.h"
 #include "nsflags.h"
+#include "nulstr-util.h"
 #include "process-util.h"
 #include "seccomp-util.h"
 #include "set.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
-#include "errno-list.h"
 
 const uint32_t seccomp_local_archs[] = {
 
@@ -291,6 +293,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
                 "pause\0"
                 "prlimit64\0"
                 "restart_syscall\0"
+                "rseq\0"
                 "rt_sigreturn\0"
                 "sched_yield\0"
                 "set_robust_list\0"
@@ -1013,7 +1016,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u
         return 0;
 }
 
-int seccomp_parse_syscall_filter_full(
+int seccomp_parse_syscall_filter(
                 const char *name,
                 int errno_num,
                 Hashmap *filter,
@@ -1046,7 +1049,7 @@ int seccomp_parse_syscall_filter_full(
                          * away the SECCOMP_PARSE_LOG flag) since any issues in the group table are our own problem,
                          * not a problem in user configuration data and we shouldn't pretend otherwise by complaining
                          * about them. */
-                        r = seccomp_parse_syscall_filter_full(i, errno_num, filter, flags &~ SECCOMP_PARSE_LOG, unit, filename, line);
+                        r = seccomp_parse_syscall_filter(i, errno_num, filter, flags &~ SECCOMP_PARSE_LOG, unit, filename, line);
                         if (r < 0)
                                 return r;
                 }
@@ -1502,14 +1505,9 @@ static int add_seccomp_syscall_filter(scmp_filter_ctx seccomp,
 assert_cc(SCMP_SYS(shmget) > 0);
 assert_cc(SCMP_SYS(shmat) > 0);
 assert_cc(SCMP_SYS(shmdt) > 0);
-#elif defined(__i386__) || defined(__powerpc64__)
-assert_cc(SCMP_SYS(shmget) < 0);
-assert_cc(SCMP_SYS(shmat) < 0);
-assert_cc(SCMP_SYS(shmdt) < 0);
 #endif
 
 int seccomp_memory_deny_write_execute(void) {
-
         uint32_t arch;
         int r;
 
@@ -1524,6 +1522,7 @@ int seccomp_memory_deny_write_execute(void) {
                 case SCMP_ARCH_X86:
                         filter_syscall = SCMP_SYS(mmap2);
                         block_syscall = SCMP_SYS(mmap);
+                        shmat_syscall = SCMP_SYS(shmat);
                         break;
 
                 case SCMP_ARCH_PPC:
@@ -1590,7 +1589,7 @@ int seccomp_memory_deny_write_execute(void) {
                         continue;
 #endif
 
-                if (shmat_syscall != 0) {
+                if (shmat_syscall > 0) {
                         r = add_seccomp_syscall_filter(seccomp, arch, SCMP_SYS(shmat),
                                                        1,
                                                        SCMP_A2(SCMP_CMP_MASKED_EQ, SHM_EXEC, SHM_EXEC));
@@ -1762,3 +1761,206 @@ int seccomp_lock_personality(unsigned long personality) {
 
         return 0;
 }
+
+int seccomp_protect_hostname(void) {
+        uint32_t arch;
+        int r;
+
+        SECCOMP_FOREACH_LOCAL_ARCH(arch) {
+                _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
+
+                r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
+                if (r < 0)
+                        return r;
+
+                r = seccomp_rule_add_exact(
+                                seccomp,
+                                SCMP_ACT_ERRNO(EPERM),
+                                SCMP_SYS(sethostname),
+                                0);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to add sethostname() rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
+                        continue;
+                }
+
+                r = seccomp_rule_add_exact(
+                                seccomp,
+                                SCMP_ACT_ERRNO(EPERM),
+                                SCMP_SYS(setdomainname),
+                                0);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to add setdomainname() rule for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
+                        continue;
+                }
+
+                r = seccomp_load(seccomp);
+                if (IN_SET(r, -EPERM, -EACCES))
+                        return r;
+                if (r < 0)
+                        log_debug_errno(r, "Failed to apply hostname restrictions for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
+        }
+
+        return 0;
+}
+
+static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) {
+        /* Checks the mode_t parameter of the following system calls:
+         *
+         *       → chmod() + fchmod() + fchmodat()
+         *       → open() + creat() + openat()
+         *       → mkdir() + mkdirat()
+         *       → mknod() + mknodat()
+         *
+         * Returns error if *everything* failed, and 0 otherwise.
+         */
+        int r = 0;
+        bool any = false;
+
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(chmod),
+                        1,
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for chmod: %m");
+        else
+                any = true;
+
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(fchmod),
+                        1,
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for fchmod: %m");
+        else
+                any = true;
+
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(fchmodat),
+                        1,
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for fchmodat: %m");
+        else
+                any = true;
+
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(mkdir),
+                        1,
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for mkdir: %m");
+        else
+                any = true;
+
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(mkdirat),
+                        1,
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for mkdirat: %m");
+        else
+                any = true;
+
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(mknod),
+                        1,
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for mknod: %m");
+        else
+                any = true;
+
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(mknodat),
+                        1,
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for mknodat: %m");
+        else
+                any = true;
+
+#if SCMP_SYS(open) > 0
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(open),
+                        2,
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for open: %m");
+        else
+                any = true;
+#endif
+
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(openat),
+                        2,
+                        SCMP_A2(SCMP_CMP_MASKED_EQ, O_CREAT, O_CREAT),
+                        SCMP_A3(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for openat: %m");
+        else
+                any = true;
+
+        r = seccomp_rule_add_exact(
+                        seccomp,
+                        SCMP_ACT_ERRNO(EPERM),
+                        SCMP_SYS(creat),
+                        1,
+                        SCMP_A1(SCMP_CMP_MASKED_EQ, m, m));
+        if (r < 0)
+                log_debug_errno(r, "Failed to add filter for creat: %m");
+        else
+                any = true;
+
+        return any ? 0 : r;
+}
+
+int seccomp_restrict_suid_sgid(void) {
+        uint32_t arch;
+        int r, k;
+
+        SECCOMP_FOREACH_LOCAL_ARCH(arch) {
+                _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
+
+                r = seccomp_init_for_arch(&seccomp, arch, SCMP_ACT_ALLOW);
+                if (r < 0)
+                        return r;
+
+                r = seccomp_restrict_sxid(seccomp, S_ISUID);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to add suid rule for architecture %s, ignoring: %m", seccomp_arch_to_string(arch));
+
+                k = seccomp_restrict_sxid(seccomp, S_ISGID);
+                if (k < 0)
+                        log_debug_errno(r, "Failed to add sgid rule for architecture %s, ignoring: %m", seccomp_arch_to_string(arch));
+
+                if (r < 0 && k < 0)
+                        continue;
+
+                r = seccomp_load(seccomp);
+                if (IN_SET(r, -EPERM, -EACCES))
+                        return r;
+                if (r < 0)
+                        log_debug_errno(r, "Failed to apply suid/sgid restrictions for architecture %s, skipping: %m", seccomp_arch_to_string(arch));
+        }
+
+        return 0;
+}
index d8a36c4..14dbc42 100644 (file)
@@ -70,13 +70,13 @@ typedef enum SeccompParseFlags {
         SECCOMP_PARSE_PERMISSIVE = 1 << 3,
 } SeccompParseFlags;
 
-int seccomp_parse_syscall_filter_full(
-                const char *name, int errno_num, Hashmap *filter, SeccompParseFlags flags,
-                const char *unit, const char *filename, unsigned line);
-
-static inline int seccomp_parse_syscall_filter(const char *name, int errno_num, Hashmap *filter, SeccompParseFlags flags) {
-        return seccomp_parse_syscall_filter_full(name, errno_num, filter, flags, NULL, NULL, 0);
-}
+int seccomp_parse_syscall_filter(
+                const char *name,
+                int errno_num,
+                Hashmap *filter,
+                SeccompParseFlags flags,
+                const char *unit,
+                const char *filename, unsigned line);
 
 int seccomp_restrict_archs(Set *archs);
 int seccomp_restrict_namespaces(unsigned long retain);
@@ -85,6 +85,8 @@ int seccomp_restrict_address_families(Set *address_families, bool whitelist);
 int seccomp_restrict_realtime(void);
 int seccomp_memory_deny_write_execute(void);
 int seccomp_lock_personality(unsigned long personality);
+int seccomp_protect_hostname(void);
+int seccomp_restrict_suid_sgid(void);
 
 extern const uint32_t seccomp_local_archs[];
 
index 4cbd98b..8f4efc7 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "fdset.h"
 #include "macro.h"
+#include "time-util.h"
 
 int serialize_item(FILE *f, const char *key, const char *value);
 int serialize_item_escaped(FILE *f, const char *key, const char *value);
index 2e22bd0..7f23e54 100644 (file)
@@ -4,12 +4,15 @@
 ***/
 
 #include <errno.h>
+#include <fcntl.h>
 #include <linux/fs.h>
 #include <stdbool.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <syslog.h>
 #include <unistd.h>
 
@@ -17,6 +20,7 @@
 #include "conf-parser.h"
 #include "def.h"
 #include "env-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "log.h"
@@ -201,8 +205,7 @@ int find_hibernate_location(char **device, char **type, size_t *size, size_t *us
         if (!f) {
                 log_full(errno == ENOENT ? LOG_DEBUG : LOG_WARNING,
                          "Failed to retrieve open /proc/swaps: %m");
-                assert(errno > 0);
-                return -errno;
+                return negative_errno();
         }
 
         (void) fscanf(f, "%*s %*s %*s %*s %*s\n");
index b8f7537..c8e7896 100644 (file)
@@ -10,6 +10,7 @@
 #include "sd-id128.h"
 
 #include "alloc-util.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "hostname-util.h"
 #include "macro.h"
index 480e6c3..9be4055 100644 (file)
@@ -60,6 +60,22 @@ int sysctl_write(const char *property, const char *value) {
         return 0;
 }
 
+int sysctl_write_ip_property(int af, const char *ifname, const char *property, const char *value) {
+        const char *p;
+
+        assert(IN_SET(af, AF_INET, AF_INET6));
+        assert(property);
+        assert(value);
+
+        p = strjoina("/proc/sys/net/ipv", af == AF_INET ? "4" : "6",
+                     ifname ? "/conf/" : "", strempty(ifname),
+                     property[0] == '/' ? "" : "/", property);
+
+        log_debug("Setting '%s' to '%s'", p, value);
+
+        return write_string_file(p, value, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER);
+}
+
 int sysctl_read(const char *property, char **content) {
         char *p;
 
@@ -69,3 +85,25 @@ int sysctl_read(const char *property, char **content) {
         p = strjoina("/proc/sys/", property);
         return read_full_file(p, content, NULL);
 }
+
+int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret) {
+        _cleanup_free_ char *value = NULL;
+        const char *p;
+        int r;
+
+        assert(IN_SET(af, AF_INET, AF_INET6));
+        assert(property);
+
+        p = strjoina("/proc/sys/net/ipv", af == AF_INET ? "4" : "6",
+                     ifname ? "/conf/" : "", strempty(ifname),
+                     property[0] == '/' ? "" : "/", property);
+
+        r = read_one_line_file(p, &value);
+        if (r < 0)
+                return r;
+
+        if (ret)
+                *ret = TAKE_PTR(value);
+
+        return r;
+}
index fd7c78b..d50c6e4 100644 (file)
@@ -1,7 +1,29 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 #pragma once
 
+#include <stdbool.h>
+#include <stdint.h>
+
+#include "macro.h"
+#include "stdio-util.h"
+#include "util.h"
+
 char *sysctl_normalize(char *s);
 int sysctl_read(const char *property, char **value);
 int sysctl_write(const char *property, const char *value);
 
+int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret);
+int sysctl_write_ip_property(int af, const char *ifname, const char *property, const char *value);
+static inline int sysctl_write_ip_property_boolean(int af, const char *ifname, const char *property, bool value) {
+        return sysctl_write_ip_property(af, ifname, property, one_zero(value));
+}
+
+#define DEFINE_SYSCTL_WRITE_IP_PROPERTY(name, type, format)           \
+        static inline int sysctl_write_ip_property_##name(int af, const char *ifname, const char *property, type value) { \
+                char buf[DECIMAL_STR_MAX(type)];                        \
+                xsprintf(buf, format, value);                           \
+                return sysctl_write_ip_property(af, ifname, property, buf); \
+        }
+
+DEFINE_SYSCTL_WRITE_IP_PROPERTY(int, int, "%i");
+DEFINE_SYSCTL_WRITE_IP_PROPERTY(uint32, uint32_t, "%" PRIu32);
index 4200032..4be9d71 100644 (file)
@@ -133,7 +133,7 @@ int device_wait_for_initialization(sd_device *device, const char *subsystem, sd_
 
         /* Wait until the device is initialized, so that we can get access to the ID_PATH property */
 
-        r = sd_event_default(&event);
+        r = sd_event_new(&event);
         if (r < 0)
                 return log_error_errno(r, "Failed to get default event: %m");
 
@@ -169,3 +169,26 @@ int device_wait_for_initialization(sd_device *device, const char *subsystem, sd_
                 *ret = TAKE_PTR(data.device);
         return 0;
 }
+
+int device_is_renaming(sd_device *dev) {
+        int r;
+
+        assert(dev);
+
+        r = sd_device_get_property_value(dev, "ID_RENAMING", NULL);
+        if (r < 0 && r != -ENOENT)
+                return r;
+
+        return r >= 0;
+}
+
+bool device_for_action(sd_device *dev, DeviceAction action) {
+        DeviceAction a;
+
+        assert(dev);
+
+        if (device_get_action(dev, &a) < 0)
+                return false;
+
+        return a == action;
+}
index 932c4a9..3c45447 100644 (file)
@@ -3,6 +3,7 @@
 
 #include "sd-device.h"
 
+#include "device-private.h"
 #include "time-util.h"
 
 typedef enum ResolveNameTiming {
@@ -27,3 +28,5 @@ static inline int udev_parse_config(void) {
 }
 
 int device_wait_for_initialization(sd_device *device, const char *subsystem, sd_device **ret);
+int device_is_renaming(sd_device *dev);
+bool device_for_action(sd_device *dev, DeviceAction action);
index 5fa7bd2..7cb7d8a 100644 (file)
@@ -6,9 +6,9 @@
 
 #include "alloc-util.h"
 #include "macro.h"
+#include "sort-util.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);
index ef9427f..4b134b6 100644 (file)
 #include "fd-util.h"
 #include "hostname-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #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) {
index 4d75bc0..5ca6ab3 100644 (file)
 
 int query_volatile_mode(VolatileMode *ret) {
         _cleanup_free_ char *mode = NULL;
-        VolatileMode m = VOLATILE_NO;
         int r;
 
         r = proc_cmdline_get_key("systemd.volatile", PROC_CMDLINE_VALUE_OPTIONAL, &mode);
         if (r < 0)
                 return r;
-        if (r == 0)
-                goto finish;
+        if (r == 0) {
+                *ret = VOLATILE_NO;
+                return 0;
+        }
 
         if (mode) {
+                VolatileMode m;
+
                 m = volatile_mode_from_string(mode);
                 if (m < 0)
                         return -EINVAL;
-        } else
-                m = VOLATILE_YES;
 
-        r = 1;
+                *ret = m;
+        } else
+                *ret = VOLATILE_YES;
 
-finish:
-        *ret = m;
-        return r;
+        return 1;
 }
 
 static const char* const volatile_mode_table[_VOLATILE_MODE_MAX] = {
         [VOLATILE_NO] = "no",
         [VOLATILE_YES] = "yes",
         [VOLATILE_STATE] = "state",
+        [VOLATILE_OVERLAY] = "overlay",
 };
 
 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(volatile_mode, VolatileMode, VOLATILE_YES);
index 8761c44..2d31bb1 100644 (file)
@@ -5,6 +5,7 @@ typedef enum VolatileMode {
         VOLATILE_NO,
         VOLATILE_YES,
         VOLATILE_STATE,
+        VOLATILE_OVERLAY,
         _VOLATILE_MODE_MAX,
         _VOLATILE_MODE_INVALID = -1
 } VolatileMode;
diff --git a/src/shutdown/meson.build b/src/shutdown/meson.build
new file mode 100644 (file)
index 0000000..ebf0bed
--- /dev/null
@@ -0,0 +1,5 @@
+systemd_shutdown_sources = files('''
+        shutdown.c
+        umount.c
+        umount.h
+'''.split())
similarity index 97%
rename from src/core/shutdown.c
rename to src/shutdown/shutdown.c
index cb47ee8..842ba57 100644 (file)
@@ -169,10 +169,10 @@ static int switch_root_initramfs(void) {
  * value input. For all other issues, report the failure and indicate that
  * the sync is not making progress.
  */
-static bool sync_making_progress(unsigned long long *prev_dirty) {
+static int sync_making_progress(unsigned long long *prev_dirty) {
         _cleanup_fclose_ FILE *f = NULL;
         unsigned long long val = 0;
-        bool r = false;
+        int ret;
 
         f = fopen("/proc/meminfo", "re");
         if (!f)
@@ -205,11 +205,9 @@ static bool sync_making_progress(unsigned long long *prev_dirty) {
                 val += ull;
         }
 
-        r = *prev_dirty > val;
-
+        ret = *prev_dirty > val;
         *prev_dirty = val;
-
-        return r;
+        return ret;
 }
 
 static void sync_with_progress(void) {
@@ -243,7 +241,7 @@ static void sync_with_progress(void) {
                 else if (r == -ETIMEDOUT) {
                         /* Reset the check counter if the "Dirty" value is
                          * decreasing */
-                        if (sync_making_progress(&dirty))
+                        if (sync_making_progress(&dirty) > 0)
                                 checks = 0;
                 } else {
                         log_error_errno(r, "Failed to sync filesystems and block devices: %m");
@@ -345,14 +343,14 @@ int main(int argc, char *argv[]) {
                 bool changed = false;
 
                 if (use_watchdog)
-                        watchdog_ping();
+                        (void) watchdog_ping();
 
                 /* Let's trim the cgroup tree on each iteration so
                    that we leave an empty cgroup tree around, so that
                    container managers get a nice notify event when we
                    are down */
                 if (cgroup)
-                        cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
+                        (void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
 
                 if (need_umount) {
                         log_info("Unmounting file systems.");
@@ -442,7 +440,7 @@ int main(int argc, char *argv[]) {
         arguments[0] = NULL;
         arguments[1] = arg_verb;
         arguments[2] = NULL;
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
+        (void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
 
         (void) rlimit_nofile_safe();
 
similarity index 95%
rename from src/core/umount.c
rename to src/shutdown/umount.c
index d4fcc5f..6afa512 100644 (file)
@@ -10,9 +10,9 @@
 #include <string.h>
 #include <sys/mount.h>
 #include <sys/swap.h>
-
-/* This needs to be after sys/mount.h :( */
-#include <libmount.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "sd-device.h"
 
@@ -23,6 +23,7 @@
 #include "escape.h"
 #include "fd-util.h"
 #include "fstab-util.h"
+#include "libmount-util.h"
 #include "mount-setup.h"
 #include "mount-util.h"
 #include "mountpoint-util.h"
@@ -35,9 +36,6 @@
 #include "util.h"
 #include "virt.h"
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table);
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter);
-
 static void mount_point_free(MountPoint **head, MountPoint *m) {
         assert(head);
         assert(m);
@@ -76,11 +74,10 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) {
                 struct libmnt_fs *fs;
                 const char *path, *fstype;
                 _cleanup_free_ char *options = NULL;
-                _cleanup_free_ char *p = NULL;
                 unsigned long remount_flags = 0u;
                 _cleanup_free_ char *remount_options = NULL;
                 bool try_remount_ro;
-                MountPoint *m;
+                _cleanup_free_ MountPoint *m = NULL;
 
                 r = mnt_table_next_fs(t, i, &fs);
                 if (r == 1)
@@ -92,18 +89,15 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) {
                 if (!path)
                         continue;
 
-                if (cunescape(path, UNESCAPE_RELAX, &p) < 0)
-                        return log_oom();
-
                 fstype = mnt_fs_get_fstype(fs);
 
                 /* Combine the generic VFS options with the FS-specific
                  * options. Duplicates are not a problem here, because the only
                  * options that should come up twice are typically ro/rw, which
-                 * are turned into MS_RDONLY or the invertion of it.
+                 * are turned into MS_RDONLY or the inversion of it.
                  *
                  * Even if there are duplicates later in mount_option_mangle()
-                 * it shouldn't hurt anyways as they override each other.
+                 * they shouldn't hurt anyways as they override each other.
                  */
                 if (!strextend_with_separator(&options, ",",
                                               mnt_fs_get_vfs_options(fs),
@@ -121,9 +115,9 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) {
                  * and hence not worth spending time on. Also, in
                  * unprivileged containers we might lack the rights to
                  * unmount these things, hence don't bother. */
-                if (mount_point_is_api(p) ||
-                    mount_point_ignore(p) ||
-                    PATH_STARTSWITH_SET(p, "/dev", "/sys", "/proc"))
+                if (mount_point_is_api(path) ||
+                    mount_point_ignore(path) ||
+                    PATH_STARTSWITH_SET(path, "/dev", "/sys", "/proc"))
                         continue;
 
                 /* If we are in a container, don't attempt to
@@ -169,12 +163,15 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) {
                 if (!m)
                         return log_oom();
 
-                free_and_replace(m->path, p);
-                free_and_replace(m->remount_options, remount_options);
+                m->path = strdup(path);
+                if (!m->path)
+                        return log_oom();
+
+                m->remount_options = TAKE_PTR(remount_options);
                 m->remount_flags = remount_flags;
                 m->try_remount_ro = try_remount_ro;
 
-                LIST_PREPEND(mount_point, *head, m);
+                LIST_PREPEND(mount_point, *head, TAKE_PTR(m));
         }
 
         return 0;
@@ -198,10 +195,8 @@ int swap_list_get(const char *swaps, MountPoint **head) {
 
         for (;;) {
                 struct libmnt_fs *fs;
-
-                MountPoint *swap;
+                _cleanup_free_ MountPoint *swap = NULL;
                 const char *source;
-                _cleanup_free_ char *d = NULL;
 
                 r = mnt_table_next_fs(t, i, &fs);
                 if (r == 1)
@@ -213,16 +208,15 @@ int swap_list_get(const char *swaps, MountPoint **head) {
                 if (!source)
                         continue;
 
-                r = cunescape(source, UNESCAPE_RELAX, &d);
-                if (r < 0)
-                        return r;
-
                 swap = new0(MountPoint, 1);
                 if (!swap)
                         return -ENOMEM;
 
-                free_and_replace(swap->path, d);
-                LIST_PREPEND(mount_point, *head, swap);
+                swap->path = strdup(source);
+                if (!swap->path)
+                        return -ENOMEM;
+
+                LIST_PREPEND(mount_point, *head, TAKE_PTR(swap));
         }
 
         return 0;
similarity index 100%
rename from src/core/umount.h
rename to src/shutdown/umount.h
index 5b7984a..11aabaf 100644 (file)
@@ -5,15 +5,20 @@
 ***/
 
 #include <errno.h>
+#include <fcntl.h>
 #include <getopt.h>
 #include <linux/fiemap.h>
 #include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "sd-messages.h"
 
 #include "def.h"
 #include "exec-util.h"
 #include "fd-util.h"
+#include "format-util.h"
 #include "fileio.h"
 #include "log.h"
 #include "main-func.h"
@@ -166,7 +171,7 @@ static int execute(char **modes, char **states) {
                         return log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");;
         }
 
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
+        (void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
 
         log_struct(LOG_INFO,
                    "MESSAGE_ID=" SD_MESSAGE_SLEEP_START_STR,
@@ -186,7 +191,7 @@ static int execute(char **modes, char **states) {
                            "SLEEP=%s", arg_verb);
 
         arguments[1] = (char*) "post";
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL);
+        (void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
 
         return r;
 }
index bac5c16..abbbc9f 100644 (file)
@@ -16,6 +16,7 @@
 #include "sd-resolve.h"
 
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "log.h"
 #include "main-func.h"
@@ -29,8 +30,8 @@
 #include "util.h"
 
 #define BUFFER_SIZE (256 * 1024)
-static unsigned arg_connections_max = 256;
 
+static unsigned arg_connections_max = 256;
 static const char *arg_remote_host = NULL;
 
 typedef struct Context {
@@ -141,7 +142,7 @@ static int connection_shovel(
                         if (z > 0) {
                                 *full += z;
                                 shoveled = true;
-                        } else if (z == 0 || IN_SET(errno, EPIPE, ECONNRESET)) {
+                        } else if (z == 0 || ERRNO_IS_DISCONNECT(errno)) {
                                 *from_source = sd_event_source_unref(*from_source);
                                 *from = safe_close(*from);
                         } else if (!IN_SET(errno, EAGAIN, EINTR))
@@ -153,7 +154,7 @@ static int connection_shovel(
                         if (z > 0) {
                                 *full -= z;
                                 shoveled = true;
-                        } else if (z == 0 || IN_SET(errno, EPIPE, ECONNRESET)) {
+                        } else if (z == 0 || ERRNO_IS_DISCONNECT(errno)) {
                                 *to_source = sd_event_source_unref(*to_source);
                                 *to = safe_close(*to);
                         } else if (!IN_SET(errno, EAGAIN, EINTR))
@@ -466,10 +467,10 @@ static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdat
 
         nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
         if (nfd < 0) {
-                if (errno != -EAGAIN)
+                if (!ERRNO_IS_ACCEPT_AGAIN(errno))
                         log_warning_errno(errno, "Failed to accept() socket: %m");
         } else {
-                getpeername_pretty(nfd, true, &peer);
+                (void) getpeername_pretty(nfd, true, &peer);
                 log_debug("New connection from %s", strna(peer));
 
                 r = add_connection_socket(context, nfd);
index 7060897..52b9ce4 100644 (file)
@@ -14,6 +14,7 @@
 #include "build.h"
 #include "bus-internal.h"
 #include "bus-util.h"
+#include "errno-util.h"
 #include "log.h"
 #include "main-func.h"
 #include "util.h"
@@ -56,31 +57,28 @@ static int parse_argv(int argc, char *argv[]) {
         assert(argc >= 0);
         assert(argv);
 
-        while ((c = getopt_long(argc, argv, "hsup:", options, NULL)) >= 0) {
+        while ((c = getopt_long(argc, argv, "hp:M:", options, NULL)) >= 0) {
 
                 switch (c) {
 
                 case 'h':
-                        help();
-                        return 0;
+                        return help();
 
                 case ARG_VERSION:
                         return version();
 
-                case '?':
-                        return -EINVAL;
-
                 case 'p':
                         arg_bus_path = optarg;
-
                         break;
 
                 case 'M':
                         arg_bus_path = optarg;
-
                         arg_transport = BUS_TRANSPORT_MACHINE;
-
                         break;
+
+                case '?':
+                        return -EINVAL;
+
                 default:
                         return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                "Unknown option code %c", c);
@@ -111,10 +109,8 @@ static int run(int argc, char *argv[]) {
         } else if (r == 1) {
                 in_fd = SD_LISTEN_FDS_START;
                 out_fd = SD_LISTEN_FDS_START;
-        } else {
-                log_error("Illegal number of file descriptors passed.");
-                return -EINVAL;
-        }
+        } else
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Illegal number of file descriptors passed.");
 
         is_unix =
                 sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
@@ -187,9 +183,13 @@ static int run(int argc, char *argv[]) {
                         continue;
 
                 r = sd_bus_process(b, &m);
-                if (r < 0)
+                if (r < 0) {
                         /* treat 'connection reset by peer' as clean exit condition */
-                        return r == -ECONNRESET ? 0 : r;
+                        if (ERRNO_IS_DISCONNECT(r))
+                                return 0;
+
+                        return log_error_errno(r, "Failed to process bus: %m");
+                }
 
                 if (m) {
                         r = sd_bus_send(a, m, NULL);
@@ -240,9 +240,10 @@ static int run(int argc, char *argv[]) {
 
                 {
                         struct pollfd p[3] = {
-                                {.fd = fd,            .events = events_a, },
-                                {.fd = STDIN_FILENO,  .events = events_b & POLLIN, },
-                                {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }};
+                                {.fd = fd,            .events = events_a           },
+                                {.fd = STDIN_FILENO,  .events = events_b & POLLIN  },
+                                {.fd = STDOUT_FILENO, .events = events_b & POLLOUT },
+                        };
 
                         r = ppoll(p, ELEMENTSOF(p), ts, NULL);
                 }
index c67d790..bb2643a 100644 (file)
@@ -7,6 +7,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 
 #include "conf-files.h"
 #include "def.h"
@@ -21,7 +23,6 @@
 #include "string-util.h"
 #include "strv.h"
 #include "sysctl-util.h"
-#include "util.h"
 
 static char **arg_prefixes = NULL;
 static bool arg_cat_config = false;
index 0fd2983..4a244ec 100644 (file)
@@ -8,6 +8,7 @@
 #include <stddef.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/mount.h>
 #include <sys/prctl.h>
 #include <sys/reboot.h>
 #include <sys/socket.h>
 #include "bus-common-errors.h"
 #include "bus-error.h"
 #include "bus-message.h"
+#include "bus-unit-procs.h"
 #include "bus-unit-util.h"
 #include "bus-util.h"
+#include "bus-wait-for-jobs.h"
 #include "cgroup-show.h"
 #include "cgroup-util.h"
 #include "copy.h"
 #include "glob-util.h"
 #include "hexdecoct.h"
 #include "hostname-util.h"
+#include "in-addr-util.h"
 #include "initreq.h"
 #include "install.h"
 #include "io-util.h"
+#include "journal-util.h"
 #include "list.h"
 #include "locale-util.h"
 #include "log.h"
 #include "logs-show.h"
 #include "macro.h"
 #include "main-func.h"
+#include "memory-util.h"
 #include "mkdir.h"
 #include "pager.h"
 #include "parse-util.h"
 #include "sigbus.h"
 #include "signal-util.h"
 #include "socket-util.h"
+#include "sort-util.h"
 #include "spawn-ask-password-agent.h"
 #include "spawn-polkit-agent.h"
 #include "special.h"
 #include "stat-util.h"
 #include "string-table.h"
 #include "strv.h"
+#include "sysv-compat.h"
 #include "terminal-util.h"
 #include "tmpfile-util.h"
 #include "unit-def.h"
 #include "unit-name.h"
 #include "user-util.h"
-#include "util.h"
+#include "utf8.h"
 #include "utmp-wtmp.h"
 #include "verbs.h"
 #include "virt.h"
 
-/* The init script exit status codes
-   0       program is running or service is OK
-   1       program is dead and /var/run pid file exists
-   2       program is dead and /var/lock lock file exists
-   3       program is not running
-   4       program or service status is unknown
-   5-99    reserved for future LSB use
-   100-149 reserved for distribution use
-   150-199 reserved for application use
-   200-254 reserved
-*/
-enum {
-        EXIT_PROGRAM_RUNNING_OR_SERVICE_OK        = 0,
-        EXIT_PROGRAM_DEAD_AND_PID_EXISTS          = 1,
-        EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS    = 2,
-        EXIT_PROGRAM_NOT_RUNNING                  = 3,
-        EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN   = 4,
-};
-
 static char **arg_types = NULL;
 static char **arg_states = NULL;
 static char **arg_properties = NULL;
@@ -125,6 +114,7 @@ static bool arg_dry_run = false;
 static bool arg_quiet = false;
 static bool arg_full = false;
 static bool arg_recursive = false;
+static bool arg_show_transaction = false;
 static int arg_force = 0;
 static bool arg_ask_password = false;
 static bool arg_runtime = false;
@@ -134,8 +124,6 @@ static const char *arg_kill_who = NULL;
 static int arg_signal = SIGTERM;
 static char *arg_root = NULL;
 static usec_t arg_when = 0;
-static char *arg_esp_path = NULL;
-static char *argv_cmdline = NULL;
 static enum action {
         ACTION_SYSTEMCTL,
         ACTION_HALT,
@@ -167,10 +155,18 @@ static unsigned arg_lines = 10;
 static OutputMode arg_output = OUTPUT_SHORT;
 static bool arg_plain = false;
 static bool arg_firmware_setup = false;
+static usec_t arg_boot_loader_menu = USEC_INFINITY;
+static const char *arg_boot_loader_entry = NULL;
 static bool arg_now = false;
 static bool arg_jobs_before = false;
 static bool arg_jobs_after = false;
 
+STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
+STATIC_DESTRUCTOR_REGISTER(arg_types, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_states, strv_freep);
+STATIC_DESTRUCTOR_REGISTER(arg_properties, strv_freep);
+
 static int daemon_reload(int argc, char *argv[], void* userdata);
 static int trivial_method(int argc, char *argv[], void *userdata);
 static int halt_now(enum action a);
@@ -733,7 +729,6 @@ static int get_unit_list_recursive(
                 *_machines = NULL;
 
         *_unit_infos = TAKE_PTR(unit_infos);
-
         *_replies = TAKE_PTR(replies);
 
         return c;
@@ -2659,10 +2654,8 @@ static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *ac
                 return log_error_errno(r, "Failed to retrieve unit state: %s", bus_error_message(&error, r));
 
         state = unit_active_state_from_string(buf);
-        if (state == _UNIT_ACTIVE_STATE_INVALID) {
-                log_error("Invalid unit state '%s' for: %s", buf, name);
-                return -EINVAL;
-        }
+        if (state < 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid unit state '%s' for: %s", buf, name);
 
         *active_state = state;
         return 0;
@@ -2748,25 +2741,26 @@ static int check_triggering_units(sd_bus *bus, const char *name) {
 }
 
 static const struct {
-        const char *verb;
-        const char *method;
+        const char *verb;      /* systemctl verb */
+        const char *method;    /* Name of the specific D-Bus method */
+        const char *job_type;  /* Job type when passing to the generic EnqueueUnitJob() method */
 } unit_actions[] = {
-        { "start",                 "StartUnit" },
-        { "stop",                  "StopUnit" },
-        { "condstop",              "StopUnit" },
-        { "reload",                "ReloadUnit" },
-        { "restart",               "RestartUnit" },
-        { "try-restart",           "TryRestartUnit" },
-        { "condrestart",           "TryRestartUnit" },
-        { "reload-or-restart",     "ReloadOrRestartUnit" },
-        { "try-reload-or-restart", "ReloadOrTryRestartUnit" },
-        { "reload-or-try-restart", "ReloadOrTryRestartUnit" },
-        { "condreload",            "ReloadOrTryRestartUnit" },
-        { "force-reload",          "ReloadOrTryRestartUnit" }
+        { "start",                 "StartUnit",              "start"                 },
+        { "stop",                  "StopUnit",               "stop"                  },
+        { "condstop",              "StopUnit",               "stop"                  }, /* legacy alias */
+        { "reload",                "ReloadUnit",             "reload"                },
+        { "restart",               "RestartUnit",            "restart"               },
+        { "try-restart",           "TryRestartUnit",         "try-restart"           },
+        { "condrestart",           "TryRestartUnit",         "try-restart"           }, /* legacy alias */
+        { "reload-or-restart",     "ReloadOrRestartUnit",    "reload-or-restart"     },
+        { "try-reload-or-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" },
+        { "reload-or-try-restart", "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
+        { "condreload",            "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
+        { "force-reload",          "ReloadOrTryRestartUnit", "reload-or-try-restart" }, /* legacy alias */
 };
 
 static const char *verb_to_method(const char *verb) {
-       uint i;
+       size_t i;
 
        for (i = 0; i < ELEMENTSOF(unit_actions); i++)
                 if (streq_ptr(unit_actions[i].verb, verb))
@@ -2775,14 +2769,14 @@ static const char *verb_to_method(const char *verb) {
        return "StartUnit";
 }
 
-static const char *method_to_verb(const char *method) {
-       uint i;
+static const char *verb_to_job_type(const char *verb) {
+       size_t i;
 
        for (i = 0; i < ELEMENTSOF(unit_actions); i++)
-                if (streq_ptr(unit_actions[i].method, method))
-                        return unit_actions[i].verb;
+                if (streq_ptr(unit_actions[i].verb, verb))
+                        return unit_actions[i].job_type;
 
-       return "n/a";
+       return "start";
 }
 
 typedef struct {
@@ -2887,9 +2881,60 @@ static int on_properties_changed(sd_bus_message *m, void *userdata, sd_bus_error
         return 0;
 }
 
+static int wait_context_watch(
+                WaitContext *wait_context,
+                sd_bus *bus,
+                const char *name) {
+
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char *unit_path = NULL;
+        int r;
+
+        assert(wait_context);
+        assert(name);
+
+        log_debug("Watching for property changes of %s", name);
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "RefUnit",
+                        &error,
+                        NULL,
+                        "s", name);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add reference to unit %s: %s", name, bus_error_message(&error, r));
+
+        unit_path = unit_dbus_path_from_name(name);
+        if (!unit_path)
+                return log_oom();
+
+        r = set_ensure_allocated(&wait_context->unit_paths, &string_hash_ops);
+        if (r < 0)
+                return log_oom();
+
+        r = set_put_strdup(wait_context->unit_paths, unit_path);
+        if (r < 0)
+                return log_error_errno(r, "Failed to add unit path %s to set: %m", unit_path);
+
+        r = sd_bus_match_signal_async(bus,
+                                      &wait_context->match,
+                                      NULL,
+                                      unit_path,
+                                      "org.freedesktop.DBus.Properties",
+                                      "PropertiesChanged",
+                                      on_properties_changed, NULL, wait_context);
+        if (r < 0)
+                return log_error_errno(r, "Failed to request match for PropertiesChanged signal: %m");
+
+        return 0;
+}
+
 static int start_unit_one(
                 sd_bus *bus,
-                const char *method,
+                const char *method,    /* When using classic per-job bus methods */
+                const char *job_type,  /* When using new-style EnqueueUnitJob() */
                 const char *name,
                 const char *mode,
                 sd_bus_error *error,
@@ -2898,6 +2943,7 @@ static int start_unit_one(
 
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
         const char *path;
+        bool done = false;
         int r;
 
         assert(method);
@@ -2906,81 +2952,88 @@ static int start_unit_one(
         assert(error);
 
         if (wait_context) {
-                _cleanup_free_ char *unit_path = NULL;
-
-                log_debug("Watching for property changes of %s", name);
-                r = sd_bus_call_method(
-                                bus,
-                                "org.freedesktop.systemd1",
-                                "/org/freedesktop/systemd1",
-                                "org.freedesktop.systemd1.Manager",
-                                "RefUnit",
-                                error,
-                                NULL,
-                                "s", name);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to RefUnit %s: %s", name, bus_error_message(error, r));
-
-                unit_path = unit_dbus_path_from_name(name);
-                if (!unit_path)
-                        return log_oom();
-
-                r = set_put_strdup(wait_context->unit_paths, unit_path);
-                if (r < 0)
-                        return log_error_errno(r, "Failed to add unit path %s to set: %m", unit_path);
-
-                r = sd_bus_match_signal_async(bus,
-                                              &wait_context->match,
-                                              NULL,
-                                              unit_path,
-                                              "org.freedesktop.DBus.Properties",
-                                              "PropertiesChanged",
-                                              on_properties_changed, NULL, wait_context);
+                r = wait_context_watch(wait_context, bus, name);
                 if (r < 0)
-                        return log_error_errno(r, "Failed to request match for PropertiesChanged signal: %m");
+                        return r;
         }
 
         log_debug("%s dbus call org.freedesktop.systemd1.Manager %s(%s, %s)",
                   arg_dry_run ? "Would execute" : "Executing",
                   method, name, mode);
+
         if (arg_dry_run)
                 return 0;
 
-        r = sd_bus_call_method(
-                        bus,
-                        "org.freedesktop.systemd1",
-                        "/org/freedesktop/systemd1",
-                        "org.freedesktop.systemd1.Manager",
-                        method,
-                        error,
-                        &reply,
-                        "ss", name, mode);
-        if (r < 0) {
-                const char *verb;
+        if (arg_show_transaction) {
+                _cleanup_(sd_bus_error_free) sd_bus_error enqueue_error = SD_BUS_ERROR_NULL;
 
-                /* There's always a fallback possible for legacy actions. */
-                if (arg_action != ACTION_SYSTEMCTL)
-                        return r;
+                /* Use the new, fancy EnqueueUnitJob() API if the user wants us to print the transaction */
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                "/org/freedesktop/systemd1",
+                                "org.freedesktop.systemd1.Manager",
+                                "EnqueueUnitJob",
+                                &enqueue_error,
+                                &reply,
+                                "sss",
+                                name, job_type, mode);
+                if (r < 0) {
+                        if (!sd_bus_error_has_name(&enqueue_error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+                                (void) sd_bus_error_move(error, &enqueue_error);
+                                goto fail;
+                        }
+
+                        /* Hmm, the API is not yet available. Let's use the classic API instead (see below). */
+                        log_notice("--show-transaction not supported by this service manager, proceeding without.");
+                } else {
+                        const char *u, *jt;
+                        uint32_t id;
 
-                verb = method_to_verb(method);
+                        r = sd_bus_message_read(reply, "uosos", &id, &path, &u, NULL, &jt);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
 
-                log_error("Failed to %s %s: %s", verb, name, bus_error_message(error, r));
+                        log_info("Enqueued anchor job %" PRIu32 " %s/%s.", id, u, jt);
 
-                if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
-                    !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
-                    !sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
-                        log_error("See %s logs and 'systemctl%s status%s %s' for details.",
-                                   arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
-                                   arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
-                                   name[0] == '-' ? " --" : "",
-                                   name);
+                        r = sd_bus_message_enter_container(reply, 'a', "(uosos)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+                        for (;;) {
+                                r = sd_bus_message_read(reply, "(uosos)", &id, NULL, &u, NULL, &jt);
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+                                if (r == 0)
+                                        break;
 
-                return r;
+                                log_info("Enqueued auxiliary job %" PRIu32 " %s/%s.", id, u, jt);
+                        }
+
+                        r = sd_bus_message_exit_container(reply);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        done = true;
+                }
         }
 
-        r = sd_bus_message_read(reply, "o", &path);
-        if (r < 0)
-                return bus_log_parse_error(r);
+        if (!done) {
+                r = sd_bus_call_method(
+                                bus,
+                                "org.freedesktop.systemd1",
+                                "/org/freedesktop/systemd1",
+                                "org.freedesktop.systemd1.Manager",
+                                method,
+                                error,
+                                &reply,
+                                "ss", name, mode);
+                if (r < 0)
+                        goto fail;
+
+                r = sd_bus_message_read(reply, "o", &path);
+                if (r < 0)
+                        return bus_log_parse_error(r);
+        }
 
         if (need_daemon_reload(bus, name) > 0)
                 warn_unit_file_changed(name);
@@ -2989,10 +3042,28 @@ static int start_unit_one(
                 log_debug("Adding %s to the set", path);
                 r = bus_wait_for_jobs_add(w, path);
                 if (r < 0)
-                        return log_oom();
+                        return log_error_errno(r, "Failed to watch job for %s: %m", name);
         }
 
         return 0;
+
+fail:
+        /* There's always a fallback possible for legacy actions. */
+        if (arg_action != ACTION_SYSTEMCTL)
+                return r;
+
+        log_error_errno(r, "Failed to %s %s: %s", job_type, name, bus_error_message(error, r));
+
+        if (!sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) &&
+            !sd_bus_error_has_name(error, BUS_ERROR_UNIT_MASKED) &&
+            !sd_bus_error_has_name(error, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE))
+                log_error("See %s logs and 'systemctl%s status%s %s' for details.",
+                          arg_scope == UNIT_FILE_SYSTEM ? "system" : "user",
+                          arg_scope == UNIT_FILE_SYSTEM ? "" : " --user",
+                          name[0] == '-' ? " --" : "",
+                          name);
+
+        return r;
 }
 
 static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***ret) {
@@ -3049,7 +3120,6 @@ static int expand_names(sd_bus *bus, char **names, const char* suffix, char ***r
         }
 
         *ret = TAKE_PTR(mangled);
-
         return 0;
 }
 
@@ -3058,21 +3128,21 @@ static const struct {
         const char *verb;
         const char *mode;
 } action_table[_ACTION_MAX] = {
-        [ACTION_HALT]                 = { SPECIAL_HALT_TARGET,                     "halt",                   "replace-irreversibly" },
-        [ACTION_POWEROFF]             = { SPECIAL_POWEROFF_TARGET,                 "poweroff",               "replace-irreversibly" },
-        [ACTION_REBOOT]               = { SPECIAL_REBOOT_TARGET,                   "reboot",                 "replace-irreversibly" },
-        [ACTION_KEXEC]                = { SPECIAL_KEXEC_TARGET,                    "kexec",                  "replace-irreversibly" },
-        [ACTION_RUNLEVEL2]            = { SPECIAL_MULTI_USER_TARGET,               NULL,                     "isolate" },
-        [ACTION_RUNLEVEL3]            = { SPECIAL_MULTI_USER_TARGET,               NULL,                     "isolate" },
-        [ACTION_RUNLEVEL4]            = { SPECIAL_MULTI_USER_TARGET,               NULL,                     "isolate" },
-        [ACTION_RUNLEVEL5]            = { SPECIAL_GRAPHICAL_TARGET,                NULL,                     "isolate" },
-        [ACTION_RESCUE]               = { SPECIAL_RESCUE_TARGET,                   "rescue",                 "isolate" },
-        [ACTION_EMERGENCY]            = { SPECIAL_EMERGENCY_TARGET,                "emergency",              "isolate" },
-        [ACTION_DEFAULT]              = { SPECIAL_DEFAULT_TARGET,                  "default",                "isolate" },
-        [ACTION_EXIT]                 = { SPECIAL_EXIT_TARGET,                     "exit",                   "replace-irreversibly" },
-        [ACTION_SUSPEND]              = { SPECIAL_SUSPEND_TARGET,                  "suspend",                "replace-irreversibly" },
-        [ACTION_HIBERNATE]            = { SPECIAL_HIBERNATE_TARGET,                "hibernate",              "replace-irreversibly" },
-        [ACTION_HYBRID_SLEEP]         = { SPECIAL_HYBRID_SLEEP_TARGET,             "hybrid-sleep",           "replace-irreversibly" },
+        [ACTION_HALT]                   = { SPECIAL_HALT_TARGET,                   "halt",                   "replace-irreversibly" },
+        [ACTION_POWEROFF]               = { SPECIAL_POWEROFF_TARGET,               "poweroff",               "replace-irreversibly" },
+        [ACTION_REBOOT]                 = { SPECIAL_REBOOT_TARGET,                 "reboot",                 "replace-irreversibly" },
+        [ACTION_KEXEC]                  = { SPECIAL_KEXEC_TARGET,                  "kexec",                  "replace-irreversibly" },
+        [ACTION_RUNLEVEL2]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
+        [ACTION_RUNLEVEL3]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
+        [ACTION_RUNLEVEL4]              = { SPECIAL_MULTI_USER_TARGET,             NULL,                     "isolate"              },
+        [ACTION_RUNLEVEL5]              = { SPECIAL_GRAPHICAL_TARGET,              NULL,                     "isolate"              },
+        [ACTION_RESCUE]                 = { SPECIAL_RESCUE_TARGET,                 "rescue",                 "isolate"              },
+        [ACTION_EMERGENCY]              = { SPECIAL_EMERGENCY_TARGET,              "emergency",              "isolate"              },
+        [ACTION_DEFAULT]                = { SPECIAL_DEFAULT_TARGET,                "default",                "isolate"              },
+        [ACTION_EXIT]                   = { SPECIAL_EXIT_TARGET,                   "exit",                   "replace-irreversibly" },
+        [ACTION_SUSPEND]                = { SPECIAL_SUSPEND_TARGET,                "suspend",                "replace-irreversibly" },
+        [ACTION_HIBERNATE]              = { SPECIAL_HIBERNATE_TARGET,              "hibernate",              "replace-irreversibly" },
+        [ACTION_HYBRID_SLEEP]           = { SPECIAL_HYBRID_SLEEP_TARGET,           "hybrid-sleep",           "replace-irreversibly" },
         [ACTION_SUSPEND_THEN_HIBERNATE] = { SPECIAL_SUSPEND_THEN_HIBERNATE_TARGET, "suspend-then-hibernate", "replace-irreversibly" },
 };
 
@@ -3086,20 +3156,38 @@ static enum action verb_to_action(const char *verb) {
         return _ACTION_INVALID;
 }
 
+static const char** make_extra_args(const char *extra_args[static 4]) {
+        size_t n = 0;
+
+        if (arg_scope != UNIT_FILE_SYSTEM)
+                extra_args[n++] = "--user";
+
+        if (arg_transport == BUS_TRANSPORT_REMOTE) {
+                extra_args[n++] = "-H";
+                extra_args[n++] = arg_host;
+        } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
+                extra_args[n++] = "-M";
+                extra_args[n++] = arg_host;
+        } else
+                assert(arg_transport == BUS_TRANSPORT_LOCAL);
+
+        extra_args[n] = NULL;
+        return extra_args;
+}
+
 static int start_unit(int argc, char *argv[], void *userdata) {
         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
         _cleanup_(wait_context_free) WaitContext wait_context = {};
-        const char *method, *mode, *one_name, *suffix = NULL;
+        const char *method, *job_type, *mode, *one_name, *suffix = NULL;
         _cleanup_free_ char **stopped_units = NULL; /* Do not use _cleanup_strv_free_ */
         _cleanup_strv_free_ char **names = NULL;
         int r, ret = EXIT_SUCCESS;
         sd_bus *bus;
         char **name;
 
-        if (arg_wait && !STR_IN_SET(argv[0], "start", "restart")) {
-                log_error("--wait may only be used with the 'start' or 'restart' commands.");
-                return -EINVAL;
-        }
+        if (arg_wait && !STR_IN_SET(argv[0], "start", "restart"))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "--wait may only be used with the 'start' or 'restart' commands.");
 
         /* we cannot do sender tracking on the private bus, so we need the full
          * one for RefUnit to implement --wait */
@@ -3116,27 +3204,34 @@ static int start_unit(int argc, char *argv[], void *userdata) {
                 action = verb_to_action(argv[0]);
 
                 if (action != _ACTION_INVALID) {
+                        /* A command in style "systemctl reboot", "systemctl poweroff", … */
                         method = "StartUnit";
+                        job_type = "start";
                         mode = action_table[action].mode;
                         one_name = action_table[action].target;
                 } else {
                         if (streq(argv[0], "isolate")) {
+                                /* A "systemctl isolate <unit1> <unit2> …" command */
                                 method = "StartUnit";
+                                job_type = "start";
                                 mode = "isolate";
-
                                 suffix = ".target";
                         } else {
+                                /* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */
                                 method = verb_to_method(argv[0]);
+                                job_type = verb_to_job_type(argv[0]);
                                 mode = arg_job_mode;
                         }
                         one_name = NULL;
                 }
         } else {
+                /* A SysV legacy command such as "halt", "reboot", "poweroff", … */
                 assert(arg_action >= 0 && arg_action < _ACTION_MAX);
                 assert(action_table[arg_action].target);
                 assert(action_table[arg_action].mode);
 
                 method = "StartUnit";
+                job_type = "start";
                 mode = action_table[arg_action].mode;
                 one_name = action_table[arg_action].target;
         }
@@ -3158,10 +3253,6 @@ static int start_unit(int argc, char *argv[], void *userdata) {
         }
 
         if (arg_wait) {
-                wait_context.unit_paths = set_new(&string_hash_ops);
-                if (!wait_context.unit_paths)
-                        return log_oom();
-
                 r = sd_bus_call_method_async(
                                 bus,
                                 NULL,
@@ -3173,9 +3264,11 @@ static int start_unit(int argc, char *argv[], void *userdata) {
                                 NULL);
                 if (r < 0)
                         return log_error_errno(r, "Failed to enable subscription: %m");
+
                 r = sd_event_default(&wait_context.event);
                 if (r < 0)
                         return log_error_errno(r, "Failed to allocate event loop: %m");
+
                 r = sd_bus_attach_event(bus, wait_context.event, 0);
                 if (r < 0)
                         return log_error_errno(r, "Failed to attach bus to event loop: %m");
@@ -3184,7 +3277,7 @@ static int start_unit(int argc, char *argv[], void *userdata) {
         STRV_FOREACH(name, names) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
 
-                r = start_unit_one(bus, method, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
+                r = start_unit_one(bus, method, job_type, *name, mode, &error, w, arg_wait ? &wait_context : NULL);
                 if (ret == EXIT_SUCCESS && r < 0)
                         ret = translate_bus_error_to_exit_status(r, &error);
 
@@ -3196,22 +3289,9 @@ static int start_unit(int argc, char *argv[], void *userdata) {
         }
 
         if (!arg_no_block) {
-                const char* extra_args[4] = {};
-                int arg_count = 0;
-
-                if (arg_scope != UNIT_FILE_SYSTEM)
-                        extra_args[arg_count++] = "--user";
-
-                assert(IN_SET(arg_transport, BUS_TRANSPORT_LOCAL, BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE));
-                if (arg_transport == BUS_TRANSPORT_REMOTE) {
-                        extra_args[arg_count++] = "-H";
-                        extra_args[arg_count++] = arg_host;
-                } else if (arg_transport == BUS_TRANSPORT_MACHINE) {
-                        extra_args[arg_count++] = "-M";
-                        extra_args[arg_count++] = arg_host;
-                }
+                const char* extra_args[4];
 
-                r = bus_wait_for_jobs(w, arg_quiet, extra_args);
+                r = bus_wait_for_jobs(w, arg_quiet, make_extra_args(extra_args));
                 if (r < 0)
                         return r;
 
@@ -3270,64 +3350,38 @@ static int logind_set_wall_message(void) {
 }
 #endif
 
-/* Ask systemd-logind, which might grant access to unprivileged users
- * through polkit */
+/* Ask systemd-logind, which might grant access to unprivileged users through polkit */
 static int logind_reboot(enum action a) {
 #if ENABLE_LOGIND
+        static const struct {
+                const char *method;
+                const char *description;
+        } actions[_ACTION_MAX] = {
+                [ACTION_POWEROFF]               = { "PowerOff",             "power off system"                },
+                [ACTION_REBOOT]                 = { "Reboot",               "reboot system"                   },
+                [ACTION_HALT]                   = { "Halt",                 "halt system"                     },
+                [ACTION_SUSPEND]                = { "Suspend",              "suspend system"                  },
+                [ACTION_HIBERNATE]              = { "Hibernate",            "hibernate system"                },
+                [ACTION_HYBRID_SLEEP]           = { "HybridSleep",          "put system into hybrid sleep"    },
+                [ACTION_SUSPEND_THEN_HIBERNATE] = { "SuspendThenHibernate", "suspend system, hibernate later" },
+        };
+
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-        const char *method, *description;
         sd_bus *bus;
         int r;
 
+        if (a < 0 || a >= _ACTION_MAX || !actions[a].method)
+                return -EINVAL;
+
         r = acquire_bus(BUS_FULL, &bus);
         if (r < 0)
                 return r;
 
-        switch (a) {
-
-        case ACTION_POWEROFF:
-                method = "PowerOff";
-                description = "power off system";
-                break;
-
-        case ACTION_REBOOT:
-                method = "Reboot";
-                description = "reboot system";
-                break;
-
-        case ACTION_HALT:
-                method = "Halt";
-                description = "halt system";
-                break;
-
-        case ACTION_SUSPEND:
-                method = "Suspend";
-                description = "suspend system";
-                break;
-
-        case ACTION_HIBERNATE:
-                method = "Hibernate";
-                description = "hibernate system";
-                break;
-
-        case ACTION_HYBRID_SLEEP:
-                method = "HybridSleep";
-                description = "put system into hybrid sleep";
-                break;
-
-        case ACTION_SUSPEND_THEN_HIBERNATE:
-                method = "SuspendThenHibernate";
-                description = "put system into suspend followed by hibernate";
-                break;
-
-        default:
-                return -EINVAL;
-        }
-
         polkit_agent_open_maybe();
         (void) logind_set_wall_message();
 
-        log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", method);
+        log_debug("%s org.freedesktop.login1.Manager %s dbus call.", arg_dry_run ? "Would execute" : "Executing", actions[a].method);
+
         if (arg_dry_run)
                 return 0;
 
@@ -3336,12 +3390,12 @@ static int logind_reboot(enum action a) {
                         "org.freedesktop.login1",
                         "/org/freedesktop/login1",
                         "org.freedesktop.login1.Manager",
-                        method,
+                        actions[a].method,
                         &error,
                         NULL,
                         "b", arg_ask_password);
         if (r < 0)
-                return log_error_errno(r, "Failed to %s via logind: %s", description, bus_error_message(&error, r));
+                return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r));
 
         return 0;
 #else
@@ -3407,10 +3461,8 @@ static int logind_check_inhibitors(enum action a) {
                 if (!sv)
                         return log_oom();
 
-                if (!pid_is_valid((pid_t) pid)) {
-                        log_error("Invalid PID "PID_FMT".", (pid_t) pid);
-                        return -ERANGE;
-                }
+                if (!pid_is_valid((pid_t) pid))
+                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Invalid PID "PID_FMT".", (pid_t) pid);
 
                 if (!strv_contains(sv,
                                    IN_SET(a,
@@ -3470,7 +3522,11 @@ static int logind_check_inhibitors(enum action a) {
 #endif
 }
 
-static int logind_prepare_firmware_setup(void) {
+static int prepare_firmware_setup(void) {
+
+        if (!arg_firmware_setup)
+                return 0;
+
 #if ENABLE_LOGIND
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         sd_bus *bus;
@@ -3494,32 +3550,80 @@ static int logind_prepare_firmware_setup(void) {
 
         return 0;
 #else
-        log_error("Cannot remotely indicate to EFI to boot into setup mode.");
-        return -ENOSYS;
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Booting into firmware setup not supported.");
 #endif
 }
 
-static int prepare_firmware_setup(void) {
+static int prepare_boot_loader_menu(void) {
+
+        if (arg_boot_loader_menu == USEC_INFINITY)
+                return 0;
+
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus;
         int r;
 
-        if (!arg_firmware_setup)
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "SetRebootToBootLoaderMenu",
+                        &error,
+                        NULL,
+                        "t", arg_boot_loader_menu);
+        if (r < 0)
+                return log_error_errno(r, "Cannot indicate to boot loader to enter boot loader entry menu: %s", bus_error_message(&error, r));
+
+        return 0;
+#else
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Booting into boot loader menu not supported.");
+#endif
+}
+
+static int prepare_boot_loader_entry(void) {
+
+        if (!arg_boot_loader_entry)
                 return 0;
 
-        if (arg_transport == BUS_TRANSPORT_LOCAL) {
+#if ENABLE_LOGIND
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        sd_bus *bus;
+        int r;
 
-                r = efi_set_reboot_to_firmware(true);
-                if (r < 0)
-                        log_debug_errno(r, "Cannot indicate to EFI to boot into setup mode, will retry via logind: %m");
-                else
-                        return r;
-        }
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_call_method(
+                        bus,
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "SetRebootToBootLoaderEntry",
+                        &error,
+                        NULL,
+                        "s", arg_boot_loader_entry);
+        if (r < 0)
+                return log_error_errno(r, "Cannot set boot into loader entry '%s': %s", arg_boot_loader_entry, bus_error_message(&error, r));
 
-        return logind_prepare_firmware_setup();
+        return 0;
+#else
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Booting into boot loader entry not supported.");
+#endif
 }
 
 static int load_kexec_kernel(void) {
         _cleanup_(boot_config_free) BootConfig config = {};
-        _cleanup_free_ char *where = NULL, *kernel = NULL, *initrd = NULL, *options = NULL;
+        _cleanup_free_ char *kernel = NULL, *initrd = NULL, *options = NULL;
         const BootEntry *e;
         pid_t pid;
         int r;
@@ -3532,21 +3636,36 @@ static int load_kexec_kernel(void) {
         if (access(KEXEC, X_OK) < 0)
                 return log_error_errno(errno, KEXEC" is not available: %m");
 
-        r = find_default_boot_entry(arg_esp_path, &where, &config, &e);
-        if (r == -ENOKEY) /* find_default_boot_entry() doesn't warn about this case */
+        r = boot_entries_load_config_auto(NULL, NULL, &config);
+        if (r == -ENOKEY) /* The call doesn't log about ENOKEY, let's do so here. */
                 return log_error_errno(r, "Cannot find the ESP partition mount point.");
         if (r < 0)
-                /* But it logs about all these cases, hence don't log here again */
                 return r;
 
-        if (strv_length(e->initrd) > 1) {
-                log_error("Boot entry specifies multiple initrds, which is not supported currently.");
-                return -EINVAL;
+        e = boot_config_default_entry(&config);
+        if (!e)
+                return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
+                                       "No boot loader entry suitable as default, refusing to guess.");
+
+        log_debug("Found default boot loader entry in file \"%s\"", e->path);
+
+        if (!e->kernel)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "Boot entry does not refer to Linux kernel, which is not supported currently.");
+        if (strv_length(e->initrd) > 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+                                       "Boot entry specifies multiple initrds, which is not supported currently.");
+
+        kernel = path_join(e->root, e->kernel);
+        if (!kernel)
+                return log_oom();
+
+        if (!strv_isempty(e->initrd)) {
+                initrd = path_join(e->root, e->initrd[0]);
+                if (!initrd)
+                        return log_oom();
         }
 
-        kernel = path_join(where, e->kernel);
-        if (!strv_isempty(e->initrd))
-                initrd = path_join(where, *e->initrd);
         options = strv_join(e->options, " ");
         if (!options)
                 return log_oom();
@@ -3560,7 +3679,7 @@ static int load_kexec_kernel(void) {
         if (arg_dry_run)
                 return 0;
 
-        r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
+        r = safe_fork("(kexec)", FORK_WAIT|FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -3569,19 +3688,14 @@ static int load_kexec_kernel(void) {
                         "--load", kernel,
                         "--append", options,
                         initrd ? "--initrd" : NULL, initrd,
-                        NULL };
+                        NULL
+                };
 
                 /* Child */
                 execv(args[0], (char * const *) args);
                 _exit(EXIT_FAILURE);
         }
 
-        r = wait_for_terminate_and_check("kexec", pid, WAIT_LOG);
-        if (r < 0)
-                return r;
-        if (r > 0)
-                /* Command failed */
-                return -EPROTO;
         return 0;
 }
 
@@ -3633,8 +3747,16 @@ static int start_special(int argc, char *argv[], void *userdata) {
         if (r < 0)
                 return r;
 
+        r = prepare_boot_loader_menu();
+        if (r < 0)
+                return r;
+
+        r = prepare_boot_loader_entry();
+        if (r < 0)
+                return r;
+
         if (a == ACTION_REBOOT && argc > 1) {
-                r = update_reboot_parameter_and_warn(argv[1]);
+                r = update_reboot_parameter_and_warn(argv[1], false);
                 if (r < 0)
                         return r;
 
@@ -4553,21 +4675,23 @@ static int map_conditions(sd_bus *bus, const char *member, sd_bus_message *m, sd
         while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
                 _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
 
-                c = new0(UnitCondition, 1);
+                c = new(UnitCondition, 1);
                 if (!c)
                         return -ENOMEM;
 
-                c->name = strdup(cond);
-                c->param = strdup(param);
+                *c = (UnitCondition) {
+                        .name = strdup(cond),
+                        .param = strdup(param),
+                        .trigger = trigger,
+                        .negate = negate,
+                        .tristate = state,
+                };
+
                 if (!c->name || !c->param)
                         return -ENOMEM;
 
-                c->trigger = trigger;
-                c->negate = negate;
-                c->tristate = state;
 
-                LIST_PREPEND(conditions, i->conditions, c);
-                c = NULL;
+                LIST_PREPEND(conditions, i->conditions, TAKE_PTR(c));
         }
         if (r < 0)
                 return r;
@@ -4664,6 +4788,23 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
 
         switch (bus_type) {
 
+        case SD_BUS_TYPE_INT32:
+                if (endswith(name, "ActionExitStatus")) {
+                        int32_t i;
+
+                        r = sd_bus_message_read_basic(m, bus_type, &i);
+                        if (r < 0)
+                                return r;
+
+                        if (i >= 0 && i <= 255)
+                                bus_print_property_valuef(name, expected_value, value, "%"PRIi32, i);
+                        else if (all)
+                                bus_print_property_value(name, expected_value, value, "[not set]");
+
+                        return 1;
+                }
+                break;
+
         case SD_BUS_TYPE_STRUCT:
 
                 if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
@@ -4674,9 +4815,9 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                 return bus_log_parse_error(r);
 
                         if (u > 0)
-                                bus_print_property_value(name, expected_value, value, "%"PRIu32, u);
+                                bus_print_property_valuef(name, expected_value, value, "%"PRIu32, u);
                         else if (all)
-                                bus_print_property_value(name, expected_value, value, "%s", "");
+                                bus_print_property_value(name, expected_value, value, "");
 
                         return 1;
 
@@ -4688,7 +4829,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                 return bus_log_parse_error(r);
 
                         if (all || !isempty(s))
-                                bus_print_property_value(name, expected_value, value, "%s", s);
+                                bus_print_property_value(name, expected_value, value, s);
 
                         return 1;
 
@@ -4699,11 +4840,14 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
-                        if (all || !isempty(a) || !isempty(b))
-                                bus_print_property_value(name, expected_value, value, "%s \"%s\"", strempty(a), strempty(b));
+                        if (!isempty(a) || !isempty(b))
+                                bus_print_property_valuef(name, expected_value, value, "%s \"%s\"", strempty(a), strempty(b));
+                        else if (all)
+                                bus_print_property_value(name, expected_value, value, "");
 
                         return 1;
-                } else if (streq_ptr(name, "SystemCallFilter")) {
+
+                } else if (STR_IN_SET(name, "SystemCallFilter", "RestrictAddressFamilies")) {
                         _cleanup_strv_free_ char **l = NULL;
                         int whitelist;
 
@@ -4747,22 +4891,99 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                         }
 
                         return 1;
-                }
-
-                break;
-
-        case SD_BUS_TYPE_ARRAY:
 
-                if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
-                        const char *path;
+                } else if (STR_IN_SET(name, "SELinuxContext", "AppArmorProfile", "SmackProcessLabel")) {
                         int ignore;
+                        const char *s;
 
-                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
+                        r = sd_bus_message_read(m, "(bs)", &ignore, &s);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
-                        while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
-                                bus_print_property_value(name, expected_value, value, "%s (ignore_errors=%s)", path, yes_no(ignore));
+                        if (!isempty(s))
+                                bus_print_property_valuef(name, expected_value, value, "%s%s", ignore ? "-" : "", s);
+                        else if (all)
+                                bus_print_property_value(name, expected_value, value, "");
+
+                        return 1;
+
+                } else if (endswith(name, "ExitStatus") && streq(contents, "aiai")) {
+                        const int32_t *status, *signal;
+                        size_t sz_status, sz_signal, i;
+
+                        r = sd_bus_message_enter_container(m, 'r', "aiai");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read_array(m, 'i', (const void **) &status, &sz_status);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_read_array(m, 'i', (const void **) &signal, &sz_signal);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        sz_status /= sizeof(int32_t);
+                        sz_signal /= sizeof(int32_t);
+
+                        if (all || sz_status > 0 || sz_signal > 0) {
+                                bool first = true;
+
+                                if (!value) {
+                                        fputs(name, stdout);
+                                        fputc('=', stdout);
+                                }
+
+                                for (i = 0; i < sz_status; i++) {
+                                        if (status[i] < 0 || status[i] > 255)
+                                                continue;
+
+                                        if (first)
+                                                first = false;
+                                        else
+                                                fputc(' ', stdout);
+
+                                        printf("%"PRIi32, status[i]);
+                                }
+
+                                for (i = 0; i < sz_signal; i++) {
+                                        const char *str;
+
+                                        str = signal_to_string((int) signal[i]);
+                                        if (!str)
+                                                continue;
+
+                                        if (first)
+                                                first = false;
+                                        else
+                                                fputc(' ', stdout);
+
+                                        fputs(str, stdout);
+                                }
+
+                                fputc('\n', stdout);
+                        }
+                        return 1;
+                }
+
+                break;
+
+        case SD_BUS_TYPE_ARRAY:
+
+                if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
+                        const char *path;
+                        int ignore;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
+                                bus_print_property_valuef(name, expected_value, value, "%s (ignore_errors=%s)", path, yes_no(ignore));
 
                         if (r < 0)
                                 return bus_log_parse_error(r);
@@ -4781,7 +5002,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
-                                bus_print_property_value(name, expected_value, value, "%s (%s)", path, type);
+                                bus_print_property_valuef(name, expected_value, value, "%s (%s)", path, type);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4799,7 +5020,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
-                                bus_print_property_value(name, expected_value, value, "%s (%s)", path, type);
+                                bus_print_property_valuef(name, expected_value, value, "%s (%s)", path, type);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4820,9 +5041,9 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                         while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0) {
                                 char timespan1[FORMAT_TIMESPAN_MAX], timespan2[FORMAT_TIMESPAN_MAX];
 
-                                bus_print_property_value(name, expected_value, value, "{ %s=%s ; next_elapse=%s }", base,
-                                                         format_timespan(timespan1, sizeof(timespan1), v, 0),
-                                                         format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
+                                bus_print_property_valuef(name, expected_value, value, "{ %s=%s ; next_elapse=%s }", base,
+                                                          format_timespan(timespan1, sizeof(timespan1), v, 0),
+                                                          format_timespan(timespan2, sizeof(timespan2), next_elapse, 0));
                         }
                         if (r < 0)
                                 return bus_log_parse_error(r);
@@ -4844,8 +5065,8 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                         while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0) {
                                 char timestamp[FORMAT_TIMESTAMP_MAX];
 
-                                bus_print_property_value(name, expected_value, value, "{ %s=%s ; next_elapse=%s }", base, spec,
-                                                         format_timestamp(timestamp, sizeof(timestamp), next_elapse));
+                                bus_print_property_valuef(name, expected_value, value, "{ %s=%s ; next_elapse=%s }", base, spec,
+                                                          format_timestamp(timestamp, sizeof(timestamp), next_elapse));
                         }
                         if (r < 0)
                                 return bus_log_parse_error(r);
@@ -4869,18 +5090,18 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
 
                                 tt = strv_join(info.argv, " ");
 
-                                 bus_print_property_value(name, expected_value, value,
-                                                          "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
-                                                          strna(info.path),
-                                                          strna(tt),
-                                                          yes_no(info.ignore),
-                                                          strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
-                                                          strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
-                                                          info.pid,
-                                                          sigchld_code_to_string(info.code),
-                                                          info.status,
-                                                          info.code == CLD_EXITED ? "" : "/",
-                                                          strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
+                                 bus_print_property_valuef(name, expected_value, value,
+                                                           "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
+                                                           strna(info.path),
+                                                           strna(tt),
+                                                           yes_no(info.ignore),
+                                                           strna(format_timestamp(timestamp1, sizeof(timestamp1), info.start_timestamp)),
+                                                           strna(format_timestamp(timestamp2, sizeof(timestamp2), info.exit_timestamp)),
+                                                           info.pid,
+                                                           sigchld_code_to_string(info.code),
+                                                           info.status,
+                                                           info.code == CLD_EXITED ? "" : "/",
+                                                           strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
 
                                 free(info.path);
                                 strv_free(info.argv);
@@ -4901,7 +5122,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
-                                bus_print_property_value(name, expected_value, value, "%s %s", strna(path), strna(rwm));
+                                bus_print_property_valuef(name, expected_value, value, "%s %s", strna(path), strna(rwm));
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4921,7 +5142,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
-                                bus_print_property_value(name, expected_value, value, "%s %"PRIu64, strna(path), weight);
+                                bus_print_property_valuef(name, expected_value, value, "%s %"PRIu64, strna(path), weight);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4942,7 +5163,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
-                                bus_print_property_value(name, expected_value, value, "%s %"PRIu64, strna(path), bandwidth);
+                                bus_print_property_valuef(name, expected_value, value, "%s %"PRIu64, strna(path), bandwidth);
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4963,8 +5184,8 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                                 return bus_log_parse_error(r);
 
                         while ((r = sd_bus_message_read(m, "(st)", &path, &target)) > 0)
-                                bus_print_property_value(name, expected_value, value, "%s %s", strna(path),
-                                                         format_timespan(ts, sizeof(ts), target, 1));
+                                bus_print_property_valuef(name, expected_value, value, "%s %s", strna(path),
+                                                          format_timespan(ts, sizeof(ts), target, 1));
                         if (r < 0)
                                 return bus_log_parse_error(r);
 
@@ -4988,7 +5209,187 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m
                         if (n < 0)
                                 return log_oom();
 
-                        bus_print_property_value(name, expected_value, value, "%s", h);
+                        bus_print_property_value(name, expected_value, value, h);
+
+                        return 1;
+
+                } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
+                        _cleanup_free_ char *addresses = NULL;
+
+                        r = sd_bus_message_enter_container(m, 'a', "(iayu)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        for (;;) {
+                                _cleanup_free_ char *str = NULL;
+                                uint32_t prefixlen;
+                                int32_t family;
+                                const void *ap;
+                                size_t an;
+
+                                r = sd_bus_message_enter_container(m, 'r', "iayu");
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+                                if (r == 0)
+                                        break;
+
+                                r = sd_bus_message_read(m, "i", &family);
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+
+                                r = sd_bus_message_read_array(m, 'y', &ap, &an);
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+
+                                r = sd_bus_message_read(m, "u", &prefixlen);
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+
+                                r = sd_bus_message_exit_container(m);
+                                if (r < 0)
+                                        return bus_log_parse_error(r);
+
+                                if (!IN_SET(family, AF_INET, AF_INET6))
+                                        continue;
+
+                                if (an != FAMILY_ADDRESS_SIZE(family))
+                                        continue;
+
+                                if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
+                                        continue;
+
+                                if (in_addr_prefix_to_string(family, (union in_addr_union *) ap, prefixlen, &str) < 0)
+                                        continue;
+
+                                if (!strextend_with_separator(&addresses, " ", str, NULL))
+                                        return log_oom();
+                        }
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (all || !isempty(addresses))
+                                bus_print_property_value(name, expected_value, value, strempty(addresses));
+
+                        return 1;
+
+                } else if (STR_IN_SET(name, "BindPaths", "BindReadOnlyPaths")) {
+                        _cleanup_free_ char *paths = NULL;
+                        const char *source, *dest;
+                        int ignore_enoent;
+                        uint64_t rbind;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssbt)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(ssbt)", &source, &dest, &ignore_enoent, &rbind)) > 0) {
+                                _cleanup_free_ char *str = NULL;
+
+                                if (isempty(source))
+                                        continue;
+
+                                if (asprintf(&str, "%s%s%s%s%s",
+                                             ignore_enoent ? "-" : "",
+                                             source,
+                                             isempty(dest) ? "" : ":",
+                                             strempty(dest),
+                                             rbind == MS_REC ? ":rbind" : "") < 0)
+                                        return log_oom();
+
+                                if (!strextend_with_separator(&paths, " ", str, NULL))
+                                        return log_oom();
+                        }
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (all || !isempty(paths))
+                                bus_print_property_value(name, expected_value, value, strempty(paths));
+
+                        return 1;
+
+                } else if (streq(name, "TemporaryFileSystem")) {
+                        _cleanup_free_ char *paths = NULL;
+                        const char *target, *option;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read(m, "(ss)", &target, &option)) > 0) {
+                                _cleanup_free_ char *str = NULL;
+
+                                if (isempty(target))
+                                        continue;
+
+                                if (asprintf(&str, "%s%s%s", target, isempty(option) ? "" : ":", strempty(option)) < 0)
+                                        return log_oom();
+
+                                if (!strextend_with_separator(&paths, " ", str, NULL))
+                                        return log_oom();
+                        }
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (all || !isempty(paths))
+                                bus_print_property_value(name, expected_value, value, strempty(paths));
+
+                        return 1;
+
+                } else if (streq(name, "LogExtraFields")) {
+                        _cleanup_free_ char *fields = NULL;
+                        const void *p;
+                        size_t sz;
+
+                        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "ay");
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        while ((r = sd_bus_message_read_array(m, 'y', &p, &sz)) > 0) {
+                                _cleanup_free_ char *str = NULL;
+                                const char *eq;
+
+                                if (memchr(p, 0, sz))
+                                        continue;
+
+                                eq = memchr(p, '=', sz);
+                                if (!eq)
+                                        continue;
+
+                                if (!journal_field_valid(p, eq - (const char*) p, false))
+                                        continue;
+
+                                str = malloc(sz + 1);
+                                if (!str)
+                                        return log_oom();
+
+                                memcpy(str, p, sz);
+                                str[sz] = '\0';
+
+                                if (!utf8_is_valid(str))
+                                        continue;
+
+                                if (!strextend_with_separator(&fields, " ", str, NULL))
+                                        return log_oom();
+                        }
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        r = sd_bus_message_exit_container(m);
+                        if (r < 0)
+                                return bus_log_parse_error(r);
+
+                        if (all || !isempty(fields))
+                                bus_print_property_value(name, expected_value, value, strempty(fields));
 
                         return 1;
                 }
@@ -5424,10 +5825,8 @@ static int cat(int argc, char *argv[], void *userdata) {
         bool first = true;
         int r;
 
-        if (arg_transport != BUS_TRANSPORT_LOCAL) {
-                log_error("Cannot remotely cat units.");
-                return -EINVAL;
-        }
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot remotely cat units.");
 
         r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
         if (r < 0)
@@ -5523,10 +5922,8 @@ static int set_property(int argc, char *argv[], void *userdata) {
                 return log_error_errno(r, "Failed to mangle unit name: %m");
 
         t = unit_name_to_type(n);
-        if (t < 0) {
-                log_error("Invalid unit type: %s", n);
-                return -EINVAL;
-        }
+        if (t < 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid unit type: %s", n);
 
         r = sd_bus_message_append(m, "sb", n, arg_runtime);
         if (r < 0)
@@ -5764,15 +6161,11 @@ static int switch_root(int argc, char *argv[], void *userdata) {
         sd_bus *bus;
         int r;
 
-        if (arg_transport != BUS_TRANSPORT_LOCAL) {
-                log_error("Cannot switch root remotely.");
-                return -EINVAL;
-        }
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot switch root remotely.");
 
-        if (argc < 2 || argc > 3) {
-                log_error("Wrong number of arguments.");
-                return -EINVAL;
-        }
+        if (argc < 2 || argc > 3)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Wrong number of arguments.");
 
         root = argv[1];
 
@@ -5799,10 +6192,11 @@ static int switch_root(int argc, char *argv[], void *userdata) {
                         init = NULL;
         }
 
-        /* Instruct PID1 to exclude us from its killing spree applied during
-         * the transition. Otherwise we would exit with a failure status even
-         * though the switch to the new root has succeed. */
-        argv_cmdline[0] = '@';
+        /* Instruct PID1 to exclude us from its killing spree applied during the transition. Otherwise we
+         * would exit with a failure status even though the switch to the new root has succeed. */
+        assert(saved_argv);
+        assert(saved_argv[0]);
+        saved_argv[0][0] = '@';
 
         r = acquire_bus(BUS_MANAGER, &bus);
         if (r < 0)
@@ -5910,10 +6304,8 @@ static int import_environment(int argc, char *argv[], void *userdata) {
 
                 STRV_FOREACH(a, strv_skip(argv, 1)) {
 
-                        if (!env_name_is_valid(*a)) {
-                                log_error("Not a valid environment variable name: %s", *a);
-                                return -EINVAL;
-                        }
+                        if (!env_name_is_valid(*a))
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid environment variable name: %s", *a);
 
                         STRV_FOREACH(b, environ) {
                                 const char *eq;
@@ -5972,13 +6364,13 @@ static int enable_sysv_units(const char *verb, char **args) {
 
                 const char *argv[] = {
                         ROOTLIBEXECDIR "/systemd-sysv-install",
-                        NULL,
-                        NULL,
-                        NULL,
+                        NULL, /* --root= */
+                        NULL, /* verb */
+                        NULL, /* service */
                         NULL,
                 };
 
-                _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL;
+                _cleanup_free_ char *p = NULL, *q = NULL, *l = NULL, *v = NULL;
                 bool found_native = false, found_sysv;
                 const char *name;
                 unsigned c = 1;
@@ -6019,10 +6411,21 @@ static int enable_sysv_units(const char *verb, char **args) {
                                 log_info("%s is not a native service, redirecting to systemd-sysv-install.", name);
                 }
 
-                if (!isempty(arg_root))
-                        argv[c++] = q = strappend("--root=", arg_root);
+                if (!isempty(arg_root)) {
+                        q = strappend("--root=", arg_root);
+                        if (!q)
+                                return log_oom();
+
+                        argv[c++] = q;
+                }
+
+                /* Let's copy the verb, since it's still pointing directly into the original argv[] array we
+                 * got passed, but safe_fork() is likely going to rewrite that for the new child */
+                v = strdup(verb);
+                if (!v)
+                        return log_oom();
 
-                argv[c++] = verb;
+                argv[c++] = v;
                 argv[c++] = basename(p);
                 argv[c] = NULL;
 
@@ -6066,7 +6469,7 @@ static int enable_sysv_units(const char *verb, char **args) {
                 assert(f > 0);
                 f--;
                 assert(args[f] == name);
-                strv_remove(args, name);
+                strv_remove(args + f, name);
         }
 
 #endif
@@ -6828,7 +7231,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
         if (r < 0)
                 return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
 
-        r = copy_file(original_path, t, 0, 0644, 0, COPY_REFLINK);
+        r = copy_file(original_path, t, 0, 0644, 0, 0, COPY_REFLINK);
         if (r == -ENOENT) {
 
                 r = touch(t);
@@ -7105,15 +7508,11 @@ static int edit(int argc, char *argv[], void *userdata) {
         sd_bus *bus;
         int r;
 
-        if (!on_tty()) {
-                log_error("Cannot edit units if not on a tty.");
-                return -EINVAL;
-        }
+        if (!on_tty())
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units if not on a tty.");
 
-        if (arg_transport != BUS_TRANSPORT_LOCAL) {
-                log_error("Cannot edit units remotely.");
-                return -EINVAL;
-        }
+        if (arg_transport != BUS_TRANSPORT_LOCAL)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit units remotely.");
 
         r = lookup_paths_init(&lp, arg_scope, 0, arg_root);
         if (r < 0)
@@ -7131,10 +7530,8 @@ static int edit(int argc, char *argv[], void *userdata) {
                 r = unit_is_masked(bus, &lp, *tmp);
                 if (r < 0)
                         return r;
-                if (r > 0) {
-                        log_error("Cannot edit %s: unit is masked.", *tmp);
-                        return -EINVAL;
-                }
+                if (r > 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot edit %s: unit is masked.", *tmp);
         }
 
         r = find_paths_to_edit(bus, names, &paths);
@@ -7201,7 +7598,7 @@ static int systemctl_help(void) {
         if (r < 0)
                 return log_oom();
 
-        printf("%s [OPTIONS...] {COMMAND} ...\n\n"
+        printf("%1$s [OPTIONS...] {COMMAND} ...\n\n"
                "Query or send control commands to the systemd manager.\n\n"
                "  -h --help           Show this help\n"
                "     --version        Show package version\n"
@@ -7213,16 +7610,18 @@ static int systemctl_help(void) {
                "                      Operate on local container\n"
                "  -t --type=TYPE      List units of a particular type\n"
                "     --state=STATE    List units with particular LOAD or SUB or ACTIVE state\n"
+               "     --failed         Shorcut for --state=failed\n"
                "  -p --property=NAME  Show only properties by this name\n"
                "  -a --all            Show all properties/all units currently in memory,\n"
                "                      including dead/empty ones. To list all units installed on\n"
                "                      the system, use the 'list-unit-files' command instead.\n"
-               "     --failed         Same as --state=failed\n"
                "  -l --full           Don't ellipsize unit names on output\n"
                "  -r --recursive      Show unit list of host and local containers\n"
                "     --reverse        Show reverse dependencies with 'list-dependencies'\n"
                "     --job-mode=MODE  Specify how to deal with already queued jobs, when\n"
                "                      queueing a new job\n"
+               "  -T --show-transaction\n"
+               "                      When enqueuing a unit job, show full transaction\n"
                "     --show-types     When showing sockets, explicitly show their type\n"
                "     --value          When showing properties, only print the value\n"
                "  -i --ignore-inhibitors\n"
@@ -7255,8 +7654,12 @@ static int systemctl_help(void) {
                "                             short-monotonic, short-unix,\n"
                "                             verbose, export, json, json-pretty, json-sse, cat)\n"
                "     --firmware-setup Tell the firmware to show the setup menu on next boot\n"
+               "     --boot-loader-menu=TIME\n"
+               "                      Boot into boot loader menu on next boot\n"
+               "     --boot-loader-entry=NAME\n"
+               "                      Boot into a specific boot loader entry on next boot\n"
                "     --plain          Print unit dependencies as a list instead of a tree\n\n"
-               "Unit Commands:\n"
+               "%3$sUnit Commands:%4$s\n"
                "  list-units [PATTERN...]             List units currently in memory\n"
                "  list-sockets [PATTERN...]           List socket units currently in memory,\n"
                "                                      ordered by address\n"
@@ -7286,7 +7689,7 @@ static int systemctl_help(void) {
                "  list-dependencies [UNIT]            Recursively show units which are required\n"
                "                                      or wanted by this unit or by which this\n"
                "                                      unit is required or wanted\n\n"
-               "Unit File Commands:\n"
+               "%3$sUnit File Commands:%4$s\n"
                "  list-unit-files [PATTERN...]        List installed unit files\n"
                "  enable [UNIT...|PATH...]            Enable one or more unit files\n"
                "  disable UNIT...                     Disable one or more unit files\n"
@@ -7309,20 +7712,20 @@ static int systemctl_help(void) {
                "  edit UNIT...                        Edit one or more unit files\n"
                "  get-default                         Get the name of the default target\n"
                "  set-default TARGET                  Set the default target\n\n"
-               "Machine Commands:\n"
+               "%3$sMachine Commands:%4$s\n"
                "  list-machines [PATTERN...]          List local containers and host\n\n"
-               "Job Commands:\n"
+               "%3$sJob Commands:%4$s\n"
                "  list-jobs [PATTERN...]              List jobs\n"
                "  cancel [JOB...]                     Cancel all, one, or more jobs\n\n"
-               "Environment Commands:\n"
+               "%3$sEnvironment Commands:%4$s\n"
                "  show-environment                    Dump environment\n"
                "  set-environment VARIABLE=VALUE...   Set one or more environment variables\n"
                "  unset-environment VARIABLE...       Unset one or more environment variables\n"
                "  import-environment [VARIABLE...]    Import all or some environment variables\n\n"
-               "Manager Lifecycle Commands:\n"
+               "%3$sManager Lifecycle Commands:%4$s\n"
                "  daemon-reload                       Reload systemd manager configuration\n"
                "  daemon-reexec                       Reexecute systemd manager\n\n"
-               "System Commands:\n"
+               "%3$sSystem Commands:%4$s\n"
                "  is-system-running                   Check whether system is fully running\n"
                "  default                             Enter system default mode\n"
                "  rescue                              Enter system rescue mode\n"
@@ -7338,9 +7741,10 @@ static int systemctl_help(void) {
                "  hybrid-sleep                        Hibernate and suspend the system\n"
                "  suspend-then-hibernate              Suspend the system, wake after a period of\n"
                "                                      time and put it into hibernate\n"
-               "\nSee the %s for details.\n"
+               "\nSee the %2$s for details.\n"
                , program_invocation_short_name
                , link
+               , ansi_underline(), ansi_normal()
         );
 
         return 0;
@@ -7513,6 +7917,37 @@ static void help_states(void) {
         DUMP_STRING_TABLE(timer_state, TimerState, _TIMER_STATE_MAX);
 }
 
+static int help_boot_loader_entry(void) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        _cleanup_free_ char **l = NULL;
+        sd_bus *bus;
+        char **i;
+        int r;
+
+        r = acquire_bus(BUS_FULL, &bus);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_get_property_strv(
+                        bus,
+                        "org.freedesktop.login1",
+                        "/org/freedesktop/login1",
+                        "org.freedesktop.login1.Manager",
+                        "BootLoaderEntries",
+                        &error,
+                        &l);
+        if (r < 0)
+                return log_error_errno(r, "Failed to enumerate boot loader entries: %s", bus_error_message(&error, r));
+
+        if (strv_isempty(l))
+                return log_error_errno(SYNTHETIC_ERRNO(ENODATA), "No boot loader entries discovered.");
+
+        STRV_FOREACH(i, l)
+                puts(*i);
+
+        return 0;
+}
+
 static int systemctl_parse_argv(int argc, char *argv[]) {
         enum {
                 ARG_FAIL = 0x100,
@@ -7543,6 +7978,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_JOB_MODE,
                 ARG_PRESET_MODE,
                 ARG_FIRMWARE_SETUP,
+                ARG_BOOT_LOADER_MENU,
+                ARG_BOOT_LOADER_ENTRY,
                 ARG_NOW,
                 ARG_MESSAGE,
                 ARG_WAIT,
@@ -7592,12 +8029,14 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "recursive",           no_argument,       NULL, 'r'                     },
                 { "preset-mode",         required_argument, NULL, ARG_PRESET_MODE         },
                 { "firmware-setup",      no_argument,       NULL, ARG_FIRMWARE_SETUP      },
+                { "boot-loader-menu",    required_argument, NULL, ARG_BOOT_LOADER_MENU    },
+                { "boot-loader-entry",   required_argument, NULL, ARG_BOOT_LOADER_ENTRY   },
                 { "now",                 no_argument,       NULL, ARG_NOW                 },
                 { "message",             required_argument, NULL, ARG_MESSAGE             },
+                { "show-transaction",    no_argument,       NULL, 'T'                     },
                 {}
         };
 
-        const char *p;
         int c, r;
 
         assert(argc >= 0);
@@ -7606,7 +8045,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
         /* we default to allowing interactive authorization only in systemctl (not in the legacy commands) */
         arg_ask_password = true;
 
-        while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:ir.::", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "ht:p:alqfs:H:M:n:o:iTr.::", options, NULL)) >= 0)
 
                 switch (c) {
 
@@ -7617,6 +8056,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         return version();
 
                 case 't': {
+                        const char *p;
+
                         if (isempty(optarg))
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "--type= requires arguments.");
@@ -7636,9 +8077,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                 }
 
                                 if (unit_type_from_string(type) >= 0) {
-                                        if (strv_push(&arg_types, type) < 0)
+                                        if (strv_consume(&arg_types, TAKE_PTR(type)) < 0)
                                                 return log_oom();
-                                        type = NULL;
                                         continue;
                                 }
 
@@ -7647,9 +8087,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                  * in --types= too for compatibility
                                  * with old versions */
                                 if (unit_load_state_from_string(type) >= 0) {
-                                        if (strv_push(&arg_states, type) < 0)
+                                        if (strv_consume(&arg_states, TAKE_PTR(type)) < 0)
                                                 return log_oom();
-                                        type = NULL;
                                         continue;
                                 }
 
@@ -7661,14 +8100,16 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         break;
                 }
 
-                case 'p': {
-                        /* Make sure that if the empty property list
-                           was specified, we won't show any properties. */
+                case 'p':
+                        /* Make sure that if the empty property list was specified, we won't show any
+                           properties. */
                         if (isempty(optarg) && !arg_properties) {
                                 arg_properties = new0(char*, 1);
                                 if (!arg_properties)
                                         return log_oom();
-                        } else
+                        } else {
+                                const char *p;
+
                                 for (p = optarg;;) {
                                         _cleanup_free_ char *prop = NULL;
 
@@ -7678,11 +8119,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                         if (r == 0)
                                                 break;
 
-                                        if (strv_push(&arg_properties, prop) < 0)
+                                        if (strv_consume(&arg_properties, TAKE_PTR(prop)) < 0)
                                                 return log_oom();
-
-                                        prop = NULL;
                                 }
+                        }
 
                         /* If the user asked for a particular
                          * property, show it to him, even if it is
@@ -7690,7 +8130,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_all = true;
 
                         break;
-                }
 
                 case 'a':
                         arg_all = true;
@@ -7865,7 +8304,30 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_firmware_setup = true;
                         break;
 
+                case ARG_BOOT_LOADER_MENU:
+
+                        r = parse_sec(optarg, &arg_boot_loader_menu);
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to parse --boot-loader-menu= argument '%s': %m", optarg);
+
+                        break;
+
+                case ARG_BOOT_LOADER_ENTRY:
+
+                        if (streq(optarg, "help")) { /* Yes, this means, "help" is not a valid boot loader entry name we can deal with */
+                                r = help_boot_loader_entry();
+                                if (r < 0)
+                                        return r;
+
+                                return 0;
+                        }
+
+                        arg_boot_loader_entry = empty_to_null(optarg);
+                        break;
+
                 case ARG_STATE: {
+                        const char *p;
+
                         if (isempty(optarg))
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                                        "--state= requires arguments.");
@@ -7884,10 +8346,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                         return 0;
                                 }
 
-                                if (strv_push(&arg_states, s) < 0)
+                                if (strv_consume(&arg_states, TAKE_PTR(s)) < 0)
                                         return log_oom();
-
-                                s = NULL;
                         }
                         break;
                 }
@@ -7922,6 +8382,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                                 return log_oom();
                         break;
 
+                case 'T':
+                        arg_show_transaction = true;
+                        break;
+
                 case '.':
                         /* Output an error mimicking getopt, and print a hint afterwards */
                         log_error("%s: invalid option -- '.'", program_invocation_name);
@@ -8030,7 +8494,7 @@ static int halt_parse_argv(int argc, char *argv[]) {
                 }
 
         if (arg_action == ACTION_REBOOT && (argc == optind || argc == optind + 1)) {
-                r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL);
+                r = update_reboot_parameter_and_warn(argc == optind + 1 ? argv[optind] : NULL, false);
                 if (r < 0)
                         return r;
         } else if (optind < argc)
@@ -8049,56 +8513,6 @@ static int halt_parse_argv(int argc, char *argv[]) {
         return 1;
 }
 
-static int parse_shutdown_time_spec(const char *t, usec_t *_u) {
-        assert(t);
-        assert(_u);
-
-        if (streq(t, "now"))
-                *_u = 0;
-        else if (!strchr(t, ':')) {
-                uint64_t u;
-
-                if (safe_atou64(t, &u) < 0)
-                        return -EINVAL;
-
-                *_u = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
-        } else {
-                char *e = NULL;
-                long hour, minute;
-                struct tm tm = {};
-                time_t s;
-                usec_t n;
-
-                errno = 0;
-                hour = strtol(t, &e, 10);
-                if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
-                        return -EINVAL;
-
-                minute = strtol(e+1, &e, 10);
-                if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
-                        return -EINVAL;
-
-                n = now(CLOCK_REALTIME);
-                s = (time_t) (n / USEC_PER_SEC);
-
-                assert_se(localtime_r(&s, &tm));
-
-                tm.tm_hour = (int) hour;
-                tm.tm_min = (int) minute;
-                tm.tm_sec = 0;
-
-                s = mktime(&tm);
-                assert(s >= 0);
-
-                *_u = (usec_t) s * USEC_PER_SEC;
-
-                while (*_u <= n)
-                        *_u += USEC_PER_DAY;
-        }
-
-        return 0;
-}
-
 static int shutdown_parse_argv(int argc, char *argv[]) {
         enum {
                 ARG_HELP = 0x100,
@@ -8399,52 +8813,10 @@ _pure_ static int action_to_runlevel(void) {
         };
 
         assert(arg_action >= 0 && arg_action < _ACTION_MAX);
-
         return table[arg_action];
 }
 #endif
 
-static int talk_initctl(void) {
-#if HAVE_SYSV_COMPAT
-        struct init_request request = {
-                .magic = INIT_MAGIC,
-                .sleeptime  = 0,
-                .cmd = INIT_CMD_RUNLVL
-        };
-
-        _cleanup_close_ int fd = -1;
-        char rl;
-        int r;
-        const char *p;
-
-        rl = action_to_runlevel();
-        if (!rl)
-                return 0;
-
-        request.runlevel = rl;
-
-        FOREACH_STRING(p, "/run/initctl", "/dev/initctl") {
-                fd = open(p, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
-                if (fd >= 0 || errno != ENOENT)
-                        break;
-        }
-        if (fd < 0) {
-                if (errno == ENOENT)
-                        return 0;
-
-                return log_error_errno(errno, "Failed to open initctl fifo: %m");
-        }
-
-        r = loop_write(fd, &request, sizeof(request), false);
-        if (r < 0)
-                return log_error_errno(r, "Failed to write to %s: %m", p);
-
-        return 1;
-#else
-        return 0;
-#endif
-}
-
 static int systemctl_main(int argc, char *argv[]) {
         static const Verb verbs[] = {
                 { "list-units",            VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_units },
@@ -8536,12 +8908,14 @@ static int reload_with_fallback(void) {
 
 static int start_with_fallback(void) {
         /* First, try systemd via D-Bus. */
-        if (start_unit(0, NULL, NULL) >= 0)
+        if (start_unit(0, NULL, NULL) == 0)
                 return 0;
 
+#if HAVE_SYSV_COMPAT
         /* Nothing else worked, so let's try /dev/initctl */
-        if (talk_initctl() > 0)
+        if (talk_initctl(action_to_runlevel()) > 0)
                 return 0;
+#endif
 
         return log_error_errno(SYNTHETIC_ERRNO(EIO),
                                "Failed to talk to init daemon.");
@@ -8641,8 +9015,8 @@ static int logind_schedule_shutdown(void) {
                 log_info("Shutdown scheduled for %s, use 'shutdown -c' to cancel.", format_timestamp(date, sizeof(date), arg_when));
         return 0;
 #else
-        log_error("Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
-        return -ENOSYS;
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Cannot schedule shutdown without logind support, proceeding with immediate shutdown.");
 #endif
 }
 
@@ -8748,16 +9122,14 @@ static int logind_cancel_shutdown(void) {
 
         return 0;
 #else
-        log_error("Not compiled with logind support, cannot cancel scheduled shutdowns.");
-        return -ENOSYS;
+        return log_error_errno(SYNTHETIC_ERRNO(ENOSYS),
+                               "Not compiled with logind support, cannot cancel scheduled shutdowns.");
 #endif
 }
 
 static int run(int argc, char *argv[]) {
         int r;
 
-        argv_cmdline = argv[0];
-
         setlocale(LC_ALL, "");
         log_parse_environment();
         log_open();
@@ -8842,14 +9214,6 @@ static int run(int argc, char *argv[]) {
 finish:
         release_busses();
 
-        strv_free(arg_types);
-        strv_free(arg_states);
-        strv_free(arg_properties);
-
-        strv_free(arg_wall);
-        free(arg_root);
-        free(arg_esp_path);
-
         /* Note that we return r here, not 0, so that we can implement the LSB-like return codes */
         return r;
 }
diff --git a/src/systemctl/sysv-compat.c b/src/systemctl/sysv-compat.c
new file mode 100644 (file)
index 0000000..0283daa
--- /dev/null
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "fd-util.h"
+#include "initreq.h"
+#include "io-util.h"
+#include "parse-util.h"
+#include "strv.h"
+#include "sysv-compat.h"
+
+#if HAVE_SYSV_COMPAT
+int talk_initctl(char rl) {
+        struct init_request request;
+        _cleanup_close_ int fd = -1;
+        const char *p;
+        int r;
+
+        /* Try to switch to the specified SysV runlevel. Returns == 0 if the operation does not apply on this
+         * system, and > 0 on success. */
+
+        if (rl == 0)
+                return 0;
+
+        FOREACH_STRING(p, "/run/initctl", "/dev/initctl") {
+                fd = open(p, O_WRONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
+                if (fd >= 0 || errno != ENOENT)
+                        break;
+        }
+        if (fd < 0) {
+                if (errno == ENOENT)
+                        return 0;
+
+                return log_error_errno(errno, "Failed to open initctl fifo: %m");
+        }
+
+        request = (struct init_request) {
+                .magic = INIT_MAGIC,
+                .sleeptime = 0,
+                .cmd = INIT_CMD_RUNLVL,
+                .runlevel = rl,
+        };
+
+        r = loop_write(fd, &request, sizeof(request), false);
+        if (r < 0)
+                return log_error_errno(r, "Failed to write to %s: %m", p);
+
+        return 1;
+}
+#endif
+
+int parse_shutdown_time_spec(const char *t, usec_t *ret) {
+        assert(t);
+        assert(ret);
+
+        if (streq(t, "now"))
+                *ret = 0;
+        else if (!strchr(t, ':')) {
+                uint64_t u;
+
+                if (safe_atou64(t, &u) < 0)
+                        return -EINVAL;
+
+                *ret = now(CLOCK_REALTIME) + USEC_PER_MINUTE * u;
+        } else {
+                char *e = NULL;
+                long hour, minute;
+                struct tm tm = {};
+                time_t s;
+                usec_t n;
+
+                errno = 0;
+                hour = strtol(t, &e, 10);
+                if (errno > 0 || *e != ':' || hour < 0 || hour > 23)
+                        return -EINVAL;
+
+                minute = strtol(e+1, &e, 10);
+                if (errno > 0 || *e != 0 || minute < 0 || minute > 59)
+                        return -EINVAL;
+
+                n = now(CLOCK_REALTIME);
+                s = (time_t) (n / USEC_PER_SEC);
+
+                assert_se(localtime_r(&s, &tm));
+
+                tm.tm_hour = (int) hour;
+                tm.tm_min = (int) minute;
+                tm.tm_sec = 0;
+
+                s = mktime(&tm);
+                assert(s >= 0);
+
+                *ret = (usec_t) s * USEC_PER_SEC;
+
+                while (*ret <= n)
+                        *ret += USEC_PER_DAY;
+        }
+
+        return 0;
+}
diff --git a/src/systemctl/sysv-compat.h b/src/systemctl/sysv-compat.h
new file mode 100644 (file)
index 0000000..e799192
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "time-util.h"
+
+#if HAVE_SYSV_COMPAT
+int talk_initctl(char runlevel);
+#endif
+
+int parse_shutdown_time_spec(const char *t, usec_t *ret);
+
+/* The init script exit codes for the LSB 'status' verb. (This is different from the 'start' verb, whose exit
+   codes are defined in exit-status.h.)
+
+   0       program is running or service is OK
+   1       program is dead and /var/run pid file exists
+   2       program is dead and /var/lock lock file exists
+   3       program is not running
+   4       program or service status is unknown
+   5-99    reserved for future LSB use
+   100-149 reserved for distribution use
+   150-199 reserved for application use
+   200-254 reserved
+
+   https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/iniscrptact.html
+*/
+enum {
+        EXIT_PROGRAM_RUNNING_OR_SERVICE_OK        = 0,
+        EXIT_PROGRAM_DEAD_AND_PID_EXISTS          = 1,
+        EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS    = 2,
+        EXIT_PROGRAM_NOT_RUNNING                  = 3,
+        EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN   = 4,
+};
index 4350a8c..8a73ef0 100644 (file)
@@ -48,6 +48,10 @@ enum {
 
 #define SD_BUS_VTABLE_CAPABILITY(x) ((uint64_t) (((x)+1) & 0xFFFF) << 40)
 
+enum {
+        _SD_BUS_VTABLE_PARAM_NAMES     = 1 << 0,
+};
+
 struct sd_bus_vtable {
         /* Please do not initialize this structure directly, use the
          * macros below instead */
@@ -57,6 +61,7 @@ struct sd_bus_vtable {
         union {
                 struct {
                         size_t element_size;
+                        uint64_t features;
                 } start;
                 struct {
                         const char *member;
@@ -64,10 +69,12 @@ struct sd_bus_vtable {
                         const char *result;
                         sd_bus_message_handler_t handler;
                         size_t offset;
+                        const char *names;
                 } method;
                 struct {
                         const char *member;
                         const char *signature;
+                        const char *names;
                 } signal;
                 struct {
                         const char *member;
@@ -85,12 +92,16 @@ struct sd_bus_vtable {
                 .flags = _flags,                                        \
                 .x = {                                                  \
                     .start = {                                          \
-                        .element_size = sizeof(sd_bus_vtable)           \
+                        .element_size = sizeof(sd_bus_vtable),          \
+                        .features = _SD_BUS_VTABLE_PARAM_NAMES          \
                     },                                                  \
                 },                                                      \
         }
 
-#define SD_BUS_METHOD_WITH_OFFSET(_member, _signature, _result, _handler, _offset, _flags)   \
+/* helper macro to format method and signal parameters, one at a time */
+#define SD_BUS_PARAM(x) #x "\0"
+
+#define SD_BUS_METHOD_WITH_NAMES_OFFSET(_member, _signature, _in_names, _result, _out_names, _handler, _offset, _flags)  \
         {                                                               \
                 .type = _SD_BUS_VTABLE_METHOD,                          \
                 .flags = _flags,                                        \
@@ -101,13 +112,18 @@ struct sd_bus_vtable {
                         .result = _result,                              \
                         .handler = _handler,                            \
                         .offset = _offset,                              \
+                        .names = _in_names _out_names,                  \
                     },                                                  \
                 },                                                      \
         }
+#define SD_BUS_METHOD_WITH_OFFSET(_member, _signature, _result, _handler, _offset, _flags)   \
+        SD_BUS_METHOD_WITH_NAMES_OFFSET(_member, _signature, "", _result, "", _handler, _offset, _flags)
+#define SD_BUS_METHOD_WITH_NAMES(_member, _signature, _in_names, _result, _out_names, _handler, _flags)   \
+        SD_BUS_METHOD_WITH_NAMES_OFFSET(_member, _signature, _in_names, _result, _out_names, _handler, 0, _flags)
 #define SD_BUS_METHOD(_member, _signature, _result, _handler, _flags)   \
-        SD_BUS_METHOD_WITH_OFFSET(_member, _signature, _result, _handler, 0, _flags)
+        SD_BUS_METHOD_WITH_NAMES_OFFSET(_member, _signature, "", _result, "", _handler, 0, _flags)
 
-#define SD_BUS_SIGNAL(_member, _signature, _flags)                      \
+#define SD_BUS_SIGNAL_WITH_NAMES(_member, _signature, _out_names, _flags)                      \
         {                                                               \
                 .type = _SD_BUS_VTABLE_SIGNAL,                          \
                 .flags = _flags,                                        \
@@ -115,9 +131,12 @@ struct sd_bus_vtable {
                     .signal = {                                         \
                         .member = _member,                              \
                         .signature = _signature,                        \
+                        .names = _out_names,                            \
                     },                                                  \
                 },                                                      \
         }
+#define SD_BUS_SIGNAL(_member, _signature, _flags)   \
+        SD_BUS_SIGNAL_WITH_NAMES(_member, _signature, "", _flags)
 
 #define SD_BUS_PROPERTY(_member, _signature, _get, _offset, _flags)     \
         {                                                               \
index 129cc93..84ceb62 100644 (file)
@@ -33,6 +33,12 @@ _SD_BEGIN_DECLARATIONS;
 #define SD_BUS_DEFAULT_USER ((sd_bus *) 2)
 #define SD_BUS_DEFAULT_SYSTEM ((sd_bus *) 3)
 
+/* https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-signature */
+#define SD_BUS_MAXIMUM_SIGNATURE_LENGTH 255
+
+/* https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names */
+#define SD_BUS_MAXIMUM_NAME_LENGTH 255
+
 /* Types */
 
 typedef struct sd_bus sd_bus;
index 4875f10..d299c79 100644 (file)
@@ -39,7 +39,7 @@ int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1);
 int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2);
 int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr);
 int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr);
-int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, struct in_addr *addr);
+int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr);
 int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr);
 int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr);
 int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr);
index 787a12f..7bb8609 100644 (file)
@@ -71,7 +71,7 @@ typedef int (*sd_event_handler_t)(sd_event_source *s, void *userdata);
 typedef int (*sd_event_io_handler_t)(sd_event_source *s, int fd, uint32_t revents, void *userdata);
 typedef int (*sd_event_time_handler_t)(sd_event_source *s, uint64_t usec, void *userdata);
 typedef int (*sd_event_signal_handler_t)(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata);
-#if defined _GNU_SOURCE || _POSIX_C_SOURCE >= 199309L
+#if defined _GNU_SOURCE || (defined _POSIX_C_SOURCE && _POSIX_C_SOURCE >= 199309L)
 typedef int (*sd_event_child_handler_t)(sd_event_source *s, const siginfo_t *si, void *userdata);
 #else
 typedef void* sd_event_child_handler_t;
index 9e6e437..804fe9f 100644 (file)
@@ -34,7 +34,13 @@ typedef struct sd_netlink sd_netlink;
 typedef struct sd_genl_socket sd_genl_socket;
 typedef struct sd_netlink_message sd_netlink_message;
 typedef struct sd_netlink_slot sd_netlink_slot;
-typedef enum {SD_GENL_ID_CTRL, SD_GENL_WIREGUARD, SD_GENL_FOU} sd_genl_family;
+
+typedef enum sd_gen_family {
+        SD_GENL_ID_CTRL,
+        SD_GENL_WIREGUARD,
+        SD_GENL_FOU,
+        SD_GENL_L2TP,
+} sd_genl_family;
 
 /* callback */
 
index cc6bca9..166c301 100644 (file)
@@ -89,6 +89,7 @@ int sd_network_link_get_setup_state(int ifindex, char **state);
  *   -ENODATA: networkd is not aware of the link
  */
 int sd_network_link_get_operational_state(int ifindex, char **state);
+int sd_network_link_get_required_operstate_for_online(int ifindex, char **state);
 
 /* Indicates whether the network is relevant to being online.
  * Possible return codes:
index df28bcf..843c383 100644 (file)
@@ -244,7 +244,7 @@ static int make_backup(const char *target, const char *x) {
         return 0;
 
 fail:
-        unlink(temp);
+        (void) unlink(temp);
         return r;
 }
 
@@ -389,15 +389,15 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char
                 while ((r = fgetpwent_sane(original, &pw)) > 0) {
 
                         i = ordered_hashmap_get(users, pw->pw_name);
-                        if (i && i->todo_user) {
-                                log_error("%s: User \"%s\" already exists.", passwd_path, pw->pw_name);
-                                return -EEXIST;
-                        }
+                        if (i && i->todo_user)
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "%s: User \"%s\" already exists.",
+                                                       passwd_path, pw->pw_name);
 
-                        if (ordered_hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid))) {
-                                log_error("%s: Detected collision for UID " UID_FMT ".", passwd_path, pw->pw_uid);
-                                return -EEXIST;
-                        }
+                        if (ordered_hashmap_contains(todo_uids, UID_TO_PTR(pw->pw_uid)))
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "%s: Detected collision for UID " UID_FMT ".",
+                                                       passwd_path, pw->pw_uid);
 
                         /* Make sure we keep the NIS entries (if any) at the end. */
                         if (IN_SET(pw->pw_name[0], '+', '-'))
@@ -592,15 +592,15 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char **
                          * step that we don't generate duplicate entries. */
 
                         i = ordered_hashmap_get(groups, gr->gr_name);
-                        if (i && i->todo_group) {
-                                log_error("%s: Group \"%s\" already exists.", group_path, gr->gr_name);
-                                return -EEXIST;
-                        }
+                        if (i && i->todo_group)
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "%s: Group \"%s\" already exists.",
+                                                       group_path, gr->gr_name);
 
-                        if (ordered_hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid))) {
-                                log_error("%s: Detected collision for GID " GID_FMT ".", group_path, gr->gr_gid);
-                                return  -EEXIST;
-                        }
+                        if (ordered_hashmap_contains(todo_gids, GID_TO_PTR(gr->gr_gid)))
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "%s: Detected collision for GID " GID_FMT ".",
+                                                       group_path, gr->gr_gid);
 
                         /* Make sure we keep the NIS entries (if any) at the end. */
                         if (IN_SET(gr->gr_name[0], '+', '-'))
@@ -687,10 +687,10 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch
                 while ((r = fgetsgent_sane(original, &sg)) > 0) {
 
                         i = ordered_hashmap_get(groups, sg->sg_namp);
-                        if (i && i->todo_group) {
-                                log_error("%s: Group \"%s\" already exists.", gshadow_path, sg->sg_namp);
-                                return -EEXIST;
-                        }
+                        if (i && i->todo_group)
+                                return log_error_errno(SYNTHETIC_ERRNO(EEXIST),
+                                                       "%s: Group \"%s\" already exists.",
+                                                       gshadow_path, sg->sg_namp);
 
                         r = putsgent_with_members(sg, gshadow);
                         if (r < 0)
@@ -1021,10 +1021,8 @@ static int add_user(Item *i) {
         if (!i->uid_set) {
                 for (;;) {
                         r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
-                        if (r < 0) {
-                                log_error("No free user ID available for %s.", i->name);
-                                return r;
-                        }
+                        if (r < 0)
+                                return log_error_errno(r, "No free user ID available for %s.", i->name);
 
                         r = uid_is_ok(search_uid, i->name, true);
                         if (r < 0)
@@ -1178,10 +1176,8 @@ static int add_group(Item *i) {
                 for (;;) {
                         /* We look for new GIDs in the UID pool! */
                         r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
-                        if (r < 0) {
-                                log_error("No free group ID available for %s.", i->name);
-                                return r;
-                        }
+                        if (r < 0)
+                                return log_error_errno(r, "No free group ID available for %s.", i->name);
 
                         r = gid_is_ok(search_uid);
                         if (r < 0)
@@ -1381,7 +1377,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                 *id = NULL, *resolved_id = NULL,
                 *description = NULL, *resolved_description = NULL,
                 *home = NULL, *resolved_home = NULL,
-                *shell, *resolved_shell = NULL;
+                *shell = NULL, *resolved_shell = NULL;
         _cleanup_(item_freep) Item *i = NULL;
         Item *existing;
         OrderedHashmap *h;
@@ -1396,135 +1392,121 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         p = buffer;
         r = extract_many_words(&p, NULL, EXTRACT_QUOTES,
                                &action, &name, &id, &description, &home, &shell, NULL);
-        if (r < 0) {
-                log_error("[%s:%u] Syntax error.", fname, line);
-                return r;
-        }
-        if (r < 2) {
-                log_error("[%s:%u] Missing action and name columns.", fname, line);
-                return -EINVAL;
-        }
-        if (!isempty(p)) {
-                log_error("[%s:%u] Trailing garbage.", fname, line);
-                return -EINVAL;
-        }
+        if (r < 0)
+                return log_error_errno(r, "[%s:%u] Syntax error.", fname, line);
+        if (r < 2)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "[%s:%u] Missing action and name columns.", fname, line);
+        if (!isempty(p))
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "[%s:%u] Trailing garbage.", fname, line);
 
         /* Verify action */
-        if (strlen(action) != 1) {
-                log_error("[%s:%u] Unknown modifier '%s'", fname, line, action);
-                return -EINVAL;
-        }
+        if (strlen(action) != 1)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                       "[%s:%u] Unknown modifier '%s'", fname, line, action);
 
-        if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE)) {
-                log_error("[%s:%u] Unknown command type '%c'.", fname, line, action[0]);
-                return -EBADMSG;
-        }
+        if (!IN_SET(action[0], ADD_USER, ADD_GROUP, ADD_MEMBER, ADD_RANGE))
+                return log_error_errno(SYNTHETIC_ERRNO(EBADMSG),
+                                       "[%s:%u] Unknown command type '%c'.", fname, line, action[0]);
 
         /* Verify name */
-        if (isempty(name) || streq(name, "-"))
+        if (empty_or_dash(name))
                 name = mfree(name);
 
         if (name) {
                 r = specifier_printf(name, specifier_table, NULL, &resolved_name);
-                if (r < 0) {
-                        log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
-                        return r;
-                }
+                if (r < 0)
+                        log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s", fname, line, name);
 
-                if (!valid_user_group_name(resolved_name)) {
-                        log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_name);
-                        return -EINVAL;
-                }
+                if (!valid_user_group_name(resolved_name))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] '%s' is not a valid user or group name.",
+                                               fname, line, resolved_name);
         }
 
         /* Verify id */
-        if (isempty(id) || streq(id, "-"))
+        if (empty_or_dash(id))
                 id = mfree(id);
 
         if (id) {
                 r = specifier_printf(id, specifier_table, NULL, &resolved_id);
-                if (r < 0) {
-                        log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, name);
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+                                               fname, line, name);
         }
 
         /* Verify description */
-        if (isempty(description) || streq(description, "-"))
+        if (empty_or_dash(description))
                 description = mfree(description);
 
         if (description) {
                 r = specifier_printf(description, specifier_table, NULL, &resolved_description);
-                if (r < 0) {
-                        log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, description);
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+                                               fname, line, description);
 
-                if (!valid_gecos(resolved_description)) {
-                        log_error("[%s:%u] '%s' is not a valid GECOS field.", fname, line, resolved_description);
-                        return -EINVAL;
-                }
+                if (!valid_gecos(resolved_description))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] '%s' is not a valid GECOS field.",
+                                               fname, line, resolved_description);
         }
 
         /* Verify home */
-        if (isempty(home) || streq(home, "-"))
+        if (empty_or_dash(home))
                 home = mfree(home);
 
         if (home) {
                 r = specifier_printf(home, specifier_table, NULL, &resolved_home);
-                if (r < 0) {
-                        log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, home);
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+                                               fname, line, home);
 
-                if (!valid_home(resolved_home)) {
-                        log_error("[%s:%u] '%s' is not a valid home directory field.", fname, line, resolved_home);
-                        return -EINVAL;
-                }
+                if (!valid_home(resolved_home))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] '%s' is not a valid home directory field.",
+                                               fname, line, resolved_home);
         }
 
         /* Verify shell */
-        if (isempty(shell) || streq(shell, "-"))
+        if (empty_or_dash(shell))
                 shell = mfree(shell);
 
         if (shell) {
                 r = specifier_printf(shell, specifier_table, NULL, &resolved_shell);
-                if (r < 0) {
-                        log_error("[%s:%u] Failed to replace specifiers: %s", fname, line, shell);
-                        return r;
-                }
+                if (r < 0)
+                        return log_error_errno(r, "[%s:%u] Failed to replace specifiers: %s",
+                                               fname, line, shell);
 
-                if (!valid_shell(resolved_shell)) {
-                        log_error("[%s:%u] '%s' is not a valid login shell field.", fname, line, resolved_shell);
-                        return -EINVAL;
-                }
+                if (!valid_shell(resolved_shell))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] '%s' is not a valid login shell field.",
+                                               fname, line, resolved_shell);
         }
 
         switch (action[0]) {
 
         case ADD_RANGE:
-                if (resolved_name) {
-                        log_error("[%s:%u] Lines of type 'r' don't take a name field.", fname, line);
-                        return -EINVAL;
-                }
-
-                if (!resolved_id) {
-                        log_error("[%s:%u] Lines of type 'r' require a ID range in the third field.", fname, line);
-                        return -EINVAL;
-                }
-
-                if (description || home || shell) {
-                        log_error("[%s:%u] Lines of type '%c' don't take a %s field.",
-                                  fname, line, action[0],
-                                  description ? "GECOS" : home ? "home directory" : "login shell");
-                        return -EINVAL;
-                }
+                if (resolved_name)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Lines of type 'r' don't take a name field.",
+                                               fname, line);
+
+                if (!resolved_id)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Lines of type 'r' require a ID range in the third field.",
+                                               fname, line);
+
+                if (description || home || shell)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Lines of type '%c' don't take a %s field.",
+                                               fname, line, action[0],
+                                               description ? "GECOS" : home ? "home directory" : "login shell");
 
                 r = uid_range_add_str(&uid_range, &n_uid_range, resolved_id);
-                if (r < 0) {
-                        log_error("[%s:%u] Invalid UID range %s.", fname, line, resolved_id);
-                        return -EINVAL;
-                }
+                if (r < 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Invalid UID range %s.", fname, line, resolved_id);
 
                 return 0;
 
@@ -1532,27 +1514,26 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                 char **l;
 
                 /* Try to extend an existing member or group item */
-                if (!name) {
-                        log_error("[%s:%u] Lines of type 'm' require a user name in the second field.", fname, line);
-                        return -EINVAL;
-                }
-
-                if (!resolved_id) {
-                        log_error("[%s:%u] Lines of type 'm' require a group name in the third field.", fname, line);
-                        return -EINVAL;
-                }
-
-                if (!valid_user_group_name(resolved_id)) {
-                        log_error("[%s:%u] '%s' is not a valid user or group name.", fname, line, resolved_id);
-                        return -EINVAL;
-                }
-
-                if (description || home || shell) {
-                        log_error("[%s:%u] Lines of type '%c' don't take a %s field.",
-                                  fname, line, action[0],
-                                  description ? "GECOS" : home ? "home directory" : "login shell");
-                        return -EINVAL;
-                }
+                if (!name)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Lines of type 'm' require a user name in the second field.",
+                                               fname, line);
+
+                if (!resolved_id)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Lines of type 'm' require a group name in the third field.",
+                                               fname, line);
+
+                if (!valid_user_group_name(resolved_id))
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] '%s' is not a valid user or group name.",
+                                               fname, line, resolved_id);
+
+                if (description || home || shell)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Lines of type '%c' don't take a %s field.",
+                                               fname, line, action[0],
+                                               description ? "GECOS" : home ? "home directory" : "login shell");
 
                 r = ordered_hashmap_ensure_allocated(&members, &members_hash_ops);
                 if (r < 0)
@@ -1591,10 +1572,10 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
         }
 
         case ADD_USER:
-                if (!name) {
-                        log_error("[%s:%u] Lines of type 'u' require a user name in the second field.", fname, line);
-                        return -EINVAL;
-                }
+                if (!name)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Lines of type 'u' require a user name in the second field.",
+                                               fname, line);
 
                 r = ordered_hashmap_ensure_allocated(&users, &item_hash_ops);
                 if (r < 0)
@@ -1635,17 +1616,16 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                 break;
 
         case ADD_GROUP:
-                if (!name) {
-                        log_error("[%s:%u] Lines of type 'g' require a user name in the second field.", fname, line);
-                        return -EINVAL;
-                }
+                if (!name)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Lines of type 'g' require a user name in the second field.",
+                                               fname, line);
 
-                if (description || home || shell) {
-                        log_error("[%s:%u] Lines of type '%c' don't take a %s field.",
-                                  fname, line, action[0],
-                                  description ? "GECOS" : home ? "home directory" : "login shell");
-                        return -EINVAL;
-                }
+                if (description || home || shell)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                               "[%s:%u] Lines of type '%c' don't take a %s field.",
+                                               fname, line, action[0],
+                                               description ? "GECOS" : home ? "home directory" : "login shell");
 
                 r = ordered_hashmap_ensure_allocated(&groups, &item_hash_ops);
                 if (r < 0)
@@ -1680,7 +1660,6 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
 
         existing = ordered_hashmap_get(h, i->name);
         if (existing) {
-
                 /* Two identical items are fine */
                 if (!item_equal(existing, i))
                         log_warning("Two or more conflicting lines for %s configured, ignoring.", i->name);
index c388283..660febc 100644 (file)
@@ -228,6 +228,11 @@ tests += [
          [],
          []],
 
+        [['src/test/test-libmount.c'],
+         [],
+         [threads,
+          libmount]],
+
         [['src/test/test-mount-util.c'],
          [],
          []],
@@ -440,6 +445,10 @@ tests += [
          [],
          []],
 
+        [['src/test/test-ordered-set.c'],
+         [],
+         []],
+
         [['src/test/test-set-disable-mempool.c'],
          [],
          [threads]],
@@ -560,6 +569,11 @@ tests += [
          [],
          '', 'manual'],
 
+        [['src/test/test-cgroup-cpu.c'],
+         [libcore,
+          libshared],
+         []],
+
         [['src/test/test-cgroup-mask.c',
           'src/test/test-helper.c'],
          [libcore,
@@ -705,11 +719,10 @@ tests += [
          'ENABLE_NSS', 'manual'],
 
         [['src/test/test-umount.c',
-          'src/core/mount-setup.c',
-          'src/core/mount-setup.h',
-          'src/core/umount.c',
-          'src/core/umount.h'],
-         [],
+          'src/shutdown/umount.c',
+          'src/shutdown/umount.h'],
+         [libcore_shared,
+          libshared],
          [libmount]],
 
         [['src/test/test-bus-util.c'],
@@ -858,6 +871,10 @@ tests += [
          [],
          [threads]],
 
+        [['src/libsystemd/sd-bus/test-bus-queue-ref-cycle.c'],
+         [],
+         [threads]],
+
         [['src/libsystemd/sd-bus/test-bus-watch-bind.c'],
          [],
          [threads], '', 'timeout=120'],
index 40c32d7..ad10eb1 100644 (file)
@@ -4,7 +4,7 @@
 
 #include "alloc-util.h"
 #include "macro.h"
-#include "util.h"
+#include "memory-util.h"
 
 static void test_alloca(void) {
         static const uint8_t zero[997] = { };
@@ -19,6 +19,25 @@ static void test_alloca(void) {
         assert_se(!memcmp(t, zero, 997));
 }
 
+static void test_GREEDY_REALLOC(void) {
+        _cleanup_free_ int *a = NULL, *b = NULL;
+        size_t n_allocated = 0, i;
+
+        /* Give valgrind a chance to verify our realloc operations */
+
+        for (i = 0; i < 2048; i++) {
+                assert_se(GREEDY_REALLOC(a, n_allocated, i + 1));
+                a[i] = i;
+                assert_se(GREEDY_REALLOC(a, n_allocated, i / 2));
+        }
+
+        for (i = 30, n_allocated = 0; i < 2048; i+=7) {
+                assert_se(GREEDY_REALLOC(b, n_allocated, i + 1));
+                b[i] = i;
+                assert_se(GREEDY_REALLOC(b, n_allocated, i / 2));
+        }
+}
+
 static void test_memdup_multiply_and_greedy_realloc(void) {
         int org[] = {1, 2, 3};
         _cleanup_free_ int *dup;
@@ -74,6 +93,7 @@ static void test_bool_assign(void) {
 
 int main(int argc, char *argv[]) {
         test_alloca();
+        test_GREEDY_REALLOC();
         test_memdup_multiply_and_greedy_realloc();
         test_bool_assign();
 
index 4f53078..7d8accc 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
 #include <unistd.h>
 
 #include "async.h"
index 6469129..10417f6 100644 (file)
@@ -18,6 +18,7 @@
 #include "util.h"
 #include "tests.h"
 #include "virt.h"
+#include "time-util.h"
 
 /* 20ms to test deadlocks; All timings use multiples of this constant as
  * alarm/sleep timers. If this timeout is too small for slow machines to perform
index a79e0cf..79b8dd4 100644 (file)
@@ -1,5 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "acpi-fpdt.h"
 #include "boot-timestamps.h"
 #include "efivars.h"
index de5fa72..563b996 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <stdio.h>
 #include <sys/prctl.h>
 
 #include "alloc-util.h"
index 325d7c8..6b2de66 100644 (file)
@@ -215,11 +215,32 @@ static void test_set_ambient_caps(void) {
         assert_se(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_CHOWN, 0, 0) == 1);
 }
 
+static void test_ensure_cap_64bit(void) {
+        _cleanup_free_ char *content = NULL;
+        unsigned long p = 0;
+        int r;
+
+        r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content);
+        if (r == -ENOENT) /* kernel pre 3.2 */
+                return;
+        assert_se(r >= 0);
+
+        assert_se(safe_atolu(content, &p) >= 0);
+
+        /* If caps don't fit into 64bit anymore, we have a problem, fail the test. */
+        assert_se(p <= 63);
+
+        /* Also check for the header definition */
+        assert_se(CAP_LAST_CAP <= 63);
+}
+
 int main(int argc, char *argv[]) {
         bool run_ambient;
 
         test_setup_logging(LOG_INFO);
 
+        test_ensure_cap_64bit();
+
         test_last_cap_file();
         test_last_cap_probe();
 
diff --git a/src/test/test-cgroup-cpu.c b/src/test/test-cgroup-cpu.c
new file mode 100644 (file)
index 0000000..a445acc
--- /dev/null
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "cgroup.h"
+#include "log.h"
+
+static void test_cgroup_cpu_adjust_period(void) {
+        log_info("/* %s */", __func__);
+
+        /* Period 1ms, quota 40% -> Period 2.5ms */
+        assert_se(2500 == cgroup_cpu_adjust_period(USEC_PER_MSEC, 400 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 10ms, quota 10% -> keep. */
+        assert_se(10 * USEC_PER_MSEC == cgroup_cpu_adjust_period(10 * USEC_PER_MSEC, 100 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 1ms, quota 1000% -> keep. */
+        assert_se(USEC_PER_MSEC == cgroup_cpu_adjust_period(USEC_PER_MSEC, 10000 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 100ms, quota 30% -> keep. */
+        assert_se(100 * USEC_PER_MSEC == cgroup_cpu_adjust_period(100 * USEC_PER_MSEC, 300 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 5s, quota 40% -> adjust to 1s. */
+        assert_se(USEC_PER_SEC == cgroup_cpu_adjust_period(5 * USEC_PER_SEC, 400 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 2s, quota 250% -> adjust to 1s. */
+        assert_se(USEC_PER_SEC == cgroup_cpu_adjust_period(2 * USEC_PER_SEC, 2500 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 10us, quota 5,000,000% -> adjust to 1ms. */
+        assert_se(USEC_PER_MSEC == cgroup_cpu_adjust_period(10, 50000000 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 10ms, quota 50,000% -> keep. */
+        assert_se(10 * USEC_PER_MSEC == cgroup_cpu_adjust_period(10 * USEC_PER_MSEC, 500000 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 10ms, quota 1% -> adjust to 100ms. */
+        assert_se(100 * USEC_PER_MSEC == cgroup_cpu_adjust_period(10 * USEC_PER_MSEC, 10 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 10ms, quota .001% -> adjust to 1s. */
+        assert_se(1 * USEC_PER_SEC == cgroup_cpu_adjust_period(10 * USEC_PER_MSEC, 10, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 0ms, quota 200% -> adjust to 1ms. */
+        assert_se(1 * USEC_PER_MSEC == cgroup_cpu_adjust_period(0, 2 * USEC_PER_SEC, USEC_PER_MSEC, USEC_PER_SEC));
+        /* Period 0ms, quota 40% -> adjust to 2.5ms. */
+        assert_se(2500 == cgroup_cpu_adjust_period(0, 400 * USEC_PER_MSEC, USEC_PER_MSEC, USEC_PER_SEC));
+}
+
+int main(int argc, char *argv[]) {
+        test_cgroup_cpu_adjust_period();
+        return 0;
+}
index 305d44f..aa11bd2 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <sys/xattr.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "chown-recursive.h"
@@ -43,6 +44,8 @@ static void test_chown_recursive(void) {
         _cleanup_(rm_rf_physical_and_freep) char *t = NULL;
         struct stat st;
         const char *p;
+        const uid_t uid = getuid();
+        const gid_t gid = getgid();
 
         umask(022);
         assert_se(mkdtemp_malloc(NULL, &t) >= 0);
@@ -52,8 +55,8 @@ static void test_chown_recursive(void) {
         assert_se(lstat(p, &st) >= 0);
         assert_se(S_ISDIR(st.st_mode));
         assert_se((st.st_mode & 07777) == 0755);
-        assert_se(st.st_uid == 0);
-        assert_se(st.st_gid == 0);
+        assert_se(st.st_uid == uid);
+        assert_se(st.st_gid == gid);
         assert_se(!has_xattr(p));
 
         p = strjoina(t, "/dir/symlink");
@@ -61,8 +64,8 @@ static void test_chown_recursive(void) {
         assert_se(lstat(p, &st) >= 0);
         assert_se(S_ISLNK(st.st_mode));
         assert_se((st.st_mode & 07777) == 0777);
-        assert_se(st.st_uid == 0);
-        assert_se(st.st_gid == 0);
+        assert_se(st.st_uid == uid);
+        assert_se(st.st_gid == gid);
         assert_se(!has_xattr(p));
 
         p = strjoina(t, "/dir/reg");
@@ -70,8 +73,8 @@ static void test_chown_recursive(void) {
         assert_se(lstat(p, &st) >= 0);
         assert_se(S_ISREG(st.st_mode));
         assert_se((st.st_mode & 07777) == 0755);
-        assert_se(st.st_uid == 0);
-        assert_se(st.st_gid == 0);
+        assert_se(st.st_uid == uid);
+        assert_se(st.st_gid == gid);
         assert_se(!has_xattr(p));
 
         p = strjoina(t, "/dir/sock");
@@ -79,8 +82,8 @@ static void test_chown_recursive(void) {
         assert_se(lstat(p, &st) >= 0);
         assert_se(S_ISSOCK(st.st_mode));
         assert_se((st.st_mode & 07777) == 0755);
-        assert_se(st.st_uid == 0);
-        assert_se(st.st_gid == 0);
+        assert_se(st.st_uid == uid);
+        assert_se(st.st_gid == gid);
         assert_se(!has_xattr(p));
 
         p = strjoina(t, "/dir/fifo");
@@ -88,8 +91,8 @@ static void test_chown_recursive(void) {
         assert_se(lstat(p, &st) >= 0);
         assert_se(S_ISFIFO(st.st_mode));
         assert_se((st.st_mode & 07777) == 0755);
-        assert_se(st.st_uid == 0);
-        assert_se(st.st_gid == 0);
+        assert_se(st.st_uid == uid);
+        assert_se(st.st_gid == gid);
         assert_se(!has_xattr(p));
 
         /* We now apply an xattr to the dir, and check it again */
@@ -99,11 +102,11 @@ static void test_chown_recursive(void) {
         assert_se(lstat(p, &st) >= 0);
         assert_se(S_ISDIR(st.st_mode));
         assert_se((st.st_mode & 07777) == 0775); /* acl change changed the mode too */
-        assert_se(st.st_uid == 0);
-        assert_se(st.st_gid == 0);
+        assert_se(st.st_uid == uid);
+        assert_se(st.st_gid == gid);
         assert_se(has_xattr(p));
 
-        assert_se(path_chown_recursive(t, 1, 2) >= 0);
+        assert_se(path_chown_recursive(t, 1, 2, 07777) >= 0);
 
         p = strjoina(t, "/dir");
         assert_se(lstat(p, &st) >= 0);
index 5c2d00a..2a5e3ab 100644 (file)
 #include "hostname-util.h"
 #include "id128-util.h"
 #include "ima-util.h"
+#include "limits-util.h"
 #include "log.h"
 #include "macro.h"
+#include "nulstr-util.h"
+#include "process-util.h"
 #include "selinux-util.h"
 #include "set.h"
 #include "smack-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 #include "tomoyo-util.h"
 #include "user-util.h"
-#include "tests.h"
-#include "util.h"
 #include "virt.h"
 
 static void test_condition_test_path(void) {
@@ -673,6 +675,127 @@ static void test_condition_test_group(void) {
         condition_free(condition);
 }
 
+static void test_condition_test_cpus_one(const char *s, bool result) {
+        Condition *condition;
+        int r;
+
+        log_debug("%s=%s", condition_type_to_string(CONDITION_CPUS), s);
+
+        condition = condition_new(CONDITION_CPUS, s, false, false);
+        assert_se(condition);
+
+        r = condition_test(condition);
+        assert_se(r >= 0);
+        assert_se(r == result);
+        condition_free(condition);
+}
+
+static void test_condition_test_cpus(void) {
+        _cleanup_free_ char *t = NULL;
+        int cpus;
+
+        cpus = cpus_in_affinity_mask();
+        assert_se(cpus >= 0);
+
+        test_condition_test_cpus_one("> 0", true);
+        test_condition_test_cpus_one(">= 0", true);
+        test_condition_test_cpus_one("!= 0", true);
+        test_condition_test_cpus_one("<= 0", false);
+        test_condition_test_cpus_one("< 0", false);
+        test_condition_test_cpus_one("= 0", false);
+
+        test_condition_test_cpus_one("> 100000", false);
+        test_condition_test_cpus_one("= 100000", false);
+        test_condition_test_cpus_one(">= 100000", false);
+        test_condition_test_cpus_one("< 100000", true);
+        test_condition_test_cpus_one("!= 100000", true);
+        test_condition_test_cpus_one("<= 100000", true);
+
+        assert_se(asprintf(&t, "= %i", cpus) >= 0);
+        test_condition_test_cpus_one(t, true);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, "<= %i", cpus) >= 0);
+        test_condition_test_cpus_one(t, true);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, ">= %i", cpus) >= 0);
+        test_condition_test_cpus_one(t, true);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, "!= %i", cpus) >= 0);
+        test_condition_test_cpus_one(t, false);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, "< %i", cpus) >= 0);
+        test_condition_test_cpus_one(t, false);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, "> %i", cpus) >= 0);
+        test_condition_test_cpus_one(t, false);
+        t = mfree(t);
+}
+
+static void test_condition_test_memory_one(const char *s, bool result) {
+        Condition *condition;
+        int r;
+
+        log_debug("%s=%s", condition_type_to_string(CONDITION_MEMORY), s);
+
+        condition = condition_new(CONDITION_MEMORY, s, false, false);
+        assert_se(condition);
+
+        r = condition_test(condition);
+        assert_se(r >= 0);
+        assert_se(r == result);
+        condition_free(condition);
+}
+
+static void test_condition_test_memory(void) {
+        _cleanup_free_ char *t = NULL;
+        uint64_t memory;
+
+        memory = physical_memory();
+
+        test_condition_test_memory_one("> 0", true);
+        test_condition_test_memory_one(">= 0", true);
+        test_condition_test_memory_one("!= 0", true);
+        test_condition_test_memory_one("<= 0", false);
+        test_condition_test_memory_one("< 0", false);
+        test_condition_test_memory_one("= 0", false);
+
+        test_condition_test_memory_one("> 18446744073709547520", false);
+        test_condition_test_memory_one("= 18446744073709547520", false);
+        test_condition_test_memory_one(">= 18446744073709547520", false);
+        test_condition_test_memory_one("< 18446744073709547520", true);
+        test_condition_test_memory_one("!= 18446744073709547520", true);
+        test_condition_test_memory_one("<= 18446744073709547520", true);
+
+        assert_se(asprintf(&t, "= %" PRIu64, memory) >= 0);
+        test_condition_test_memory_one(t, true);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, "<= %" PRIu64, memory) >= 0);
+        test_condition_test_memory_one(t, true);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, ">= %" PRIu64, memory) >= 0);
+        test_condition_test_memory_one(t, true);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, "!= %" PRIu64, memory) >= 0);
+        test_condition_test_memory_one(t, false);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, "< %" PRIu64, memory) >= 0);
+        test_condition_test_memory_one(t, false);
+        t = mfree(t);
+
+        assert_se(asprintf(&t, "> %" PRIu64, memory) >= 0);
+        test_condition_test_memory_one(t, false);
+        t = mfree(t);
+}
+
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_DEBUG);
 
@@ -689,6 +812,8 @@ int main(int argc, char *argv[]) {
         test_condition_test_user();
         test_condition_test_group();
         test_condition_test_control_group_controller();
+        test_condition_test_cpus();
+        test_condition_test_memory();
 
         return 0;
 }
index b17a1c5..5f4bc39 100644 (file)
@@ -38,7 +38,7 @@ static void test_copy_file(void) {
 
         assert_se(write_string_file(fn, "foo bar bar bar foo", WRITE_STRING_FILE_CREATE) == 0);
 
-        assert_se(copy_file(fn, fn_copy, 0, 0644, 0, COPY_REFLINK) == 0);
+        assert_se(copy_file(fn, fn_copy, 0, 0644, 0, 0, COPY_REFLINK) == 0);
 
         assert_se(read_full_file(fn_copy, &buf, &sz) == 0);
         assert_se(streq(buf, "foo bar bar bar foo\n"));
@@ -246,13 +246,13 @@ static void test_copy_atomic(void) {
 
         q = strjoina(p, "/fstab");
 
-        r = copy_file_atomic("/etc/fstab", q, 0644, 0, COPY_REFLINK);
+        r = copy_file_atomic("/etc/fstab", q, 0644, 0, 0, COPY_REFLINK);
         if (r == -ENOENT)
                 return;
 
-        assert_se(copy_file_atomic("/etc/fstab", q, 0644, 0, COPY_REFLINK) == -EEXIST);
+        assert_se(copy_file_atomic("/etc/fstab", q, 0644, 0, 0, COPY_REFLINK) == -EEXIST);
 
-        assert_se(copy_file_atomic("/etc/fstab", q, 0644, 0, COPY_REPLACE) >= 0);
+        assert_se(copy_file_atomic("/etc/fstab", q, 0644, 0, 0, COPY_REPLACE) >= 0);
 }
 
 int main(int argc, char *argv[]) {
index a4b96da..6ca8215 100644 (file)
@@ -6,6 +6,7 @@
 
 #include "parse-util.h"
 #include "strv.h"
+#include "time-util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_strv_free_ char **l = NULL;
index cba51e2..9888b65 100644 (file)
@@ -5,7 +5,7 @@
 #include "alloc-util.h"
 #include "string-util.h"
 #include "tests.h"
-#include "util.h"
+#include "time-util.h"
 
 static void test_should_pass(const char *p) {
         usec_t t, q;
index 0673d36..701594f 100644 (file)
@@ -40,7 +40,7 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test1: (Trivial)\n");
-        r = manager_add_job(m, JOB_START, c, JOB_REPLACE, &err, &j);
+        r = manager_add_job(m, JOB_START, c, JOB_REPLACE, NULL, &err, &j);
         if (sd_bus_error_is_set(&err))
                 log_error("error: %s: %s", err.name, err.message);
         assert_se(r == 0);
@@ -53,15 +53,15 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test2: (Cyclic Order, Unfixable)\n");
-        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, &j) == -EDEADLK);
+        assert_se(manager_add_job(m, JOB_START, d, JOB_REPLACE, NULL, NULL, &j) == -EDEADLK);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test3: (Cyclic Order, Fixable, Garbage Collector)\n");
-        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, e, JOB_REPLACE, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test4: (Identical transaction)\n");
-        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, e, JOB_FAIL, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Load3:\n");
@@ -69,21 +69,21 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test5: (Colliding transaction, fail)\n");
-        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, &j) == -EDEADLK);
+        assert_se(manager_add_job(m, JOB_START, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
 
         printf("Test6: (Colliding transaction, replace)\n");
-        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test7: (Unmergeable job type, fail)\n");
-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, &j) == -EDEADLK);
+        assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, NULL, NULL, &j) == -EDEADLK);
 
         printf("Test8: (Mergeable job type, fail)\n");
-        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Test9: (Unmergeable job type, replace)\n");
-        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         printf("Load4:\n");
@@ -91,7 +91,7 @@ int main(int argc, char *argv[]) {
         manager_dump_units(m, stdout, "\t");
 
         printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
-        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, &j) == 0);
+        assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, NULL, NULL, &j) == 0);
         manager_dump_jobs(m, stdout, "\t");
 
         assert_se(!hashmap_get(a->dependencies[UNIT_PROPAGATES_RELOAD_TO], b));
index 21a4538..25ca7a2 100644 (file)
@@ -117,9 +117,9 @@ static void test_execute_directory(bool gather_stdout) {
         assert_se(chmod(mask2e, 0755) == 0);
 
         if (gather_stdout)
-                execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL);
+                execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
         else
-                execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL, NULL);
+                execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
 
         assert_se(chdir(template_lo) == 0);
         assert_se(access("it_works", F_OK) >= 0);
@@ -184,7 +184,7 @@ static void test_execution_order(void) {
         assert_se(chmod(override, 0755) == 0);
         assert_se(chmod(masked, 0755) == 0);
 
-        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL);
+        execute_directories(dirs, DEFAULT_TIMEOUT_USEC, ignore_stdout, ignore_stdout_args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
 
         assert_se(read_full_file(output, &contents, NULL) >= 0);
         assert_se(streq(contents, "30-override\n80-foo\n90-bar\nlast\n"));
@@ -266,7 +266,7 @@ static void test_stdout_gathering(void) {
         assert_se(chmod(name2, 0755) == 0);
         assert_se(chmod(name3, 0755) == 0);
 
-        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL, NULL);
+        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_stdout, args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
         assert_se(r >= 0);
 
         log_info("got: %s", output);
@@ -332,7 +332,7 @@ static void test_environment_gathering(void) {
         r = setenv("PATH", "no-sh-built-in-path", 1);
         assert_se(r >= 0);
 
-        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, NULL);
+        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
         assert_se(r >= 0);
 
         STRV_FOREACH(p, env)
@@ -349,7 +349,7 @@ static void test_environment_gathering(void) {
         env = strv_new("PATH=" DEFAULT_PATH);
         assert_se(env);
 
-        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, env);
+        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, gather_environment, args, NULL, env, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS);
         assert_se(r >= 0);
 
         STRV_FOREACH(p, env)
@@ -364,6 +364,41 @@ static void test_environment_gathering(void) {
         (void) setenv("PATH", old, 1);
 }
 
+static void test_error_catching(void) {
+        char template[] = "/tmp/test-exec-util.XXXXXXX";
+        const char *dirs[] = {template, NULL};
+        const char *name, *name2, *name3;
+        int r;
+
+        assert_se(mkdtemp(template));
+
+        log_info("/* %s */", __func__);
+
+        /* write files */
+        name = strjoina(template, "/10-foo");
+        name2 = strjoina(template, "/20-bar");
+        name3 = strjoina(template, "/30-last");
+
+        assert_se(write_string_file(name,
+                                    "#!/bin/sh\necho a\necho b\necho c\n",
+                                    WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(write_string_file(name2,
+                                    "#!/bin/sh\nexit 42\n",
+                                    WRITE_STRING_FILE_CREATE) == 0);
+        assert_se(write_string_file(name3,
+                                    "#!/bin/sh\nexit 12",
+                                    WRITE_STRING_FILE_CREATE) == 0);
+
+        assert_se(chmod(name, 0755) == 0);
+        assert_se(chmod(name2, 0755) == 0);
+        assert_se(chmod(name3, 0755) == 0);
+
+        r = execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, NULL, NULL, EXEC_DIR_NONE);
+
+        /* we should exit with the error code of the first script that failed */
+        assert_se(r == 42);
+}
+
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_DEBUG);
 
@@ -372,6 +407,7 @@ int main(int argc, char *argv[]) {
         test_execution_order();
         test_stdout_gathering();
         test_environment_gathering();
+        test_error_catching();
 
         return 0;
 }
index eb8f7c4..9f1cb0c 100644 (file)
@@ -33,7 +33,7 @@ static bool can_unshare;
 
 typedef void (*test_function_t)(Manager *m);
 
-static void check(Manager *m, Unit *unit, int status_expected, int code_expected) {
+static void check(const char *func, Manager *m, Unit *unit, int status_expected, int code_expected) {
         Service *service = NULL;
         usec_t ts;
         usec_t timeout = 2 * USEC_PER_MINUTE;
@@ -62,8 +62,18 @@ static void check(Manager *m, Unit *unit, int status_expected, int code_expected
                 }
         }
         exec_status_dump(&service->main_exec_status, stdout, "\t");
-        assert_se(service->main_exec_status.status == status_expected);
-        assert_se(service->main_exec_status.code == code_expected);
+        if (service->main_exec_status.status != status_expected) {
+                log_error("%s: %s: exit status %d, expected %d",
+                          func, unit->id,
+                          service->main_exec_status.status, status_expected);
+                abort();
+        }
+        if (service->main_exec_status.code != code_expected) {
+                log_error("%s: %s: exit code %d, expected %d",
+                          func, unit->id,
+                          service->main_exec_status.code, code_expected);
+                abort();
+        }
 }
 
 static bool check_nobody_user_and_group(void) {
@@ -148,21 +158,21 @@ static bool is_inaccessible_available(void) {
         return true;
 }
 
-static void test(Manager *m, const char *unit_name, int status_expected, int code_expected) {
+static void test(const char *func, Manager *m, const char *unit_name, int status_expected, int code_expected) {
         Unit *unit;
 
         assert_se(unit_name);
 
         assert_se(manager_load_startable_unit_or_warn(m, unit_name, NULL, &unit) >= 0);
         assert_se(unit_start(unit) >= 0);
-        check(m, unit, status_expected, code_expected);
+        check(func, m, unit, status_expected, code_expected);
 }
 
 static void test_exec_bindpaths(Manager *m) {
         assert_se(mkdir_p("/tmp/test-exec-bindpaths", 0755) >= 0);
         assert_se(mkdir_p("/tmp/test-exec-bindreadonlypaths", 0755) >= 0);
 
-        test(m, "exec-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
 
         (void) rm_rf("/tmp/test-exec-bindpaths", REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf("/tmp/test-exec-bindreadonlypaths", REMOVE_ROOT|REMOVE_PHYSICAL);
@@ -180,8 +190,8 @@ static void test_exec_cpuaffinity(Manager *m) {
                 return;
         }
 
-        test(m, "exec-cpuaffinity1.service", 0, CLD_EXITED);
-        test(m, "exec-cpuaffinity2.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-cpuaffinity1.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-cpuaffinity2.service", 0, CLD_EXITED);
 
         if (CPU_ISSET_S(1, CPU_ALLOC_SIZE(n), c) == 0 ||
             CPU_ISSET_S(2, CPU_ALLOC_SIZE(n), c) == 0) {
@@ -189,52 +199,52 @@ static void test_exec_cpuaffinity(Manager *m) {
                 return;
         }
 
-        test(m, "exec-cpuaffinity3.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-cpuaffinity3.service", 0, CLD_EXITED);
 }
 
 static void test_exec_workingdirectory(Manager *m) {
         assert_se(mkdir_p("/tmp/test-exec_workingdirectory", 0755) >= 0);
 
-        test(m, "exec-workingdirectory.service", 0, CLD_EXITED);
-        test(m, "exec-workingdirectory-trailing-dot.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-workingdirectory.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-workingdirectory-trailing-dot.service", 0, CLD_EXITED);
 
         (void) rm_rf("/tmp/test-exec_workingdirectory", REMOVE_ROOT|REMOVE_PHYSICAL);
 }
 
 static void test_exec_personality(Manager *m) {
 #if defined(__x86_64__)
-        test(m, "exec-personality-x86-64.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-personality-x86-64.service", 0, CLD_EXITED);
 
 #elif defined(__s390__)
-        test(m, "exec-personality-s390.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-personality-s390.service", 0, CLD_EXITED);
 
 #elif defined(__powerpc64__)
 #  if __BYTE_ORDER == __BIG_ENDIAN
-        test(m, "exec-personality-ppc64.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-personality-ppc64.service", 0, CLD_EXITED);
 #  else
-        test(m, "exec-personality-ppc64le.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-personality-ppc64le.service", 0, CLD_EXITED);
 #  endif
 
 #elif defined(__aarch64__)
-        test(m, "exec-personality-aarch64.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-personality-aarch64.service", 0, CLD_EXITED);
 
 #elif defined(__i386__)
-        test(m, "exec-personality-x86.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-personality-x86.service", 0, CLD_EXITED);
 #else
         log_notice("Unknown personality, skipping %s", __func__);
 #endif
 }
 
 static void test_exec_ignoresigpipe(Manager *m) {
-        test(m, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED);
-        test(m, "exec-ignoresigpipe-no.service", SIGPIPE, CLD_KILLED);
+        test(__func__, m, "exec-ignoresigpipe-yes.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-ignoresigpipe-no.service", SIGPIPE, CLD_KILLED);
 }
 
 static void test_exec_privatetmp(Manager *m) {
         assert_se(touch("/tmp/test-exec_privatetmp") >= 0);
 
-        test(m, "exec-privatetmp-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
-        test(m, "exec-privatetmp-no.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-privatetmp-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-privatetmp-no.service", 0, CLD_EXITED);
 
         unlink("/tmp/test-exec_privatetmp");
 }
@@ -251,9 +261,9 @@ static void test_exec_privatedevices(Manager *m) {
                 return;
         }
 
-        test(m, "exec-privatedevices-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
-        test(m, "exec-privatedevices-no.service", 0, CLD_EXITED);
-        test(m, "exec-privatedevices-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-privatedevices-yes.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-privatedevices-no.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-privatedevices-disabled-by-prefix.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
 
         /* We use capsh to test if the capabilities are
          * properly set, so be sure that it exists */
@@ -263,10 +273,19 @@ static void test_exec_privatedevices(Manager *m) {
                 return;
         }
 
-        test(m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
-        test(m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
-        test(m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
-        test(m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-privatedevices-yes-capability-mknod.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-privatedevices-no-capability-mknod.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-privatedevices-yes-capability-sys-rawio.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-privatedevices-no-capability-sys-rawio.service", 0, CLD_EXITED);
+}
+
+static void test_exec_protecthome(Manager *m) {
+        if (!can_unshare) {
+                log_notice("Cannot reliably unshare, skipping %s", __func__);
+                return;
+        }
+
+        test(__func__, m, "exec-protecthome-tmpfs-vs-protectsystem-strict.service", 0, CLD_EXITED);
 }
 
 static void test_exec_protectkernelmodules(Manager *m) {
@@ -287,23 +306,23 @@ static void test_exec_protectkernelmodules(Manager *m) {
                 return;
         }
 
-        test(m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
-        test(m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
-        test(m, "exec-protectkernelmodules-yes-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-protectkernelmodules-no-capabilities.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-protectkernelmodules-yes-capabilities.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-protectkernelmodules-yes-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
 }
 
 static void test_exec_readonlypaths(Manager *m) {
 
-        test(m, "exec-readonlypaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-readonlypaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
 
         if (path_is_read_only_fs("/var") > 0) {
                 log_notice("Directory /var is readonly, skipping remaining tests in %s", __func__);
                 return;
         }
 
-        test(m, "exec-readonlypaths.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
-        test(m, "exec-readonlypaths-with-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
-        test(m, "exec-readonlypaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-readonlypaths.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-readonlypaths-with-bindpaths.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-readonlypaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
 }
 
 static void test_exec_readwritepaths(Manager *m) {
@@ -313,7 +332,7 @@ static void test_exec_readwritepaths(Manager *m) {
                 return;
         }
 
-        test(m, "exec-readwritepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-readwritepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
 }
 
 static void test_exec_inaccessiblepaths(Manager *m) {
@@ -323,22 +342,22 @@ static void test_exec_inaccessiblepaths(Manager *m) {
                 return;
         }
 
-        test(m, "exec-inaccessiblepaths-proc.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-inaccessiblepaths-sys.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
 
         if (path_is_read_only_fs("/") > 0) {
                 log_notice("Root directory is readonly, skipping remaining tests in %s", __func__);
                 return;
         }
 
-        test(m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
 }
 
 static void test_exec_temporaryfilesystem(Manager *m) {
 
-        test(m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
-        test(m, "exec-temporaryfilesystem-ro.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
-        test(m, "exec-temporaryfilesystem-rw.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
-        test(m, "exec-temporaryfilesystem-usr.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-temporaryfilesystem-ro.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-temporaryfilesystem-rw.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-temporaryfilesystem-usr.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
 }
 
 static void test_exec_systemcallfilter(Manager *m) {
@@ -350,10 +369,10 @@ static void test_exec_systemcallfilter(Manager *m) {
                 return;
         }
 
-        test(m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
-        test(m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
-        test(m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
-        test(m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
+        test(__func__, m, "exec-systemcallfilter-not-failing.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-systemcallfilter-not-failing2.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-systemcallfilter-failing.service", SIGSYS, CLD_KILLED);
+        test(__func__, m, "exec-systemcallfilter-failing2.service", SIGSYS, CLD_KILLED);
 
         r = find_binary("python3", NULL);
         if (r < 0) {
@@ -361,9 +380,9 @@ static void test_exec_systemcallfilter(Manager *m) {
                 return;
         }
 
-        test(m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
-        test(m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
-        test(m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED);
+        test(__func__, m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED);
+        test(__func__, m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED);
+        test(__func__, m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED);
 #endif
 }
 
@@ -382,8 +401,8 @@ static void test_exec_systemcallerrornumber(Manager *m) {
                 return;
         }
 
-        test(m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
-        test(m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
+        test(__func__, m, "exec-systemcallerrornumber-name.service", errno_from_name("EACCES"), CLD_EXITED);
+        test(__func__, m, "exec-systemcallerrornumber-number.service", 255, CLD_EXITED);
 #endif
 }
 
@@ -394,13 +413,13 @@ static void test_exec_restrictnamespaces(Manager *m) {
                 return;
         }
 
-        test(m, "exec-restrictnamespaces-no.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
-        test(m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
-        test(m, "exec-restrictnamespaces-mnt.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
-        test(m, "exec-restrictnamespaces-mnt-blacklist.service", 1, CLD_EXITED);
-        test(m, "exec-restrictnamespaces-merge-and.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
-        test(m, "exec-restrictnamespaces-merge-or.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
-        test(m, "exec-restrictnamespaces-merge-all.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-restrictnamespaces-no.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-restrictnamespaces-yes.service", 1, CLD_EXITED);
+        test(__func__, m, "exec-restrictnamespaces-mnt.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-restrictnamespaces-mnt-blacklist.service", 1, CLD_EXITED);
+        test(__func__, m, "exec-restrictnamespaces-merge-and.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-restrictnamespaces-merge-or.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
+        test(__func__, m, "exec-restrictnamespaces-merge-all.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED);
 #endif
 }
 
@@ -411,7 +430,7 @@ static void test_exec_systemcallfilter_system(Manager *m) {
                 return;
         }
 
-        test(m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-systemcallfilter-system-user.service", 0, CLD_EXITED);
 
         if (!check_nobody_user_and_group()) {
                 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -423,12 +442,12 @@ static void test_exec_systemcallfilter_system(Manager *m) {
                 return;
         }
 
-        test(m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+        test(__func__, m, "exec-systemcallfilter-system-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
 #endif
 }
 
 static void test_exec_user(Manager *m) {
-        test(m, "exec-user.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-user.service", 0, CLD_EXITED);
 
         if (!check_nobody_user_and_group()) {
                 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -440,11 +459,11 @@ static void test_exec_user(Manager *m) {
                 return;
         }
 
-        test(m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+        test(__func__, m, "exec-user-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
 }
 
 static void test_exec_group(Manager *m) {
-        test(m, "exec-group.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-group.service", 0, CLD_EXITED);
 
         if (!check_nobody_user_and_group()) {
                 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -456,36 +475,36 @@ static void test_exec_group(Manager *m) {
                 return;
         }
 
-        test(m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
+        test(__func__, m, "exec-group-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
 }
 
 static void test_exec_supplementarygroups(Manager *m) {
-        test(m, "exec-supplementarygroups.service", 0, CLD_EXITED);
-        test(m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
-        test(m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
-        test(m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
-        test(m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
-        test(m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-supplementarygroups.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-supplementarygroups-single-group.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-supplementarygroups-single-group-user.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-supplementarygroups-multiple-groups-default-group-user.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-supplementarygroups-multiple-groups-withgid.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-supplementarygroups-multiple-groups-withuid.service", 0, CLD_EXITED);
 }
 
 static void test_exec_dynamicuser(Manager *m) {
 
-        test(m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
         if (check_user_has_group_with_same_name("adm"))
-                test(m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+                test(__func__, m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
         if (check_user_has_group_with_same_name("games"))
-                test(m, "exec-dynamicuser-fixeduser-games.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
-        test(m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
-        test(m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
-        test(m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+                test(__func__, m, "exec-dynamicuser-fixeduser-games.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-dynamicuser-fixeduser-one-supplementarygroup.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-dynamicuser-supplementarygroups.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-dynamicuser-statedir.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
 
         (void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf("/var/lib/private/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf("/var/lib/private/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
 
-        test(m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
-        test(m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
+        test(__func__, m, "exec-dynamicuser-statedir-migrate-step1.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-dynamicuser-statedir-migrate-step2.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED);
 
         (void) rm_rf("/var/lib/test-dynamicuser-migrate", REMOVE_ROOT|REMOVE_PHYSICAL);
         (void) rm_rf("/var/lib/test-dynamicuser-migrate2", REMOVE_ROOT|REMOVE_PHYSICAL);
@@ -494,9 +513,10 @@ static void test_exec_dynamicuser(Manager *m) {
 }
 
 static void test_exec_environment(Manager *m) {
-        test(m, "exec-environment.service", 0, CLD_EXITED);
-        test(m, "exec-environment-multiple.service", 0, CLD_EXITED);
-        test(m, "exec-environment-empty.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-environment-no-substitute.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-environment.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-environment-multiple.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-environment-empty.service", 0, CLD_EXITED);
 }
 
 static void test_exec_environmentfile(Manager *m) {
@@ -516,7 +536,7 @@ static void test_exec_environmentfile(Manager *m) {
         r = write_string_file("/tmp/test-exec_environmentfile.conf", e, WRITE_STRING_FILE_CREATE);
         assert_se(r == 0);
 
-        test(m, "exec-environmentfile.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-environmentfile.service", 0, CLD_EXITED);
 
         (void) unlink("/tmp/test-exec_environmentfile.conf");
 }
@@ -538,26 +558,26 @@ static void test_exec_passenvironment(Manager *m) {
         assert_se(setenv("VAR3", "$word 5 6", 1) == 0);
         assert_se(setenv("VAR4", "new\nline", 1) == 0);
         assert_se(setenv("VAR5", "passwordwithbackslashes", 1) == 0);
-        test(m, "exec-passenvironment.service", 0, CLD_EXITED);
-        test(m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
-        test(m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-passenvironment.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-passenvironment-repeated.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-passenvironment-empty.service", 0, CLD_EXITED);
         assert_se(unsetenv("VAR1") == 0);
         assert_se(unsetenv("VAR2") == 0);
         assert_se(unsetenv("VAR3") == 0);
         assert_se(unsetenv("VAR4") == 0);
         assert_se(unsetenv("VAR5") == 0);
-        test(m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-passenvironment-absent.service", 0, CLD_EXITED);
 }
 
 static void test_exec_umask(Manager *m) {
-        test(m, "exec-umask-default.service", 0, CLD_EXITED);
-        test(m, "exec-umask-0177.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-umask-default.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-umask-0177.service", 0, CLD_EXITED);
 }
 
 static void test_exec_runtimedirectory(Manager *m) {
-        test(m, "exec-runtimedirectory.service", 0, CLD_EXITED);
-        test(m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
-        test(m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-runtimedirectory.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-runtimedirectory-mode.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-runtimedirectory-owner.service", 0, CLD_EXITED);
 
         if (!check_nobody_user_and_group()) {
                 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -569,7 +589,7 @@ static void test_exec_runtimedirectory(Manager *m) {
                 return;
         }
 
-        test(m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
+        test(__func__, m, "exec-runtimedirectory-owner-" NOBODY_GROUP_NAME ".service", 0, CLD_EXITED);
 }
 
 static void test_exec_capabilityboundingset(Manager *m) {
@@ -588,14 +608,14 @@ static void test_exec_capabilityboundingset(Manager *m) {
                 return;
         }
 
-        test(m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
-        test(m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
-        test(m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
-        test(m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-capabilityboundingset-simple.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-capabilityboundingset-reset.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-capabilityboundingset-merge.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-capabilityboundingset-invert.service", 0, CLD_EXITED);
 }
 
 static void test_exec_basic(Manager *m) {
-        test(m, "exec-basic.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-basic.service", 0, CLD_EXITED);
 }
 
 static void test_exec_ambientcapabilities(Manager *m) {
@@ -617,8 +637,8 @@ static void test_exec_ambientcapabilities(Manager *m) {
                 return;
         }
 
-        test(m, "exec-ambientcapabilities.service", 0, CLD_EXITED);
-        test(m, "exec-ambientcapabilities-merge.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-ambientcapabilities.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-ambientcapabilities-merge.service", 0, CLD_EXITED);
 
         if (!check_nobody_user_and_group()) {
                 log_notice("nobody user/group is not synthesized or may conflict to other entries, skipping remaining tests in %s", __func__);
@@ -630,8 +650,8 @@ static void test_exec_ambientcapabilities(Manager *m) {
                 return;
         }
 
-        test(m, "exec-ambientcapabilities-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
-        test(m, "exec-ambientcapabilities-merge-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+        test(__func__, m, "exec-ambientcapabilities-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
+        test(__func__, m, "exec-ambientcapabilities-merge-" NOBODY_USER_NAME ".service", 0, CLD_EXITED);
 }
 
 static void test_exec_privatenetwork(Manager *m) {
@@ -643,56 +663,63 @@ static void test_exec_privatenetwork(Manager *m) {
                 return;
         }
 
-        test(m, "exec-privatenetwork-yes.service", can_unshare ? 0 : EXIT_NETWORK, CLD_EXITED);
+        test(__func__, m, "exec-privatenetwork-yes.service", can_unshare ? 0 : EXIT_NETWORK, CLD_EXITED);
 }
 
 static void test_exec_oomscoreadjust(Manager *m) {
-        test(m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-oomscoreadjust-positive.service", 0, CLD_EXITED);
 
         if (detect_container() > 0) {
                 log_notice("Testing in container, skipping remaining tests in %s", __func__);
                 return;
         }
-        test(m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-oomscoreadjust-negative.service", 0, CLD_EXITED);
 }
 
 static void test_exec_ioschedulingclass(Manager *m) {
-        test(m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
-        test(m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
-        test(m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-ioschedulingclass-none.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-ioschedulingclass-idle.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-ioschedulingclass-best-effort.service", 0, CLD_EXITED);
 
         if (detect_container() > 0) {
                 log_notice("Testing in container, skipping remaining tests in %s", __func__);
                 return;
         }
-        test(m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-ioschedulingclass-realtime.service", 0, CLD_EXITED);
 }
 
 static void test_exec_unsetenvironment(Manager *m) {
-        test(m, "exec-unsetenvironment.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-unsetenvironment.service", 0, CLD_EXITED);
 }
 
 static void test_exec_specifier(Manager *m) {
-        test(m, "exec-specifier.service", 0, CLD_EXITED);
-        test(m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
-        test(m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-specifier.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-specifier@foo-bar.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-specifier-interpolation.service", 0, CLD_EXITED);
 }
 
 static void test_exec_standardinput(Manager *m) {
-        test(m, "exec-standardinput-data.service", 0, CLD_EXITED);
-        test(m, "exec-standardinput-file.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-standardinput-data.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-standardinput-file.service", 0, CLD_EXITED);
 }
 
 static void test_exec_standardoutput(Manager *m) {
-        test(m, "exec-standardoutput-file.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-standardoutput-file.service", 0, CLD_EXITED);
 }
 
 static void test_exec_standardoutput_append(Manager *m) {
-        test(m, "exec-standardoutput-append.service", 0, CLD_EXITED);
+        test(__func__, m, "exec-standardoutput-append.service", 0, CLD_EXITED);
 }
 
-static int run_tests(UnitFileScope scope, const test_function_t *tests) {
-        const test_function_t *test = NULL;
+typedef struct test_entry {
+        test_function_t f;
+        const char *name;
+} test_entry;
+
+#define entry(x) {x, #x}
+
+static int run_tests(UnitFileScope scope, const test_entry tests[], char **patterns) {
+        const test_entry *test = NULL;
         _cleanup_(manager_freep) Manager *m = NULL;
         int r;
 
@@ -704,57 +731,62 @@ static int run_tests(UnitFileScope scope, const test_function_t *tests) {
         assert_se(r >= 0);
         assert_se(manager_startup(m, NULL, NULL) >= 0);
 
-        for (test = tests; test && *test; test++)
-                (*test)(m);
+        for (test = tests; test && test->f; test++)
+                if (strv_fnmatch_or_empty(patterns, test->name, FNM_NOESCAPE))
+                        test->f(m);
+                else
+                        log_info("Skipping %s because it does not match any pattern.", test->name);
 
         return 0;
 }
 
+
 int main(int argc, char *argv[]) {
         _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
         _cleanup_free_ char *test_execute_path = NULL;
-        _cleanup_hashmap_free_ Hashmap *s = NULL;
-        static const test_function_t user_tests[] = {
-                test_exec_basic,
-                test_exec_ambientcapabilities,
-                test_exec_bindpaths,
-                test_exec_capabilityboundingset,
-                test_exec_cpuaffinity,
-                test_exec_environment,
-                test_exec_environmentfile,
-                test_exec_group,
-                test_exec_ignoresigpipe,
-                test_exec_inaccessiblepaths,
-                test_exec_ioschedulingclass,
-                test_exec_oomscoreadjust,
-                test_exec_passenvironment,
-                test_exec_personality,
-                test_exec_privatedevices,
-                test_exec_privatenetwork,
-                test_exec_privatetmp,
-                test_exec_protectkernelmodules,
-                test_exec_readonlypaths,
-                test_exec_readwritepaths,
-                test_exec_restrictnamespaces,
-                test_exec_runtimedirectory,
-                test_exec_standardinput,
-                test_exec_standardoutput,
-                test_exec_standardoutput_append,
-                test_exec_supplementarygroups,
-                test_exec_systemcallerrornumber,
-                test_exec_systemcallfilter,
-                test_exec_temporaryfilesystem,
-                test_exec_umask,
-                test_exec_unsetenvironment,
-                test_exec_user,
-                test_exec_workingdirectory,
-                NULL,
+
+        static const test_entry user_tests[] = {
+                entry(test_exec_basic),
+                entry(test_exec_ambientcapabilities),
+                entry(test_exec_bindpaths),
+                entry(test_exec_capabilityboundingset),
+                entry(test_exec_cpuaffinity),
+                entry(test_exec_environment),
+                entry(test_exec_environmentfile),
+                entry(test_exec_group),
+                entry(test_exec_ignoresigpipe),
+                entry(test_exec_inaccessiblepaths),
+                entry(test_exec_ioschedulingclass),
+                entry(test_exec_oomscoreadjust),
+                entry(test_exec_passenvironment),
+                entry(test_exec_personality),
+                entry(test_exec_privatedevices),
+                entry(test_exec_privatenetwork),
+                entry(test_exec_privatetmp),
+                entry(test_exec_protecthome),
+                entry(test_exec_protectkernelmodules),
+                entry(test_exec_readonlypaths),
+                entry(test_exec_readwritepaths),
+                entry(test_exec_restrictnamespaces),
+                entry(test_exec_runtimedirectory),
+                entry(test_exec_standardinput),
+                entry(test_exec_standardoutput),
+                entry(test_exec_standardoutput_append),
+                entry(test_exec_supplementarygroups),
+                entry(test_exec_systemcallerrornumber),
+                entry(test_exec_systemcallfilter),
+                entry(test_exec_temporaryfilesystem),
+                entry(test_exec_umask),
+                entry(test_exec_unsetenvironment),
+                entry(test_exec_user),
+                entry(test_exec_workingdirectory),
+                {},
         };
-        static const test_function_t system_tests[] = {
-                test_exec_dynamicuser,
-                test_exec_specifier,
-                test_exec_systemcallfilter_system,
-                NULL,
+        static const test_entry system_tests[] = {
+                entry(test_exec_dynamicuser),
+                entry(test_exec_specifier),
+                entry(test_exec_systemcallfilter_system),
+                {},
         };
         int r;
 
@@ -796,11 +828,11 @@ int main(int argc, char *argv[]) {
         assert_se(unsetenv("VAR2") == 0);
         assert_se(unsetenv("VAR3") == 0);
 
-        r = run_tests(UNIT_FILE_USER, user_tests);
+        r = run_tests(UNIT_FILE_USER, user_tests, argv + 1);
         if (r != 0)
                 return r;
 
-        r = run_tests(UNIT_FILE_SYSTEM, system_tests);
+        r = run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1);
         if (r != 0)
                 return r;
 
@@ -811,6 +843,7 @@ int main(int argc, char *argv[]) {
                 return 0;
         }
 
+        _cleanup_hashmap_free_ Hashmap *s = NULL;
         assert_se(s = hashmap_new(NULL));
         r = seccomp_syscall_resolve_name("unshare");
         assert_se(r != __NR_SCMP_ERROR);
@@ -821,11 +854,11 @@ int main(int argc, char *argv[]) {
 
         can_unshare = false;
 
-        r = run_tests(UNIT_FILE_USER, user_tests);
+        r = run_tests(UNIT_FILE_USER, user_tests, argv + 1);
         if (r != 0)
                 return r;
 
-        return run_tests(UNIT_FILE_SYSTEM, system_tests);
+        return run_tests(UNIT_FILE_SYSTEM, system_tests, argv + 1);
 #else
         return 0;
 #endif
index 7a0a2ad..7137958 100644 (file)
@@ -7,6 +7,7 @@
 #include "fd-util.h"
 #include "fileio.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "path-util.h"
 #include "process-util.h"
 #include "random-util.h"
@@ -14,7 +15,6 @@
 #include "string-util.h"
 #include "tests.h"
 #include "tmpfile-util.h"
-#include "util.h"
 
 static void test_close_many(void) {
         int fds[3];
index 2ddaabe..2ff5b9a 100644 (file)
@@ -629,6 +629,10 @@ static void test_tempfn(void) {
 static const char chars[] =
         "Aąę„”\n루\377";
 
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wtype-limits"
+
 static void test_fgetc(void) {
         _cleanup_fclose_ FILE *f = NULL;
         char c;
@@ -640,7 +644,7 @@ static void test_fgetc(void) {
                 assert_se(safe_fgetc(f, &c) == 1);
                 assert_se(c == chars[i]);
 
-                /* EOF is -1, and hence we can't push value 255 in this way */
+                /* EOF is -1, and hence we can't push value 255 in this way if char is signed */
                 assert_se(ungetc(c, f) != EOF || c == EOF);
                 assert_se(c == EOF || safe_fgetc(f, &c) == 1);
                 assert_se(c == chars[i]);
@@ -654,6 +658,8 @@ static void test_fgetc(void) {
         assert_se(safe_fgetc(f, &c) == 0);
 }
 
+#pragma GCC diagnostic pop
+
 static const char buffer[] =
         "Some test data\n"
         "루Non-ascii chars: ąę„”\n"
@@ -753,7 +759,11 @@ static void test_read_line3(void) {
         assert_se(f);
 
         r = read_line(f, LINE_MAX, &line);
-        assert_se((size_t) r == strlen(line) + 1);
+        assert_se(r >= 0);
+        if (r == 0)
+                assert_se(line && isempty(line));
+        else
+                assert_se((size_t) r == strlen(line) + 1);
         assert_se(read_line(f, LINE_MAX, NULL) == 0);
 }
 
index e049abc..f0f0150 100644 (file)
@@ -154,6 +154,30 @@ static void test_chase_symlinks(void) {
         assert_se(path_equal(result, q));
         result = mfree(result);
 
+        /* Paths underneath the "root" with different UIDs while using CHASE_SAFE */
+
+        if (geteuid() == 0) {
+                p = strjoina(temp, "/user");
+                assert_se(mkdir(p, 0755) >= 0);
+                assert_se(chown(p, UID_NOBODY, GID_NOBODY) >= 0);
+
+                q = strjoina(temp, "/user/root");
+                assert_se(mkdir(q, 0755) >= 0);
+
+                p = strjoina(q, "/link");
+                assert_se(symlink("/", p) >= 0);
+
+                /* Fail when user-owned directories contain root-owned subdirectories. */
+                r = chase_symlinks(p, temp, CHASE_SAFE, &result);
+                assert_se(r == -ENOLINK);
+                result = mfree(result);
+
+                /* Allow this when the user-owned directories are all in the "root". */
+                r = chase_symlinks(p, q, CHASE_SAFE, &result);
+                assert_se(r > 0);
+                result = mfree(result);
+        }
+
         /* Paths using . */
 
         r = chase_symlinks("/etc/./.././", NULL, 0, &result);
index bd873a3..4cd504e 100644 (file)
@@ -1,10 +1,11 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <stdio.h>
+
 #include "alloc-util.h"
 #include "fstab-util.h"
 #include "log.h"
 #include "string-util.h"
-#include "util.h"
 
 /*
 int fstab_filter_options(const char *opts, const char *names,
index 5376aa8..fdb0c7e 100644 (file)
@@ -3,11 +3,12 @@
 #include "alloc-util.h"
 #include "hashmap.h"
 #include "log.h"
+#include "nulstr-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "time-util.h"
 #include "tests.h"
-#include "util.h"
 
 void test_hashmap_funcs(void);
 
index 4126a24..ec34f9c 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <unistd.h>
+
 #include "alloc-util.h"
 #include "fileio.h"
 #include "hostname-util.h"
index ec50e05..8840788 100644 (file)
@@ -1,6 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
 #include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "sd-daemon.h"
 #include "sd-id128.h"
index 16844e9..916bd35 100644 (file)
@@ -1,11 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fnmatch.h>
 #include <netinet/in.h>
 
 #include "log.h"
+#include "strv.h"
 #include "in-addr-util.h"
 
-static void test_in_addr_prefix_from_string(
+static void test_in_addr_prefix_from_string_one(
                 const char *p,
                 int family,
                 int ret,
@@ -55,32 +57,130 @@ static void test_in_addr_prefix_from_string(
         }
 }
 
+static void test_in_addr_prefix_from_string(void) {
+        test_in_addr_prefix_from_string_one("", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
+        test_in_addr_prefix_from_string_one("/", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
+        test_in_addr_prefix_from_string_one("/8", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
+        test_in_addr_prefix_from_string_one("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, -ENOANO, 0, 0, 8);
+        test_in_addr_prefix_from_string_one("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0, 0, 0, 0, 0);
+        test_in_addr_prefix_from_string_one("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1, 0, 1, 0, 1);
+        test_in_addr_prefix_from_string_one("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2, 0, 2, 0, 2);
+        test_in_addr_prefix_from_string_one("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, 0, 32, 0, 32);
+        test_in_addr_prefix_from_string_one("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0);
+        test_in_addr_prefix_from_string_one("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0);
+        test_in_addr_prefix_from_string_one("::1", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
+
+        test_in_addr_prefix_from_string_one("", AF_INET6, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
+        test_in_addr_prefix_from_string_one("/", AF_INET6, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
+        test_in_addr_prefix_from_string_one("/8", AF_INET6, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
+        test_in_addr_prefix_from_string_one("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, -ENOANO, 0, 0, 0);
+        test_in_addr_prefix_from_string_one("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, 0, 0, 0, 0);
+        test_in_addr_prefix_from_string_one("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1, 0, 1, 0, 1);
+        test_in_addr_prefix_from_string_one("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2, 0, 2, 0, 2);
+        test_in_addr_prefix_from_string_one("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32, 0, 32, 0, 32);
+        test_in_addr_prefix_from_string_one("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33, 0, 33, 0, 33);
+        test_in_addr_prefix_from_string_one("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64, 0, 64, 0, 64);
+        test_in_addr_prefix_from_string_one("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, 0, 128, 0, 128);
+        test_in_addr_prefix_from_string_one("::1/129", AF_INET6, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0);
+        test_in_addr_prefix_from_string_one("::1/-1", AF_INET6, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0);
+}
+
+static void test_in_addr_prefix_to_string_valid(int family, const char *p) {
+        _cleanup_free_ char *str = NULL;
+        union in_addr_union u;
+        unsigned char l;
+
+        log_info("/* %s */", p);
+
+        assert_se(in_addr_prefix_from_string(p, family, &u, &l) >= 0);
+        assert_se(in_addr_prefix_to_string(family, &u, l, &str) >= 0);
+        assert_se(streq(str, p));
+}
+
+static void test_in_addr_prefix_to_string_unoptimized(int family, const char *p) {
+        _cleanup_free_ char *str1 = NULL, *str2 = NULL;
+        union in_addr_union u1, u2;
+        unsigned char len1, len2;
+
+        log_info("/* %s */", p);
+
+        assert_se(in_addr_prefix_from_string(p, family, &u1, &len1) >= 0);
+        assert_se(in_addr_prefix_to_string(family, &u1, len1, &str1) >= 0);
+        assert_se(in_addr_prefix_from_string(str1, family, &u2, &len2) >= 0);
+        assert_se(in_addr_prefix_to_string(family, &u2, len2, &str2) >= 0);
+
+        assert_se(streq(str1, str2));
+        assert_se(len1 == len2);
+        assert_se(in_addr_equal(family, &u1, &u2) > 0);
+}
+
+static void test_in_addr_prefix_to_string(void) {
+        test_in_addr_prefix_to_string_valid(AF_INET, "0.0.0.0/32");
+        test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/0");
+        test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/24");
+        test_in_addr_prefix_to_string_valid(AF_INET, "1.2.3.4/32");
+        test_in_addr_prefix_to_string_valid(AF_INET, "255.255.255.255/32");
+
+        test_in_addr_prefix_to_string_valid(AF_INET6, "::1/128");
+        test_in_addr_prefix_to_string_valid(AF_INET6, "fd00:abcd::1/64");
+        test_in_addr_prefix_to_string_valid(AF_INET6, "fd00:abcd::1234:1/64");
+        test_in_addr_prefix_to_string_valid(AF_INET6, "1111:2222:3333:4444:5555:6666:7777:8888/128");
+
+        test_in_addr_prefix_to_string_unoptimized(AF_INET, "0.0.0.0");
+        test_in_addr_prefix_to_string_unoptimized(AF_INET, "192.168.0.1");
+
+        test_in_addr_prefix_to_string_unoptimized(AF_INET6, "fd00:0000:0000:0000:0000:0000:0000:0001/64");
+        test_in_addr_prefix_to_string_unoptimized(AF_INET6, "fd00:1111::0000:2222:3333:4444:0001/64");
+}
+
+static void test_in_addr_random_prefix(void) {
+        _cleanup_free_ char *str = NULL;
+        union in_addr_union a;
+
+        assert_se(in_addr_from_string(AF_INET, "192.168.10.1", &a) >= 0);
+
+        assert_se(in_addr_random_prefix(AF_INET, &a, 31, 32) >= 0);
+        assert_se(in_addr_to_string(AF_INET, &a, &str) >= 0);
+        assert_se(STR_IN_SET(str, "192.168.10.0", "192.168.10.1"));
+        str = mfree(str);
+
+        assert_se(in_addr_random_prefix(AF_INET, &a, 24, 26) >= 0);
+        assert_se(in_addr_to_string(AF_INET, &a, &str) >= 0);
+        assert_se(startswith(str, "192.168.10."));
+        str = mfree(str);
+
+        assert_se(in_addr_random_prefix(AF_INET, &a, 16, 24) >= 0);
+        assert_se(in_addr_to_string(AF_INET, &a, &str) >= 0);
+        assert_se(fnmatch("192.168.[0-9]*.0", str, 0) == 0);
+        str = mfree(str);
+
+        assert_se(in_addr_random_prefix(AF_INET, &a, 8, 24) >= 0);
+        assert_se(in_addr_to_string(AF_INET, &a, &str) >= 0);
+        assert_se(fnmatch("192.[0-9]*.[0-9]*.0", str, 0) == 0);
+        str = mfree(str);
+
+        assert_se(in_addr_random_prefix(AF_INET, &a, 8, 16) >= 0);
+        assert_se(in_addr_to_string(AF_INET, &a, &str) >= 0);
+        assert_se(fnmatch("192.[0-9]*.0.0", str, 0) == 0);
+        str = mfree(str);
+
+        assert_se(in_addr_from_string(AF_INET6, "fd00::1", &a) >= 0);
+
+        assert_se(in_addr_random_prefix(AF_INET6, &a, 16, 64) >= 0);
+        assert_se(in_addr_to_string(AF_INET6, &a, &str) >= 0);
+        assert_se(startswith(str, "fd00:"));
+        str = mfree(str);
+
+        assert_se(in_addr_random_prefix(AF_INET6, &a, 8, 16) >= 0);
+        assert_se(in_addr_to_string(AF_INET6, &a, &str) >= 0);
+        assert_se(fnmatch("fd??::", str, 0) == 0);
+        str = mfree(str);
+}
+
 int main(int argc, char *argv[]) {
-        test_in_addr_prefix_from_string("", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
-        test_in_addr_prefix_from_string("/", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
-        test_in_addr_prefix_from_string("/8", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
-        test_in_addr_prefix_from_string("1.2.3.4", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, -ENOANO, 0, 0, 8);
-        test_in_addr_prefix_from_string("1.2.3.4/0", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 0, 0, 0, 0, 0);
-        test_in_addr_prefix_from_string("1.2.3.4/1", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 1, 0, 1, 0, 1);
-        test_in_addr_prefix_from_string("1.2.3.4/2", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 2, 0, 2, 0, 2);
-        test_in_addr_prefix_from_string("1.2.3.4/32", AF_INET, 0, &(union in_addr_union) { .in = (struct in_addr) { .s_addr = htobe32(0x01020304) } }, 32, 0, 32, 0, 32);
-        test_in_addr_prefix_from_string("1.2.3.4/33", AF_INET, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0);
-        test_in_addr_prefix_from_string("1.2.3.4/-1", AF_INET, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0);
-        test_in_addr_prefix_from_string("::1", AF_INET, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
-
-        test_in_addr_prefix_from_string("", AF_INET6, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
-        test_in_addr_prefix_from_string("/", AF_INET6, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
-        test_in_addr_prefix_from_string("/8", AF_INET6, -EINVAL, NULL, 0, -EINVAL, 0, -EINVAL, 0);
-        test_in_addr_prefix_from_string("::1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, -ENOANO, 0, 0, 0);
-        test_in_addr_prefix_from_string("::1/0", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 0, 0, 0, 0, 0);
-        test_in_addr_prefix_from_string("::1/1", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 1, 0, 1, 0, 1);
-        test_in_addr_prefix_from_string("::1/2", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 2, 0, 2, 0, 2);
-        test_in_addr_prefix_from_string("::1/32", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 32, 0, 32, 0, 32);
-        test_in_addr_prefix_from_string("::1/33", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 33, 0, 33, 0, 33);
-        test_in_addr_prefix_from_string("::1/64", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 64, 0, 64, 0, 64);
-        test_in_addr_prefix_from_string("::1/128", AF_INET6, 0, &(union in_addr_union) { .in6 = IN6ADDR_LOOPBACK_INIT }, 128, 0, 128, 0, 128);
-        test_in_addr_prefix_from_string("::1/129", AF_INET6, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0);
-        test_in_addr_prefix_from_string("::1/-1", AF_INET6, -ERANGE, NULL, 0, -ERANGE, 0, -ERANGE, 0);
+        test_in_addr_prefix_from_string();
+        test_in_addr_random_prefix();
+        test_in_addr_prefix_to_string();
 
         return 0;
 }
index 73ea68f..cfddfe1 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <unistd.h>
+
 #include "alloc-util.h"
 #include "fileio.h"
 #include "install.h"
index fdf1b4f..9b8a2a9 100644 (file)
@@ -8,6 +8,7 @@
 #include "json.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 #include "util.h"
 
 static void test_tokenizer(const char *data, ...) {
@@ -391,6 +392,13 @@ static void test_depth(void) {
                         log_info("max depth at %u", i);
                         break;
                 }
+#if HAS_FEATURE_MEMORY_SANITIZER
+                /* msan doesn't like the stack nesting to be too deep. Let's quit early. */
+                if (i >= 128) {
+                        log_info("quitting early at depth %u", i);
+                        break;
+                }
+#endif
 
                 assert_se(r >= 0);
 
@@ -403,10 +411,7 @@ static void test_depth(void) {
 }
 
 int main(int argc, char *argv[]) {
-
-        log_set_max_level(LOG_DEBUG);
-        log_parse_environment();
-        log_open();
+        test_setup_logging(LOG_DEBUG);
 
         test_tokenizer("x", -EINVAL);
         test_tokenizer("", JSON_TOKEN_END);
diff --git a/src/test/test-libmount.c b/src/test/test-libmount.c
new file mode 100644 (file)
index 0000000..fc28f27
--- /dev/null
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "escape.h"
+#include "libmount-util.h"
+#include "tests.h"
+
+static void test_libmount_unescaping_one(
+                const char *title,
+                const char *string,
+                bool may_fail,
+                const char *expected_source,
+                const char *expected_target) {
+        /* A test for libmount really */
+        int r;
+
+        log_info("/* %s %s */", __func__, title);
+
+        _cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
+        _cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
+        _cleanup_fclose_ FILE *f = NULL;
+
+        assert_se(table = mnt_new_table());
+        assert_se(iter = mnt_new_iter(MNT_ITER_FORWARD));
+
+        f = fmemopen((char*) string, strlen(string), "re");
+        assert_se(f);
+
+        assert_se(mnt_table_parse_stream(table, f, title) >= 0);
+
+        struct libmnt_fs *fs;
+        const char *source, *target;
+        _cleanup_free_ char *x = NULL, *cs = NULL, *s = NULL, *ct = NULL, *t = NULL;
+
+        /* We allow this call and the checks below to fail in some cases. See the case definitions below. */
+
+        r = mnt_table_next_fs(table, iter, &fs);
+        if (r != 0 && may_fail) {
+                log_error_errno(r, "mnt_table_next_fs failed: %m");
+                return;
+        }
+        assert_se(r == 0);
+
+        assert_se(x = cescape(string));
+
+        assert_se(source = mnt_fs_get_source(fs));
+        assert_se(target = mnt_fs_get_target(fs));
+
+        assert_se(cs = cescape(source));
+        assert_se(ct = cescape(target));
+
+        assert_se(cunescape(source, UNESCAPE_RELAX, &s) >= 0);
+        assert_se(cunescape(target, UNESCAPE_RELAX, &t) >= 0);
+
+        log_info("from '%s'", x);
+        log_info("source: '%s'", source);
+        log_info("source: '%s'", cs);
+        log_info("source: '%s'", s);
+        log_info("expected: '%s'", strna(expected_source));
+        log_info("target: '%s'", target);
+        log_info("target: '%s'", ct);
+        log_info("target: '%s'", t);
+        log_info("expected: '%s'", strna(expected_target));
+
+        assert_se(may_fail || streq(source, expected_source));
+        assert_se(may_fail || streq(target, expected_target));
+
+        assert_se(mnt_table_next_fs(table, iter, &fs) == 1);
+}
+
+static void test_libmount_unescaping(void) {
+        test_libmount_unescaping_one(
+                        "escaped space + utf8",
+                        "729 38 0:59 / /tmp/„zupa\\040zębowa” rw,relatime shared:395 - tmpfs die\\040Brühe rw,seclabel",
+                        false,
+                        "die Brühe",
+                        "/tmp/„zupa zębowa”"
+        );
+
+        test_libmount_unescaping_one(
+                        "escaped newline",
+                        "729 38 0:59 / /tmp/x\\012y rw,relatime shared:395 - tmpfs newline rw,seclabel",
+                        false,
+                        "newline",
+                        "/tmp/x\ny"
+        );
+
+        /* The result of "mount -t tmpfs '' /tmp/emptysource".
+         * This will fail with libmount <= v2.33.
+         * See https://github.com/karelzak/util-linux/commit/18a52a5094.
+         */
+        test_libmount_unescaping_one(
+                        "empty source",
+                        "760 38 0:60 / /tmp/emptysource rw,relatime shared:410 - tmpfs  rw,seclabel",
+                        true,
+                        "",
+                        "/tmp/emptysource"
+        );
+
+        /* The kernel leaves \r as is.
+         * Also see https://github.com/karelzak/util-linux/issues/780.
+         */
+        test_libmount_unescaping_one(
+                        "foo\\rbar",
+                        "790 38 0:61 / /tmp/foo\rbar rw,relatime shared:425 - tmpfs tmpfs rw,seclabel",
+                        true,
+                        "tmpfs",
+                        "/tmp/foo\rbar"
+        );
+}
+
+int main(int argc, char *argv[]) {
+        test_setup_logging(LOG_DEBUG);
+
+        test_libmount_unescaping();
+        return 0;
+}
index 15c0f88..f634ca2 100644 (file)
 #include "libudev-list-internal.h"
 #include "libudev-util.h"
 #include "log.h"
+#include "main-func.h"
 #include "stdio-util.h"
 #include "string-util.h"
+#include "tests.h"
+
+static bool arg_monitor = false;
 
 static void print_device(struct udev_device *device) {
         const char *str;
@@ -23,7 +27,7 @@ static void print_device(struct udev_device *device) {
 
         log_info("*** device: %p ***", device);
         str = udev_device_get_action(device);
-        if (str != NULL)
+        if (str)
                 log_info("action:    '%s'", str);
 
         str = udev_device_get_syspath(device);
@@ -33,26 +37,26 @@ static void print_device(struct udev_device *device) {
         log_info("sysname:   '%s'", str);
 
         str = udev_device_get_sysnum(device);
-        if (str != NULL)
+        if (str)
                 log_info("sysnum:    '%s'", str);
 
         str = udev_device_get_devpath(device);
         log_info("devpath:   '%s'", str);
 
         str = udev_device_get_subsystem(device);
-        if (str != NULL)
+        if (str)
                 log_info("subsystem: '%s'", str);
 
         str = udev_device_get_devtype(device);
-        if (str != NULL)
+        if (str)
                 log_info("devtype:   '%s'", str);
 
         str = udev_device_get_driver(device);
-        if (str != NULL)
+        if (str)
                 log_info("driver:    '%s'", str);
 
         str = udev_device_get_devnode(device);
-        if (str != NULL)
+        if (str)
                 log_info("devname:   '%s'", str);
 
         devnum = udev_device_get_devnum(device);
@@ -78,30 +82,30 @@ static void print_device(struct udev_device *device) {
                 log_info("found %i properties", count);
 
         str = udev_device_get_property_value(device, "MAJOR");
-        if (str != NULL)
+        if (str)
                 log_info("MAJOR: '%s'", str);
 
         str = udev_device_get_sysattr_value(device, "dev");
-        if (str != NULL)
+        if (str)
                 log_info("attr{dev}: '%s'", str);
 }
 
 static void test_device(struct udev *udev, const char *syspath) {
         _cleanup_(udev_device_unrefp) struct udev_device *device;
 
-        log_info("looking at device: %s", syspath);
+        log_info("/* %s, device %s */", __func__, syspath);
         device = udev_device_new_from_syspath(udev, syspath);
-        if (device == NULL)
-                log_warning_errno(errno, "udev_device_new_from_syspath: %m");
-        else
+        if (device)
                 print_device(device);
+        else
+                log_warning_errno(errno, "udev_device_new_from_syspath: %m");
 }
 
 static void test_device_parents(struct udev *udev, const char *syspath) {
         _cleanup_(udev_device_unrefp) struct udev_device *device;
         struct udev_device *device_parent;
 
-        log_info("looking at device: %s", syspath);
+        log_info("/* %s, device %s */", __func__, syspath);
         device = udev_device_new_from_syspath(udev, syspath);
         if (device == NULL)
                 return;
@@ -125,12 +129,13 @@ static void test_device_devnum(struct udev *udev) {
         dev_t devnum = makedev(1, 3);
         _cleanup_(udev_device_unrefp) struct udev_device *device;
 
-        log_info("looking up device: %u:%u", major(devnum), minor(devnum));
+        log_info("/* %s, device %d:%d */", __func__, major(devnum), minor(devnum));
+
         device = udev_device_new_from_devnum(udev, 'c', devnum);
-        if (device == NULL)
-                log_warning_errno(errno, "udev_device_new_from_devnum: %m");
-        else
+        if (device)
                 print_device(device);
+        else
+                log_warning_errno(errno, "udev_device_new_from_devnum: %m");
 }
 
 static void test_device_subsys_name(struct udev *udev, const char *subsys, const char *dev) {
@@ -144,7 +149,7 @@ static void test_device_subsys_name(struct udev *udev, const char *subsys, const
                 print_device(device);
 }
 
-static int test_enumerate_print_list(struct udev_enumerate *enumerate) {
+static int enumerate_print_list(struct udev_enumerate *enumerate) {
         struct udev_list_entry *list_entry;
         int count = 0;
 
@@ -176,6 +181,8 @@ static void test_monitor(struct udev *udev) {
                 .data.fd = STDIN_FILENO,
         };
 
+        log_info("/* %s */", __func__);
+
         fd_ep = epoll_create1(EPOLL_CLOEXEC);
         assert_se(fd_ep >= 0);
 
@@ -225,8 +232,9 @@ static void test_queue(struct udev *udev) {
         struct udev_queue *udev_queue;
         bool empty;
 
-        udev_queue = udev_queue_new(udev);
-        assert_se(udev_queue);
+        log_info("/* %s */", __func__);
+
+        assert_se(udev_queue = udev_queue_new(udev));
 
         empty = udev_queue_get_queue_is_empty(udev_queue);
         log_info("queue is %s", empty ? "empty" : "not empty");
@@ -237,13 +245,15 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
         struct udev_enumerate *udev_enumerate;
         int r;
 
+        log_info("/* %s */", __func__);
+
         log_info("enumerate '%s'", subsystem == NULL ? "<all>" : subsystem);
         udev_enumerate = udev_enumerate_new(udev);
         if (udev_enumerate == NULL)
                 return -1;
         udev_enumerate_add_match_subsystem(udev_enumerate, subsystem);
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'net' + duplicated scan + null + zero");
@@ -263,7 +273,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
         udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
         udev_enumerate_add_syspath(udev_enumerate, "/sys/class/mem/zero");
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'block'");
@@ -277,7 +287,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
                 return r;
         }
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'not block'");
@@ -286,7 +296,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
                 return -1;
         udev_enumerate_add_nomatch_subsystem(udev_enumerate, "block");
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'pci, mem, vc'");
@@ -297,7 +307,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
         udev_enumerate_add_match_subsystem(udev_enumerate, "mem");
         udev_enumerate_add_match_subsystem(udev_enumerate, "vc");
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'subsystem'");
@@ -305,7 +315,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
         if (udev_enumerate == NULL)
                 return -1;
         udev_enumerate_scan_subsystems(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
 
         log_info("enumerate 'property IF_FS_*=filesystem'");
@@ -314,7 +324,7 @@ static int test_enumerate(struct udev *udev, const char *subsystem) {
                 return -1;
         udev_enumerate_add_match_property(udev_enumerate, "ID_FS*", "filesystem");
         udev_enumerate_scan_devices(udev_enumerate);
-        test_enumerate_print_list(udev_enumerate);
+        enumerate_print_list(udev_enumerate);
         udev_enumerate_unref(udev_enumerate);
         return 0;
 }
@@ -323,7 +333,11 @@ static void test_hwdb(struct udev *udev, const char *modalias) {
         struct udev_hwdb *hwdb;
         struct udev_list_entry *entry;
 
+        log_info("/* %s */", __func__);
+
         hwdb = udev_hwdb_new(udev);
+        if (!hwdb)
+                log_warning_errno(errno, "Failed to open hwdb: %m");
 
         udev_list_entry_foreach(entry, udev_hwdb_get_properties_list_entry(hwdb, modalias, 0))
                 log_info("'%s'='%s'", udev_list_entry_get_name(entry), udev_list_entry_get_value(entry));
@@ -348,6 +362,8 @@ static void test_util_replace_whitespace_one(const char *str, const char *expect
 }
 
 static void test_util_replace_whitespace(void) {
+        log_info("/* %s */", __func__);
+
         test_util_replace_whitespace_one("hogehoge", "hogehoge");
         test_util_replace_whitespace_one("hoge  hoge", "hoge_hoge");
         test_util_replace_whitespace_one("  hoge  hoge  ", "hoge_hoge");
@@ -385,16 +401,19 @@ static void test_util_replace_whitespace(void) {
 }
 
 static void test_util_resolve_subsys_kernel_one(const char *str, bool read_value, int retval, const char *expected) {
-        char result[UTIL_PATH_SIZE];
+        char result[UTIL_PATH_SIZE] = "";
         int r;
 
         r = util_resolve_subsys_kernel(str, result, sizeof(result), read_value);
+        log_info("\"%s\" → expect: \"%s\", %d, actual: \"%s\", %d", str, strnull(expected), retval, result, r);
         assert_se(r == retval);
         if (r >= 0)
                 assert_se(streq(result, expected));
 }
 
 static void test_util_resolve_subsys_kernel(void) {
+        log_info("/* %s */", __func__);
+
         test_util_resolve_subsys_kernel_one("hoge", false, -EINVAL, NULL);
         test_util_resolve_subsys_kernel_one("[hoge", false, -EINVAL, NULL);
         test_util_resolve_subsys_kernel_one("[hoge/foo", false, -EINVAL, NULL);
@@ -471,9 +490,7 @@ static void test_list(void) {
         udev_list_cleanup(&list);
 }
 
-int main(int argc, char *argv[]) {
-        _cleanup_(udev_unrefp) struct udev *udev = NULL;
-        bool arg_monitor = false;
+static int parse_args(int argc, char *argv[], const char **syspath, const char **subsystem) {
         static const struct option options[] = {
                 { "syspath",   required_argument, NULL, 'p' },
                 { "subsystem", required_argument, NULL, 's' },
@@ -483,52 +500,59 @@ int main(int argc, char *argv[]) {
                 { "monitor",   no_argument,       NULL, 'm' },
                 {}
         };
-        const char *syspath = "/devices/virtual/mem/null";
-        const char *subsystem = NULL;
         int c;
 
-        udev = udev_new();
-        log_info("context: %p", udev);
-        if (udev == NULL) {
-                log_info("no context");
-                return 1;
-        }
-
         while ((c = getopt_long(argc, argv, "p:s:dhVm", options, NULL)) >= 0)
                 switch (c) {
-
                 case 'p':
-                        syspath = optarg;
+                        *syspath = optarg;
                         break;
 
                 case 's':
-                        subsystem = optarg;
+                        *subsystem = optarg;
                         break;
 
                 case 'd':
-                        if (log_get_max_level() < LOG_INFO)
-                                log_set_max_level(LOG_INFO);
+                        log_set_max_level(LOG_DEBUG);
                         break;
 
                 case 'h':
                         printf("--debug --syspath= --subsystem= --help\n");
-                        return EXIT_SUCCESS;
+                        return 0;
 
                 case 'V':
                         printf("%s\n", GIT_VERSION);
-                        return EXIT_SUCCESS;
+                        return 0;
 
                 case 'm':
                         arg_monitor = true;
                         break;
 
                 case '?':
-                        return EXIT_FAILURE;
+                        return -EINVAL;
 
                 default:
                         assert_not_reached("Unhandled option code.");
                 }
 
+        return 1;
+}
+
+static int run(int argc, char *argv[]) {
+        _cleanup_(udev_unrefp) struct udev *udev = NULL;
+
+        const char *syspath = "/devices/virtual/mem/null";
+        const char *subsystem = NULL;
+        int r;
+
+        test_setup_logging(LOG_INFO);
+
+        r = parse_args(argc, argv, &syspath, &subsystem);
+        if (r <= 0)
+                return r;
+
+        assert_se(udev = udev_new());
+
         /* add sys path if needed */
         if (!startswith(syspath, "/sys"))
                 syspath = strjoina("/sys/", syspath);
@@ -555,5 +579,7 @@ int main(int argc, char *argv[]) {
 
         test_list();
 
-        return EXIT_SUCCESS;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);
index c6f8c1f..28d90be 100644 (file)
@@ -1,8 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include "kbd-util.h"
 #include "locale-util.h"
 #include "macro.h"
 #include "strv.h"
+#include "util.h"
 
 static void test_get_locales(void) {
         _cleanup_strv_free_ char **locales = NULL;
index 1e010c0..18ef56a 100644 (file)
@@ -59,15 +59,22 @@ static void test_long_lines(void) {
                             "asdfasdf %s asdfasdfa", "foobar");
 }
 
+static void test_log_syntax(void) {
+        assert_se(log_syntax("unit", LOG_ERR, "filename", 10, EINVAL, "EINVAL: %s: %m", "hogehoge") == -EINVAL);
+        assert_se(log_syntax("unit", LOG_ERR, "filename", 10, -ENOENT, "ENOENT: %s: %m", "hogehoge") == -ENOENT);
+        assert_se(log_syntax("unit", LOG_ERR, "filename", 10, SYNTHETIC_ERRNO(ENOTTY), "ENOTTY: %s: %m", "hogehoge") == -ENOTTY);
+}
+
 int main(int argc, char* argv[]) {
         int target;
 
-        for (target = 0; target <  _LOG_TARGET_MAX; target++) {
+        for (target = 0; target < _LOG_TARGET_MAX; target++) {
                 log_set_target(target);
                 log_open();
 
                 test_log_struct();
                 test_long_lines();
+                test_log_syntax();
         }
 
         assert_se(log_info_errno(SYNTHETIC_ERRNO(EUCLEAN), "foo") == -EUCLEAN);
index 8e45c0b..8c5aac8 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <sys/mount.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "def.h"
@@ -36,7 +37,7 @@ static void test_mount_propagation_flags(const char *name, int ret, unsigned lon
 
 static void test_mnt_id(void) {
         _cleanup_fclose_ FILE *f = NULL;
-        Hashmap *h;
+        _cleanup_hashmap_free_free_ Hashmap *h = NULL;
         Iterator i;
         char *p;
         void *k;
@@ -57,7 +58,14 @@ static void test_mnt_id(void) {
                 assert_se(r > 0);
 
                 assert_se(sscanf(line, "%i %*s %*s %*s %ms", &mnt_id, &path) == 2);
-
+#if HAS_FEATURE_MEMORY_SANITIZER
+                /* We don't know the length of the string, so we need to unpoison it one char at a time */
+                for (const char *c = path; ;c++) {
+                        msan_unpoison(c, 1);
+                        if (!*c)
+                                break;
+                }
+#endif
                 log_debug("mountinfo: %s → %i", path, mnt_id);
 
                 assert_se(hashmap_put(h, INT_TO_PTR(mnt_id), path) >= 0);
@@ -84,8 +92,6 @@ static void test_mnt_id(void) {
                 log_debug("the other path for mnt id %i is %s\n", mnt_id2, t);
                 assert_se(path_equal(p, t));
         }
-
-        hashmap_free_free(h);
 }
 
 static void test_path_is_mount_point(void) {
index cc2efec..73ad2b2 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <sys/socket.h>
+#include <sys/stat.h>
 
 #include "alloc-util.h"
 #include "fd-util.h"
index 20aa6cf..27afe36 100644 (file)
@@ -3,6 +3,7 @@
 #include <dlfcn.h>
 #include <net/if.h>
 #include <stdlib.h>
+#include <unistd.h>
 
 #include "af-list.h"
 #include "alloc-util.h"
 #include "in-addr-util.h"
 #include "local-addresses.h"
 #include "log.h"
+#include "main-func.h"
 #include "nss-util.h"
 #include "path-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 
 static const char* nss_status_to_string(enum nss_status status, char *buf, size_t buf_len) {
         switch (status) {
@@ -485,7 +488,7 @@ static int parse_argv(int argc, char **argv,
         return 0;
 }
 
-int main(int argc, char **argv) {
+static int run(int argc, char **argv) {
         _cleanup_free_ char *dir = NULL;
         _cleanup_strv_free_ char **modules = NULL, **names = NULL;
         _cleanup_free_ struct local_address *addresses = NULL;
@@ -493,8 +496,7 @@ int main(int argc, char **argv) {
         char **module;
         int r;
 
-        log_set_max_level(LOG_INFO);
-        log_parse_environment();
+        test_setup_logging(LOG_INFO);
 
         r = parse_argv(argc, argv, &modules, &names, &addresses, &n_addresses);
         if (r < 0) {
@@ -504,13 +506,15 @@ int main(int argc, char **argv) {
 
         dir = dirname_malloc(argv[0]);
         if (!dir)
-                return EXIT_FAILURE;
+                return log_oom();
 
         STRV_FOREACH(module, modules) {
                 r = test_one_module(dir, *module, names, addresses, n_addresses);
                 if (r < 0)
-                        return EXIT_FAILURE;
+                        return r;
         }
 
-        return EXIT_SUCCESS;
+        return 0;
 }
+
+DEFINE_MAIN_FUNCTION(run);
diff --git a/src/test/test-ordered-set.c b/src/test/test-ordered-set.c
new file mode 100644 (file)
index 0000000..0d29fcf
--- /dev/null
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <stdio.h>
+
+#include "ordered-set.h"
+#include "string-util.h"
+#include "strv.h"
+
+static void test_set_steal_first(void) {
+        _cleanup_ordered_set_free_ OrderedSet *m = NULL;
+        int seen[3] = {};
+        char *val;
+
+        m = ordered_set_new(&string_hash_ops);
+        assert_se(m);
+
+        assert_se(ordered_set_put(m, (void*) "1") == 1);
+        assert_se(ordered_set_put(m, (void*) "22") == 1);
+        assert_se(ordered_set_put(m, (void*) "333") == 1);
+
+        ordered_set_print(stdout, "SET=", m);
+
+        while ((val = ordered_set_steal_first(m)))
+                seen[strlen(val) - 1]++;
+
+        assert_se(seen[0] == 1 && seen[1] == 1 && seen[2] == 1);
+
+        assert_se(ordered_set_isempty(m));
+
+        ordered_set_print(stdout, "SET=", m);
+}
+
+typedef struct Item {
+        int seen;
+} Item;
+static void item_seen(Item *item) {
+        item->seen++;
+}
+
+DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(item_hash_ops, void, trivial_hash_func, trivial_compare_func, Item, item_seen);
+
+static void test_set_free_with_hash_ops(void) {
+        OrderedSet *m;
+        struct Item items[4] = {};
+        unsigned i;
+
+        assert_se(m = ordered_set_new(&item_hash_ops));
+        for (i = 0; i < ELEMENTSOF(items) - 1; i++)
+                assert_se(ordered_set_put(m, items + i) == 1);
+
+        m = ordered_set_free(m);
+        assert_se(items[0].seen == 1);
+        assert_se(items[1].seen == 1);
+        assert_se(items[2].seen == 1);
+        assert_se(items[3].seen == 0);
+}
+
+static void test_set_put(void) {
+        _cleanup_ordered_set_free_ OrderedSet *m = NULL;
+        _cleanup_free_ char **t = NULL;
+
+        m = ordered_set_new(&string_hash_ops);
+        assert_se(m);
+
+        assert_se(ordered_set_put(m, (void*) "1") == 1);
+        assert_se(ordered_set_put(m, (void*) "22") == 1);
+        assert_se(ordered_set_put(m, (void*) "333") == 1);
+        assert_se(ordered_set_put(m, (void*) "333") == 0);
+        assert_se(ordered_set_remove(m, (void*) "333"));
+        assert_se(ordered_set_put(m, (void*) "333") == 1);
+        assert_se(ordered_set_put(m, (void*) "333") == 0);
+        assert_se(ordered_set_put(m, (void*) "22") == 0);
+
+        assert_se(t = ordered_set_get_strv(m));
+        assert_se(streq(t[0], "1"));
+        assert_se(streq(t[1], "22"));
+        assert_se(streq(t[2], "333"));
+        assert_se(!t[3]);
+
+        ordered_set_print(stdout, "FOO=", m);
+}
+
+static void test_set_put_string_set(void) {
+        _cleanup_ordered_set_free_free_ OrderedSet *m = NULL;
+        _cleanup_ordered_set_free_ OrderedSet *q = NULL;
+        _cleanup_free_ char **final = NULL; /* "just free" because the strings are in the set */
+        void *t;
+
+        m = ordered_set_new(&string_hash_ops);
+        assert_se(m);
+
+        q = ordered_set_new(&string_hash_ops);
+        assert_se(q);
+
+        assert_se(t = strdup("1"));
+        assert_se(ordered_set_put(m, t) == 1);
+        assert_se(t = strdup("22"));
+        assert_se(ordered_set_put(m, t) == 1);
+        assert_se(t = strdup("333"));
+        assert_se(ordered_set_put(m, t) == 1);
+
+        assert_se(ordered_set_put(q, (void*) "11") == 1);
+        assert_se(ordered_set_put(q, (void*) "22") == 1);
+        assert_se(ordered_set_put(q, (void*) "33") == 1);
+
+        assert_se(ordered_set_put_string_set(m, q) == 2);
+
+        assert_se(final = ordered_set_get_strv(m));
+        assert_se(strv_equal(final, STRV_MAKE("1", "22", "333", "11", "33")));
+
+        ordered_set_print(stdout, "BAR=", m);
+}
+
+int main(int argc, const char *argv[]) {
+        test_set_steal_first();
+        test_set_free_with_hash_ops();
+        test_set_put();
+        test_set_put_string_set();
+
+        return 0;
+}
index c64ca7b..1829916 100644 (file)
@@ -179,7 +179,14 @@ static void test_find_binary(const char *self) {
 }
 
 static void test_prefixes(void) {
-        static const char* values[] = { "/a/b/c/d", "/a/b/c", "/a/b", "/a", "", NULL};
+        static const char* const values[] = {
+                "/a/b/c/d",
+                "/a/b/c",
+                "/a/b",
+                "/a",
+                "",
+                NULL
+        };
         unsigned i;
         char s[PATH_MAX];
         bool b;
index 53ec512..3ad80d1 100644 (file)
@@ -1,6 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "macro.h"
index 53c9e09..21d5b44 100644 (file)
@@ -6,7 +6,7 @@
 #include "prioq.h"
 #include "set.h"
 #include "siphash24.h"
-#include "util.h"
+#include "sort-util.h"
 
 #define SET_SIZE 1024*4
 
index b0fc217..4e209de 100644 (file)
@@ -92,7 +92,7 @@ static void test_proc_cmdline_get_key(void) {
         _cleanup_free_ char *value = NULL;
 
         log_info("/* %s */", __func__);
-        assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm spaaace='ö ü ß' ticks=\"''\"") == 0);
+        assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm spaaace='ö ü ß' ticks=\"''\"\n\nkkk=uuu\n\n\n") == 0);
 
         assert_se(proc_cmdline_get_key("", 0, &value) == -EINVAL);
         assert_se(proc_cmdline_get_key("abc", 0, NULL) == 0);
@@ -129,13 +129,16 @@ static void test_proc_cmdline_get_key(void) {
         value = mfree(value);
 
         assert_se(proc_cmdline_get_key("ticks", 0, &value) > 0 && streq_ptr(value, "''"));
+        value = mfree(value);
+
+        assert_se(proc_cmdline_get_key("kkk", 0, &value) > 0 && streq_ptr(value, "uuu"));
 }
 
 static void test_proc_cmdline_get_bool(void) {
         bool value = false;
 
         log_info("/* %s */", __func__);
-        assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar bar-waldo=1 x_y-z=0 quux=miep") == 0);
+        assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar bar-waldo=1 x_y-z=0 quux=miep\nda=yes\nthe=1") == 0);
 
         assert_se(proc_cmdline_get_bool("", &value) == -EINVAL);
         assert_se(proc_cmdline_get_bool("abc", &value) == 0 && value == false);
@@ -148,13 +151,15 @@ static void test_proc_cmdline_get_bool(void) {
         assert_se(proc_cmdline_get_bool("x-y_z", &value) > 0 && value == false);
         assert_se(proc_cmdline_get_bool("x_y_z", &value) > 0 && value == false);
         assert_se(proc_cmdline_get_bool("quux", &value) == -EINVAL && value == false);
+        assert_se(proc_cmdline_get_bool("da", &value) > 0 && value == true);
+        assert_se(proc_cmdline_get_bool("the", &value) > 0 && value == true);
 }
 
 static void test_proc_cmdline_get_key_many(void) {
-        _cleanup_free_ char *value1 = NULL, *value2 = NULL, *value3 = NULL, *value4 = NULL, *value5 = NULL, *value6 = NULL;
+        _cleanup_free_ char *value1 = NULL, *value2 = NULL, *value3 = NULL, *value4 = NULL, *value5 = NULL, *value6 = NULL, *value7 = NULL;
 
         log_info("/* %s */", __func__);
-        assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm SPACE='one two' doubleticks=\" aaa aaa \"") == 0);
+        assert_se(putenv((char*) "SYSTEMD_PROC_CMDLINE=foo_bar=quux wuff-piep=tuet zumm SPACE='one two' doubleticks=\" aaa aaa \"\n\nzummm='\n'\n") == 0);
 
         assert_se(proc_cmdline_get_key_many(0,
                                             "wuff-piep", &value3,
@@ -162,7 +167,9 @@ static void test_proc_cmdline_get_key_many(void) {
                                             "idontexist", &value2,
                                             "zumm", &value4,
                                             "SPACE", &value5,
-                                            "doubleticks", &value6) == 4);
+                                            "doubleticks", &value6,
+                                            "zummm", &value7) == 5);
+
 
         assert_se(streq_ptr(value1, "quux"));
         assert_se(!value2);
@@ -170,6 +177,7 @@ static void test_proc_cmdline_get_key_many(void) {
         assert_se(!value4);
         assert_se(streq_ptr(value5, "one two"));
         assert_se(streq_ptr(value6, " aaa aaa "));
+        assert_se(streq_ptr(value7, "\n"));
 }
 
 static void test_proc_cmdline_key_streq(void) {
index b5ba651..89f6618 100644 (file)
@@ -603,8 +603,7 @@ static void test_ioprio_class_from_to_string(void) {
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_DEBUG);
 
-        saved_argc = argc;
-        saved_argv = argv;
+        save_argc_argv(argc, argv);
 
         if (argc > 1) {
                 pid_t pid = 0;
index 55208b1..8620e72 100644 (file)
@@ -1,11 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
-#include <string.h>
+#include <stdio.h>
 
 #include "macro.h"
 #include "replace-var.h"
 #include "string-util.h"
-#include "util.h"
 
 static char *lookup(const char *variable, void *userdata) {
         return strjoin("<<<", variable, ">>>");
index 771719a..fac3012 100644 (file)
@@ -8,7 +8,7 @@
 #include "missing.h"
 #include "rlimit-util.h"
 #include "string-util.h"
-#include "util.h"
+#include "time-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;
index fbfeedd..9b7307c 100644 (file)
@@ -7,21 +7,25 @@
 #include <sys/mman.h>
 #include <sys/personality.h>
 #include <sys/shm.h>
+#include <sys/syscall.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "nsflags.h"
+#include "nulstr-util.h"
 #include "process-util.h"
 #include "raw-clone.h"
+#include "rm-rf.h"
 #include "seccomp-util.h"
 #include "set.h"
 #include "string-util.h"
 #include "tests.h"
-#include "util.h"
+#include "tmpfile-util.h"
 #include "virt.h"
 
 #if SCMP_SYS(socket) < 0 || defined(__i386__) || defined(__s390x__) || defined(__s390__)
@@ -506,9 +510,18 @@ static void test_memory_deny_write_execute_mmap(void) {
 static void test_memory_deny_write_execute_shmat(void) {
         int shmid;
         pid_t pid;
+        uint32_t arch;
 
         log_info("/* %s */", __func__);
 
+        SECCOMP_FOREACH_LOCAL_ARCH(arch) {
+                log_debug("arch %s: SCMP_SYS(mmap) = %d", seccomp_arch_to_string(arch), SCMP_SYS(mmap));
+                log_debug("arch %s: SCMP_SYS(mmap2) = %d", seccomp_arch_to_string(arch), SCMP_SYS(mmap2));
+                log_debug("arch %s: SCMP_SYS(shmget) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmget));
+                log_debug("arch %s: SCMP_SYS(shmat) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmat));
+                log_debug("arch %s: SCMP_SYS(shmdt) = %d", seccomp_arch_to_string(arch), SCMP_SYS(shmdt));
+        }
+
         if (!is_seccomp_available()) {
                 log_notice("Seccomp not available, skipping %s", __func__);
                 return;
@@ -538,15 +551,18 @@ static void test_memory_deny_write_execute_shmat(void) {
                 assert_se(seccomp_memory_deny_write_execute() >= 0);
 
                 p = shmat(shmid, NULL, SHM_EXEC);
+                log_debug_errno(p == MAP_FAILED ? errno : 0, "shmat(SHM_EXEC): %m");
 #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
                 assert_se(p == MAP_FAILED);
                 assert_se(errno == EPERM);
-#else /* __i386__, __powerpc64__, and "unknown" architectures */
-                assert_se(p != MAP_FAILED);
-                assert_se(shmdt(p) == 0);
 #endif
+                /* Depending on kernel, libseccomp, and glibc versions, other architectures
+                 * might fail or not. Let's not assert success. */
+                if (p != MAP_FAILED)
+                        assert_se(shmdt(p) == 0);
 
                 p = shmat(shmid, NULL, 0);
+                log_debug_errno(p == MAP_FAILED ? errno : 0, "shmat(0): %m");
                 assert_se(p != MAP_FAILED);
                 assert_se(shmdt(p) == 0);
 
@@ -746,6 +762,216 @@ static void test_lock_personality(void) {
         assert_se(wait_for_terminate_and_check("lockpersonalityseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
 }
 
+static int real_open(const char *path, int flags, mode_t mode) {
+        /* glibc internally calls openat() when open() is requested. Let's hence define our own wrapper for
+         * testing purposes that calls the real syscall, on architectures where SYS_open is defined. On
+         * other architectures, let's just fall back to the glibc call. */
+
+#ifdef SYS_open
+        return (int) syscall(SYS_open, path, flags, mode);
+#else
+        return open(path, flags, mode);
+#endif
+}
+
+static void test_restrict_suid_sgid(void) {
+        pid_t pid;
+
+        log_info("/* %s */", __func__);
+
+        if (!is_seccomp_available()) {
+                log_notice("Seccomp not available, skipping %s", __func__);
+                return;
+        }
+        if (geteuid() != 0) {
+                log_notice("Not root, skipping %s", __func__);
+                return;
+        }
+
+        pid = fork();
+        assert_se(pid >= 0);
+
+        if (pid == 0) {
+                char path[] = "/tmp/suidsgidXXXXXX", dir[] = "/tmp/suidsgiddirXXXXXX";
+                int fd = -1, k = -1;
+                const char *z;
+
+                fd = mkostemp_safe(path);
+                assert_se(fd >= 0);
+
+                assert_se(mkdtemp(dir));
+                z = strjoina(dir, "/test");
+
+                assert_se(chmod(path, 0755 | S_ISUID) >= 0);
+                assert_se(chmod(path, 0755 | S_ISGID) >= 0);
+                assert_se(chmod(path, 0755 | S_ISGID | S_ISUID) >= 0);
+                assert_se(chmod(path, 0755) >= 0);
+
+                assert_se(fchmod(fd, 0755 | S_ISUID) >= 0);
+                assert_se(fchmod(fd, 0755 | S_ISGID) >= 0);
+                assert_se(fchmod(fd, 0755 | S_ISGID | S_ISUID) >= 0);
+                assert_se(fchmod(fd, 0755) >= 0);
+
+                assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) >= 0);
+                assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) >= 0);
+                assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) >= 0);
+                assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
+
+                k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = creat(z, 0644 | S_ISUID);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = creat(z, 0644 | S_ISGID);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = creat(z, 0644 | S_ISUID | S_ISGID);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = creat(z, 0644);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                assert_se(mkdir(z, 0755 | S_ISUID) >= 0);
+                assert_se(rmdir(z) >= 0);
+                assert_se(mkdir(z, 0755 | S_ISGID) >= 0);
+                assert_se(rmdir(z) >= 0);
+                assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) >= 0);
+                assert_se(rmdir(z) >= 0);
+                assert_se(mkdir(z, 0755) >= 0);
+                assert_se(rmdir(z) >= 0);
+
+                assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) >= 0);
+                assert_se(rmdir(z) >= 0);
+                assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) >= 0);
+                assert_se(rmdir(z) >= 0);
+                assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) >= 0);
+                assert_se(rmdir(z) >= 0);
+                assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0);
+                assert_se(rmdir(z) >= 0);
+
+                assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+                assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+                assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+                assert_se(mknod(z, S_IFREG | 0755, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+
+                assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+                assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+                assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+                assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+
+                assert_se(seccomp_restrict_suid_sgid() >= 0);
+
+                assert_se(chmod(path, 0775 | S_ISUID) < 0 && errno == EPERM);
+                assert_se(chmod(path, 0775 | S_ISGID) < 0  && errno == EPERM);
+                assert_se(chmod(path, 0775 | S_ISGID | S_ISUID) < 0  && errno == EPERM);
+                assert_se(chmod(path, 0775) >= 0);
+
+                assert_se(fchmod(fd, 0775 | S_ISUID) < 0 && errno == EPERM);
+                assert_se(fchmod(fd, 0775 | S_ISGID) < 0  && errno == EPERM);
+                assert_se(fchmod(fd, 0775 | S_ISGID | S_ISUID) < 0  && errno == EPERM);
+                assert_se(fchmod(fd, 0775) >= 0);
+
+                assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISUID, 0) < 0 && errno == EPERM);
+                assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID, 0) < 0 && errno == EPERM);
+                assert_se(fchmodat(AT_FDCWD, path, 0755 | S_ISGID | S_ISUID, 0) < 0 && errno == EPERM);
+                assert_se(fchmodat(AT_FDCWD, path, 0755, 0) >= 0);
+
+                assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM);
+                assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM);
+                assert_se(real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+                k = real_open(z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                assert_se(creat(z, 0644 | S_ISUID) < 0 && errno == EPERM);
+                assert_se(creat(z, 0644 | S_ISGID) < 0 && errno == EPERM);
+                assert_se(creat(z, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+                k = creat(z, 0644);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID) < 0 && errno == EPERM);
+                assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISGID) < 0 && errno == EPERM);
+                assert_se(openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+                k = openat(AT_FDCWD, z, O_CREAT|O_RDWR|O_CLOEXEC|O_EXCL, 0644);
+                k = safe_close(k);
+                assert_se(unlink(z) >= 0);
+
+                assert_se(mkdir(z, 0755 | S_ISUID) < 0 && errno == EPERM);
+                assert_se(mkdir(z, 0755 | S_ISGID) < 0 && errno == EPERM);
+                assert_se(mkdir(z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+                assert_se(mkdir(z, 0755) >= 0);
+                assert_se(rmdir(z) >= 0);
+
+                assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID) < 0 && errno == EPERM);
+                assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISGID) < 0 && errno == EPERM);
+                assert_se(mkdirat(AT_FDCWD, z, 0755 | S_ISUID | S_ISGID) < 0 && errno == EPERM);
+                assert_se(mkdirat(AT_FDCWD, z, 0755) >= 0);
+                assert_se(rmdir(z) >= 0);
+
+                assert_se(mknod(z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM);
+                assert_se(mknod(z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM);
+                assert_se(mknod(z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM);
+                assert_se(mknod(z, S_IFREG | 0755, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+
+                assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID, 0) < 0 && errno == EPERM);
+                assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISGID, 0) < 0 && errno == EPERM);
+                assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755 | S_ISUID | S_ISGID, 0) < 0 && errno == EPERM);
+                assert_se(mknodat(AT_FDCWD, z, S_IFREG | 0755, 0) >= 0);
+                assert_se(unlink(z) >= 0);
+
+                assert_se(unlink(path) >= 0);
+                assert_se(rm_rf(dir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
+
+                _exit(EXIT_SUCCESS);
+        }
+
+        assert_se(wait_for_terminate_and_check("suidsgidseccomp", pid, WAIT_LOG) == EXIT_SUCCESS);
+}
+
 int main(int argc, char *argv[]) {
         test_setup_logging(LOG_DEBUG);
 
@@ -763,6 +989,7 @@ int main(int argc, char *argv[]) {
         test_restrict_archs();
         test_load_syscall_filter_set_raw();
         test_lock_personality();
+        test_restrict_suid_sgid();
 
         return 0;
 }
index 340edeb..b4e7a52 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "set.h"
+#include "strv.h"
 
 static void test_set_steal_first(void) {
         _cleanup_set_free_ Set *m = NULL;
@@ -77,6 +78,12 @@ static void test_set_put(void) {
         assert_se(set_put(m, (void*) "333") == 1);
         assert_se(set_put(m, (void*) "333") == 0);
         assert_se(set_put(m, (void*) "22") == 0);
+
+        _cleanup_free_ char **t = set_get_strv(m);
+        assert_se(strv_contains(t, "1"));
+        assert_se(strv_contains(t, "22"));
+        assert_se(strv_contains(t, "333"));
+        assert_se(strv_length(t) == 3);
 }
 
 int main(int argc, const char *argv[]) {
index d2666dd..f753e38 100644 (file)
@@ -1,15 +1,17 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
 #include <sys/mman.h>
+#include <unistd.h>
 
 #if HAVE_VALGRIND_VALGRIND_H
 #  include <valgrind/valgrind.h>
 #endif
 
 #include "fd-util.h"
+#include "memory-util.h"
 #include "sigbus.h"
 #include "tests.h"
-#include "util.h"
 
 int main(int argc, char *argv[]) {
         _cleanup_close_ int fd = -1;
index 218200e..6ae272f 100644 (file)
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include "memory-util.h"
 #include "siphash24.h"
-#include "util.h"
 
 #define ITERATIONS 10000000ULL
 
index 2a6d5e7..e0c513a 100644 (file)
@@ -1,11 +1,15 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
 #include <inttypes.h>
 #include <linux/fiemap.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 #include "fd-util.h"
 #include "log.h"
+#include "memory-util.h"
 #include "sleep-config.h"
 #include "strv.h"
 #include "tests.h"
index 07ff487..057840d 100644 (file)
@@ -1,8 +1,10 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
+#include <grp.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
-#include <grp.h>
 
 #include "alloc-util.h"
 #include "async.h"
@@ -19,7 +21,6 @@
 #include "string-util.h"
 #include "tests.h"
 #include "tmpfile-util.h"
-#include "util.h"
 
 static void test_ifname_valid(void) {
         log_info("/* %s */", __func__);
@@ -165,20 +166,35 @@ static void test_socket_address_parse_netlink(void) {
         assert_se(socket_address_parse_netlink(&a, "") < 0);
 
         assert_se(socket_address_parse_netlink(&a, "route") >= 0);
+        assert_se(a.sockaddr.nl.nl_family == AF_NETLINK);
+        assert_se(a.sockaddr.nl.nl_groups == 0);
+        assert_se(a.protocol == NETLINK_ROUTE);
+        assert_se(socket_address_parse_netlink(&a, "route") >= 0);
         assert_se(socket_address_parse_netlink(&a, "route 10") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_NETLINK);
+        assert_se(a.sockaddr.nl.nl_family == AF_NETLINK);
+        assert_se(a.sockaddr.nl.nl_groups == 10);
         assert_se(a.protocol == NETLINK_ROUTE);
 
         /* With spaces and tabs */
         assert_se(socket_address_parse_netlink(&a, " kobject-uevent ") >= 0);
-        assert_se(socket_address_parse_netlink(&a, " \t kobject-uevent \t 10 \t") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_NETLINK);
+        assert_se(a.sockaddr.nl.nl_family == AF_NETLINK);
+        assert_se(a.sockaddr.nl.nl_groups == 0);
+        assert_se(a.protocol == NETLINK_KOBJECT_UEVENT);
+        assert_se(socket_address_parse_netlink(&a, " \t kobject-uevent \t 10") >= 0);
+        assert_se(a.sockaddr.nl.nl_family == AF_NETLINK);
+        assert_se(a.sockaddr.nl.nl_groups == 10);
         assert_se(a.protocol == NETLINK_KOBJECT_UEVENT);
-
         assert_se(socket_address_parse_netlink(&a, "kobject-uevent\t10") >= 0);
-        assert_se(a.sockaddr.sa.sa_family == AF_NETLINK);
+        assert_se(a.sockaddr.nl.nl_family == AF_NETLINK);
+        assert_se(a.sockaddr.nl.nl_groups == 10);
         assert_se(a.protocol == NETLINK_KOBJECT_UEVENT);
 
+        /* trailing space is not supported */
+        assert_se(socket_address_parse_netlink(&a, "kobject-uevent\t10 ") < 0);
+
+        /* Group must be unsigned */
+        assert_se(socket_address_parse_netlink(&a, "kobject-uevent -1") < 0);
+
         /* oss-fuzz #6884 */
         assert_se(socket_address_parse_netlink(&a, "\xff") < 0);
 }
index f9036a3..64a68a2 100644 (file)
@@ -13,6 +13,7 @@
 #include "rm-rf.h"
 #include "missing.h"
 #include "mountpoint-util.h"
+#include "namespace-util.h"
 #include "path-util.h"
 #include "stat-util.h"
 #include "stdio-util.h"
index 8c1f91d..064a5ab 100644 (file)
@@ -7,6 +7,7 @@
 #include "strv.h"
 #include "tests.h"
 #include "utf8.h"
+#include "util.h"
 
 static void test_string_erase(void) {
         char *x;
index 31ef1ab..18ad036 100644 (file)
@@ -4,10 +4,10 @@
 
 #include "alloc-util.h"
 #include "escape.h"
+#include "nulstr-util.h"
 #include "specifier.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 static void test_specifier_printf(void) {
         static const Specifier table[] = {
index bce7e33..9d47186 100644 (file)
@@ -6,7 +6,7 @@
 #include "cgroup.h"
 #include "compress.h"
 #include "condition.h"
-#include "device-internal.h"
+#include "device-private.h"
 #include "device.h"
 #include "execute.h"
 #include "import-util.h"
@@ -74,7 +74,7 @@ int main(int argc, char **argv) {
         test_table(kill_who, KILL_WHO);
         test_table(locale_variable, VARIABLE_LC);
         test_table(log_target, LOG_TARGET);
-        test_table(mac_policy, MACPOLICY);
+        test_table(mac_address_policy, MAC_ADDRESS_POLICY);
         test_table(manager_state, MANAGER_STATE);
         test_table(manager_timestamp, MANAGER_TIMESTAMP);
         test_table(mount_exec_command, MOUNT_EXEC_COMMAND);
index 958d369..96d9227 100644 (file)
@@ -1,11 +1,14 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <fcntl.h>
 #include <stdbool.h>
 #include <stdio.h>
+#include <unistd.h>
 
 #include "alloc-util.h"
 #include "fd-util.h"
 #include "macro.h"
+#include "path-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "tests.h"
@@ -13,6 +16,8 @@
 #include "util.h"
 
 static void test_default_term_for_tty(void) {
+        log_info("/* %s */", __func__);
+
         puts(default_term_for_tty("/dev/tty23"));
         puts(default_term_for_tty("/dev/ttyS23"));
         puts(default_term_for_tty("/dev/tty0"));
@@ -33,7 +38,9 @@ static void test_read_one_char(void) {
         bool need_nl;
         char name[] = "/tmp/test-read_one_char.XXXXXX";
 
-        assert(fmkostemp_safe(name, "r+", &file) == 0);
+        log_info("/* %s */", __func__);
+
+        assert_se(fmkostemp_safe(name, "r+", &file) == 0);
 
         assert_se(fputs("c\n", file) >= 0);
         rewind(file);
@@ -52,7 +59,20 @@ static void test_read_one_char(void) {
         rewind(file);
         assert_se(read_one_char(file, &r, 1000000, &need_nl) < 0);
 
-        unlink(name);
+        assert_se(unlink(name) >= 0);
+}
+
+static void test_getttyname_malloc(void) {
+        _cleanup_free_ char *ttyname = NULL;
+        _cleanup_close_ int master = -1;
+
+        log_info("/* %s */", __func__);
+
+        assert_se((master = posix_openpt(O_RDWR|O_NOCTTY)) >= 0);
+        assert_se(getttyname_malloc(master, &ttyname) >= 0);
+        log_info("ttyname = %s", ttyname);
+
+        assert_se(PATH_IN_SET(ttyname, "ptmx", "pts/ptmx"));
 }
 
 int main(int argc, char *argv[]) {
@@ -60,6 +80,7 @@ int main(int argc, char *argv[]) {
 
         test_default_term_for_tty();
         test_read_one_char();
+        test_getttyname_malloc();
 
         return 0;
 }
index eb6041c..d05bb61 100644 (file)
@@ -4,6 +4,7 @@
 #include "serialize.h"
 #include "string-util.h"
 #include "strv.h"
+#include "tests.h"
 #include "time-util.h"
 
 static void test_parse_sec(void) {
@@ -85,6 +86,26 @@ static void test_parse_sec_fix_0(void) {
         assert_se(u == USEC_INFINITY);
 }
 
+static void test_parse_sec_def_infinity(void) {
+        usec_t u;
+
+        log_info("/* %s */", __func__);
+
+        assert_se(parse_sec_def_infinity("5s", &u) >= 0);
+        assert_se(u == 5 * USEC_PER_SEC);
+        assert_se(parse_sec_def_infinity("", &u) >= 0);
+        assert_se(u == USEC_INFINITY);
+        assert_se(parse_sec_def_infinity("     ", &u) >= 0);
+        assert_se(u == USEC_INFINITY);
+        assert_se(parse_sec_def_infinity("0s", &u) >= 0);
+        assert_se(u == 0);
+        assert_se(parse_sec_def_infinity("0", &u) >= 0);
+        assert_se(u == 0);
+        assert_se(parse_sec_def_infinity(" 0", &u) >= 0);
+        assert_se(u == 0);
+        assert_se(parse_sec_def_infinity("-5s", &u) < 0);
+}
+
 static void test_parse_time(void) {
         usec_t u;
 
@@ -240,8 +261,10 @@ static void test_get_timezones(void) {
         r = get_timezones(&zones);
         assert_se(r == 0);
 
-        STRV_FOREACH(zone, zones)
+        STRV_FOREACH(zone, zones) {
+                log_info("zone: %s", *zone);
                 assert_se(timezone_is_valid(*zone, LOG_ERR));
+        }
 }
 
 static void test_usec_add(void) {
@@ -461,7 +484,7 @@ static void test_in_utc_timezone(void) {
 }
 
 int main(int argc, char *argv[]) {
-        uintmax_t x;
+        test_setup_logging(LOG_INFO);
 
         log_info("realtime=" USEC_FMT "\n"
                  "monotonic=" USEC_FMT "\n"
@@ -472,6 +495,7 @@ int main(int argc, char *argv[]) {
 
         test_parse_sec();
         test_parse_sec_fix_0();
+        test_parse_sec_def_infinity();
         test_parse_time();
         test_parse_nsec();
         test_format_timespan(1);
@@ -492,7 +516,7 @@ int main(int argc, char *argv[]) {
         assert_cc((time_t) -1 < (time_t) 1);
 
         /* Ensure TIME_T_MAX works correctly */
-        x = (uintmax_t) TIME_T_MAX;
+        uintmax_t x = TIME_T_MAX;
         x++;
         assert((time_t) x < 0);
 
index 96d6b22..3d6f9a0 100644 (file)
@@ -1,8 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include "memory-util.h"
 #include "sparse-endian.h"
 #include "unaligned.h"
-#include "util.h"
 
 static uint8_t data[] = {
         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
index f5578f9..8a0251e 100644 (file)
@@ -13,6 +13,7 @@
 #include "conf-parser.h"
 #include "env-file.h"
 #include "fd-util.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "hashmap.h"
 #include "hostname-util.h"
@@ -20,6 +21,7 @@
 #include "install.h"
 #include "load-fragment.h"
 #include "macro.h"
+#include "memory-util.h"
 #include "rm-rf.h"
 #include "specifier.h"
 #include "string-util.h"
@@ -28,7 +30,6 @@
 #include "tests.h"
 #include "tmpfile-util.h"
 #include "user-util.h"
-#include "util.h"
 
 static int test_unit_file_get_set(void) {
         int r;
index 2afae22..8b230bb 100644 (file)
@@ -8,6 +8,7 @@
 #include "alloc-util.h"
 #include "all-units.h"
 #include "glob-util.h"
+#include "format-util.h"
 #include "hostname-util.h"
 #include "macro.h"
 #include "manager.h"
@@ -758,7 +759,7 @@ static void test_unit_name_from_dbus_path(void) {
         test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dcoredump_2esocket", 0, "systemd-coredump.socket");
         test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dcoredump_400_2eservice", 0, "systemd-coredump@0.service");
         test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dfirstboot_2eservice", 0, "systemd-firstboot.service");
-        test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dfsck_2droot_2eservice", 0, "systemd-fsck-root.service");
+        test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dfsck_2droot_2eservice", 0, SPECIAL_FSCK_ROOT_SERVICE);
         test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dhwdb_2dupdate_2eservice", 0, "systemd-hwdb-update.service");
         test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dinitctl_2eservice", 0, "systemd-initctl.service");
         test_unit_name_from_dbus_path_one("/org/freedesktop/systemd1/unit/systemd_2dinitctl_2esocket", 0, "systemd-initctl.socket");
index 801824a..1a507bc 100644 (file)
@@ -1,12 +1,12 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include "alloc-util.h"
+#include "format-util.h"
 #include "log.h"
 #include "macro.h"
+#include "path-util.h"
 #include "string-util.h"
 #include "user-util.h"
-#include "util.h"
-#include "path-util.h"
 
 static void test_uid_to_name_one(uid_t uid, const char *name) {
         _cleanup_free_ char *t = NULL;
index 9849530..d1e48da 100644 (file)
@@ -36,11 +36,21 @@ static void test_ascii_is_valid_n(void) {
 }
 
 static void test_utf8_encoded_valid_unichar(void) {
-        assert_se(utf8_encoded_valid_unichar("\342\204\242") == 3);
-        assert_se(utf8_encoded_valid_unichar("\302\256") == 2);
-        assert_se(utf8_encoded_valid_unichar("a") == 1);
-        assert_se(utf8_encoded_valid_unichar("\341\204") < 0);
-        assert_se(utf8_encoded_valid_unichar("\341\204\341\204") < 0);
+        assert_se(utf8_encoded_valid_unichar("\342\204\242", 1) == -EINVAL); /* truncated */
+        assert_se(utf8_encoded_valid_unichar("\342\204\242", 2) == -EINVAL); /* truncated */
+        assert_se(utf8_encoded_valid_unichar("\342\204\242", 3) == 3);
+        assert_se(utf8_encoded_valid_unichar("\342\204\242", 4) == 3);
+        assert_se(utf8_encoded_valid_unichar("\302\256", 1) == -EINVAL); /* truncated */
+        assert_se(utf8_encoded_valid_unichar("\302\256", 2) == 2);
+        assert_se(utf8_encoded_valid_unichar("\302\256", 3) == 2);
+        assert_se(utf8_encoded_valid_unichar("\302\256", (size_t) -1) == 2);
+        assert_se(utf8_encoded_valid_unichar("a", 1) == 1);
+        assert_se(utf8_encoded_valid_unichar("a", 2) == 1);
+        assert_se(utf8_encoded_valid_unichar("\341\204", 1) == -EINVAL); /* truncated, potentially valid */
+        assert_se(utf8_encoded_valid_unichar("\341\204", 2) == -EINVAL); /* truncated, potentially valid */
+        assert_se(utf8_encoded_valid_unichar("\341\204", 3) == -EINVAL);
+        assert_se(utf8_encoded_valid_unichar("\341\204\341\204", 4) == -EINVAL);
+        assert_se(utf8_encoded_valid_unichar("\341\204\341\204", 5) == -EINVAL);
 }
 
 static void test_utf8_escaping(void) {
index ffacd65..120baa3 100644 (file)
@@ -5,9 +5,10 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include "def.h"
 #include "fileio.h"
 #include "fs-util.h"
+#include "limits-util.h"
+#include "memory-util.h"
 #include "missing_syscall.h"
 #include "parse-util.h"
 #include "process-util.h"
index efb9664..24593c7 100644 (file)
@@ -1,5 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <getopt.h>
+
 #include "macro.h"
 #include "strv.h"
 #include "verbs.h"
index 2c6ca0a..04d7e1f 100644 (file)
@@ -42,25 +42,25 @@ int main(int argc, char *argv[]) {
         assert_se(hashmap_isempty(m->watch_pids));
         assert_se(manager_get_unit_by_pid(m, 4711) == NULL);
 
-        assert_se(unit_watch_pid(a, 4711) >= 0);
+        assert_se(unit_watch_pid(a, 4711, false) >= 0);
         assert_se(manager_get_unit_by_pid(m, 4711) == a);
 
-        assert_se(unit_watch_pid(a, 4711) >= 0);
+        assert_se(unit_watch_pid(a, 4711, false) >= 0);
         assert_se(manager_get_unit_by_pid(m, 4711) == a);
 
-        assert_se(unit_watch_pid(b, 4711) >= 0);
+        assert_se(unit_watch_pid(b, 4711, false) >= 0);
         u = manager_get_unit_by_pid(m, 4711);
         assert_se(u == a || u == b);
 
-        assert_se(unit_watch_pid(b, 4711) >= 0);
+        assert_se(unit_watch_pid(b, 4711, false) >= 0);
         u = manager_get_unit_by_pid(m, 4711);
         assert_se(u == a || u == b);
 
-        assert_se(unit_watch_pid(c, 4711) >= 0);
+        assert_se(unit_watch_pid(c, 4711, false) >= 0);
         u = manager_get_unit_by_pid(m, 4711);
         assert_se(u == a || u == b || u == c);
 
-        assert_se(unit_watch_pid(c, 4711) >= 0);
+        assert_se(unit_watch_pid(c, 4711, false) >= 0);
         u = manager_get_unit_by_pid(m, 4711);
         assert_se(u == a || u == b || u == c);
 
index 1e7b262..406ca1d 100644 (file)
@@ -670,7 +670,7 @@ static int print_timesync_property(const char *name, const char *expected_value,
                                 return r;
 
                         if (arg_all || !isempty(str))
-                                bus_print_property_value(name, expected_value, value, "%s", str);
+                                bus_print_property_value(name, expected_value, value, str);
 
                         return 1;
                 }
index eeb17b6..fe91854 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <errno.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "sd-bus.h"
@@ -20,6 +22,7 @@
 #include "hashmap.h"
 #include "list.h"
 #include "main-func.h"
+#include "memory-util.h"
 #include "missing_capability.h"
 #include "path-util.h"
 #include "selinux-util.h"
@@ -29,7 +32,6 @@
 #include "unit-def.h"
 #include "unit-name.h"
 #include "user-util.h"
-#include "util.h"
 
 #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n"
 #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n"
@@ -377,9 +379,9 @@ static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *er
                         n += !!u->path;
 
         if (n == 0) {
-                (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL);
-
                 c->slot_job_removed = sd_bus_slot_unref(c->slot_job_removed);
+
+                (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/timedate1", "org.freedesktop.timedate1", "NTP", NULL);
         }
 
         return 0;
index 6fde4a3..4c00fa4 100644 (file)
@@ -17,6 +17,7 @@
 #include "alloc-util.h"
 #include "dns-domain.h"
 #include "fd-util.h"
+#include "format-util.h"
 #include "fs-util.h"
 #include "list.h"
 #include "log.h"
index b4f70c0..73d40c0 100644 (file)
@@ -1,5 +1,8 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include "sd-daemon.h"
 #include "sd-event.h"
 
index b66765b..d9d1cc1 100644 (file)
@@ -12,6 +12,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/file.h>
 #include <sys/stat.h>
 #include <sys/xattr.h>
 #include <sysexits.h>
 #include "path-lookup.h"
 #include "path-util.h"
 #include "pretty-print.h"
+#include "rlimit-util.h"
 #include "rm-rf.h"
 #include "selinux-util.h"
 #include "set.h"
+#include "sort-util.h"
 #include "specifier.h"
 #include "stat-util.h"
 #include "stdio-util.h"
@@ -59,7 +62,6 @@
 #include "strv.h"
 #include "umask-util.h"
 #include "user-util.h"
-#include "util.h"
 
 /* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
  * them in the file system. This is intended to be used to create
@@ -525,7 +527,6 @@ static int dir_cleanup(
                 bool keep_this_level) {
 
         struct dirent *dent;
-        struct timespec times[2];
         bool deleted = false;
         int r = 0;
 
@@ -580,42 +581,45 @@ static int dir_cleanup(
                 }
 
                 if (S_ISDIR(s.st_mode)) {
+                        _cleanup_closedir_ DIR *sub_dir = NULL;
 
                         if (mountpoint &&
                             streq(dent->d_name, "lost+found") &&
                             s.st_uid == 0) {
-                                log_debug("Ignoring \"%s\".", sub_path);
+                                log_debug("Ignoring directory \"%s\".", sub_path);
                                 continue;
                         }
 
                         if (maxdepth <= 0)
                                 log_warning("Reached max depth on \"%s\".", sub_path);
                         else {
-                                _cleanup_closedir_ DIR *sub_dir;
                                 int q;
 
                                 sub_dir = xopendirat_nomod(dirfd(d), dent->d_name);
                                 if (!sub_dir) {
                                         if (errno != ENOENT)
-                                                r = log_error_errno(errno, "opendir(%s) failed: %m", sub_path);
+                                                r = log_warning_errno(errno, "Opening directory \"%s\" failed, ignoring: %m", sub_path);
 
                                         continue;
                                 }
 
+                                if (flock(dirfd(sub_dir), LOCK_EX|LOCK_NB) < 0) {
+                                        log_debug_errno(errno, "Couldn't acquire shared BSD lock on directory \"%s\", skipping: %m", p);
+                                        continue;
+                                }
+
                                 q = dir_cleanup(i, sub_path, sub_dir, &s, cutoff, rootdev, false, maxdepth-1, false);
                                 if (q < 0)
                                         r = q;
                         }
 
-                        /* Note: if you are wondering why we don't
-                         * support the sticky bit for excluding
-                         * directories from cleaning like we do it for
-                         * other file system objects: well, the sticky
-                         * bit already has a meaning for directories,
-                         * so we don't want to overload that. */
+                        /* Note: if you are wondering why we don't support the sticky bit for excluding
+                         * directories from cleaning like we do it for other file system objects: well, the
+                         * sticky bit already has a meaning for directories, so we don't want to overload
+                         * that. */
 
                         if (keep_this_level) {
-                                log_debug("Keeping \"%s\".", sub_path);
+                                log_debug("Keeping directory \"%s\".", sub_path);
                                 continue;
                         }
 
@@ -642,13 +646,11 @@ static int dir_cleanup(
                         log_debug("Removing directory \"%s\".", sub_path);
                         if (unlinkat(dirfd(d), dent->d_name, AT_REMOVEDIR) < 0)
                                 if (!IN_SET(errno, ENOENT, ENOTEMPTY))
-                                        r = log_error_errno(errno, "rmdir(%s): %m", sub_path);
+                                        r = log_warning_errno(errno, "Failed to remove directory \"%s\", ignoring: %m", sub_path);
 
                 } else {
-                        /* Skip files for which the sticky bit is
-                         * set. These are semantics we define, and are
-                         * unknown elsewhere. See XDG_RUNTIME_DIR
-                         * specification for details. */
+                        /* Skip files for which the sticky bit is set. These are semantics we define, and are
+                         * unknown elsewhere. See XDG_RUNTIME_DIR specification for details. */
                         if (s.st_mode & S_ISVTX) {
                                 log_debug("Skipping \"%s\": sticky bit set.", sub_path);
                                 continue;
@@ -675,8 +677,7 @@ static int dir_cleanup(
                                 continue;
                         }
 
-                        /* Keep files on this level around if this is
-                         * requested */
+                        /* Keep files on this level around if this is requested */
                         if (keep_this_level) {
                                 log_debug("Keeping \"%s\".", sub_path);
                                 continue;
@@ -710,11 +711,10 @@ static int dir_cleanup(
                                 continue;
                         }
 
-                        log_debug("unlink \"%s\"", sub_path);
-
+                        log_debug("Removing \"%s\".", sub_path);
                         if (unlinkat(dirfd(d), dent->d_name, 0) < 0)
                                 if (errno != ENOENT)
-                                        r = log_error_errno(errno, "unlink(%s): %m", sub_path);
+                                        r = log_warning_errno(errno, "Failed to remove \"%s\", ignoring: %m", sub_path);
 
                         deleted = true;
                 }
@@ -722,21 +722,22 @@ static int dir_cleanup(
 
 finish:
         if (deleted) {
-                usec_t age1, age2;
                 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
-
-                /* Restore original directory timestamps */
-                times[0] = ds->st_atim;
-                times[1] = ds->st_mtim;
+                usec_t age1, age2;
 
                 age1 = timespec_load(&ds->st_atim);
                 age2 = timespec_load(&ds->st_mtim);
+
                 log_debug("Restoring access and modification time on \"%s\": %s, %s",
                           p,
                           format_timestamp_us(a, sizeof(a), age1),
                           format_timestamp_us(b, sizeof(b), age2));
-                if (futimens(dirfd(d), times) < 0)
-                        log_error_errno(errno, "utimensat(%s): %m", p);
+
+                /* Restore original directory timestamps */
+                if (futimens(dirfd(d), (struct timespec[]) {
+                                ds->st_atim,
+                                ds->st_mtim }) < 0)
+                        log_warning_errno(errno, "Failed to revert timestamps of '%s', ignoring: %m", p);
         }
 
         return r;
@@ -855,7 +856,7 @@ static int path_open_parent_safe(const char *path) {
         if (!dn)
                 return log_oom();
 
-        fd = chase_symlinks(dn, NULL, CHASE_OPEN|CHASE_SAFE|CHASE_WARN, NULL);
+        fd = chase_symlinks(dn, arg_root, CHASE_OPEN|CHASE_SAFE|CHASE_WARN, NULL);
         if (fd < 0 && fd != -ENOLINK)
                 return log_error_errno(fd, "Failed to validate path %s: %m", path);
 
@@ -876,7 +877,7 @@ static int path_open_safe(const char *path) {
                                        "Failed to open invalid path '%s'.",
                                        path);
 
-        fd = chase_symlinks(path, NULL, CHASE_OPEN|CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW, NULL);
+        fd = chase_symlinks(path, arg_root, CHASE_OPEN|CHASE_SAFE|CHASE_WARN|CHASE_NOFOLLOW, NULL);
         if (fd < 0 && fd != -ENOLINK)
                 return log_error_errno(fd, "Failed to validate path %s: %m", path);
 
@@ -1095,22 +1096,6 @@ static int path_set_acls(Item *item, const char *path) {
         return r;
 }
 
-#define ATTRIBUTES_ALL                          \
-        (FS_NOATIME_FL      |                   \
-         FS_SYNC_FL         |                   \
-         FS_DIRSYNC_FL      |                   \
-         FS_APPEND_FL       |                   \
-         FS_COMPR_FL        |                   \
-         FS_NODUMP_FL       |                   \
-         FS_EXTENT_FL       |                   \
-         FS_IMMUTABLE_FL    |                   \
-         FS_JOURNAL_DATA_FL |                   \
-         FS_SECRM_FL        |                   \
-         FS_UNRM_FL         |                   \
-         FS_NOTAIL_FL       |                   \
-         FS_TOPDIR_FL       |                   \
-         FS_NOCOW_FL)
-
 static int parse_attribute_from_arg(Item *item) {
 
         static const struct {
@@ -1131,6 +1116,7 @@ static int parse_attribute_from_arg(Item *item) {
                 { 't', FS_NOTAIL_FL },       /* file tail should not be merged */
                 { 'T', FS_TOPDIR_FL },       /* Top of directory hierarchies */
                 { 'C', FS_NOCOW_FL },        /* Do not cow file */
+                { 'P', FS_PROJINHERIT_FL },  /* Inherit the quota project ID */
         };
 
         enum {
@@ -1183,7 +1169,7 @@ static int parse_attribute_from_arg(Item *item) {
         }
 
         if (mode == MODE_SET)
-                mask |= ATTRIBUTES_ALL;
+                mask |= CHATTR_ALL_FL;
 
         assert(mask != 0);
 
@@ -1503,7 +1489,7 @@ typedef enum {
         _CREATION_MODE_INVALID = -1
 } CreationMode;
 
-static const char *creation_mode_verb_table[_CREATION_MODE_MAX] = {
+static const char *const creation_mode_verb_table[_CREATION_MODE_MAX] = {
         [CREATION_NORMAL] = "Created",
         [CREATION_EXISTING] = "Found existing",
         [CREATION_FORCE] = "Created replacement",
@@ -2255,7 +2241,7 @@ static int process_item(Item *i, OperationMask operation) {
 
         i->done |= operation;
 
-        r = chase_symlinks(i->path, NULL, CHASE_NO_AUTOFS|CHASE_WARN, NULL);
+        r = chase_symlinks(i->path, arg_root, CHASE_NO_AUTOFS|CHASE_WARN, NULL);
         if (r == -EREMOTE) {
                 log_notice_errno(r, "Skipping %s", i->path);
                 return 0;
@@ -2521,7 +2507,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                 return -EIO;
         }
 
-        if (!isempty(buffer) && !streq(buffer, "-")) {
+        if (!empty_or_dash(buffer)) {
                 i.argument = strdup(buffer);
                 if (!i.argument)
                         return log_oom();
@@ -2718,7 +2704,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                 free_and_replace(i.path, p);
         }
 
-        if (!isempty(user) && !streq(user, "-")) {
+        if (!empty_or_dash(user)) {
                 const char *u = user;
 
                 r = get_user_creds(&u, &i.uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
@@ -2730,7 +2716,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                 i.uid_set = true;
         }
 
-        if (!isempty(group) && !streq(group, "-")) {
+        if (!empty_or_dash(group)) {
                 const char *g = group;
 
                 r = get_group_creds(&g, &i.gid, USER_CREDS_ALLOW_MISSING);
@@ -2743,7 +2729,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
                 i.gid_set = true;
         }
 
-        if (!isempty(mode) && !streq(mode, "-")) {
+        if (!empty_or_dash(mode)) {
                 const char *mm = mode;
                 unsigned m;
 
@@ -2763,7 +2749,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer, bool
         } else
                 i.mode = IN_SET(i.type, CREATE_DIRECTORY, TRUNCATE_DIRECTORY, CREATE_SUBVOLUME, CREATE_SUBVOLUME_INHERIT_QUOTA, CREATE_SUBVOLUME_NEW_QUOTA) ? 0755 : 0644;
 
-        if (!isempty(age) && !streq(age, "-")) {
+        if (!empty_or_dash(age)) {
                 const char *a = age;
 
                 if (*a == '~') {
@@ -3175,6 +3161,9 @@ static int run(int argc, char *argv[]) {
 
         log_setup_service();
 
+        /* Descending down file system trees might take a lot of fds */
+        (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
+
         if (arg_user) {
                 r = user_config_paths(&config_dirs);
                 if (r < 0)
index fc165ff..271d0bb 100644 (file)
 #include <sys/prctl.h>
 #include <sys/signalfd.h>
 #include <sys/socket.h>
-#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <sys/un.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
 #include "io-util.h"
 #include "macro.h"
 #include "main-func.h"
+#include "memory-util.h"
 #include "mkdir.h"
 #include "path-util.h"
+#include "plymouth-util.h"
 #include "pretty-print.h"
 #include "process-util.h"
 #include "signal-util.h"
@@ -40,7 +44,6 @@
 #include "string-util.h"
 #include "strv.h"
 #include "terminal-util.h"
-#include "util.h"
 #include "utmp-wtmp.h"
 
 static enum {
@@ -685,51 +688,53 @@ static int parse_argv(int argc, char *argv[]) {
 }
 
 /*
- * To be able to ask on all terminal devices of /dev/console
- * the devices are collected. If more than one device is found,
- * then on each of the terminals a inquiring task is forked.
- * Every task has its own session and its own controlling terminal.
- * If one of the tasks does handle a password, the remaining tasks
- * will be terminated.
+ * To be able to ask on all terminal devices of /dev/console the devices are collected. If more than one
+ * device is found, then on each of the terminals a inquiring task is forked.  Every task has its own session
+ * and its own controlling terminal.  If one of the tasks does handle a password, the remaining tasks will be
+ * terminated.
  */
-static int ask_on_this_console(const char *tty, pid_t *ret_pid, int argc, char *argv[]) {
-        struct sigaction sig = {
+static int ask_on_this_console(const char *tty, pid_t *ret_pid, char **arguments) {
+        static const struct sigaction sigchld = {
                 .sa_handler = nop_signal_handler,
                 .sa_flags = SA_NOCLDSTOP | SA_RESTART,
         };
-        pid_t pid;
+        static const struct sigaction sighup = {
+                .sa_handler = SIG_DFL,
+                .sa_flags = SA_RESTART,
+        };
         int r;
 
+        assert_se(sigaction(SIGCHLD, &sigchld, NULL) >= 0);
+        assert_se(sigaction(SIGHUP, &sighup, NULL) >= 0);
         assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGHUP, SIGCHLD, -1) >= 0);
 
-        assert_se(sigemptyset(&sig.sa_mask) >= 0);
-        assert_se(sigaction(SIGCHLD, &sig, NULL) >= 0);
-
-        sig.sa_handler = SIG_DFL;
-        assert_se(sigaction(SIGHUP, &sig, NULL) >= 0);
-
-        r = safe_fork("(sd-passwd)", FORK_RESET_SIGNALS|FORK_LOG, &pid);
+        r = safe_fork("(sd-passwd)", FORK_RESET_SIGNALS|FORK_LOG, ret_pid);
         if (r < 0)
                 return r;
         if (r == 0) {
-                int ac;
+                char **i;
 
                 assert_se(prctl(PR_SET_PDEATHSIG, SIGHUP) >= 0);
 
-                for (ac = 0; ac < argc; ac++) {
-                        if (streq(argv[ac], "--console")) {
-                                argv[ac] = strjoina("--console=", tty);
-                                break;
+                STRV_FOREACH(i, arguments) {
+                        char *k;
+
+                        if (!streq(*i, "--console"))
+                                continue;
+
+                        k = strjoin("--console=", tty);
+                        if (!k) {
+                                log_oom();
+                                _exit(EXIT_FAILURE);
                         }
-                }
 
-                assert(ac < argc);
+                        free_and_replace(*i, k);
+                }
 
-                execv(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, argv);
+                execv(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, arguments);
                 _exit(EXIT_FAILURE);
         }
 
-        *ret_pid = pid;
         return 0;
 }
 
@@ -785,9 +790,9 @@ static void terminate_agents(Set *pids) {
         }
 }
 
-static int ask_on_consoles(int argc, char *argv[]) {
+static int ask_on_consoles(char *argv[]) {
         _cleanup_set_free_ Set *pids = NULL;
-        _cleanup_strv_free_ char **consoles = NULL;
+        _cleanup_strv_free_ char **consoles = NULL, **arguments = NULL;
         siginfo_t status = {};
         char **tty;
         pid_t pid;
@@ -801,9 +806,13 @@ static int ask_on_consoles(int argc, char *argv[]) {
         if (!pids)
                 return log_oom();
 
+        arguments = strv_copy(argv);
+        if (!arguments)
+                return log_oom();
+
         /* Start an agent on each console. */
         STRV_FOREACH(tty, consoles) {
-                r = ask_on_this_console(*tty, &pid, argc, argv);
+                r = ask_on_this_console(*tty, &pid, arguments);
                 if (r < 0)
                         return r;
 
@@ -848,7 +857,7 @@ static int run(int argc, char *argv[]) {
                 /*
                  * Spawn a separate process for each console device.
                  */
-                return ask_on_consoles(argc, argv);
+                return ask_on_consoles(argv);
 
         if (arg_device) {
                 /*
index 6c2233e..8ea2e1e 100644 (file)
@@ -26,8 +26,8 @@
 #include "fd-util.h"
 #include "libudev-util.h"
 #include "log.h"
+#include "memory-util.h"
 #include "udev-util.h"
-#include "util.h"
 
 #define COMMAND_TIMEOUT_MSEC (30 * 1000)
 
index aed24a3..3f882f5 100644 (file)
@@ -21,9 +21,9 @@
 #include <unistd.h>
 
 #include "log.h"
+#include "memory-util.h"
 #include "random-util.h"
 #include "udev-util.h"
-#include "util.h"
 
 /* device info */
 static unsigned cd_cd_rom;
@@ -585,7 +585,7 @@ out:
 static int cd_media_info(int fd) {
         struct scsi_cmd sc;
         unsigned char header[32];
-        static const char *media_status[] = {
+        static const char *const media_status[] = {
                 "blank",
                 "appendable",
                 "complete",
index 9d3f6d1..01e4c09 100644 (file)
@@ -180,6 +180,7 @@ foreach prog : [['ata_id/ata_id.c'],
                    prog,
                    include_directories : includes,
                    c_args : ['-DLOG_REALM=LOG_REALM_UDEV'],
+                   dependencies : [versiondep],
                    link_with : [libudev_static],
                    install_rpath : udev_rpath,
                    install : true,
@@ -197,3 +198,14 @@ configure_file(
 
 meson.add_install_script('sh', '-c',
                          mkdir_p.format(join_paths(sysconfdir, 'udev/rules.d')))
+
+fuzzers += [
+        [['src/udev/net/fuzz-link-parser.c',
+          'src/fuzz/fuzz.h'],
+         [libudev_core,
+          libudev_static,
+          libsystemd_network,
+          libshared],
+         [threads,
+          libacl]]
+        ]
index 0dcec03..c94977e 100644 (file)
@@ -9,11 +9,11 @@
 #include "ethtool-util.h"
 #include "link-config.h"
 #include "log.h"
+#include "memory-util.h"
 #include "missing.h"
 #include "socket-util.h"
 #include "string-table.h"
 #include "strxcpyx.h"
-#include "util.h"
 
 static const char* const duplex_table[_DUP_MAX] = {
         [DUP_FULL] = "full",
@@ -358,7 +358,7 @@ static int find_feature_index(struct ethtool_gstrings *strings, const char *feat
                         return i;
         }
 
-        return -1;
+        return -ENODATA;
 }
 
 int ethtool_set_features(int *fd, const char *ifname, int *features) {
@@ -775,7 +775,9 @@ int config_parse_advertise(const char *unit,
                         break;
 
                 mode = ethtool_link_mode_bit_from_string(w);
-                if (mode < 0) {
+                /* We reuse the kernel provided enum which does not contain negative value. So, the cast
+                 * below is mandatory. Otherwise, the check below always passes and access an invalid address. */
+                if ((int) mode < 0) {
                         log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse advertise mode, ignoring: %s", w);
                         continue;
                 }
diff --git a/src/udev/net/fuzz-link-parser.c b/src/udev/net/fuzz-link-parser.c
new file mode 100644 (file)
index 0000000..e0dacc7
--- /dev/null
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include "fd-util.h"
+#include "fs-util.h"
+#include "fuzz.h"
+#include "link-config.h"
+#include "tmpfile-util.h"
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+        _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
+        _cleanup_(unlink_tempfilep) char filename[] = "/tmp/fuzz-link-config.XXXXXX";
+        _cleanup_fclose_ FILE *f = NULL;
+
+        if (size > 65535)
+                return 0;
+
+        if (!getenv("SYSTEMD_LOG_LEVEL"))
+                log_set_max_level(LOG_CRIT);
+
+        assert_se(fmkostemp_safe(filename, "r+", &f) == 0);
+        if (size != 0)
+                assert_se(fwrite(data, size, 1, f) == 1);
+
+        fflush(f);
+        assert_se(link_config_ctx_new(&ctx) >= 0);
+        (void) link_load_one(ctx, filename);
+        return 0;
+}
diff --git a/src/udev/net/fuzz-link-parser.options b/src/udev/net/fuzz-link-parser.options
new file mode 100644 (file)
index 0000000..0824b19
--- /dev/null
@@ -0,0 +1,2 @@
+[libfuzzer]
+max_len = 65535
index 2bc18bf..dff849a 100644 (file)
@@ -19,36 +19,36 @@ struct ConfigPerfItem;
 %struct-type
 %includes
 %%
-Match.MACAddress,                config_parse_hwaddrs,       0,                             offsetof(link_config, match_mac)
-Match.OriginalName,              config_parse_ifnames,       0,                             offsetof(link_config, match_name)
-Match.Path,                      config_parse_strv,          0,                             offsetof(link_config, match_path)
-Match.Driver,                    config_parse_strv,          0,                             offsetof(link_config, match_driver)
-Match.Type,                      config_parse_strv,          0,                             offsetof(link_config, match_type)
-Match.Host,                      config_parse_net_condition, CONDITION_HOST,                offsetof(link_config, match_host)
-Match.Virtualization,            config_parse_net_condition, CONDITION_VIRTUALIZATION,      offsetof(link_config, match_virt)
-Match.KernelCommandLine,         config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, match_kernel_cmdline)
-Match.KernelVersion,             config_parse_net_condition, CONDITION_KERNEL_VERSION,      offsetof(link_config, match_kernel_version)
-Match.Architecture,              config_parse_net_condition, CONDITION_ARCHITECTURE,        offsetof(link_config, match_arch)
-Link.Description,                config_parse_string,        0,                             offsetof(link_config, description)
-Link.MACAddressPolicy,           config_parse_mac_policy,    0,                             offsetof(link_config, mac_policy)
-Link.MACAddress,                 config_parse_hwaddr,        0,                             offsetof(link_config, mac)
-Link.NamePolicy,                 config_parse_name_policy,   0,                             offsetof(link_config, name_policy)
-Link.Name,                       config_parse_ifname,        0,                             offsetof(link_config, name)
-Link.Alias,                      config_parse_ifalias,       0,                             offsetof(link_config, alias)
-Link.MTUBytes,                   config_parse_mtu,           AF_UNSPEC,                     offsetof(link_config, mtu)
-Link.BitsPerSecond,              config_parse_si_size,       0,                             offsetof(link_config, speed)
-Link.Duplex,                     config_parse_duplex,        0,                             offsetof(link_config, duplex)
-Link.AutoNegotiation,            config_parse_tristate,      0,                             offsetof(link_config, autonegotiation)
-Link.WakeOnLan,                  config_parse_wol,           0,                             offsetof(link_config, wol)
-Link.Port,                       config_parse_port,          0,                             offsetof(link_config, port)
-Link.GenericSegmentationOffload, config_parse_tristate,      0,                             offsetof(link_config, features[NET_DEV_FEAT_GSO])
-Link.TCPSegmentationOffload,     config_parse_tristate,      0,                             offsetof(link_config, features[NET_DEV_FEAT_TSO])
-Link.TCP6SegmentationOffload,    config_parse_tristate,      0,                             offsetof(link_config, features[NET_DEV_FEAT_TSO6])
-Link.UDPSegmentationOffload,     config_parse_warn_compat,   DISABLED_LEGACY,               0
-Link.GenericReceiveOffload,      config_parse_tristate,      0,                             offsetof(link_config, features[NET_DEV_FEAT_GRO])
-Link.LargeReceiveOffload,        config_parse_tristate,      0,                             offsetof(link_config, features[NET_DEV_FEAT_LRO])
-Link.RxChannels,                 config_parse_channel,       0,                             0
-Link.TxChannels,                 config_parse_channel,       0,                             0
-Link.OtherChannels,              config_parse_channel,       0,                             0
-Link.CombinedChannels,           config_parse_channel,       0,                             0
-Link.Advertise,                  config_parse_advertise,     0,                             0
+Match.MACAddress,                config_parse_hwaddrs,            0,                             offsetof(link_config, match_mac)
+Match.OriginalName,              config_parse_ifnames,            0,                             offsetof(link_config, match_name)
+Match.Path,                      config_parse_strv,               0,                             offsetof(link_config, match_path)
+Match.Driver,                    config_parse_strv,               0,                             offsetof(link_config, match_driver)
+Match.Type,                      config_parse_strv,               0,                             offsetof(link_config, match_type)
+Match.Host,                      config_parse_net_condition,      CONDITION_HOST,                offsetof(link_config, conditions)
+Match.Virtualization,            config_parse_net_condition,      CONDITION_VIRTUALIZATION,      offsetof(link_config, conditions)
+Match.KernelCommandLine,         config_parse_net_condition,      CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, conditions)
+Match.KernelVersion,             config_parse_net_condition,      CONDITION_KERNEL_VERSION,      offsetof(link_config, conditions)
+Match.Architecture,              config_parse_net_condition,      CONDITION_ARCHITECTURE,        offsetof(link_config, conditions)
+Link.Description,                config_parse_string,             0,                             offsetof(link_config, description)
+Link.MACAddressPolicy,           config_parse_mac_address_policy, 0,                             offsetof(link_config, mac_address_policy)
+Link.MACAddress,                 config_parse_hwaddr,             0,                             offsetof(link_config, mac)
+Link.NamePolicy,                 config_parse_name_policy,        0,                             offsetof(link_config, name_policy)
+Link.Name,                       config_parse_ifname,             0,                             offsetof(link_config, name)
+Link.Alias,                      config_parse_ifalias,            0,                             offsetof(link_config, alias)
+Link.MTUBytes,                   config_parse_mtu,                AF_UNSPEC,                     offsetof(link_config, mtu)
+Link.BitsPerSecond,              config_parse_si_size,            0,                             offsetof(link_config, speed)
+Link.Duplex,                     config_parse_duplex,             0,                             offsetof(link_config, duplex)
+Link.AutoNegotiation,            config_parse_tristate,           0,                             offsetof(link_config, autonegotiation)
+Link.WakeOnLan,                  config_parse_wol,                0,                             offsetof(link_config, wol)
+Link.Port,                       config_parse_port,               0,                             offsetof(link_config, port)
+Link.GenericSegmentationOffload, config_parse_tristate,           0,                             offsetof(link_config, features[NET_DEV_FEAT_GSO])
+Link.TCPSegmentationOffload,     config_parse_tristate,           0,                             offsetof(link_config, features[NET_DEV_FEAT_TSO])
+Link.TCP6SegmentationOffload,    config_parse_tristate,           0,                             offsetof(link_config, features[NET_DEV_FEAT_TSO6])
+Link.UDPSegmentationOffload,     config_parse_warn_compat,        DISABLED_LEGACY,               0
+Link.GenericReceiveOffload,      config_parse_tristate,           0,                             offsetof(link_config, features[NET_DEV_FEAT_GRO])
+Link.LargeReceiveOffload,        config_parse_tristate,           0,                             offsetof(link_config, features[NET_DEV_FEAT_LRO])
+Link.RxChannels,                 config_parse_channel,            0,                             0
+Link.TxChannels,                 config_parse_channel,            0,                             0
+Link.OtherChannels,              config_parse_channel,            0,                             0
+Link.CombinedChannels,           config_parse_channel,            0,                             0
+Link.Advertise,                  config_parse_advertise,          0,                             0
index 23bc5c1..a26c4ce 100644 (file)
@@ -9,11 +9,13 @@
 #include "alloc-util.h"
 #include "conf-files.h"
 #include "conf-parser.h"
+#include "def.h"
 #include "device-util.h"
 #include "ethtool-util.h"
 #include "fd-util.h"
 #include "link-config.h"
 #include "log.h"
+#include "memory-util.h"
 #include "naming-scheme.h"
 #include "netlink-util.h"
 #include "network-internal.h"
@@ -25,7 +27,6 @@
 #include "string-table.h"
 #include "string-util.h"
 #include "strv.h"
-#include "util.h"
 
 struct link_config_ctx {
         LIST_HEAD(link_config, links);
@@ -36,18 +37,9 @@ struct link_config_ctx {
 
         sd_netlink *rtnl;
 
-        usec_t link_dirs_ts_usec;
+        usec_t network_dirs_ts_usec;
 };
 
-static const char* const link_dirs[] = {
-        "/etc/systemd/network",
-        "/run/systemd/network",
-        "/usr/lib/systemd/network",
-#if HAVE_SPLIT_USR
-        "/lib/systemd/network",
-#endif
-        NULL};
-
 static void link_config_free(link_config *link) {
         if (!link)
                 return;
@@ -58,12 +50,8 @@ static void link_config_free(link_config *link) {
         strv_free(link->match_path);
         strv_free(link->match_driver);
         strv_free(link->match_type);
-        free(link->match_name);
-        free(link->match_host);
-        free(link->match_virt);
-        free(link->match_kernel_cmdline);
-        free(link->match_kernel_version);
-        free(link->match_arch);
+        strv_free(link->match_name);
+        condition_free_list(link->conditions);
 
         free(link->description);
         free(link->mac);
@@ -101,8 +89,6 @@ void link_config_ctx_free(link_config_ctx *ctx) {
         return;
 }
 
-DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
-
 int link_config_ctx_new(link_config_ctx **ret) {
         _cleanup_(link_config_ctx_freep) link_config_ctx *ctx = NULL;
 
@@ -124,60 +110,63 @@ int link_config_ctx_new(link_config_ctx **ret) {
         return 0;
 }
 
-static int load_link(link_config_ctx *ctx, const char *filename) {
+int link_load_one(link_config_ctx *ctx, const char *filename) {
         _cleanup_(link_config_freep) link_config *link = NULL;
         _cleanup_fclose_ FILE *file = NULL;
-        int i;
+        _cleanup_free_ char *name = NULL;
+        size_t i;
         int r;
 
         assert(ctx);
         assert(filename);
 
         file = fopen(filename, "re");
-        if (!file) {
-                if (errno == ENOENT)
-                        return 0;
-                else
-                        return -errno;
-        }
+        if (!file)
+                return errno == ENOENT ? 0 : -errno;
 
         if (null_or_empty_fd(fileno(file))) {
                 log_debug("Skipping empty file: %s", filename);
                 return 0;
         }
 
-        link = new0(link_config, 1);
+        name = strdup(filename);
+        if (!name)
+                return -ENOMEM;
+
+        link = new(link_config, 1);
         if (!link)
-                return log_oom();
+                return -ENOMEM;
 
-        link->mac_policy = _MACPOLICY_INVALID;
-        link->wol = _WOL_INVALID;
-        link->duplex = _DUP_INVALID;
-        link->port = _NET_DEV_PORT_INVALID;
-        link->autonegotiation = -1;
+        *link = (link_config) {
+                .filename = TAKE_PTR(name),
+                .mac_address_policy = _MAC_ADDRESS_POLICY_INVALID,
+                .wol = _WOL_INVALID,
+                .duplex = _DUP_INVALID,
+                .port = _NET_DEV_PORT_INVALID,
+                .autonegotiation = -1,
+        };
 
-        for (i = 0; i < (int)ELEMENTSOF(link->features); i++)
+        for (i = 0; i < ELEMENTSOF(link->features); i++)
                 link->features[i] = -1;
 
         r = config_parse(NULL, filename, file,
-                         "Match\0Link\0Ethernet\0",
+                         "Match\0Link\0",
                          config_item_perf_lookup, link_config_gperf_lookup,
                          CONFIG_PARSE_WARN, link);
         if (r < 0)
                 return r;
-        else
-                log_debug("Parsed configuration file %s", filename);
 
         if (link->speed > UINT_MAX)
                 return -ERANGE;
 
-        link->filename = strdup(filename);
-        if (!link->filename)
-                return log_oom();
+        if (!condition_test_list(link->conditions, NULL, NULL, NULL)) {
+                log_debug("%s: Conditions do not match the system environment, skipping.", filename);
+                return 0;
+        }
 
-        LIST_PREPEND(links, ctx->links, link);
-        link = NULL;
+        log_debug("Parsed configuration file %s", filename);
 
+        LIST_PREPEND(links, ctx->links, TAKE_PTR(link));
         return 0;
 }
 
@@ -187,19 +176,19 @@ static bool enable_name_policy(void) {
         return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
 }
 
-static int link_name_type(sd_device *device, unsigned *type) {
+static int link_unsigned_attribute(sd_device *device, const char *attr, unsigned *type) {
         const char *s;
         int r;
 
-        r = sd_device_get_sysattr_value(device, "name_assign_type", &s);
+        r = sd_device_get_sysattr_value(device, attr, &s);
         if (r < 0)
-                return log_device_debug_errno(device, r, "Failed to query name_assign_type: %m");
+                return log_device_debug_errno(device, r, "Failed to query %s: %m", attr);
 
         r = safe_atou(s, type);
         if (r < 0)
-                return log_device_warning_errno(device, r, "Failed to parse name_assign_type \"%s\": %m", s);
+                return log_device_warning_errno(device, r, "Failed to parse %s \"%s\": %m", attr, s);
 
-        log_device_debug(device, "Device has name_assign_type=%d", *type);
+        log_device_debug(device, "Device has %s=%u", attr, *type);
         return 0;
 }
 
@@ -216,23 +205,23 @@ int link_config_load(link_config_ctx *ctx) {
         }
 
         /* update timestamp */
-        paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, true);
+        paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, true);
 
-        r = conf_files_list_strv(&files, ".link", NULL, 0, link_dirs);
+        r = conf_files_list_strv(&files, ".link", NULL, 0, NETWORK_DIRS);
         if (r < 0)
                 return log_error_errno(r, "failed to enumerate link files: %m");
 
         STRV_FOREACH_BACKWARDS(f, files) {
-                r = load_link(ctx, *f);
+                r = link_load_one(ctx, *f);
                 if (r < 0)
-                        return r;
+                        log_error_errno(r, "Failed to load %s, ignoring: %m", *f);
         }
 
         return 0;
 }
 
 bool link_config_should_reload(link_config_ctx *ctx) {
-        return paths_check_timestamp(link_dirs, &ctx->link_dirs_ts_usec, false);
+        return paths_check_timestamp(NETWORK_DIRS, &ctx->network_dirs_ts_usec, false);
 }
 
 int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
@@ -243,33 +232,25 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
         assert(ret);
 
         LIST_FOREACH(links, link, ctx->links) {
-                const char *address = NULL, *id_path = NULL, *parent_driver = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL;
-                sd_device *parent;
+                const char *address = NULL, *id_path = NULL, *id_net_driver = NULL, *devtype = NULL, *sysname = NULL;
 
                 (void) sd_device_get_sysattr_value(device, "address", &address);
                 (void) sd_device_get_property_value(device, "ID_PATH", &id_path);
-                if (sd_device_get_parent(device, &parent) >= 0)
-                        (void) sd_device_get_driver(parent, &parent_driver);
                 (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &id_net_driver);
                 (void) sd_device_get_devtype(device, &devtype);
                 (void) sd_device_get_sysname(device, &sysname);
 
                 if (net_match_config(link->match_mac, link->match_path, link->match_driver,
-                                     link->match_type, link->match_name, link->match_host,
-                                     link->match_virt, link->match_kernel_cmdline,
-                                     link->match_kernel_version, link->match_arch,
+                                     link->match_type, link->match_name,
                                      address ? ether_aton(address) : NULL,
                                      id_path,
-                                     parent_driver,
                                      id_net_driver,
                                      devtype,
                                      sysname)) {
                         if (link->match_name) {
-                                unsigned char name_assign_type = NET_NAME_UNKNOWN;
-                                const char *attr_value;
+                                unsigned name_assign_type = NET_NAME_UNKNOWN;
 
-                                if (sd_device_get_sysattr_value(device, "name_assign_type", &attr_value) >= 0)
-                                        (void) safe_atou8(attr_value, &name_assign_type);
+                                (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type);
 
                                 if (name_assign_type == NET_NAME_ENUM) {
                                         log_warning("Config file %s applies to device based on potentially unpredictable interface name '%s'",
@@ -297,34 +278,41 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret)
         return -ENOENT;
 }
 
-static bool mac_is_random(sd_device *device) {
-        const char *s;
-        unsigned type;
+static int get_mac(sd_device *device, MACAddressPolicy policy, struct ether_addr *mac) {
+        unsigned addr_type;
+        bool want_random = policy == MAC_ADDRESS_POLICY_RANDOM;
         int r;
 
-        /* if we can't get the assign type, assume it is not random */
-        if (sd_device_get_sysattr_value(device, "addr_assign_type", &s) < 0)
-                return false;
+        assert(IN_SET(policy, MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_PERSISTENT));
 
-        r = safe_atou(s, &type);
+        r = link_unsigned_attribute(device, "addr_assign_type", &addr_type);
         if (r < 0)
-                return false;
-
-        return type == NET_ADDR_RANDOM;
-}
+                return r;
+        switch (addr_type) {
+        case NET_ADDR_SET:
+                return log_device_debug(device, "MAC on the device already set by userspace");
+        case NET_ADDR_STOLEN:
+                return log_device_debug(device, "MAC on the device already set based on another device");
+        case NET_ADDR_RANDOM:
+        case NET_ADDR_PERM:
+                break;
+        default:
+                return log_device_warning(device, "Unknown addr_assign_type %u, ignoring", addr_type);
+        }
 
-static int get_mac(sd_device *device, bool want_random,
-                   struct ether_addr *mac) {
-        int r;
+        if (want_random == (addr_type == NET_ADDR_RANDOM))
+                return log_device_debug(device, "MAC on the device already matches policy *%s*",
+                                        mac_address_policy_to_string(policy));
 
-        if (want_random)
+        if (want_random) {
+                log_device_debug(device, "Using random bytes to generate MAC");
                 random_bytes(mac->ether_addr_octet, ETH_ALEN);
-        else {
+        else {
                 uint64_t result;
 
                 r = net_get_unique_predictable_data(device, &result);
                 if (r < 0)
-                        return r;
+                        return log_device_warning_errno(device, r, "Could not generate persistent MAC: %m");
 
                 assert_cc(ETH_ALEN <= sizeof(result));
                 memcpy(mac->ether_addr_octet, &result, ETH_ALEN);
@@ -333,8 +321,7 @@ static int get_mac(sd_device *device, bool want_random,
         /* see eth_random_addr in the kernel */
         mac->ether_addr_octet[0] &= 0xfe;  /* clear multicast bit */
         mac->ether_addr_octet[0] |= 0x02;  /* set local assignment bit (IEEE802) */
-
-        return 0;
+        return 1;
 }
 
 int link_config_apply(link_config_ctx *ctx, link_config *config,
@@ -398,7 +385,7 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
                 return log_device_warning_errno(device, r, "Could not find ifindex: %m");
 
 
-        (void) link_name_type(device, &name_type);
+        (void) link_unsigned_attribute(device, "name_assign_type", &name_type);
 
         if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
             && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
@@ -455,33 +442,11 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
                 log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
  no_rename:
 
-        switch (config->mac_policy) {
-                case MACPOLICY_PERSISTENT:
-                        if (mac_is_random(device)) {
-                                r = get_mac(device, false, &generated_mac);
-                                if (r == -ENOENT) {
-                                        log_warning_errno(r, "Could not generate persistent MAC address for %s: %m", old_name);
-                                        break;
-                                } else if (r < 0)
-                                        return r;
-                                mac = &generated_mac;
-                        }
-                        break;
-                case MACPOLICY_RANDOM:
-                        if (!mac_is_random(device)) {
-                                r = get_mac(device, true, &generated_mac);
-                                if (r == -ENOENT) {
-                                        log_warning_errno(r, "Could not generate random MAC address for %s: %m", old_name);
-                                        break;
-                                } else if (r < 0)
-                                        return r;
-                                mac = &generated_mac;
-                        }
-                        break;
-                case MACPOLICY_NONE:
-                default:
-                        mac = config->mac;
-        }
+        if (IN_SET(config->mac_address_policy, MAC_ADDRESS_POLICY_PERSISTENT, MAC_ADDRESS_POLICY_RANDOM)) {
+                if (get_mac(device, config->mac_address_policy, &generated_mac) > 0)
+                        mac = &generated_mac;
+        } else
+                mac = config->mac;
 
         r = rtnl_set_link_properties(&ctx->rtnl, ifindex, config->alias, mac, config->mtu);
         if (r < 0)
@@ -509,14 +474,14 @@ int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
         return 0;
 }
 
-static const char* const mac_policy_table[_MACPOLICY_MAX] = {
-        [MACPOLICY_PERSISTENT] = "persistent",
-        [MACPOLICY_RANDOM] = "random",
-        [MACPOLICY_NONE] = "none",
+static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = {
+        [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent",
+        [MAC_ADDRESS_POLICY_RANDOM] = "random",
+        [MAC_ADDRESS_POLICY_NONE] = "none",
 };
 
-DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
+DEFINE_STRING_TABLE_LOOKUP(mac_address_policy, MACAddressPolicy);
+DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_address_policy, mac_address_policy, MACAddressPolicy,
                          "Failed to parse MAC address policy");
 
 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
index 1113b10..efe5f2c 100644 (file)
 typedef struct link_config_ctx link_config_ctx;
 typedef struct link_config link_config;
 
-typedef enum MACPolicy {
-        MACPOLICY_PERSISTENT,
-        MACPOLICY_RANDOM,
-        MACPOLICY_NONE,
-        _MACPOLICY_MAX,
-        _MACPOLICY_INVALID = -1
-} MACPolicy;
+typedef enum MACAddressPolicy {
+        MAC_ADDRESS_POLICY_PERSISTENT,
+        MAC_ADDRESS_POLICY_RANDOM,
+        MAC_ADDRESS_POLICY_NONE,
+        _MAC_ADDRESS_POLICY_MAX,
+        _MAC_ADDRESS_POLICY_INVALID = -1
+} MACAddressPolicy;
 
 typedef enum NamePolicy {
         NAMEPOLICY_KERNEL,
@@ -40,15 +40,11 @@ struct link_config {
         char **match_driver;
         char **match_type;
         char **match_name;
-        Condition *match_host;
-        Condition *match_virt;
-        Condition *match_kernel_cmdline;
-        Condition *match_kernel_version;
-        Condition *match_arch;
+        LIST_HEAD(Condition, conditions);
 
         char *description;
         struct ether_addr *mac;
-        MACPolicy mac_policy;
+        MACAddressPolicy mac_address_policy;
         NamePolicy *name_policy;
         char *name;
         char *alias;
@@ -67,7 +63,9 @@ struct link_config {
 
 int link_config_ctx_new(link_config_ctx **ret);
 void link_config_ctx_free(link_config_ctx *ctx);
+DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free);
 
+int link_load_one(link_config_ctx *ctx, const char *filename);
 int link_config_load(link_config_ctx *ctx);
 bool link_config_should_reload(link_config_ctx *ctx);
 
@@ -78,11 +76,11 @@ int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret);
 const char *name_policy_to_string(NamePolicy p) _const_;
 NamePolicy name_policy_from_string(const char *p) _pure_;
 
-const char *mac_policy_to_string(MACPolicy p) _const_;
-MACPolicy mac_policy_from_string(const char *p) _pure_;
+const char *mac_address_policy_to_string(MACAddressPolicy p) _const_;
+MACAddressPolicy mac_address_policy_from_string(const char *p) _pure_;
 
 /* gperf lookup function */
 const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, GPERF_LEN_TYPE length);
 
-CONFIG_PARSER_PROTOTYPE(config_parse_mac_policy);
+CONFIG_PARSER_PROTOTYPE(config_parse_mac_address_policy);
 CONFIG_PARSER_PROTOTYPE(config_parse_name_policy);
index c67d047..7ca0185 100644 (file)
 #include <time.h>
 #include <unistd.h>
 
+#include "memory-util.h"
 #include "random-util.h"
 #include "scsi.h"
 #include "scsi_id.h"
 #include "string-util.h"
-#include "util.h"
 
 /*
  * A priority based list of id, naa, and binary/ascii for the identifier
index 3525d25..7bdf6cf 100644 (file)
@@ -138,13 +138,12 @@ static void set_scsi_type(char *to, const char *from, size_t len) {
 #define USB_DT_INTERFACE                0x04
 
 static int dev_if_packed_info(sd_device *dev, char *ifs_str, size_t len) {
-        _cleanup_free_ char *filename = NULL;
         _cleanup_close_ int fd = -1;
         ssize_t size;
         unsigned char buf[18 + 65535];
         size_t pos = 0;
         unsigned strpos = 0;
-        const char *syspath;
+        const char *filename, *syspath;
         int r;
         struct usb_interface_descriptor {
                 uint8_t bLength;
@@ -161,16 +160,17 @@ static int dev_if_packed_info(sd_device *dev, char *ifs_str, size_t len) {
         r = sd_device_get_syspath(dev, &syspath);
         if (r < 0)
                 return r;
-        if (asprintf(&filename, "%s/descriptors", syspath) < 0)
-                return log_oom();
 
+        filename = strjoina(syspath, "/descriptors");
         fd = open(filename, O_RDONLY|O_CLOEXEC);
         if (fd < 0)
-                return log_device_debug_errno(dev, errno, "Failed to open USB device 'descriptors' file: %m");
+                return log_device_debug_errno(dev, errno, "Failed to open \"%s\": %m", filename);
 
         size = read(fd, buf, sizeof(buf));
-        if (size < 18 || (size_t) size >= sizeof(buf))
-                return -EIO;
+        if (size < 18)
+                return log_device_warning_errno(dev, SYNTHETIC_ERRNO(EIO),
+                                                "Short read from \"%s\"", filename);
+        assert((size_t) size <= sizeof buf);
 
         ifs_str[0] = '\0';
         while (pos + sizeof(struct usb_interface_descriptor) < (size_t) size &&
@@ -179,9 +179,12 @@ static int dev_if_packed_info(sd_device *dev, char *ifs_str, size_t len) {
                 struct usb_interface_descriptor *desc;
                 char if_str[8];
 
-                desc = (struct usb_interface_descriptor *) &buf[pos];
+                desc = (struct usb_interface_descriptor *) (buf + pos);
                 if (desc->bLength < 3)
                         break;
+                if (desc->bLength > size - sizeof(struct usb_interface_descriptor))
+                        return log_device_debug_errno(dev, SYNTHETIC_ERRNO(EIO),
+                                                      "Corrupt data read from \"%s\"", filename);
                 pos += desc->bLength;
 
                 if (desc->bDescriptorType != USB_DT_INTERFACE)
index 48ce295..7bbfd14 100644 (file)
@@ -12,7 +12,7 @@
 
 static bool initialized;
 
-static const struct udev_builtin *builtins[_UDEV_BUILTIN_MAX] = {
+static const struct udev_builtin *const builtins[_UDEV_BUILTIN_MAX] = {
 #if HAVE_BLKID
         [UDEV_BUILTIN_BLKID] = &udev_builtin_blkid,
 #endif
index c217815..c3dc213 100644 (file)
 #include <sys/un.h>
 #include <unistd.h>
 
+#include "sd-event.h"
+
 #include "alloc-util.h"
+#include "errno-util.h"
 #include "fd-util.h"
 #include "format-util.h"
 #include "io-util.h"
 /* wire protocol magic must match */
 #define UDEV_CTRL_MAGIC                                0xdead1dea
 
-enum udev_ctrl_msg_type {
-        UDEV_CTRL_UNKNOWN,
-        UDEV_CTRL_SET_LOG_LEVEL,
-        UDEV_CTRL_STOP_EXEC_QUEUE,
-        UDEV_CTRL_START_EXEC_QUEUE,
-        UDEV_CTRL_RELOAD,
-        UDEV_CTRL_SET_ENV,
-        UDEV_CTRL_SET_CHILDREN_MAX,
-        UDEV_CTRL_PING,
-        UDEV_CTRL_EXIT,
-};
-
 struct udev_ctrl_msg_wire {
         char version[16];
         unsigned magic;
         enum udev_ctrl_msg_type type;
-        union {
-                int intval;
-                char buf[256];
-        };
-};
-
-struct udev_ctrl_msg {
-        unsigned n_ref;
-        struct udev_ctrl_connection *conn;
-        struct udev_ctrl_msg_wire ctrl_msg_wire;
+        union udev_ctrl_msg_value value;
 };
 
 struct udev_ctrl {
         unsigned n_ref;
         int sock;
+        int sock_connect;
         union sockaddr_union saddr;
         socklen_t addrlen;
-        bool bound;
-        bool cleanup_socket;
-        bool connected;
-};
-
-struct udev_ctrl_connection {
-        unsigned n_ref;
-        struct udev_ctrl *uctrl;
-        int sock;
+        bool bound:1;
+        bool cleanup_socket:1;
+        bool connected:1;
+        bool maybe_disconnected:1;
+        sd_event *event;
+        sd_event_source *event_source;
+        sd_event_source *event_source_connect;
+        udev_ctrl_handler_t callback;
+        void *userdata;
 };
 
-struct udev_ctrl *udev_ctrl_new_from_fd(int fd) {
+int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd) {
+        _cleanup_close_ int sock = -1;
         struct udev_ctrl *uctrl;
         int r;
 
-        uctrl = new0(struct udev_ctrl, 1);
-        if (!uctrl)
-                return NULL;
-        uctrl->n_ref = 1;
+        assert(ret);
 
         if (fd < 0) {
-                uctrl->sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
-                if (uctrl->sock < 0) {
-                        log_error_errno(errno, "Failed to create socket: %m");
-                        udev_ctrl_unref(uctrl);
-                        return NULL;
-                }
-        } else {
-                uctrl->bound = true;
-                uctrl->sock = fd;
+                sock = socket(AF_LOCAL, SOCK_SEQPACKET|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
+                if (sock < 0)
+                        return log_error_errno(errno, "Failed to create socket: %m");
         }
 
+        uctrl = new(struct udev_ctrl, 1);
+        if (!uctrl)
+                return -ENOMEM;
+
+        *uctrl = (struct udev_ctrl) {
+                .n_ref = 1,
+                .sock = fd >= 0 ? fd : TAKE_FD(sock),
+                .bound = fd >= 0,
+        };
+
         /*
          * FIXME: remove it as soon as we can depend on this:
          *   http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=90c6bd34f884cd9cee21f1d152baf6c18bcac949
@@ -108,45 +93,58 @@ struct udev_ctrl *udev_ctrl_new_from_fd(int fd) {
         };
 
         uctrl->addrlen = SOCKADDR_UN_LEN(uctrl->saddr.un);
-        return uctrl;
-}
 
-struct udev_ctrl *udev_ctrl_new(void) {
-        return udev_ctrl_new_from_fd(-1);
+        *ret = TAKE_PTR(uctrl);
+        return 0;
 }
 
 int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl) {
-        int err;
-
-        if (!uctrl->bound) {
-                err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
-                if (err < 0 && errno == EADDRINUSE) {
-                        (void) sockaddr_un_unlink(&uctrl->saddr.un);
-                        err = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
-                }
+        int r;
 
-                if (err < 0)
-                        return log_error_errno(errno, "Failed to bind socket: %m");
+        assert(uctrl);
 
-                err = listen(uctrl->sock, 0);
-                if (err < 0)
-                        return log_error_errno(errno, "Failed to listen: %m");
+        if (uctrl->bound)
+                return 0;
 
-                uctrl->bound = true;
-                uctrl->cleanup_socket = true;
+        r = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
+        if (r < 0 && errno == EADDRINUSE) {
+                (void) sockaddr_un_unlink(&uctrl->saddr.un);
+                r = bind(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen);
         }
+
+        if (r < 0)
+                return log_error_errno(errno, "Failed to bind udev control socket: %m");
+
+        if (listen(uctrl->sock, 0) < 0)
+                return log_error_errno(errno, "Failed to listen udev control socket: %m");
+
+        uctrl->bound = true;
+        uctrl->cleanup_socket = true;
+
         return 0;
 }
 
+static void udev_ctrl_disconnect(struct udev_ctrl *uctrl) {
+        if (!uctrl)
+                return;
+
+        uctrl->event_source_connect = sd_event_source_unref(uctrl->event_source_connect);
+        uctrl->sock_connect = safe_close(uctrl->sock_connect);
+}
+
 static struct udev_ctrl *udev_ctrl_free(struct udev_ctrl *uctrl) {
         assert(uctrl);
 
+        udev_ctrl_disconnect(uctrl);
+
+        sd_event_source_unref(uctrl->event_source);
         safe_close(uctrl->sock);
+
+        sd_event_unref(uctrl->event);
         return mfree(uctrl);
 }
 
-DEFINE_PRIVATE_TRIVIAL_REF_FUNC(struct udev_ctrl, udev_ctrl);
-DEFINE_TRIVIAL_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free);
+DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl, udev_ctrl, udev_ctrl_free);
 
 int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
         if (!uctrl)
@@ -156,142 +154,41 @@ int udev_ctrl_cleanup(struct udev_ctrl *uctrl) {
         return 0;
 }
 
-int udev_ctrl_get_fd(struct udev_ctrl *uctrl) {
-        if (!uctrl)
-                return -EINVAL;
-        return uctrl->sock;
-}
-
-struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl) {
-        struct udev_ctrl_connection *conn;
-        struct ucred ucred = {};
+int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event) {
         int r;
 
-        conn = new(struct udev_ctrl_connection, 1);
-        if (!conn)
-                return NULL;
-        conn->n_ref = 1;
-        conn->uctrl = uctrl;
+        assert_return(uctrl, -EINVAL);
+        assert_return(!uctrl->event, -EBUSY);
 
-        conn->sock = accept4(uctrl->sock, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
-        if (conn->sock < 0) {
-                if (errno != EINTR)
-                        log_error_errno(errno, "Failed to receive ctrl connection: %m");
-                goto err;
+        if (event)
+                uctrl->event = sd_event_ref(event);
+        else {
+                r = sd_event_default(&uctrl->event);
+                if (r < 0)
+                        return r;
         }
 
-        /* check peer credential of connection */
-        r = getpeercred(conn->sock, &ucred);
-        if (r < 0) {
-                log_error_errno(r, "Failed to receive credentials of ctrl connection: %m");
-                goto err;
-        }
-        if (ucred.uid > 0) {
-                log_error("Sender uid="UID_FMT", message ignored", ucred.uid);
-                goto err;
-        }
-
-        /* enable receiving of the sender credentials in the messages */
-        r = setsockopt_int(conn->sock, SOL_SOCKET, SO_PASSCRED, true);
-        if (r < 0)
-                log_warning_errno(r, "Failed to set SO_PASSCRED: %m");
-
-        udev_ctrl_ref(uctrl);
-        return conn;
-err:
-        safe_close(conn->sock);
-        return mfree(conn);
-}
-
-static struct udev_ctrl_connection *udev_ctrl_connection_free(struct udev_ctrl_connection *conn) {
-        assert(conn);
-
-        safe_close(conn->sock);
-        udev_ctrl_unref(conn->uctrl);
-        return mfree(conn);
-}
-
-DEFINE_TRIVIAL_REF_UNREF_FUNC(struct udev_ctrl_connection, udev_ctrl_connection, udev_ctrl_connection_free);
-
-static int ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf, usec_t timeout) {
-        struct udev_ctrl_msg_wire ctrl_msg_wire = {
-                .version = "udev-" STRINGIFY(PROJECT_VERSION),
-                .magic = UDEV_CTRL_MAGIC,
-                .type = type,
-        };
-
-        if (buf)
-                strscpy(ctrl_msg_wire.buf, sizeof(ctrl_msg_wire.buf), buf);
-        else
-                ctrl_msg_wire.intval = intval;
-
-        if (!uctrl->connected) {
-                if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0)
-                        return -errno;
-                uctrl->connected = true;
-        }
-        if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0)
-                return -errno;
-
-        /* wait for peer message handling or disconnect */
-        for (;;) {
-                struct pollfd pfd = {
-                        .fd = uctrl->sock,
-                        .events = POLLIN,
-                };
-                int r;
-
-                r = poll(&pfd, 1, DIV_ROUND_UP(timeout, USEC_PER_MSEC));
-                if (r < 0) {
-                        if (errno == EINTR)
-                                continue;
-                        return -errno;
-                }
-                if (r == 0)
-                        return -ETIMEDOUT;
-                if (pfd.revents & POLLERR)
-                        return -EIO;
-                return 0;
-        }
-}
-
-int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, usec_t timeout) {
-        return ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL, timeout);
-}
-
-int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, usec_t timeout) {
-        return ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL, timeout);
-}
-
-int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, usec_t timeout) {
-        return ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL, timeout);
+        return 0;
 }
 
-int udev_ctrl_send_reload(struct udev_ctrl *uctrl, usec_t timeout) {
-        return ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL, timeout);
-}
+sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl) {
+        assert(uctrl);
 
-int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, usec_t timeout) {
-        return ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key, timeout);
+        return uctrl->event_source;
 }
 
-int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, usec_t timeout) {
-        return ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL, timeout);
+static void udev_ctrl_disconnect_and_listen_again(struct udev_ctrl *uctrl) {
+        udev_ctrl_disconnect(uctrl);
+        udev_ctrl_unref(uctrl);
+        (void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON);
 }
 
-int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout) {
-        return ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL, timeout);
-}
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl *, udev_ctrl_disconnect_and_listen_again);
 
-int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout) {
-        return ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL, timeout);
-}
-
-struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) {
-        struct udev_ctrl_msg *uctrl_msg;
-        ssize_t size;
-        struct cmsghdr *cmsg;
-        struct iovec iov;
+static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        _cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL;
+        struct udev_ctrl_msg_wire msg_wire;
+        struct iovec iov = IOVEC_MAKE(&msg_wire, sizeof(struct udev_ctrl_msg_wire));
         char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
         struct msghdr smsg = {
                 .msg_iov = &iov,
@@ -299,47 +196,28 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) {
                 .msg_control = cred_msg,
                 .msg_controllen = sizeof(cred_msg),
         };
+        struct cmsghdr *cmsg;
         struct ucred *cred;
+        ssize_t size;
 
-        uctrl_msg = new0(struct udev_ctrl_msg, 1);
-        if (!uctrl_msg)
-                return NULL;
-        uctrl_msg->n_ref = 1;
-        uctrl_msg->conn = conn;
-        udev_ctrl_connection_ref(conn);
-
-        /* wait for the incoming message */
-        for (;;) {
-                struct pollfd pfd[1];
-                int r;
-
-                pfd[0].fd = conn->sock;
-                pfd[0].events = POLLIN;
-
-                r = poll(pfd, 1, 10000);
-                if (r < 0) {
-                        if (errno == EINTR)
-                                continue;
-                        goto err;
-                } else if (r == 0) {
-                        log_error("Timeout waiting for ctrl message");
-                        goto err;
-                } else {
-                        if (!(pfd[0].revents & POLLIN)) {
-                                log_error("Invalid ctrl connection: %m");
-                                goto err;
-                        }
-                }
-
-                break;
-        }
+        assert(userdata);
+
+        /* When UDEV_CTRL_EXIT is received, manager unref udev_ctrl object.
+         * To avoid the object freed, let's increment the refcount. */
+        uctrl = udev_ctrl_ref(userdata);
 
-        iov = IOVEC_MAKE(&uctrl_msg->ctrl_msg_wire, sizeof(struct udev_ctrl_msg_wire));
+        size = next_datagram_size_fd(fd);
+        if (size < 0)
+                return log_error_errno(size, "Failed to get size of message: %m");
+        if (size == 0)
+                return 0; /* Client disconnects? */
 
-        size = recvmsg(conn->sock, &smsg, 0);
+        size = recvmsg(fd, &smsg, 0);
         if (size < 0) {
-                log_error_errno(errno, "Failed to receive ctrl message: %m");
-                goto err;
+                if (errno != EINTR)
+                        return log_error_errno(errno, "Failed to receive ctrl message: %m");
+
+                return 0;
         }
 
         cmsg_close_all(&smsg);
@@ -348,80 +226,183 @@ struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn) {
 
         if (!cmsg || cmsg->cmsg_type != SCM_CREDENTIALS) {
                 log_error("No sender credentials received, ignoring message");
-                goto err;
+                return 0;
         }
 
         cred = (struct ucred *) CMSG_DATA(cmsg);
 
         if (cred->uid != 0) {
-                log_error("Sender uid="UID_FMT", ignoring message", cred->uid);
-                goto err;
+                log_error("Invalid sender uid "UID_FMT", ignoring message", cred->uid);
+                return 0;
         }
 
-        if (uctrl_msg->ctrl_msg_wire.magic != UDEV_CTRL_MAGIC) {
-                log_error("Message magic 0x%08x doesn't match, ignoring", uctrl_msg->ctrl_msg_wire.magic);
-                goto err;
+        if (msg_wire.magic != UDEV_CTRL_MAGIC) {
+                log_error("Message magic 0x%08x doesn't match, ignoring message", msg_wire.magic);
+                return 0;
         }
 
-        return uctrl_msg;
-err:
-        udev_ctrl_msg_unref(uctrl_msg);
-        return NULL;
-}
+        if (msg_wire.type == _UDEV_CTRL_END_MESSAGES)
+                return 0;
 
-static struct udev_ctrl_msg *udev_ctrl_msg_free(struct udev_ctrl_msg *ctrl_msg) {
-        assert(ctrl_msg);
+        if (uctrl->callback)
+                (void) uctrl->callback(uctrl, msg_wire.type, &msg_wire.value, uctrl->userdata);
 
-        udev_ctrl_connection_unref(ctrl_msg->conn);
-        return mfree(ctrl_msg);
+        /* Do not disconnect and wait for next message. */
+        uctrl = udev_ctrl_unref(uctrl);
+        return 0;
 }
 
-DEFINE_TRIVIAL_UNREF_FUNC(struct udev_ctrl_msg, udev_ctrl_msg, udev_ctrl_msg_free);
+static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        struct udev_ctrl *uctrl = userdata;
+        _cleanup_close_ int sock = -1;
+        struct ucred ucred;
+        int r;
 
-int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg) {
-        if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_LOG_LEVEL)
-                return ctrl_msg->ctrl_msg_wire.intval;
-        return -1;
-}
+        assert(uctrl);
 
-int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg) {
-        if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_STOP_EXEC_QUEUE)
-                return 1;
-        return -1;
-}
+        sock = accept4(fd, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
+        if (sock < 0) {
+                if (ERRNO_IS_ACCEPT_AGAIN(errno))
+                        return 0;
 
-int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg) {
-        if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_START_EXEC_QUEUE)
-                return 1;
-        return -1;
-}
+                return log_error_errno(errno, "Failed to accept ctrl connection: %m");
+        }
+
+        /* check peer credential of connection */
+        r = getpeercred(sock, &ucred);
+        if (r < 0) {
+                log_error_errno(r, "Failed to receive credentials of ctrl connection: %m");
+                return 0;
+        }
 
-int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg) {
-        if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_RELOAD)
-                return 1;
-        return -1;
+        if (ucred.uid > 0) {
+                log_error("Invalid sender uid "UID_FMT", closing connection", ucred.uid);
+                return 0;
+        }
+
+        /* enable receiving of the sender credentials in the messages */
+        r = setsockopt_int(sock, SOL_SOCKET, SO_PASSCRED, true);
+        if (r < 0)
+                log_warning_errno(r, "Failed to set SO_PASSCRED, ignoring: %m");
+
+        r = sd_event_add_io(uctrl->event, &uctrl->event_source_connect, sock, EPOLLIN, udev_ctrl_connection_event_handler, uctrl);
+        if (r < 0) {
+                log_error_errno(r, "Failed to create event source for udev control connection: %m");
+                return 0;
+        }
+
+        (void) sd_event_source_set_description(uctrl->event_source_connect, "udev-ctrl-connection");
+
+        /* Do not accept multiple connection. */
+        (void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_OFF);
+
+        uctrl->sock_connect = TAKE_FD(sock);
+        return 0;
 }
 
-const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg) {
-        if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_ENV)
-                return ctrl_msg->ctrl_msg_wire.buf;
-        return NULL;
+int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata) {
+        int r;
+
+        assert(uctrl);
+
+        if (!uctrl->event) {
+                r = udev_ctrl_attach_event(uctrl, NULL);
+                if (r < 0)
+                        return r;
+        }
+
+        r = udev_ctrl_enable_receiving(uctrl);
+        if (r < 0)
+                return r;
+
+        uctrl->callback = callback;
+        uctrl->userdata = userdata;
+
+        r = sd_event_add_io(uctrl->event, &uctrl->event_source, uctrl->sock, EPOLLIN, udev_ctrl_event_handler, uctrl);
+        if (r < 0)
+                return r;
+
+        (void) sd_event_source_set_description(uctrl->event_source, "udev-ctrl");
+
+        return 0;
 }
 
-int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg) {
-        if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_SET_CHILDREN_MAX)
-                return ctrl_msg->ctrl_msg_wire.intval;
-        return -1;
+int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf) {
+        struct udev_ctrl_msg_wire ctrl_msg_wire = {
+                .version = "udev-" STRINGIFY(PROJECT_VERSION),
+                .magic = UDEV_CTRL_MAGIC,
+                .type = type,
+        };
+
+        if (uctrl->maybe_disconnected)
+                return -ENOANO; /* to distinguish this from other errors. */
+
+        if (buf)
+                strscpy(ctrl_msg_wire.value.buf, sizeof(ctrl_msg_wire.value.buf), buf);
+        else
+                ctrl_msg_wire.value.intval = intval;
+
+        if (!uctrl->connected) {
+                if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0)
+                        return -errno;
+                uctrl->connected = true;
+        }
+
+        if (send(uctrl->sock, &ctrl_msg_wire, sizeof(ctrl_msg_wire), 0) < 0)
+                return -errno;
+
+        if (type == UDEV_CTRL_EXIT)
+                uctrl->maybe_disconnected = true;
+
+        return 0;
 }
 
-int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg) {
-        if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_PING)
-                return 1;
-        return -1;
+static int udev_ctrl_wait_io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+        return sd_event_exit(sd_event_source_get_event(s), 0);
 }
 
-int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg) {
-        if (ctrl_msg->ctrl_msg_wire.type == UDEV_CTRL_EXIT)
-                return 1;
-        return -1;
+int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout) {
+        _cleanup_(sd_event_source_unrefp) sd_event_source *source_io = NULL, *source_timeout = NULL;
+        int r;
+
+        assert(uctrl);
+
+        if (uctrl->sock < 0)
+                return 0;
+        if (!uctrl->connected)
+                return 0;
+
+        if (!uctrl->maybe_disconnected) {
+                r = udev_ctrl_send(uctrl, _UDEV_CTRL_END_MESSAGES, 0, NULL);
+                if (r < 0)
+                        return r;
+        }
+
+        if (timeout == 0)
+                return 0;
+
+        if (!uctrl->event) {
+                r = udev_ctrl_attach_event(uctrl, NULL);
+                if (r < 0)
+                        return r;
+        }
+
+        r = sd_event_add_io(uctrl->event, &source_io, uctrl->sock, EPOLLIN, udev_ctrl_wait_io_handler, NULL);
+        if (r < 0)
+                return r;
+
+        (void) sd_event_source_set_description(uctrl->event_source, "udev-ctrl-wait-io");
+
+        if (timeout != USEC_INFINITY) {
+                usec_t usec;
+
+                usec = now(clock_boottime_or_monotonic()) + timeout;
+                r = sd_event_add_time(uctrl->event, &source_timeout, clock_boottime_or_monotonic(), usec, 0, NULL, INT_TO_PTR(-ETIMEDOUT));
+                if (r < 0)
+                        return r;
+
+                (void) sd_event_source_set_description(source_timeout, "udev-ctrl-wait-io");
+        }
+
+        return sd_event_loop(uctrl->event);
 }
index 8e452a4..2c84a8b 100644 (file)
@@ -1,42 +1,79 @@
 /* SPDX-License-Identifier: GPL-2.0+ */
 #pragma once
 
+#include "sd-event.h"
+
 #include "macro.h"
 #include "time-util.h"
 
 struct udev_ctrl;
-struct udev_ctrl *udev_ctrl_new(void);
-struct udev_ctrl *udev_ctrl_new_from_fd(int fd);
+
+enum udev_ctrl_msg_type {
+        _UDEV_CTRL_END_MESSAGES,
+        UDEV_CTRL_SET_LOG_LEVEL,
+        UDEV_CTRL_STOP_EXEC_QUEUE,
+        UDEV_CTRL_START_EXEC_QUEUE,
+        UDEV_CTRL_RELOAD,
+        UDEV_CTRL_SET_ENV,
+        UDEV_CTRL_SET_CHILDREN_MAX,
+        UDEV_CTRL_PING,
+        UDEV_CTRL_EXIT,
+};
+
+union udev_ctrl_msg_value {
+        int intval;
+        char buf[256];
+};
+
+typedef int (*udev_ctrl_handler_t)(struct udev_ctrl *udev_ctrl, enum udev_ctrl_msg_type type,
+                                   const union udev_ctrl_msg_value *value, void *userdata);
+
+int udev_ctrl_new_from_fd(struct udev_ctrl **ret, int fd);
+static inline int udev_ctrl_new(struct udev_ctrl **ret) {
+        return udev_ctrl_new_from_fd(ret, -1);
+}
+
 int udev_ctrl_enable_receiving(struct udev_ctrl *uctrl);
+struct udev_ctrl *udev_ctrl_ref(struct udev_ctrl *uctrl);
 struct udev_ctrl *udev_ctrl_unref(struct udev_ctrl *uctrl);
 int udev_ctrl_cleanup(struct udev_ctrl *uctrl);
-int udev_ctrl_get_fd(struct udev_ctrl *uctrl);
-int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority, usec_t timeout);
-int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl, usec_t timeout);
-int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl, usec_t timeout);
-int udev_ctrl_send_reload(struct udev_ctrl *uctrl, usec_t timeout);
-int udev_ctrl_send_ping(struct udev_ctrl *uctrl, usec_t timeout);
-int udev_ctrl_send_exit(struct udev_ctrl *uctrl, usec_t timeout);
-int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key, usec_t timeout);
-int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count, usec_t timeout);
-
-struct udev_ctrl_connection;
-struct udev_ctrl_connection *udev_ctrl_get_connection(struct udev_ctrl *uctrl);
-struct udev_ctrl_connection *udev_ctrl_connection_ref(struct udev_ctrl_connection *conn);
-struct udev_ctrl_connection *udev_ctrl_connection_unref(struct udev_ctrl_connection *conn);
-
-struct udev_ctrl_msg;
-struct udev_ctrl_msg *udev_ctrl_receive_msg(struct udev_ctrl_connection *conn);
-struct udev_ctrl_msg *udev_ctrl_msg_unref(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_set_log_level(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_stop_exec_queue(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_start_exec_queue(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_reload(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_ping(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_exit(struct udev_ctrl_msg *ctrl_msg);
-const char *udev_ctrl_get_set_env(struct udev_ctrl_msg *ctrl_msg);
-int udev_ctrl_get_set_children_max(struct udev_ctrl_msg *ctrl_msg);
+int udev_ctrl_attach_event(struct udev_ctrl *uctrl, sd_event *event);
+int udev_ctrl_start(struct udev_ctrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
+sd_event_source *udev_ctrl_get_event_source(struct udev_ctrl *uctrl);
+
+int udev_ctrl_wait(struct udev_ctrl *uctrl, usec_t timeout);
+
+int udev_ctrl_send(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, int intval, const char *buf);
+static inline int udev_ctrl_send_set_log_level(struct udev_ctrl *uctrl, int priority) {
+        return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
+}
+
+static inline int udev_ctrl_send_stop_exec_queue(struct udev_ctrl *uctrl) {
+        return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
+}
+
+static inline int udev_ctrl_send_start_exec_queue(struct udev_ctrl *uctrl) {
+        return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
+}
+
+static inline int udev_ctrl_send_reload(struct udev_ctrl *uctrl) {
+        return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL);
+}
+
+static inline int udev_ctrl_send_set_env(struct udev_ctrl *uctrl, const char *key) {
+        return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
+}
+
+static inline int udev_ctrl_send_set_children_max(struct udev_ctrl *uctrl, int count) {
+        return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL);
+}
+
+static inline int udev_ctrl_send_ping(struct udev_ctrl *uctrl) {
+        return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL);
+}
+
+static inline int udev_ctrl_send_exit(struct udev_ctrl *uctrl) {
+        return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL);
+}
 
 DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl*, udev_ctrl_unref);
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_connection*, udev_ctrl_connection_unref);
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl_msg*, udev_ctrl_msg_unref);
index 07b7365..cab1b5a 100644 (file)
@@ -28,6 +28,7 @@
 #include "strxcpyx.h"
 #include "udev-builtin.h"
 #include "udev-node.h"
+#include "udev-util.h"
 #include "udev-watch.h"
 #include "udev.h"
 
@@ -71,8 +72,8 @@ UdevEvent *udev_event_free(UdevEvent *event) {
         sd_device_unref(event->dev);
         sd_device_unref(event->dev_db_clone);
         sd_netlink_unref(event->rtnl);
-        hashmap_free_free_key(event->run_list);
-        hashmap_free_free_free(event->seclabel_list);
+        ordered_hashmap_free_free_key(event->run_list);
+        ordered_hashmap_free_free_free(event->seclabel_list);
         free(event->program_result);
         free(event->name);
 
@@ -151,13 +152,15 @@ static ssize_t subst_format_var(UdevEvent *event,
                 break;
         case SUBST_KERNEL_NUMBER:
                 r = sd_device_get_sysnum(dev, &val);
+                if (r == -ENOENT)
+                        goto null_terminate;
                 if (r < 0)
-                        return r == -ENOENT ? 0 : r;
+                        return r;
                 l = strpcpy(&s, l, val);
                 break;
         case SUBST_ID:
                 if (!event->dev_parent)
-                        return 0;
+                        goto null_terminate;
                 r = sd_device_get_sysname(event->dev_parent, &val);
                 if (r < 0)
                         return r;
@@ -165,10 +168,12 @@ static ssize_t subst_format_var(UdevEvent *event,
                 break;
         case SUBST_DRIVER:
                 if (!event->dev_parent)
-                        return 0;
+                        goto null_terminate;
                 r = sd_device_get_driver(event->dev_parent, &val);
+                if (r == -ENOENT)
+                        goto null_terminate;
                 if (r < 0)
-                        return r == -ENOENT ? 0 : r;
+                        return r;
                 l = strpcpy(&s, l, val);
                 break;
         case SUBST_MAJOR:
@@ -187,7 +192,7 @@ static ssize_t subst_format_var(UdevEvent *event,
                 int i;
 
                 if (!event->program_result)
-                        return 0;
+                        goto null_terminate;
 
                 /* get part of the result string */
                 i = 0;
@@ -243,7 +248,7 @@ static ssize_t subst_format_var(UdevEvent *event,
                         (void) sd_device_get_sysattr_value(event->dev_parent, attr, &val);
 
                 if (!val)
-                        return 0;
+                        goto null_terminate;
 
                 /* strip trailing whitespace, and replace unwanted characters */
                 if (val != vbuf)
@@ -259,17 +264,23 @@ static ssize_t subst_format_var(UdevEvent *event,
         }
         case SUBST_PARENT:
                 r = sd_device_get_parent(dev, &parent);
+                if (r == -ENODEV)
+                        goto null_terminate;
                 if (r < 0)
-                        return r == -ENODEV ? 0 : r;
+                        return r;
                 r = sd_device_get_devname(parent, &val);
+                if (r == -ENOENT)
+                        goto null_terminate;
                 if (r < 0)
-                        return r == -ENOENT ? 0 : r;
+                        return r;
                 l = strpcpy(&s, l, val + STRLEN("/dev/"));
                 break;
         case SUBST_DEVNODE:
                 r = sd_device_get_devname(dev, &val);
+                if (r == -ENOENT)
+                        goto null_terminate;
                 if (r < 0)
-                        return r == -ENOENT ? 0 : r;
+                        return r;
                 l = strpcpy(&s, l, val);
                 break;
         case SUBST_NAME:
@@ -290,6 +301,8 @@ static ssize_t subst_format_var(UdevEvent *event,
                                 l = strpcpy(&s, l, val + STRLEN("/dev/"));
                         else
                                 l = strpcpyl(&s, l, " ", val + STRLEN("/dev/"), NULL);
+                if (s == dest)
+                        goto null_terminate;
                 break;
         case SUBST_ROOT:
                 l = strpcpy(&s, l, "/dev");
@@ -299,10 +312,12 @@ static ssize_t subst_format_var(UdevEvent *event,
                 break;
         case SUBST_ENV:
                 if (!attr)
-                        return 0;
+                        goto null_terminate;
                 r = sd_device_get_property_value(dev, attr, &val);
+                if (r == -ENOENT)
+                        goto null_terminate;
                 if (r < 0)
-                        return r == -ENOENT ? 0 : r;
+                        return r;
                 l = strpcpy(&s, l, val);
                 break;
         default:
@@ -310,6 +325,10 @@ static ssize_t subst_format_var(UdevEvent *event,
         }
 
         return s - dest;
+
+null_terminate:
+        *s = '\0';
+        return 0;
 }
 
 ssize_t udev_event_apply_format(UdevEvent *event,
@@ -677,8 +696,7 @@ int udev_event_spawn(UdevEvent *event,
 
 static int rename_netif(UdevEvent *event) {
         sd_device *dev = event->dev;
-        const char *action, *oldname;
-        char name[IFNAMSIZ];
+        const char *oldname;
         int ifindex, r;
 
         if (!event->name)
@@ -691,11 +709,7 @@ static int rename_netif(UdevEvent *event) {
         if (streq(event->name, oldname))
                 return 0; /* The interface name is already requested name. */
 
-        r = sd_device_get_property_value(dev, "ACTION", &action);
-        if (r < 0)
-                return log_device_error_errno(dev, r, "Failed to get property 'ACTION': %m");
-
-        if (!streq(action, "add"))
+        if (!device_for_action(dev, DEVICE_ACTION_ADD))
                 return 0; /* Rename the interface only when it is added. */
 
         r = sd_device_get_ifindex(dev, &ifindex);
@@ -704,23 +718,27 @@ static int rename_netif(UdevEvent *event) {
         if (r < 0)
                 return log_device_error_errno(dev, r, "Failed to get ifindex: %m");
 
-        strscpy(name, IFNAMSIZ, event->name);
-        r = rtnl_set_link_name(&event->rtnl, ifindex, name);
+        r = rtnl_set_link_name(&event->rtnl, ifindex, event->name);
+        if (r < 0)
+                return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m",
+                                              ifindex, oldname, event->name);
+
+        /* Set ID_RENAMING boolean property here, and drop it in the corresponding move uevent later. */
+        r = device_add_property(dev, "ID_RENAMING", "1");
         if (r < 0)
-                return log_device_error_errno(dev, r, "Failed to rename network interface %i from '%s' to '%s': %m", ifindex, oldname, name);
+                log_device_warning_errno(dev, r, "Failed to add 'ID_RENAMING' property: %m");
 
         r = device_rename(dev, event->name);
         if (r < 0)
-                return log_warning_errno(r, "Network interface %i is renamed from '%s' to '%s', but could not update sd_device object: %m", ifindex, oldname, name);
+                log_device_warning_errno(dev, r, "Failed to update properties with new name '%s': %m", event->name);
 
-        log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, name);
+        log_device_debug(dev, "Network interface %i is renamed from '%s' to '%s'", ifindex, oldname, event->name);
 
         return 1;
 }
 
 static int update_devnode(UdevEvent *event) {
         sd_device *dev = event->dev;
-        const char *action;
         bool apply;
         int r;
 
@@ -760,11 +778,7 @@ static int update_devnode(UdevEvent *event) {
                 }
         }
 
-        r = sd_device_get_property_value(dev, "ACTION", &action);
-        if (r < 0)
-                return log_device_error_errno(dev, r, "Failed to get property 'ACTION': %m");
-
-        apply = streq(action, "add") || event->owner_set || event->group_set || event->mode_set;
+        apply = device_for_action(dev, DEVICE_ACTION_ADD) || event->owner_set || event->group_set || event->mode_set;
         return udev_node_add(dev, apply, event->mode, event->uid, event->gid, event->seclabel_list);
 }
 
@@ -798,26 +812,48 @@ static void event_execute_rules_on_remove(
                 (void) udev_node_remove(dev);
 }
 
+static int udev_event_on_move(UdevEvent *event) {
+        sd_device *dev = event->dev;
+        int r;
+
+        if (event->dev_db_clone &&
+            sd_device_get_devnum(dev, NULL) < 0) {
+                r = device_copy_properties(dev, event->dev_db_clone);
+                if (r < 0)
+                        log_device_debug_errno(dev, r, "Failed to copy properties from cloned sd_device object, ignoring: %m");
+        }
+
+        /* Drop previously added property */
+        r = device_add_property(dev, "ID_RENAMING", NULL);
+        if (r < 0)
+                return log_device_debug_errno(dev, r, "Failed to remove 'ID_RENAMING' property, ignoring: %m");
+
+        return 0;
+}
+
 int udev_event_execute_rules(UdevEvent *event,
                              usec_t timeout_usec,
                              Hashmap *properties_list,
                              UdevRules *rules) {
-        sd_device *dev = event->dev;
-        const char *subsystem, *action;
+        const char *subsystem;
+        DeviceAction action;
+        sd_device *dev;
         int r;
 
         assert(event);
         assert(rules);
 
+        dev = event->dev;
+
         r = sd_device_get_subsystem(dev, &subsystem);
         if (r < 0)
                 return log_device_error_errno(dev, r, "Failed to get subsystem: %m");
 
-        r = sd_device_get_property_value(dev, "ACTION", &action);
+        r = device_get_action(dev, &action);
         if (r < 0)
-                return log_device_error_errno(dev, r, "Failed to get property 'ACTION': %m");
+                return log_device_error_errno(dev, r, "Failed to get ACTION: %m");
 
-        if (streq(action, "remove")) {
+        if (action == DEVICE_ACTION_REMOVE) {
                 event_execute_rules_on_remove(event, timeout_usec, properties_list, rules);
                 return 0;
         }
@@ -826,21 +862,12 @@ int udev_event_execute_rules(UdevEvent *event,
         if (r < 0)
                 log_device_debug_errno(dev, r, "Failed to clone sd_device object, ignoring: %m");
 
-        if (event->dev_db_clone) {
-                r = sd_device_get_devnum(dev, NULL);
-                if (r < 0) {
-                        if (r != -ENOENT)
-                                log_device_debug_errno(dev, r, "Failed to get devnum, ignoring: %m");
+        if (event->dev_db_clone && sd_device_get_devnum(dev, NULL) >= 0)
+                /* Disable watch during event processing. */
+                (void) udev_watch_end(event->dev_db_clone);
 
-                        if (streq(action, "move")) {
-                                r = device_copy_properties(dev, event->dev_db_clone);
-                                if (r < 0)
-                                        log_device_debug_errno(dev, r, "Failed to copy properties from cloned device, ignoring: %m");
-                        }
-                } else
-                        /* Disable watch during event processing. */
-                        (void) udev_watch_end(event->dev_db_clone);
-        }
+        if (action == DEVICE_ACTION_MOVE)
+                (void) udev_event_on_move(event);
 
         (void) udev_rules_apply_to_event(rules, event, timeout_usec, properties_list);
 
@@ -873,7 +900,7 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec) {
         void *val;
         Iterator i;
 
-        HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) {
+        ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) {
                 enum udev_builtin_cmd builtin_cmd = PTR_TO_INT(val);
                 char command[UTIL_PATH_SIZE];
 
index 1c00dd1..cfbbd7b 100644 (file)
@@ -272,7 +272,7 @@ int udev_node_update_old_links(sd_device *dev, sd_device *dev_old) {
 
 static int node_permissions_apply(sd_device *dev, bool apply,
                                   mode_t mode, uid_t uid, gid_t gid,
-                                  Hashmap *seclabel_list) {
+                                  OrderedHashmap *seclabel_list) {
         const char *devnode, *subsystem, *id_filename = NULL;
         struct stat stats;
         dev_t devnum;
@@ -318,7 +318,7 @@ static int node_permissions_apply(sd_device *dev, bool apply,
                         log_device_debug(dev, "Preserve permissions of %s, %#o, uid=%u, gid=%u", devnode, mode, uid, gid);
 
                 /* apply SECLABEL{$module}=$label */
-                HASHMAP_FOREACH_KEY(label, name, seclabel_list, i) {
+                ORDERED_HASHMAP_FOREACH_KEY(label, name, seclabel_list, i) {
                         int q;
 
                         if (streq(name, "selinux")) {
@@ -386,7 +386,7 @@ static int xsprintf_dev_num_path_from_sd_device(sd_device *dev, char **ret) {
 
 int udev_node_add(sd_device *dev, bool apply,
                   mode_t mode, uid_t uid, gid_t gid,
-                  Hashmap *seclabel_list) {
+                  OrderedHashmap *seclabel_list) {
         const char *devnode, *devlink;
         _cleanup_free_ char *filename = NULL;
         int r;
index 223c8f0..5ae816d 100644 (file)
@@ -10,6 +10,6 @@
 
 int udev_node_add(sd_device *dev, bool apply,
                   mode_t mode, uid_t uid, gid_t gid,
-                  Hashmap *seclabel_list);
+                  OrderedHashmap *seclabel_list);
 int udev_node_remove(sd_device *dev);
 int udev_node_update_old_links(sd_device *dev, sd_device *dev_old);
index bc9c6c2..ee87d7c 100644 (file)
@@ -15,6 +15,7 @@
 
 #include "alloc-util.h"
 #include "conf-files.h"
+#include "def.h"
 #include "device-private.h"
 #include "device-util.h"
 #include "dirent-util.h"
@@ -41,6 +42,7 @@
 #include "util.h"
 
 #define PREALLOC_TOKEN          2048
+#define RULES_DIRS (const char* const*) CONF_PATHS_STRV("udev/rules.d")
 
 struct uid_gid {
         unsigned name_off;
@@ -50,32 +52,25 @@ struct uid_gid {
         };
 };
 
-static const char* const rules_dirs[] = {
-        "/etc/udev/rules.d",
-        "/run/udev/rules.d",
-        UDEVLIBEXECDIR "/rules.d",
-        NULL
-};
-
 struct UdevRules {
         usec_t dirs_ts_usec;
         ResolveNameTiming resolve_name_timing;
 
         /* every key in the rules file becomes a token */
         struct token *tokens;
-        unsigned token_cur;
-        unsigned token_max;
+        size_t token_cur;
+        size_t token_max;
 
         /* all key strings are copied and de-duplicated in a single continuous string buffer */
         struct strbuf *strbuf;
 
         /* during rule parsing, uid/gid lookup results are cached */
         struct uid_gid *uids;
-        unsigned uids_cur;
-        unsigned uids_max;
+        size_t uids_cur;
+        size_t uids_max;
         struct uid_gid *gids;
-        unsigned gids_cur;
-        unsigned gids_max;
+        size_t gids_cur;
+        size_t gids_max;
 };
 
 static char *rules_str(UdevRules *rules, unsigned off) {
@@ -219,12 +214,12 @@ struct rule_tmp {
         UdevRules *rules;
         struct token rule;
         struct token token[MAX_TK];
-        unsigned token_cur;
+        size_t token_cur;
 };
 
 #if ENABLE_DEBUG_UDEV
 static const char *operation_str(enum operation_type type) {
-        static const char *operation_strs[] = {
+        static const char *const operation_strs[] = {
                 [OP_UNSET] =            "UNSET",
                 [OP_MATCH] =            "match",
                 [OP_NOMATCH] =          "nomatch",
@@ -240,7 +235,7 @@ static const char *operation_str(enum operation_type type) {
 }
 
 static const char *string_glob_str(enum string_glob_type type) {
-        static const char *string_glob_strs[] = {
+        static const char *const string_glob_strs[] = {
                 [GL_UNSET] =            "UNSET",
                 [GL_PLAIN] =            "plain",
                 [GL_GLOB] =             "glob",
@@ -253,7 +248,7 @@ static const char *string_glob_str(enum string_glob_type type) {
 }
 
 static const char *token_str(enum token_type type) {
-        static const char *token_strs[] = {
+        static const char *const token_strs[] = {
                 [TK_UNSET] =                    "UNSET",
                 [TK_RULE] =                     "RULE",
 
@@ -430,9 +425,9 @@ static void dump_token(UdevRules *rules, struct token *token) {
 }
 
 static void dump_rules(UdevRules *rules) {
-        unsigned i;
+        size_t i;
 
-        log_debug("Dumping %u (%zu bytes) tokens, %zu (%zu bytes) strings",
+        log_debug("Dumping %zu (%zu bytes) tokens, %zu (%zu bytes) strings",
                   rules->token_cur,
                   rules->token_cur * sizeof(struct token),
                   rules->strbuf->nodes_count,
@@ -447,21 +442,9 @@ static void dump_rules(UdevRules *rules) {}
 
 static int add_token(UdevRules *rules, struct token *token) {
         /* grow buffer if needed */
-        if (rules->token_cur+1 >= rules->token_max) {
-                struct token *tokens;
-                unsigned add;
-
-                /* double the buffer size */
-                add = rules->token_max;
-                if (add < 8)
-                        add = 8;
-
-                tokens = reallocarray(rules->tokens, rules->token_max + add, sizeof(struct token));
-                if (!tokens)
-                        return -1;
-                rules->tokens = tokens;
-                rules->token_max += add;
-        }
+        if (!GREEDY_REALLOC(rules->tokens, rules->token_max, rules->token_cur + 1))
+                return -ENOMEM;
+
         memcpy(&rules->tokens[rules->token_cur], token, sizeof(struct token));
         rules->token_cur++;
         return 0;
@@ -475,39 +458,25 @@ static void log_unknown_owner(sd_device *dev, int error, const char *entity, con
 }
 
 static uid_t add_uid(UdevRules *rules, const char *owner) {
-        unsigned i;
         uid_t uid = 0;
         unsigned off;
+        size_t i;
         int r;
 
         /* lookup, if we know it already */
         for (i = 0; i < rules->uids_cur; i++) {
                 off = rules->uids[i].name_off;
-                if (streq(rules_str(rules, off), owner)) {
-                        uid = rules->uids[i].uid;
-                        return uid;
-                }
+                if (streq(rules_str(rules, off), owner))
+                        return rules->uids[i].uid;
         }
         r = get_user_creds(&owner, &uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
         if (r < 0)
                 log_unknown_owner(NULL, r, "user", owner);
 
         /* grow buffer if needed */
-        if (rules->uids_cur+1 >= rules->uids_max) {
-                struct uid_gid *uids;
-                unsigned add;
-
-                /* double the buffer size */
-                add = rules->uids_max;
-                if (add < 1)
-                        add = 8;
-
-                uids = reallocarray(rules->uids, rules->uids_max + add, sizeof(struct uid_gid));
-                if (!uids)
-                        return uid;
-                rules->uids = uids;
-                rules->uids_max += add;
-        }
+        if (!GREEDY_REALLOC(rules->uids, rules->uids_max, rules->uids_cur + 1))
+                return -ENOMEM;
+
         rules->uids[rules->uids_cur].uid = uid;
         off = rules_add_string(rules, owner);
         if (off <= 0)
@@ -518,39 +487,25 @@ static uid_t add_uid(UdevRules *rules, const char *owner) {
 }
 
 static gid_t add_gid(UdevRules *rules, const char *group) {
-        unsigned i;
         gid_t gid = 0;
         unsigned off;
+        size_t i;
         int r;
 
         /* lookup, if we know it already */
         for (i = 0; i < rules->gids_cur; i++) {
                 off = rules->gids[i].name_off;
-                if (streq(rules_str(rules, off), group)) {
-                        gid = rules->gids[i].gid;
-                        return gid;
-                }
+                if (streq(rules_str(rules, off), group))
+                        return rules->gids[i].gid;
         }
         r = get_group_creds(&group, &gid, USER_CREDS_ALLOW_MISSING);
         if (r < 0)
                 log_unknown_owner(NULL, r, "group", group);
 
         /* grow buffer if needed */
-        if (rules->gids_cur+1 >= rules->gids_max) {
-                struct uid_gid *gids;
-                unsigned add;
-
-                /* double the buffer size */
-                add = rules->gids_max;
-                if (add < 1)
-                        add = 8;
-
-                gids = reallocarray(rules->gids, rules->gids_max + add, sizeof(struct uid_gid));
-                if (!gids)
-                        return gid;
-                rules->gids = gids;
-                rules->gids_max += add;
-        }
+        if (!GREEDY_REALLOC(rules->gids, rules->gids_max, rules->gids_cur + 1))
+                return -ENOMEM;
+
         rules->gids[rules->gids_cur].gid = gid;
         off = rules_add_string(rules, group);
         if (off <= 0)
@@ -647,7 +602,7 @@ static int import_program_into_properties(UdevEvent *event,
         char *line;
         int r;
 
-        r = udev_event_spawn(event, timeout_usec, false, program, result, sizeof result);
+        r = udev_event_spawn(event, timeout_usec, true, program, result, sizeof result);
         if (r < 0)
                 return r;
         if (r > 0)
@@ -716,11 +671,11 @@ static void attr_subst_subdir(char *attr, size_t len) {
 static int get_key(char **line, char **key, enum operation_type *op, char **value) {
         char *linepos;
         char *temp;
-        unsigned i, j;
+        size_t i, j;
 
         linepos = *line;
         if (!linepos || linepos[0] == '\0')
-                return -1;
+                return -EINVAL;
 
         /* skip whitespace */
         while (isspace(linepos[0]) || linepos[0] == ',')
@@ -728,13 +683,13 @@ static int get_key(char **line, char **key, enum operation_type *op, char **valu
 
         /* get the key */
         if (linepos[0] == '\0')
-                return -1;
+                return -EINVAL;
         *key = linepos;
 
         for (;;) {
                 linepos++;
                 if (linepos[0] == '\0')
-                        return -1;
+                        return -EINVAL;
                 if (isspace(linepos[0]))
                         break;
                 if (linepos[0] == '=')
@@ -751,7 +706,7 @@ static int get_key(char **line, char **key, enum operation_type *op, char **valu
         while (isspace(linepos[0]))
                 linepos++;
         if (linepos[0] == '\0')
-                return -1;
+                return -EINVAL;
 
         /* get operation type */
         if (linepos[0] == '=' && linepos[1] == '=') {
@@ -773,7 +728,7 @@ static int get_key(char **line, char **key, enum operation_type *op, char **valu
                 *op = OP_ASSIGN_FINAL;
                 linepos += 2;
         } else
-                return -1;
+                return -EINVAL;
 
         /* terminate key */
         temp[0] = '\0';
@@ -782,13 +737,13 @@ static int get_key(char **line, char **key, enum operation_type *op, char **valu
         while (isspace(linepos[0]))
                 linepos++;
         if (linepos[0] == '\0')
-                return -1;
+                return -EINVAL;
 
         /* get the value */
         if (linepos[0] == '"')
                 linepos++;
         else
-                return -1;
+                return -EINVAL;
         *value = linepos;
 
         /* terminate */
@@ -798,7 +753,7 @@ static int get_key(char **line, char **key, enum operation_type *op, char **valu
                         break;
 
                 if (linepos[i] == '\0')
-                        return -1;
+                        return -EINVAL;
 
                 /* double quotes can be escaped */
                 if (linepos[i] == '\\')
@@ -977,14 +932,15 @@ static int rule_add_key(struct rule_tmp *rule_tmp, enum token_type type,
 }
 
 static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) {
-        unsigned i;
-        unsigned start = 0;
-        unsigned end = rule_tmp->token_cur;
+        size_t i;
+        size_t start = 0;
+        size_t end = rule_tmp->token_cur;
+        int r;
 
         for (i = 0; i < rule_tmp->token_cur; i++) {
                 enum token_type next_val = TK_UNSET;
-                unsigned next_idx = 0;
-                unsigned j;
+                size_t next_idx = 0;
+                size_t j;
 
                 /* find smallest value */
                 for (j = start; j < end; j++) {
@@ -997,8 +953,9 @@ static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) {
                 }
 
                 /* add token and mark done */
-                if (add_token(rules, &rule_tmp->token[next_idx]) != 0)
-                        return -1;
+                r = add_token(rules, &rule_tmp->token[next_idx]);
+                if (r < 0)
+                        return r;
                 rule_tmp->token[next_idx].type = TK_UNSET;
 
                 /* shrink range */
@@ -1015,7 +972,7 @@ static int sort_token(UdevRules *rules, struct rule_tmp *rule_tmp) {
 #define LOG_RULE_WARNING(fmt, ...) LOG_RULE_FULL(LOG_WARNING, fmt, ##__VA_ARGS__)
 #define LOG_RULE_DEBUG(fmt, ...) LOG_RULE_FULL(LOG_DEBUG, fmt, ##__VA_ARGS__)
 #define LOG_AND_RETURN(fmt, ...) { LOG_RULE_ERROR(fmt, __VA_ARGS__); return; }
-#define LOG_AND_RETURN_ADD_KEY LOG_AND_RETURN("Temporary rule array too small, aborting event processing with %u items", rule_tmp.token_cur);
+#define LOG_AND_RETURN_ADD_KEY LOG_AND_RETURN("Temporary rule array too small, aborting event processing with %zu items", rule_tmp.token_cur);
 
 static void add_rule(UdevRules *rules, char *line,
                      const char *filename, unsigned filename_off, unsigned lineno) {
@@ -1038,7 +995,7 @@ static void add_rule(UdevRules *rules, char *line,
                 char *value;
                 enum operation_type op;
 
-                if (get_key(&linepos, &key, &op, &value) != 0) {
+                if (get_key(&linepos, &key, &op, &value) < 0) {
                         /* Avoid erroring on trailing whitespace. This is probably rare
                          * so save the work for the error case instead of always trying
                          * to strip the trailing whitespace with strstrip(). */
@@ -1199,6 +1156,7 @@ static void add_rule(UdevRules *rules, char *line,
                         else {
                                 if (STR_IN_SET(attr,
                                                "ACTION",
+                                               "SEQNUM",
                                                "SUBSYSTEM",
                                                "DEVTYPE",
                                                "MAJOR",
@@ -1372,13 +1330,11 @@ static void add_rule(UdevRules *rules, char *line,
 
                 } else if (streq(key, "OWNER")) {
                         uid_t uid;
-                        char *endptr;
 
                         if (op == OP_REMOVE)
                                 LOG_AND_RETURN("Invalid %s operation", key);
 
-                        uid = strtoul(value, &endptr, 10);
-                        if (endptr[0] == '\0')
+                        if (parse_uid(value, &uid) >= 0)
                                 r = rule_add_key(&rule_tmp, TK_A_OWNER_ID, op, NULL, &uid);
                         else if (rules->resolve_name_timing == RESOLVE_NAME_EARLY && !strchr("$%", value[0])) {
                                 uid = add_uid(rules, value);
@@ -1386,7 +1342,7 @@ static void add_rule(UdevRules *rules, char *line,
                         } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER)
                                 r = rule_add_key(&rule_tmp, TK_A_OWNER, op, value, NULL);
                         else {
-                                LOG_RULE_ERROR("Invalid %s operation", key);
+                                LOG_RULE_DEBUG("Resolving user name is disabled, ignoring %s=%s", key, value);
                                 continue;
                         }
                         if (r < 0)
@@ -1396,13 +1352,11 @@ static void add_rule(UdevRules *rules, char *line,
 
                 } else if (streq(key, "GROUP")) {
                         gid_t gid;
-                        char *endptr;
 
                         if (op == OP_REMOVE)
                                 LOG_AND_RETURN("Invalid %s operation", key);
 
-                        gid = strtoul(value, &endptr, 10);
-                        if (endptr[0] == '\0')
+                        if (parse_gid(value, &gid) >= 0)
                                 r = rule_add_key(&rule_tmp, TK_A_GROUP_ID, op, NULL, &gid);
                         else if ((rules->resolve_name_timing == RESOLVE_NAME_EARLY) && !strchr("$%", value[0])) {
                                 gid = add_gid(rules, value);
@@ -1410,7 +1364,7 @@ static void add_rule(UdevRules *rules, char *line,
                         } else if (rules->resolve_name_timing != RESOLVE_NAME_NEVER)
                                 r = rule_add_key(&rule_tmp, TK_A_GROUP, op, value, NULL);
                         else {
-                                LOG_RULE_ERROR("Invalid %s operation", key);
+                                LOG_RULE_DEBUG("Resolving group name is disabled, ignoring %s=%s", key, value);
                                 continue;
                         }
                         if (r < 0)
@@ -1496,17 +1450,17 @@ static void add_rule(UdevRules *rules, char *line,
 
         /* add rule token and sort tokens */
         rule_tmp.rule.rule.token_count = 1 + rule_tmp.token_cur;
-        if (add_token(rules, &rule_tmp.rule) != 0 || sort_token(rules, &rule_tmp) != 0)
+        if (add_token(rules, &rule_tmp.rule) < 0 || sort_token(rules, &rule_tmp) < 0)
                 LOG_RULE_ERROR("Failed to add rule token");
 }
 
 static int parse_file(UdevRules *rules, const char *filename) {
+        _cleanup_free_ char *continuation = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        unsigned first_token;
+        bool ignore_line = false;
+        size_t first_token, i;
         unsigned filename_off;
-        char line[UTIL_LINE_SIZE];
-        int line_nr = 0;
-        unsigned i;
+        int line_nr = 0, r;
 
         f = fopen(filename, "re");
         if (!f) {
@@ -1525,46 +1479,66 @@ static int parse_file(UdevRules *rules, const char *filename) {
         first_token = rules->token_cur;
         filename_off = rules_add_string(rules, filename);
 
-        while (fgets(line, sizeof(line), f)) {
-                char *key;
+        for (;;) {
+                _cleanup_free_ char *buf = NULL;
                 size_t len;
+                char *line;
+
+                r = read_line(f, UTIL_LINE_SIZE, &buf);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
 
-                /* skip whitespace */
                 line_nr++;
-                key = line;
-                while (isspace(key[0]))
-                        key++;
+                line = buf + strspn(buf, WHITESPACE);
 
-                /* comment */
-                if (key[0] == '#')
+                if (line[0] == '#')
                         continue;
 
                 len = strlen(line);
-                if (len < 3)
-                        continue;
 
-                /* continue reading if backslash+newline is found */
-                while (line[len-2] == '\\') {
-                        if (!fgets(&line[len-2], (sizeof(line)-len)+2, f))
-                                break;
-                        if (strlen(&line[len-2]) < 2)
-                                break;
-                        line_nr++;
-                        len = strlen(line);
+                if (continuation && !ignore_line) {
+                        if (strlen(continuation) + len >= UTIL_LINE_SIZE)
+                                ignore_line = true;
+
+                        if (!strextend(&continuation, line, NULL))
+                                return log_oom();
+
+                        if (!ignore_line) {
+                                line = continuation;
+                                len = strlen(line);
+                        }
                 }
 
-                if (len+1 >= sizeof(line)) {
-                        log_error("Line too long '%s':%u, ignored", filename, line_nr);
+                if (len > 0 && line[len - 1] == '\\') {
+                        if (ignore_line)
+                                continue;
+
+                        line[len - 1] = '\0';
+                        if (!continuation) {
+                                continuation = strdup(line);
+                                if (!continuation)
+                                        return log_oom();
+                        }
+
                         continue;
                 }
-                add_rule(rules, key, filename, filename_off, line_nr);
+
+                if (ignore_line)
+                        log_error("Line too long '%s':%u, ignored", filename, line_nr);
+                else if (len > 0)
+                        add_rule(rules, line, filename, filename_off, line_nr);
+
+                continuation = mfree(continuation);
+                ignore_line = false;
         }
 
         /* link GOTOs to LABEL rules in this file to be able to fast-forward */
         for (i = first_token+1; i < rules->token_cur; i++) {
                 if (rules->tokens[i].type == TK_A_GOTO) {
                         char *label = rules_str(rules, rules->tokens[i].key.value_off);
-                        unsigned j;
+                        size_t j;
 
                         for (j = i+1; j < rules->token_cur; j++) {
                                 if (rules->tokens[j].type != TK_RULE)
@@ -1600,7 +1574,7 @@ int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing)
         };
 
         /* init token array and string buffer */
-        rules->tokens = malloc_multiply(PREALLOC_TOKEN, sizeof(struct token));
+        rules->tokens = new(struct token, PREALLOC_TOKEN);
         if (!rules->tokens)
                 return -ENOMEM;
         rules->token_max = PREALLOC_TOKEN;
@@ -1611,7 +1585,7 @@ int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing)
 
         udev_rules_check_timestamp(rules);
 
-        r = conf_files_list_strv(&files, ".rules", NULL, 0, rules_dirs);
+        r = conf_files_list_strv(&files, ".rules", NULL, 0, RULES_DIRS);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate rules files: %m");
 
@@ -1627,7 +1601,7 @@ int udev_rules_new(UdevRules **ret_rules, ResolveNameTiming resolve_name_timing)
 
         struct token end_token = { .type = TK_END };
         add_token(rules, &end_token);
-        log_debug("Rules contain %zu bytes tokens (%u * %zu bytes), %zu bytes strings",
+        log_debug("Rules contain %zu bytes tokens (%zu * %zu bytes), %zu bytes strings",
                   rules->token_max * sizeof(struct token), rules->token_max, sizeof(struct token), rules->strbuf->len);
 
         /* cleanup temporary strbuf data */
@@ -1663,20 +1637,19 @@ bool udev_rules_check_timestamp(UdevRules *rules) {
         if (!rules)
                 return false;
 
-        return paths_check_timestamp(rules_dirs, &rules->dirs_ts_usec, true);
+        return paths_check_timestamp(RULES_DIRS, &rules->dirs_ts_usec, true);
 }
 
-static int match_key(UdevRules *rules, struct token *token, const char *val) {
+static bool match_key(UdevRules *rules, struct token *token, const char *val) {
         char *key_value = rules_str(rules, token->key.value_off);
         char *pos;
         bool match = false;
 
-        if (!val)
-                val = "";
+        val = strempty(val);
 
         switch (token->key.glob) {
         case GL_PLAIN:
-                match = (streq(key_value, val));
+                match = streq(key_value, val);
                 break;
         case GL_GLOB:
                 match = (fnmatch(key_value, val, 0) == 0);
@@ -1699,7 +1672,7 @@ static int match_key(UdevRules *rules, struct token *token, const char *val) {
                                         if (match)
                                                 break;
                                 } else {
-                                        match = (streq(s, val));
+                                        match = streq(s, val);
                                         break;
                                 }
                                 s = &next[1];
@@ -1729,17 +1702,13 @@ static int match_key(UdevRules *rules, struct token *token, const char *val) {
                 match = (val[0] != '\0');
                 break;
         case GL_UNSET:
-                return -1;
+                return false;
         }
 
-        if (match && (token->key.op == OP_MATCH))
-                return 0;
-        if (!match && (token->key.op == OP_NOMATCH))
-                return 0;
-        return -1;
+        return token->key.op == (match ? OP_MATCH : OP_NOMATCH);
 }
 
-static int match_attr(UdevRules *rules, sd_device *dev, UdevEvent *event, struct token *cur) {
+static bool match_attr(UdevRules *rules, sd_device *dev, UdevEvent *event, struct token *cur) {
         char nbuf[UTIL_NAME_SIZE], vbuf[UTIL_NAME_SIZE];
         const char *name, *value;
         size_t len;
@@ -1752,15 +1721,15 @@ static int match_attr(UdevRules *rules, sd_device *dev, UdevEvent *event, struct
                 _fallthrough_;
         case SB_NONE:
                 if (sd_device_get_sysattr_value(dev, name, &value) < 0)
-                        return -1;
+                        return false;
                 break;
         case SB_SUBSYS:
-                if (util_resolve_subsys_kernel(name, vbuf, sizeof(vbuf), true) != 0)
-                        return -1;
+                if (util_resolve_subsys_kernel(name, vbuf, sizeof(vbuf), true) < 0)
+                        return false;
                 value = vbuf;
                 break;
         default:
-                return -1;
+                return false;
         }
 
         /* remove trailing whitespace, if not asked to match for it */
@@ -1798,18 +1767,19 @@ int udev_rules_apply_to_event(
         sd_device *dev = event->dev;
         enum escape_type esc = ESCAPE_UNSET;
         struct token *cur, *rule;
-        const char *action, *val;
+        DeviceAction action;
+        const char *val;
         bool can_set_name;
         int r;
 
         if (!rules->tokens)
                 return 0;
 
-        r = sd_device_get_property_value(dev, "ACTION", &action);
+        r = device_get_action(dev, &action);
         if (r < 0)
                 return r;
 
-        can_set_name = (!streq(action, "remove") &&
+        can_set_name = (action != DEVICE_ACTION_REMOVE &&
                         (sd_device_get_devnum(dev, NULL) >= 0 ||
                          sd_device_get_ifindex(dev, NULL) >= 0));
 
@@ -1828,19 +1798,19 @@ int udev_rules_apply_to_event(
                         esc = ESCAPE_UNSET;
                         break;
                 case TK_M_ACTION:
-                        if (match_key(rules, cur, action) != 0)
+                        if (!match_key(rules, cur, device_action_to_string(action)))
                                 goto nomatch;
                         break;
                 case TK_M_DEVPATH:
                         if (sd_device_get_devpath(dev, &val) < 0)
                                 goto nomatch;
-                        if (match_key(rules, cur, val) != 0)
+                        if (!match_key(rules, cur, val))
                                 goto nomatch;
                         break;
                 case TK_M_KERNEL:
                         if (sd_device_get_sysname(dev, &val) < 0)
                                 goto nomatch;
-                        if (match_key(rules, cur, val) != 0)
+                        if (!match_key(rules, cur, val))
                                 goto nomatch;
                         break;
                 case TK_M_DEVLINK: {
@@ -1848,7 +1818,7 @@ int udev_rules_apply_to_event(
                         bool match = false;
 
                         FOREACH_DEVICE_DEVLINK(dev, devlink)
-                                if (match_key(rules, cur, devlink + STRLEN("/dev/")) == 0) {
+                                if (match_key(rules, cur, devlink + STRLEN("/dev/"))) {
                                         match = true;
                                         break;
                                 }
@@ -1858,7 +1828,7 @@ int udev_rules_apply_to_event(
                         break;
                 }
                 case TK_M_NAME:
-                        if (match_key(rules, cur, event->name) != 0)
+                        if (!match_key(rules, cur, event->name))
                                 goto nomatch;
                         break;
                 case TK_M_ENV: {
@@ -1872,7 +1842,7 @@ int udev_rules_apply_to_event(
                                         val = NULL;
                         }
 
-                        if (match_key(rules, cur, strempty(val)))
+                        if (!match_key(rules, cur, strempty(val)))
                                 goto nomatch;
                         break;
                 }
@@ -1894,17 +1864,17 @@ int udev_rules_apply_to_event(
                 case TK_M_SUBSYSTEM:
                         if (sd_device_get_subsystem(dev, &val) < 0)
                                 goto nomatch;
-                        if (match_key(rules, cur, val) != 0)
+                        if (!match_key(rules, cur, val))
                                 goto nomatch;
                         break;
                 case TK_M_DRIVER:
                         if (sd_device_get_driver(dev, &val) < 0)
                                 goto nomatch;
-                        if (match_key(rules, cur, val) != 0)
+                        if (!match_key(rules, cur, val))
                                 goto nomatch;
                         break;
                 case TK_M_ATTR:
-                        if (match_attr(rules, dev, event, cur) != 0)
+                        if (!match_attr(rules, dev, event, cur))
                                 goto nomatch;
                         break;
                 case TK_M_SYSCTL: {
@@ -1920,7 +1890,7 @@ int udev_rules_apply_to_event(
                         len = strlen(value);
                         while (len > 0 && isspace(value[--len]))
                                 value[len] = '\0';
-                        if (match_key(rules, cur, value) != 0)
+                        if (!match_key(rules, cur, value))
                                 goto nomatch;
                         break;
                 }
@@ -1948,23 +1918,23 @@ int udev_rules_apply_to_event(
                                         case TK_M_KERNELS:
                                                 if (sd_device_get_sysname(event->dev_parent, &val) < 0)
                                                         goto try_parent;
-                                                if (match_key(rules, key, val) != 0)
+                                                if (!match_key(rules, key, val))
                                                         goto try_parent;
                                                 break;
                                         case TK_M_SUBSYSTEMS:
                                                 if (sd_device_get_subsystem(event->dev_parent, &val) < 0)
                                                         goto try_parent;
-                                                if (match_key(rules, key, val) != 0)
+                                                if (!match_key(rules, key, val))
                                                         goto try_parent;
                                                 break;
                                         case TK_M_DRIVERS:
                                                 if (sd_device_get_driver(event->dev_parent, &val) < 0)
                                                         goto try_parent;
-                                                if (match_key(rules, key, val) != 0)
+                                                if (!match_key(rules, key, val))
                                                         goto try_parent;
                                                 break;
                                         case TK_M_ATTRS:
-                                                if (match_attr(rules, event->dev_parent, event, key) != 0)
+                                                if (!match_attr(rules, event->dev_parent, event, key))
                                                         goto try_parent;
                                                 break;
                                         case TK_M_TAGS: {
@@ -1998,7 +1968,7 @@ int udev_rules_apply_to_event(
                         int match;
 
                         udev_event_apply_format(event, rules_str(rules, cur->key.value_off), filename, sizeof(filename), false);
-                        if (util_resolve_subsys_kernel(filename, filename, sizeof(filename), false) != 0) {
+                        if (util_resolve_subsys_kernel(filename, filename, sizeof(filename), false) < 0) {
                                 if (filename[0] != '/') {
                                         char tmp[UTIL_PATH_SIZE];
 
@@ -2052,7 +2022,7 @@ int udev_rules_apply_to_event(
                         char import[UTIL_PATH_SIZE];
 
                         udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false);
-                        if (import_file_into_properties(dev, import) != 0)
+                        if (import_file_into_properties(dev, import) < 0)
                                 if (cur->key.op != OP_NOMATCH)
                                         goto nomatch;
                         break;
@@ -2066,7 +2036,7 @@ int udev_rules_apply_to_event(
                                          rules_str(rules, rule->rule.filename_off),
                                          rule->rule.filename_line);
 
-                        if (import_program_into_properties(event, timeout_usec, import) != 0)
+                        if (import_program_into_properties(event, timeout_usec, import) < 0)
                                 if (cur->key.op != OP_NOMATCH)
                                         goto nomatch;
                         break;
@@ -2146,13 +2116,13 @@ int udev_rules_apply_to_event(
                         char import[UTIL_PATH_SIZE];
 
                         udev_event_apply_format(event, rules_str(rules, cur->key.value_off), import, sizeof(import), false);
-                        if (import_parent_into_properties(dev, import) != 0)
+                        if (import_parent_into_properties(dev, import) < 0)
                                 if (cur->key.op != OP_NOMATCH)
                                         goto nomatch;
                         break;
                 }
                 case TK_M_RESULT:
-                        if (match_key(rules, cur, event->program_result) != 0)
+                        if (!match_key(rules, cur, event->program_result))
                                 goto nomatch;
                         break;
                 case TK_A_STRING_ESCAPE_NONE:
@@ -2291,13 +2261,13 @@ int udev_rules_apply_to_event(
                                 return log_oom();
 
                         if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
-                                hashmap_clear_free_free(event->seclabel_list);
+                                ordered_hashmap_clear_free_free(event->seclabel_list);
 
-                        r = hashmap_ensure_allocated(&event->seclabel_list, NULL);
+                        r = ordered_hashmap_ensure_allocated(&event->seclabel_list, NULL);
                         if (r < 0)
                                 return log_oom();
 
-                        r = hashmap_put(event->seclabel_list, name, label);
+                        r = ordered_hashmap_put(event->seclabel_list, name, label);
                         if (r < 0)
                                 return log_oom();
                         log_device_debug(dev, "SECLABEL{%s}='%s' %s:%u",
@@ -2440,7 +2410,7 @@ int udev_rules_apply_to_event(
                         const char *key_name;
 
                         key_name = rules_str(rules, cur->key.attr_off);
-                        if (util_resolve_subsys_kernel(key_name, attr, sizeof(attr), false) != 0 &&
+                        if (util_resolve_subsys_kernel(key_name, attr, sizeof(attr), false) < 0 &&
                             sd_device_get_syspath(dev, &val) >= 0)
                                 strscpyl(attr, sizeof(attr), val, "/", key_name, NULL);
                         attr_subst_subdir(attr, sizeof(attr));
@@ -2474,9 +2444,9 @@ int udev_rules_apply_to_event(
                         _cleanup_free_ char *cmd = NULL;
 
                         if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
-                                hashmap_clear_free_key(event->run_list);
+                                ordered_hashmap_clear_free_key(event->run_list);
 
-                        r = hashmap_ensure_allocated(&event->run_list, NULL);
+                        r = ordered_hashmap_ensure_allocated(&event->run_list, NULL);
                         if (r < 0)
                                 return log_oom();
 
@@ -2484,7 +2454,7 @@ int udev_rules_apply_to_event(
                         if (!cmd)
                                 return log_oom();
 
-                        r = hashmap_put(event->run_list, cmd, INT_TO_PTR(cur->key.builtin_cmd));
+                        r = ordered_hashmap_put(event->run_list, cmd, INT_TO_PTR(cur->key.builtin_cmd));
                         if (r < 0)
                                 return log_oom();
 
@@ -2581,7 +2551,7 @@ int udev_rules_apply_static_dev_perms(UdevRules *rules) {
                                 goto next;
 
                         strscpyl(device_node, sizeof(device_node), "/dev/", rules_str(rules, cur->key.value_off), NULL);
-                        if (stat(device_node, &stats) != 0)
+                        if (stat(device_node, &stats) < 0)
                                 break;
                         if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode))
                                 break;
index 3bc69ff..2fb49dc 100644 (file)
@@ -25,8 +25,8 @@ typedef struct UdevEvent {
         mode_t mode;
         uid_t uid;
         gid_t gid;
-        Hashmap *seclabel_list;
-        Hashmap *run_list;
+        OrderedHashmap *seclabel_list;
+        OrderedHashmap *run_list;
         usec_t exec_delay_usec;
         usec_t birth_usec;
         sd_netlink *rtnl;
index 7cfc4c9..f9b3e95 100644 (file)
@@ -86,48 +86,60 @@ int control_main(int argc, char *argv[], void *userdata) {
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "This command expects one or more options.");
 
-        uctrl = udev_ctrl_new();
-        if (!uctrl)
-                return log_oom();
+        r = udev_ctrl_new(&uctrl);
+        if (r < 0)
+                return log_error_errno(r, "Failed to initialize udev control: %m");
 
         while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0)
                 switch (c) {
                 case 'e':
-                        r = udev_ctrl_send_exit(uctrl, timeout);
-                        if (r < 0)
-                                return r;
+                        r = udev_ctrl_send_exit(uctrl);
+                        if (r == -ENOANO)
+                                log_warning("Cannot specify --exit after --exit, ignoring.");
+                        else if (r < 0)
+                                return log_error_errno(r, "Failed to send exit request: %m");
                         break;
                 case 'l':
                         r = log_level_from_string(optarg);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse log priority '%s': %m", optarg);
 
-                        r = udev_ctrl_send_set_log_level(uctrl, r, timeout);
-                        if (r < 0)
-                                return r;
+                        r = udev_ctrl_send_set_log_level(uctrl, r);
+                        if (r == -ENOANO)
+                                log_warning("Cannot specify --log-priority after --exit, ignoring.");
+                        else if (r < 0)
+                                return log_error_errno(r, "Failed to send request to set log level: %m");
                         break;
                 case 's':
-                        r = udev_ctrl_send_stop_exec_queue(uctrl, timeout);
-                        if (r < 0)
-                                return r;
+                        r = udev_ctrl_send_stop_exec_queue(uctrl);
+                        if (r == -ENOANO)
+                                log_warning("Cannot specify --stop-exec-queue after --exit, ignoring.");
+                        else if (r < 0)
+                                return log_error_errno(r, "Failed to send request to stop exec queue: %m");
                         break;
                 case 'S':
-                        r = udev_ctrl_send_start_exec_queue(uctrl, timeout);
-                        if (r < 0)
-                                return r;
+                        r = udev_ctrl_send_start_exec_queue(uctrl);
+                        if (r == -ENOANO)
+                                log_warning("Cannot specify --start-exec-queue after --exit, ignoring.");
+                        else if (r < 0)
+                                return log_error_errno(r, "Failed to send request to start exec queue: %m");
                         break;
                 case 'R':
-                        r = udev_ctrl_send_reload(uctrl, timeout);
-                        if (r < 0)
-                                return r;
+                        r = udev_ctrl_send_reload(uctrl);
+                        if (r == -ENOANO)
+                                log_warning("Cannot specify --reload after --exit, ignoring.");
+                        else if (r < 0)
+                                return log_error_errno(r, "Failed to send reload request: %m");
                         break;
                 case 'p':
                         if (!strchr(optarg, '='))
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "expect <KEY>=<value> instead of '%s'", optarg);
 
-                        r = udev_ctrl_send_set_env(uctrl, optarg, timeout);
-                        if (r < 0)
-                                return r;
+                        r = udev_ctrl_send_set_env(uctrl, optarg);
+                        if (r == -ENOANO)
+                                log_warning("Cannot specify --property after --exit, ignoring.");
+                        else if (r < 0)
+                                return log_error_errno(r, "Failed to send request to update environment: %m");
                         break;
                 case 'm': {
                         unsigned i;
@@ -136,15 +148,19 @@ int control_main(int argc, char *argv[], void *userdata) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to parse maximum number of events '%s': %m", optarg);
 
-                        r = udev_ctrl_send_set_children_max(uctrl, i, timeout);
-                        if (r < 0)
-                                return r;
+                        r = udev_ctrl_send_set_children_max(uctrl, i);
+                        if (r == -ENOANO)
+                                log_warning("Cannot specify --children-max after --exit, ignoring.");
+                        else if (r < 0)
+                                return log_error_errno(r, "Failed to send request to set number of children: %m");
                         break;
                 }
                 case ARG_PING:
-                        r = udev_ctrl_send_ping(uctrl, timeout);
-                        if (r < 0)
-                                return log_error_errno(r, "Failed to connect to udev daemon: %m");
+                        r = udev_ctrl_send_ping(uctrl);
+                        if (r == -ENOANO)
+                                log_error("Cannot specify --ping after --exit, ignoring.");
+                        else if (r < 0)
+                                return log_error_errno(r, "Failed to send a ping message: %m");
                         break;
                 case 't':
                         r = parse_sec(optarg, &timeout);
@@ -165,5 +181,9 @@ int control_main(int argc, char *argv[], void *userdata) {
                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
                                        "Extraneous argument: %s", argv[optind]);
 
+        r = udev_ctrl_wait(uctrl, timeout);
+        if (r < 0)
+                return log_error_errno(r, "Failed to wait for daemon to reply: %m");
+
         return 0;
 }
index ebd15d3..6742cda 100644 (file)
 #include "device-util.h"
 #include "dirent-util.h"
 #include "fd-util.h"
+#include "string-table.h"
 #include "string-util.h"
-#include "udevadm.h"
 #include "udevadm-util.h"
+#include "udevadm.h"
 
 typedef enum ActionType {
         ACTION_QUERY,
@@ -50,12 +51,8 @@ static bool skip_attribute(const char *name) {
                 "subsystem",
                 "module",
         };
-        unsigned i;
 
-        for (i = 0; i < ELEMENTSOF(skip); i++)
-                if (streq(name, skip[i]))
-                        return true;
-        return false;
+        return string_table_lookup(skip, ELEMENTSOF(skip), name) >= 0;
 }
 
 static void print_all_attributes(sd_device *device, const char *key) {
@@ -361,7 +358,7 @@ int info_main(int argc, char *argv[], void *userdata) {
         ActionType action = ACTION_QUERY;
         QueryType query = QUERY_ALL;
 
-        while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:RVh", options, NULL)) >= 0)
+        while ((c = getopt_long(argc, argv, "aced:n:p:q:rxP:Vh", options, NULL)) >= 0)
                 switch (c) {
                 case 'n':
                 case 'p': {
index 3dde3f3..ca7ca3c 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "alloc-util.h"
 #include "device-monitor-private.h"
+#include "device-private.h"
 #include "device-util.h"
 #include "fd-util.h"
 #include "format-util.h"
@@ -18,6 +19,7 @@
 #include "string-util.h"
 #include "udevadm.h"
 #include "virt.h"
+#include "time-util.h"
 
 static bool arg_show_property = false;
 static bool arg_print_kernel = false;
@@ -26,14 +28,15 @@ static Set *arg_tag_filter = NULL;
 static Hashmap *arg_subsystem_filter = NULL;
 
 static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) {
-        const char *action = NULL, *devpath = NULL, *subsystem = NULL;
+        DeviceAction action = _DEVICE_ACTION_INVALID;
+        const char *devpath = NULL, *subsystem = NULL;
         MonitorNetlinkGroup group = PTR_TO_INT(userdata);
         struct timespec ts;
 
         assert(device);
         assert(IN_SET(group, MONITOR_GROUP_UDEV, MONITOR_GROUP_KERNEL));
 
-        (void) sd_device_get_property_value(device, "ACTION", &action);
+        (void) device_get_action(device, &action);
         (void) sd_device_get_devpath(device, &devpath);
         (void) sd_device_get_subsystem(device, &subsystem);
 
@@ -42,7 +45,8 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device,
         printf("%-6s[%"PRI_TIME".%06"PRI_NSEC"] %-8s %s (%s)\n",
                group == MONITOR_GROUP_UDEV ? "UDEV" : "KERNEL",
                ts.tv_sec, (nsec_t)ts.tv_nsec/1000,
-               action, devpath, subsystem);
+               strna(device_action_to_string(action)),
+               devpath, subsystem);
 
         if (arg_show_property) {
                 const char *key, *value;
index 8d9c450..9cf88b2 100644 (file)
@@ -100,13 +100,16 @@ int settle_main(int argc, char *argv[], void *userdata) {
         if (getuid() == 0) {
                 _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
 
-                uctrl = udev_ctrl_new();
-                if (uctrl) {
-                        r = udev_ctrl_send_ping(uctrl, MAX(5 * USEC_PER_SEC, arg_timeout));
+                if (udev_ctrl_new(&uctrl) >= 0) {
+                        r = udev_ctrl_send_ping(uctrl);
                         if (r < 0) {
                                 log_debug_errno(r, "Failed to connect to udev daemon: %m");
                                 return 0;
                         }
+
+                        r = udev_ctrl_wait(uctrl, MAX(5 * USEC_PER_SEC, arg_timeout));
+                        if (r < 0)
+                                return log_error_errno(r, "Failed to wait for daemon to reply: %m");
                 }
         }
 
index 54c525e..da4c4cb 100644 (file)
@@ -53,9 +53,17 @@ static int parse_argv(int argc, char *argv[]) {
 
         while ((c = getopt_long(argc, argv, "a:N:Vh", options, NULL)) >= 0)
                 switch (c) {
-                case 'a':
+                case 'a': {
+                        DeviceAction a;
+
+                        a = device_action_from_string(optarg);
+                        if (a < 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
+                                                       "Invalid action '%s'", optarg);
+
                         arg_action = optarg;
                         break;
+                }
                 case 'N':
                         arg_resolve_name_timing = resolve_name_timing_from_string(optarg);
                         if (arg_resolve_name_timing < 0)
@@ -135,7 +143,7 @@ int test_main(int argc, char *argv[], void *userdata) {
         FOREACH_DEVICE_PROPERTY(dev, key, value)
                 printf("%s=%s\n", key, value);
 
-        HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) {
+        ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list, i) {
                 char program[UTIL_PATH_SIZE];
 
                 udev_event_apply_format(event, cmd, program, sizeof(program), false);
index 9532946..b7dafb7 100644 (file)
@@ -7,6 +7,7 @@
 #include "sd-event.h"
 
 #include "device-enumerator-private.h"
+#include "device-private.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "path-util.h"
@@ -59,6 +60,7 @@ static int exec_list(sd_device_enumerator *e, const char *action, Set *settle_se
 }
 
 static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *userdata) {
+        _cleanup_free_ char *val = NULL;
         Set *settle_set = userdata;
         const char *syspath;
 
@@ -71,7 +73,8 @@ static int device_monitor_handler(sd_device_monitor *m, sd_device *dev, void *us
         if (arg_verbose)
                 printf("settle %s\n", syspath);
 
-        if (!set_remove(settle_set, syspath))
+        val = set_remove(settle_set, syspath);
+        if (!val)
                 log_debug("Got epoll event on syspath %s not present in syspath set", syspath);
 
         if (set_isempty(settle_set))
@@ -199,11 +202,10 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                                 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg);
                         break;
                 case 'c':
-                        if (STR_IN_SET(optarg, "add", "remove", "change"))
-                                action = optarg;
-                        else
-                                log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown action '%s'", optarg);
+                        if (device_action_from_string(optarg) < 0)
+                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown action '%s'", optarg);
 
+                        action = optarg;
                         break;
                 case 's':
                         r = sd_device_enumerator_add_match_subsystem(e, optarg, true);
@@ -256,7 +258,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to open the device '%s': %m", optarg);
 
-                        r = sd_device_enumerator_add_match_parent(e, dev);
+                        r = device_enumerator_add_match_parent_incremental(e, dev);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
                         break;
@@ -272,7 +274,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                         if (r < 0)
                                 return log_error_errno(r, "Failed to open the device '%s': %m", optarg);
 
-                        r = sd_device_enumerator_add_match_parent(e, dev);
+                        r = device_enumerator_add_match_parent_incremental(e, dev);
                         if (r < 0)
                                 return log_error_errno(r, "Failed to add parent match '%s': %m", optarg);
                         break;
@@ -308,13 +310,17 @@ int trigger_main(int argc, char *argv[], void *userdata) {
         if (ping) {
                 _cleanup_(udev_ctrl_unrefp) struct udev_ctrl *uctrl = NULL;
 
-                uctrl = udev_ctrl_new();
-                if (!uctrl)
-                        return log_oom();
+                r = udev_ctrl_new(&uctrl);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to initialize udev control: %m");
 
-                r = udev_ctrl_send_ping(uctrl, ping_timeout_usec);
+                r = udev_ctrl_send_ping(uctrl);
                 if (r < 0)
                         return log_error_errno(r, "Failed to connect to udev daemon: %m");
+
+                r = udev_ctrl_wait(uctrl, ping_timeout_usec);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to wait for daemon to reply: %m");
         }
 
         for (; optind < argc; optind++) {
@@ -324,7 +330,7 @@ int trigger_main(int argc, char *argv[], void *userdata) {
                 if (r < 0)
                         return log_error_errno(r, "Failed to open the device '%s': %m", argv[optind]);
 
-                r = sd_device_enumerator_add_match_parent(e, dev);
+                r = device_enumerator_add_match_parent_incremental(e, dev);
                 if (r < 0)
                         return log_error_errno(r, "Failed to add parent match '%s': %m", argv[optind]);
         }
index 2819431..e6dbb11 100644 (file)
@@ -16,7 +16,7 @@
 #include "util.h"
 
 static int help(void) {
-        static const char * short_descriptions[][2] = {
+        static const char *const short_descriptions[][2] = {
                 { "info",         "Query sysfs or the udev database" },
                 { "trigger",      "Request events from the kernel"   },
                 { "settle",       "Wait for pending udev events"     },
index 0303f36..140ec35 100644 (file)
@@ -46,6 +46,7 @@
 #include "hashmap.h"
 #include "io-util.h"
 #include "libudev-device-internal.h"
+#include "limits-util.h"
 #include "list.h"
 #include "main-func.h"
 #include "mkdir.h"
@@ -89,12 +90,9 @@ typedef struct Manager {
 
         sd_device_monitor *monitor;
         struct udev_ctrl *ctrl;
-        struct udev_ctrl_connection *ctrl_conn_blocking;
         int fd_inotify;
         int worker_watch[2];
 
-        sd_event_source *ctrl_event;
-        sd_event_source *uevent_event;
         sd_event_source *inotify_event;
         sd_event_source *kill_workers_event;
 
@@ -278,8 +276,6 @@ static void worker_attach_event(struct worker *worker, struct event *event) {
 static void manager_clear_for_worker(Manager *manager) {
         assert(manager);
 
-        manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
-        manager->uevent_event = sd_event_source_unref(manager->uevent_event);
         manager->inotify_event = sd_event_source_unref(manager->inotify_event);
         manager->kill_workers_event = sd_event_source_unref(manager->kill_workers_event);
 
@@ -289,7 +285,6 @@ static void manager_clear_for_worker(Manager *manager) {
         event_queue_cleanup(manager, EVENT_UNDEF);
 
         manager->monitor = sd_device_monitor_unref(manager->monitor);
-        manager->ctrl_conn_blocking = udev_ctrl_connection_unref(manager->ctrl_conn_blocking);
         manager->ctrl = udev_ctrl_unref(manager->ctrl);
 
         manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]);
@@ -301,6 +296,9 @@ static void manager_free(Manager *manager) {
 
         udev_builtin_exit();
 
+        if (manager->pid == getpid_cached())
+                udev_ctrl_cleanup(manager->ctrl);
+
         manager_clear_for_worker(manager);
 
         sd_netlink_unref(manager->rtnl);
@@ -339,11 +337,7 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) {
          * udev has finished its event handling.
          */
 
-        r = sd_device_get_property_value(dev, "ACTION", &val);
-        if (r < 0)
-                return log_device_debug_errno(dev, r, "Failed to get the value of property 'ACTION': %m");
-
-        if (streq(val, "remove"))
+        if (device_for_action(dev, DEVICE_ACTION_REMOVE))
                 return 0;
 
         r = sd_device_get_subsystem(dev, &val);
@@ -391,21 +385,23 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) {
 static int worker_process_device(Manager *manager, sd_device *dev) {
         _cleanup_(udev_event_freep) UdevEvent *udev_event = NULL;
         _cleanup_close_ int fd_lock = -1;
-        const char *seqnum, *action;
+        DeviceAction action;
+        uint64_t seqnum;
         int r;
 
         assert(manager);
         assert(dev);
 
-        r = sd_device_get_property_value(dev, "SEQNUM", &seqnum);
+        r = device_get_seqnum(dev, &seqnum);
         if (r < 0)
                 return log_device_debug_errno(dev, r, "Failed to get SEQNUM: %m");
 
-        r = sd_device_get_property_value(dev, "ACTION", &action);
+        r = device_get_action(dev, &action);
         if (r < 0)
                 return log_device_debug_errno(dev, r, "Failed to get ACTION: %m");
 
-        log_device_debug(dev, "Processing device (SEQNUM=%s, ACTION=%s)", seqnum, action);
+        log_device_debug(dev, "Processing device (SEQNUM=%"PRIu64", ACTION=%s)",
+                         seqnum, device_action_to_string(action));
 
         udev_event = udev_event_new(dev, arg_exec_delay_usec, manager->rtnl);
         if (!udev_event)
@@ -431,7 +427,8 @@ static int worker_process_device(Manager *manager, sd_device *dev) {
                         return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m");
         }
 
-        log_device_debug(dev, "Device (SEQNUM=%s, ACTION=%s) processed", seqnum, action);
+        log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) processed",
+                         seqnum, device_action_to_string(action));
 
         return 0;
 }
@@ -587,8 +584,8 @@ static void event_run(Manager *manager, struct event *event) {
 
 static int event_queue_insert(Manager *manager, sd_device *dev) {
         _cleanup_(sd_device_unrefp) sd_device *clone = NULL;
-        const char *val, *action;
         struct event *event;
+        DeviceAction action;
         uint64_t seqnum;
         int r;
 
@@ -596,25 +593,15 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
         assert(dev);
 
         /* only one process can add events to the queue */
-        if (manager->pid == 0)
-                manager->pid = getpid_cached();
-
         assert(manager->pid == getpid_cached());
 
         /* We only accepts devices received by device monitor. */
-        r = sd_device_get_property_value(dev, "SEQNUM", &val);
+        r = device_get_seqnum(dev, &seqnum);
         if (r < 0)
                 return r;
 
-        r = safe_atou64(val, &seqnum);
-        if (r < 0)
-                return r;
-
-        if (seqnum == 0)
-                return -EINVAL;
-
         /* Refuse devices do not have ACTION property. */
-        r = sd_device_get_property_value(dev, "ACTION", &action);
+        r = device_get_action(dev, &action);
         if (r < 0)
                 return r;
 
@@ -647,7 +634,8 @@ static int event_queue_insert(Manager *manager, sd_device *dev) {
 
         LIST_APPEND(event, manager->events, event);
 
-        log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) is queued", seqnum, action);
+        log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) is queued",
+                         seqnum, device_action_to_string(action));
 
         return 0;
 }
@@ -727,7 +715,7 @@ static int is_device_busy(Manager *manager, struct event *event) {
 
                         if (sd_device_get_devnum(loop_event->dev, &d) >= 0 &&
                             devnum == d && is_block == streq(s, "block"))
-                                return true;
+                                goto set_delaying_seqnum;
                 }
 
                 /* check network device ifindex */
@@ -736,17 +724,15 @@ static int is_device_busy(Manager *manager, struct event *event) {
 
                         if (sd_device_get_ifindex(loop_event->dev, &i) >= 0 &&
                             ifindex == i)
-                                return true;
+                                goto set_delaying_seqnum;
                 }
 
                 if (sd_device_get_devpath(loop_event->dev, &loop_devpath) < 0)
                         continue;
 
                 /* check our old name */
-                if (devpath_old && streq(devpath_old, loop_devpath)) {
-                        event->delaying_seqnum = loop_event->seqnum;
-                        return true;
-                }
+                if (devpath_old && streq(devpath_old, loop_devpath))
+                        goto set_delaying_seqnum;
 
                 loop_devpath_len = strlen(loop_devpath);
 
@@ -758,28 +744,23 @@ static int is_device_busy(Manager *manager, struct event *event) {
                         continue;
 
                 /* identical device event found */
-                if (devpath_len == loop_devpath_len) {
-                        /* devices names might have changed/swapped in the meantime */
-                        if (major(devnum) != 0 || ifindex > 0)
-                                continue;
-                        event->delaying_seqnum = loop_event->seqnum;
-                        return true;
-                }
+                if (devpath_len == loop_devpath_len)
+                        goto set_delaying_seqnum;
 
                 /* parent device event found */
-                if (devpath[common] == '/') {
-                        event->delaying_seqnum = loop_event->seqnum;
-                        return true;
-                }
+                if (devpath[common] == '/')
+                        goto set_delaying_seqnum;
 
                 /* child device event found */
-                if (loop_devpath[common] == '/') {
-                        event->delaying_seqnum = loop_event->seqnum;
-                        return true;
-                }
+                if (loop_devpath[common] == '/')
+                        goto set_delaying_seqnum;
         }
 
         return false;
+
+set_delaying_seqnum:
+        event->delaying_seqnum = loop_event->seqnum;
+        return true;
 }
 
 static int on_exit_timeout(sd_event_source *s, uint64_t usec, void *userdata) {
@@ -806,13 +787,11 @@ static void manager_exit(Manager *manager) {
                   "STATUS=Starting shutdown...");
 
         /* close sources of new events and discard buffered events */
-        manager->ctrl_event = sd_event_source_unref(manager->ctrl_event);
         manager->ctrl = udev_ctrl_unref(manager->ctrl);
 
         manager->inotify_event = sd_event_source_unref(manager->inotify_event);
         manager->fd_inotify = safe_close(manager->fd_inotify);
 
-        manager->uevent_event = sd_event_source_unref(manager->uevent_event);
         manager->monitor = sd_device_monitor_unref(manager->monitor);
 
         /* discard queued events and kill workers */
@@ -1007,59 +986,44 @@ static int on_uevent(sd_device_monitor *monitor, sd_device *dev, void *userdata)
 }
 
 /* receive the udevd message from userspace */
-static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
+static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, const union udev_ctrl_msg_value *value, void *userdata) {
         Manager *manager = userdata;
-        _cleanup_(udev_ctrl_connection_unrefp) struct udev_ctrl_connection *ctrl_conn = NULL;
-        _cleanup_(udev_ctrl_msg_unrefp) struct udev_ctrl_msg *ctrl_msg = NULL;
-        const char *str;
-        int i, r;
+        int r;
 
+        assert(value);
         assert(manager);
 
-        ctrl_conn = udev_ctrl_get_connection(manager->ctrl);
-        if (!ctrl_conn)
-                return 1;
-
-        ctrl_msg = udev_ctrl_receive_msg(ctrl_conn);
-        if (!ctrl_msg)
-                return 1;
-
-        i = udev_ctrl_get_set_log_level(ctrl_msg);
-        if (i >= 0) {
-                log_debug("Received udev control message (SET_LOG_LEVEL), setting log_priority=%i", i);
-                log_set_max_level_realm(LOG_REALM_UDEV, i);
-                log_set_max_level_realm(LOG_REALM_SYSTEMD, i);
+        switch (type) {
+        case UDEV_CTRL_SET_LOG_LEVEL:
+                log_debug("Received udev control message (SET_LOG_LEVEL), setting log_priority=%i", value->intval);
+                log_set_max_level_realm(LOG_REALM_UDEV, value->intval);
+                log_set_max_level_realm(LOG_REALM_SYSTEMD, value->intval);
                 manager_kill_workers(manager);
-        }
-
-        if (udev_ctrl_get_stop_exec_queue(ctrl_msg) > 0) {
+                break;
+        case UDEV_CTRL_STOP_EXEC_QUEUE:
                 log_debug("Received udev control message (STOP_EXEC_QUEUE)");
                 manager->stop_exec_queue = true;
-        }
-
-        if (udev_ctrl_get_start_exec_queue(ctrl_msg) > 0) {
+                break;
+        case UDEV_CTRL_START_EXEC_QUEUE:
                 log_debug("Received udev control message (START_EXEC_QUEUE)");
                 manager->stop_exec_queue = false;
                 event_queue_start(manager);
-        }
-
-        if (udev_ctrl_get_reload(ctrl_msg) > 0) {
+                break;
+        case UDEV_CTRL_RELOAD:
                 log_debug("Received udev control message (RELOAD)");
                 manager_reload(manager);
-        }
-
-        str = udev_ctrl_get_set_env(ctrl_msg);
-        if (str) {
+                break;
+        case UDEV_CTRL_SET_ENV: {
                 _cleanup_free_ char *key = NULL, *val = NULL, *old_key = NULL, *old_val = NULL;
-                char *eq;
+                const char *eq;
 
-                eq = strchr(str, '=');
+                eq = strchr(value->buf, '=');
                 if (!eq) {
-                        log_error("Invalid key format '%s'", str);
+                        log_error("Invalid key format '%s'", value->buf);
                         return 1;
                 }
 
-                key = strndup(str, eq - str);
+                key = strndup(value->buf, eq - value->buf);
                 if (!key) {
                         log_oom();
                         return 1;
@@ -1100,27 +1064,30 @@ static int on_ctrl_msg(sd_event_source *s, int fd, uint32_t revents, void *userd
 
                 key = val = NULL;
                 manager_kill_workers(manager);
+                break;
         }
+        case UDEV_CTRL_SET_CHILDREN_MAX:
+                if (value->intval <= 0) {
+                        log_debug("Received invalid udev control message (SET_MAX_CHILDREN, %i), ignoring.", value->intval);
+                        return 0;
+                }
 
-        i = udev_ctrl_get_set_children_max(ctrl_msg);
-        if (i >= 0) {
-                log_debug("Receivd udev control message (SET_MAX_CHILDREN), setting children_max=%i", i);
-                arg_children_max = i;
+                log_debug("Received udev control message (SET_MAX_CHILDREN), setting children_max=%i", value->intval);
+                arg_children_max = value->intval;
 
                 (void) sd_notifyf(false,
                                   "READY=1\n"
                                   "STATUS=Processing with %u children at max", arg_children_max);
-        }
-
-        if (udev_ctrl_get_ping(ctrl_msg) > 0)
+                break;
+        case UDEV_CTRL_PING:
                 log_debug("Received udev control message (PING)");
-
-        if (udev_ctrl_get_exit(ctrl_msg) > 0) {
+                break;
+        case UDEV_CTRL_EXIT:
                 log_debug("Received udev control message (EXIT)");
                 manager_exit(manager);
-                /* keep reference to block the client until we exit
-                   TODO: deal with several blocking exit requests */
-                manager->ctrl_conn_blocking = udev_ctrl_connection_ref(ctrl_conn);
+                break;
+        default:
+                log_debug("Received unknown udev control message, ignoring");
         }
 
         return 1;
@@ -1603,9 +1570,9 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
                 .cgroup = cgroup,
         };
 
-        manager->ctrl = udev_ctrl_new_from_fd(fd_ctrl);
-        if (!manager->ctrl)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to initialize udev control socket");
+        r = udev_ctrl_new_from_fd(&manager->ctrl, fd_ctrl);
+        if (r < 0)
+                return log_error_errno(r, "Failed to initialize udev control socket: %m");
 
         r = udev_ctrl_enable_receiving(manager->ctrl);
         if (r < 0)
@@ -1627,7 +1594,9 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg
 }
 
 static int main_loop(Manager *manager) {
-        int fd_worker, fd_ctrl, r;
+        int fd_worker, r;
+
+        manager->pid = getpid_cached();
 
         /* unnamed socket from workers to the main daemon */
         r = socketpair(AF_LOCAL, SOCK_DGRAM|SOCK_CLOEXEC, 0, manager->worker_watch);
@@ -1674,19 +1643,19 @@ static int main_loop(Manager *manager) {
         if (r < 0)
                 return log_error_errno(r, "Failed to create watchdog event source: %m");
 
-        fd_ctrl = udev_ctrl_get_fd(manager->ctrl);
-        if (fd_ctrl < 0)
-                return log_error_errno(fd_ctrl, "Failed to get udev control socket fd: %m");
+        r = udev_ctrl_attach_event(manager->ctrl, manager->event);
+        if (r < 0)
+                return log_error_errno(r, "Failed to attach event to udev control: %m");
 
-        r = sd_event_add_io(manager->event, &manager->ctrl_event, fd_ctrl, EPOLLIN, on_ctrl_msg, manager);
+        r = udev_ctrl_start(manager->ctrl, on_ctrl_msg, manager);
         if (r < 0)
-                return log_error_errno(r, "Failed to create udev control event source: %m");
+                return log_error_errno(r, "Failed to start device monitor: %m");
 
         /* This needs to be after the inotify and uevent handling, to make sure
          * that the ping is send back after fully processing the pending uevents
          * (including the synthetic ones we may create due to inotify events).
          */
-        r = sd_event_source_set_priority(manager->ctrl_event, SD_EVENT_PRIORITY_IDLE);
+        r = sd_event_source_set_priority(udev_ctrl_get_event_source(manager->ctrl), SD_EVENT_PRIORITY_IDLE);
         if (r < 0)
                 return log_error_errno(r, "Failed to set IDLE event priority for udev control event source: %m");
 
@@ -1846,10 +1815,7 @@ static int run(int argc, char *argv[]) {
                         log_debug_errno(r, "Failed to adjust OOM score, ignoring: %m");
         }
 
-        r = main_loop(manager);
-        /* FIXME: move this into manager_free() */
-        udev_ctrl_cleanup(manager->ctrl);
-        return r;
+        return main_loop(manager);
 }
 
 DEFINE_MAIN_FUNCTION(run);
index 4d48289..4d60ee3 100644 (file)
@@ -64,22 +64,27 @@ int main(int argc, char *argv[]) {
                 return 3;
 
         if (ioctl(fd, VIDIOC_QUERYCAP, &v2cap) == 0) {
+                int capabilities;
                 printf("ID_V4L_VERSION=2\n");
                 printf("ID_V4L_PRODUCT=%s\n", v2cap.card);
                 printf("ID_V4L_CAPABILITIES=:");
-                if ((v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0 ||
-                    (v2cap.capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) > 0)
+                if (v2cap.capabilities & V4L2_CAP_DEVICE_CAPS)
+                        capabilities = v2cap.device_caps;
+                else
+                        capabilities = v2cap.capabilities;
+                if ((capabilities & V4L2_CAP_VIDEO_CAPTURE) > 0 ||
+                    (capabilities & V4L2_CAP_VIDEO_CAPTURE_MPLANE) > 0)
                         printf("capture:");
-                if ((v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0 ||
-                    (v2cap.capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) > 0)
+                if ((capabilities & V4L2_CAP_VIDEO_OUTPUT) > 0 ||
+                    (capabilities & V4L2_CAP_VIDEO_OUTPUT_MPLANE) > 0)
                         printf("video_output:");
-                if ((v2cap.capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0)
+                if ((capabilities & V4L2_CAP_VIDEO_OVERLAY) > 0)
                         printf("video_overlay:");
-                if ((v2cap.capabilities & V4L2_CAP_AUDIO) > 0)
+                if ((capabilities & V4L2_CAP_AUDIO) > 0)
                         printf("audio:");
-                if ((v2cap.capabilities & V4L2_CAP_TUNER) > 0)
+                if ((capabilities & V4L2_CAP_TUNER) > 0)
                         printf("tuner:");
-                if ((v2cap.capabilities & V4L2_CAP_RADIO) > 0)
+                if ((capabilities & V4L2_CAP_RADIO) > 0)
                         printf("radio:");
                 printf("\n");
         }
index c76c2d1..bbd1416 100644 (file)
@@ -1,9 +1,13 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
 #include "alloc-util.h"
 #include "fileio-label.h"
 #include "selinux-util.h"
-#include "util.h"
+#include "time-util.h"
 
 #define MESSAGE                                                         \
         "# This file was created by systemd-update-done. Its only \n"   \
index 7d66ed3..bfc78b9 100644 (file)
@@ -2,6 +2,8 @@
 
 #include <errno.h>
 #include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #if HAVE_AUDIT
index 490d9f0..c241429 100644 (file)
@@ -1,6 +1,9 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
 #include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "fileio.h"
@@ -10,7 +13,6 @@
 #include "log.h"
 #include "selinux-util.h"
 #include "string-util.h"
-#include "util.h"
 
 static int run(int argc, char *argv[]) {
         int r, k;
index ebdeba3..67dc2e4 100644 (file)
@@ -15,6 +15,8 @@
 #include <sys/ioctl.h>
 #include <sysexits.h>
 #include <termios.h>
+#include <sys/stat.h>
+#include <sys/types.h>
 #include <unistd.h>
 
 #include "alloc-util.h"
index 5da9ce1..d1193a7 100644 (file)
@@ -3,6 +3,8 @@
 #include <sys/mount.h>
 
 #include "alloc-util.h"
+#include "blockdev-util.h"
+#include "escape.h"
 #include "fs-util.h"
 #include "main-func.h"
 #include "mkdir.h"
@@ -17,20 +19,7 @@ static int make_volatile(const char *path) {
         _cleanup_free_ char *old_usr = NULL;
         int r;
 
-        r = path_is_mount_point(path, NULL, AT_SYMLINK_FOLLOW);
-        if (r < 0)
-                return log_error_errno(r, "Couldn't determine whether %s is a mount point: %m", path);
-        if (r == 0)
-                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
-                                       "%s is not a mount point.", path);
-
-        r = path_is_temporary_fs(path);
-        if (r < 0)
-                return log_error_errno(r, "Couldn't determine whether %s is a temporary file system: %m", path);
-        if (r > 0) {
-                log_info("%s already is a temporary file system.", path);
-                return 0;
-        }
+        assert(path);
 
         r = chase_symlinks("/usr", path, CHASE_PREFIX_ROOT, &old_usr);
         if (r < 0)
@@ -45,7 +34,7 @@ static int make_volatile(const char *path) {
                 goto finish_rmdir;
 
         if (mkdir("/run/systemd/volatile-sysroot/usr", 0755) < 0) {
-                r = -errno;
+                r = log_error_errno(errno, "Failed to create /usr directory: %m");
                 goto finish_umount;
         }
 
@@ -53,9 +42,11 @@ static int make_volatile(const char *path) {
         if (r < 0)
                 goto finish_umount;
 
-        r = bind_remount_recursive("/run/systemd/volatile-sysroot/usr", true, NULL);
-        if (r < 0)
+        r = bind_remount_recursive("/run/systemd/volatile-sysroot/usr", MS_RDONLY, MS_RDONLY, NULL);
+        if (r < 0) {
+                log_error_errno(r, "Failed to remount /usr read-only: %m");
                 goto finish_umount;
+        }
 
         r = umount_recursive(path, 0);
         if (r < 0) {
@@ -64,7 +55,7 @@ static int make_volatile(const char *path) {
         }
 
         if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
-                log_warning_errno(errno, "Failed to remount %s MS_SLAVE|MS_REC: %m", path);
+                log_warning_errno(errno, "Failed to remount %s MS_SLAVE|MS_REC, ignoring: %m", path);
 
         r = mount_verbose(LOG_ERR, "/run/systemd/volatile-sysroot", path, NULL, MS_MOVE, NULL);
 
@@ -77,9 +68,55 @@ finish_rmdir:
         return r;
 }
 
+static int make_overlay(const char *path) {
+        _cleanup_free_ char *escaped_path = NULL;
+        bool tmpfs_mounted = false;
+        const char *options = NULL;
+        int r;
+
+        assert(path);
+
+        r = mkdir_p("/run/systemd/overlay-sysroot", 0700);
+        if (r < 0)
+                return log_error_errno(r, "Couldn't create overlay sysroot directory: %m");
+
+        r = mount_verbose(LOG_ERR, "tmpfs", "/run/systemd/overlay-sysroot", "tmpfs", MS_STRICTATIME, "mode=755");
+        if (r < 0)
+                goto finish;
+
+        tmpfs_mounted = true;
+
+        if (mkdir("/run/systemd/overlay-sysroot/upper", 0755) < 0) {
+                r = log_error_errno(errno, "Failed to create /run/systemd/overlay-sysroot/upper: %m");
+                goto finish;
+        }
+
+        if (mkdir("/run/systemd/overlay-sysroot/work", 0755) < 0) {
+                r = log_error_errno(errno, "Failed to create /run/systemd/overlay-sysroot/work: %m");
+                goto finish;
+        }
+
+        escaped_path = shell_escape(path, ",:");
+        if (!escaped_path) {
+                r = log_oom();
+                goto finish;
+        }
+
+        options = strjoina("lowerdir=", escaped_path, ",upperdir=/run/systemd/overlay-sysroot/upper,workdir=/run/systemd/overlay-sysroot/work");
+        r = mount_verbose(LOG_ERR, "overlay", path, "overlay", 0, options);
+
+finish:
+        if (tmpfs_mounted)
+                (void) umount_verbose("/run/systemd/overlay-sysroot");
+
+        (void) rmdir("/run/systemd/overlay-sysroot");
+        return r;
+}
+
 static int run(int argc, char *argv[]) {
         VolatileMode m = _VOLATILE_MODE_INVALID;
         const char *path;
+        dev_t devt;
         int r;
 
         log_setup_service();
@@ -94,10 +131,8 @@ static int run(int argc, char *argv[]) {
         if (r == 0 && argc >= 2) {
                 /* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */
                 m = volatile_mode_from_string(argv[1]);
-                if (m < 0) {
-                        log_error("Couldn't parse volatile mode: %s", argv[1]);
-                        r = -EINVAL;
-                }
+                if (m < 0)
+                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Couldn't parse volatile mode: %s", argv[1]);
         }
 
         if (argc < 3)
@@ -116,10 +151,47 @@ static int run(int argc, char *argv[]) {
                                                "Directory cannot be the root directory.");
         }
 
-        if (m != VOLATILE_YES)
+        if (!IN_SET(m, VOLATILE_YES, VOLATILE_OVERLAY))
                 return 0;
 
-        return make_volatile(path);
+        r = path_is_mount_point(path, NULL, AT_SYMLINK_FOLLOW);
+        if (r < 0)
+                return log_error_errno(r, "Couldn't determine whether %s is a mount point: %m", path);
+        if (r == 0)
+                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s is not a mount point.", path);
+
+        r = path_is_temporary_fs(path);
+        if (r < 0)
+                return log_error_errno(r, "Couldn't determine whether %s is a temporary file system: %m", path);
+        if (r > 0) {
+                log_info("%s already is a temporary file system.", path);
+                return 0;
+        }
+
+        /* We are about to replace the root directory with something else. Later code might want to know what we
+         * replaced here, hence let's save that information as a symlink we can later use. (This is particularly
+         * relevant for the overlayfs case where we'll fully obstruct the view onto the underlying device, hence
+         * querying the backing device node from the file system directly is no longer possible. */
+        r = get_block_device_harder(path, &devt);
+        if (r < 0)
+                return log_error_errno(r, "Failed to determine device major/minor of %s: %m", path);
+        else if (r > 0) {
+                _cleanup_free_ char *dn = NULL;
+
+                r = device_path_make_major_minor(S_IFBLK, devt, &dn);
+                if (r < 0)
+                        return log_error_errno(r, "Failed to format device node path: %m");
+
+                if (symlink(dn, "/run/systemd/volatile-root") < 0)
+                        log_warning_errno(errno, "Failed to create symlink /run/systemd/volatile-root: %m");
+        }
+
+        if (m == VOLATILE_YES)
+                return make_volatile(path);
+        else {
+                assert(m == VOLATILE_OVERLAY);
+                return make_overlay(path);
+        }
 }
 
 DEFINE_MAIN_FUNCTION(run);
index 2edcf6a..7ff148e 100644 (file)
@@ -44,11 +44,38 @@ An absolute path may also be used in both cases.
 Configuration variables
 =======================
 
-TEST_NO_QEMU=1 can be used to disable qemu tests.
+TEST_NO_QEMU=1
+    Don't run tests under QEMU
 
-TEST_NO_NSPAWN=1 can be used to disable nspawn tests.
+TEST_NO_NSPAWN=1
+    Don't run tests under systemd-nspawn
 
-KERNEL_APPEND='...' can be used to add additional kernel parameters for the QEMU runs.
+TEST_NO_KVM=1
+    Disable QEMU KVM autodetection (may be necessary when you're trying to run the
+    *vanilla* QEMU and have both qemu and qemu-kvm installed)
+
+QEMU_MEM=512M
+    Configure amount of memory for QEMU VMs (defaults to 512M)
+
+QEMU_SMP=1
+    Configure number of CPUs for QEMU VMs (defaults to 1)
+
+KERNEL_APPEND='...'
+    Append additional parameters to the kernel command line
+
+NSPAWN_ARGUMENTS='...'
+    Specify additional arguments for systemd-nspawn
+
+QEMU_TIMEOUT=infinity
+    Set a timeout for tests under QEMU (defaults to infinity)
+
+NSPAWN_TIMEOUT=infinity
+    Set a timeout for tests under systemd-nspawn (defaults to infinity)
+
+INTERACTIVE_DEBUG=1
+    Configure the machine to be more *user-friendly* for interactive debuggung
+    (e.g. by setting a usable default terminal, suppressing the shutdown after
+    the test, etc.)
 
 The kernel and initramfs can be specified with $KERNEL_BIN and $INITRD.
 (Fedora's or Debian's default kernel path and initramfs are used by default)
index 71709f7..97eb2f4 100755 (executable)
@@ -29,7 +29,7 @@ check_result_qemu() {
 test_setup() {
     create_empty_image
     echo -n test >$TESTDIR/keyfile
-    cryptsetup -q luksFormat ${LOOPDEV}p2 $TESTDIR/keyfile
+    cryptsetup -q luksFormat --pbkdf pbkdf2 --pbkdf-force-iterations 1000 ${LOOPDEV}p2 $TESTDIR/keyfile
     cryptsetup luksOpen ${LOOPDEV}p2 varcrypt <$TESTDIR/keyfile
     mkfs.ext4 -L var /dev/mapper/varcrypt
     mkdir -p $TESTDIR/root
index e66ea53..42190cf 100755 (executable)
@@ -26,6 +26,13 @@ grep 'sleep\.service.*running' /root/list-jobs.txt
 grep 'hello\.service' /root/list-jobs.txt && exit 1
 systemctl stop sleep.service hello-after-sleep.target
 
+# Some basic testing that --show-transaction does something useful
+! systemctl is-active systemd-importd
+systemctl -T start systemd-importd
+systemctl is-active systemd-importd
+systemctl --show-transaction stop systemd-importd
+! systemctl is-active systemd-importd
+
 # Test for a crash when enqueuing a JOB_NOP when other job already exists
 systemctl start --no-block hello-after-sleep.target
 # hello.service should still be waiting, so these try-restarts will collapse
index 260cae0..e198cb6 100755 (executable)
@@ -63,6 +63,18 @@ grep -q '^PRIORITY=6$' /output
 ! grep -q '^FOO=' /output
 ! grep -q '^SYSLOG_FACILITY=' /output
 
+# `-b all` negates earlier use of -b (-b and -m are otherwise exclusive)
+journalctl -b -1 -b all -m > /dev/null
+
+# -b always behaves like -b0
+journalctl -q -b-1 -b0 | head -1 > /expected
+journalctl -q -b-1 -b  | head -1 > /output
+cmp /expected /output
+# ... even when another option follows (both of these should fail due to -m)
+{ journalctl -ball -b0 -m 2>&1 || :; } | head -1 > /expected
+{ journalctl -ball -b  -m 2>&1 || :; } | head -1 > /output
+cmp /expected /output
+
 # Don't lose streams on restart
 systemctl start forever-print-hola
 sleep 3
index 6cde7fd..38c725f 100755 (executable)
@@ -41,6 +41,8 @@ EOF
         cat >$initdir/etc/systemd/system/fail-on-restart.service <<EOF
 [Unit]
 Description=Fail on restart
+StartLimitIntervalSec=1m
+StartLimitBurst=3
 
 [Service]
 Type=simple
index 0e1a116..b183ec9 100644 (file)
@@ -4,8 +4,8 @@
 set -ex
 set -o pipefail
 
-systemd-analyze set-log-level debug
-systemd-analyze set-log-target console
+systemd-analyze log-level debug
+systemd-analyze log-target console
 
 test `systemctl show -p MainPID --value testsuite.service` -eq $$
 
@@ -134,7 +134,7 @@ chmod 755 /dev/shm/mainpid3.sh
 # Test that this failed due to timeout, and not some other error
 test `systemctl show -p Result --value mainpidsh3.service` = timeout
 
-systemd-analyze set-log-level info
+systemd-analyze log-level info
 
 echo OK > /testok
 
diff --git a/test/TEST-22-TMPFILES/test-08.sh b/test/TEST-22-TMPFILES/test-08.sh
new file mode 100755 (executable)
index 0000000..e7bf044
--- /dev/null
@@ -0,0 +1,32 @@
+#! /bin/bash
+#
+# Verify tmpfiles can run in a root directory under a path prefix that contains
+# directories owned by unprivileged users, for example when a root file system
+# is mounted in a regular user's home directory.
+#
+# https://github.com/systemd/systemd/pull/11820
+#
+
+set -e
+
+rm -fr /tmp/root /tmp/user
+mkdir -p /tmp/root /tmp/user/root
+chown daemon:daemon /tmp/user
+
+# Verify the command works as expected with no prefix or a root-owned prefix.
+echo 'd /tmp/root/test1' | systemd-tmpfiles --create -
+test -d /tmp/root/test1
+echo 'd /test2' | systemd-tmpfiles --root=/tmp/root --create -
+test -d /tmp/root/test2
+
+# Verify the command fails to write to a root-owned subdirectory under an
+# unprivileged user's directory when it's not part of the prefix, as expected
+# by the unsafe_transition function.
+! echo 'd /tmp/user/root/test' | systemd-tmpfiles --create -
+! test -e /tmp/user/root/test
+! echo 'd /user/root/test' | systemd-tmpfiles --root=/tmp --create -
+! test -e /tmp/user/root/test
+
+# Verify the above works when all user-owned directories are in the prefix.
+echo 'd /test' | systemd-tmpfiles --root=/tmp/user/root --create -
+test -d /tmp/user/root/test
index 80734bb..4f7cc44 100755 (executable)
@@ -4,8 +4,8 @@
 set -ex
 set -o pipefail
 
-systemd-analyze set-log-level debug
-systemd-analyze set-log-target console
+systemd-analyze log-level debug
+systemd-analyze log-target console
 
 # Create a binary for which execve() will fail
 touch /tmp/brokenbinary
@@ -21,7 +21,7 @@ systemd-run --unit=four -p Type=exec /bin/sleep infinity
 ! systemd-run --unit=five -p Type=exec -p User=idontexist /bin/sleep infinity
 ! systemd-run --unit=six -p Type=exec /tmp/brokenbinary
 
-systemd-analyze set-log-level info
+systemd-analyze log-level info
 
 echo OK > /testok
 
index 014ee52..fc8c89f 100755 (executable)
@@ -78,6 +78,8 @@ test_setup() {
         setup_basic_environment
         install_keymaps yes
         install_zoneinfo
+        # Install nproc to determine # of CPUs for correct parallelization
+        inst_binary nproc
 
         # setup the testsuite service
         cat >$initdir/etc/systemd/system/testsuite.service <<EOF
index 7c0e495..7c7a068 100755 (executable)
@@ -4,31 +4,84 @@
 #set -ex
 #set -o pipefail
 
-for i in /usr/lib/systemd/tests/test-*; do
-    if [[ ! -x $i ]]; then continue; fi
-    NAME=${i##*/}
-    echo "Running $NAME"
-    $i > /$NAME.log 2>&1
-    ret=$?
-    if (( $ret && $ret != 77 )); then
-        echo "$NAME failed with $ret"
-        echo $NAME >> /failed-tests
-        echo "--- $NAME begin ---" >> /failed
-        cat /$NAME.log >> /failed
-        echo "--- $NAME end ---" >> /failed
-    elif (( $ret == 77 )); then
-        echo "$NAME skipped"
-        echo $NAME >> /skipped-tests
-        echo "--- $NAME begin ---" >> /skipped
-        cat /$NAME.log >> /skipped
-        echo "--- $NAME end ---" >> /skipped
+NPROC=$(nproc)
+MAX_QUEUE_SIZE=${NPROC:-2}
+IFS=$'\n' TEST_LIST=($(ls /usr/lib/systemd/tests/test-*))
+
+# Check & report test results
+# Arguments:
+#   $1: test path
+#   $2: test exit code
+function report_result() {
+    if [[ $# -ne 2 ]]; then
+        echo >&2 "check_result: missing arguments"
+        exit 1
+    fi
+
+    local name="${1##*/}"
+    local ret=$2
+
+    if [[ $ret -ne 0 && $ret != 77 ]]; then
+        echo "$name failed with $ret"
+        echo "$name" >> /failed-tests
+        {
+            echo "--- $name begin ---"
+            cat "/$name.log"
+            echo "--- $name end ---"
+        } >> /failed
+    elif [[ $ret == 77 ]]; then
+        echo "$name skipped"
+        echo "$name" >> /skipped-tests
+        {
+            echo "--- $name begin ---"
+            cat "/$name.log"
+            echo "--- $name end ---"
+        } >> /skipped
     else
-        echo "$NAME OK"
-        echo $NAME >> /testok
+        echo "$name OK"
+        echo "$name" >> /testok
+    fi
+
+    systemd-cat echo "--- $name ---"
+    systemd-cat cat "/$name.log"
+}
+
+# Associative array for running tasks, where running[test-path]=PID
+declare -A running=()
+for task in "${TEST_LIST[@]}"; do
+    # If there's MAX_QUEUE_SIZE running tasks, keep checking the running queue
+    # until one of the tasks finishes, so we can replace it.
+    while [[ ${#running[@]} -ge $MAX_QUEUE_SIZE ]]; do
+        for key in "${!running[@]}"; do
+            if ! kill -0 ${running[$key]} &>/dev/null; then
+                # Task has finished, report its result and drop it from the queue
+                wait ${running[$key]}
+                ec=$?
+                report_result "$key" $ec
+                unset running["$key"]
+                # Break from inner for loop and outer while loop to skip
+                # the sleep below when we find a free slot in the queue
+                break 2
+            fi
+        done
+
+        # Precisely* calculated constant to keep the spinlock from burning the CPU(s)
+        sleep 0.01
+    done
+
+    if [[ -x $task ]]; then
+        log_file="/${task##*/}.log"
+        $task &> "$log_file" &
+        running[$task]=$!
     fi
+done
 
-    systemd-cat echo "--- $NAME ---"
-    systemd-cat cat /$NAME.log
+# Wait for remaining running tasks
+for key in "${!running[@]}"; do
+    wait ${running[$key]}
+    ec=$?
+    report_result "$key" $ec
+    unset running["$key"]
 done
 
 exit 0
index b8fcc46..6975b79 100755 (executable)
@@ -4,8 +4,8 @@
 set -ex
 set -o pipefail
 
-systemd-analyze set-log-level debug
-systemd-analyze set-log-target console
+systemd-analyze log-level debug
+systemd-analyze log-target console
 
 systemd-run --wait --unit=one -p StandardOutput=file:/tmp/stdout -p StandardError=file:/tmp/stderr -p Type=exec sh -c 'echo x ; echo y >&2'
 cmp /tmp/stdout <<EOF
@@ -33,7 +33,7 @@ a
 c
 EOF
 
-systemd-analyze set-log-level info
+systemd-analyze log-level info
 
 echo OK > /testok
 
diff --git a/test/TEST-29-UDEV-ID_RENAMING/Makefile b/test/TEST-29-UDEV-ID_RENAMING/Makefile
new file mode 120000 (symlink)
index 0000000..e9f93b1
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-29-UDEV-ID_RENAMING/test.sh b/test/TEST-29-UDEV-ID_RENAMING/test.sh
new file mode 100755 (executable)
index 0000000..74362c0
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -e
+TEST_DESCRIPTION="UDEV ID_RENAMING property"
+TEST_NO_NSPAWN=1
+
+. $TEST_BASE_DIR/test-functions
+QEMU_TIMEOUT=300
+
+test_setup() {
+    create_empty_image
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+
+    (
+        LOG_LEVEL=5
+        eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+        setup_basic_environment
+
+        # 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
+
+        # setup the testsuite service
+        cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/bin/bash -x /testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+EOF
+        cp testsuite.sh $initdir/
+
+        setup_testsuite
+    ) || return 1
+
+    ddebug "umount $TESTDIR/root"
+    umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-29-UDEV-ID_RENAMING/testsuite.sh b/test/TEST-29-UDEV-ID_RENAMING/testsuite.sh
new file mode 100755 (executable)
index 0000000..9452c3a
--- /dev/null
@@ -0,0 +1,45 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -ex
+set -o pipefail
+
+mkdir -p /run/udev/rules.d/
+
+cat > /run/udev/rules.d/50-testsuite.rules <<EOF
+ACTION=="remove", GOTO="lo_end"
+
+SUBSYSTEM=="net", KERNEL=="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/lo"
+
+ACTION!="change", GOTO="lo_end"
+
+SUBSYSTEM=="net", KERNEL=="lo", ENV{ID_RENAMING}="1"
+
+LABEL="lo_end"
+EOF
+
+udevadm control --log-priority=debug --reload --timeout=600
+udevadm trigger --action=add --settle /sys/devices/virtual/net/lo
+udevadm info /sys/devices/virtual/net/lo
+sleep 1
+STATE=$(systemctl show --property=ActiveState --value sys-devices-virtual-net-lo.device)
+[[ $STATE == "active" ]] || exit 1
+
+udevadm trigger --action=change --settle /sys/devices/virtual/net/lo
+udevadm info /sys/devices/virtual/net/lo
+sleep 1
+STATE=$(systemctl show --property=ActiveState --value sys-devices-virtual-net-lo.device)
+[[ $STATE == "inactive" ]] || exit 1
+
+udevadm trigger --action=move --settle /sys/devices/virtual/net/lo
+udevadm info /sys/devices/virtual/net/lo
+sleep 1
+STATE=$(systemctl show --property=ActiveState --value sys-devices-virtual-net-lo.device)
+[[ $STATE == "active" ]] || exit 1
+
+rm -f /run/udev/rules.d/50-testsuite.rules
+udevadm control --reload --timeout=600
+
+echo OK > /testok
+
+exit 0
diff --git a/test/TEST-30-ONCLOCKCHANGE/Makefile b/test/TEST-30-ONCLOCKCHANGE/Makefile
new file mode 120000 (symlink)
index 0000000..e9f93b1
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-30-ONCLOCKCHANGE/test.sh b/test/TEST-30-ONCLOCKCHANGE/test.sh
new file mode 100755 (executable)
index 0000000..a9b3d78
--- /dev/null
@@ -0,0 +1,60 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -e
+TEST_DESCRIPTION="test OnClockChange= + OnTimezoneChange="
+TEST_NO_NSPAWN=1
+
+. $TEST_BASE_DIR/test-functions
+
+test_setup() {
+    create_empty_image
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+
+    (
+        LOG_LEVEL=5
+        eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+        inst_any /usr/share/zoneinfo/Europe/Kiev
+        inst_any /usr/share/zoneinfo/Europe/Berlin
+
+        setup_basic_environment
+
+        # mask some services that we do not want to run in these tests
+        ln -fs /dev/null $initdir/etc/systemd/system/systemd-hwdb-update.service
+        ln -fs /dev/null $initdir/etc/systemd/system/systemd-journal-catalog-update.service
+        ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.service
+        ln -fs /dev/null $initdir/etc/systemd/system/systemd-networkd.socket
+        ln -fs /dev/null $initdir/etc/systemd/system/systemd-resolved.service
+        ln -fs /dev/null $initdir/etc/systemd/system/systemd-machined.service
+
+        # extend the watchdog
+        mkdir -p $initdir/etc/systemd/system/systemd-timedated.service.d
+        cat >$initdir/etc/systemd/system/systemd-timedated.service.d/watchdog.conf <<EOF
+[Service]
+WatchdogSec=10min
+EOF
+
+        # setup the testsuite service
+        cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+NotifyAccess=all
+EOF
+        cp testsuite.sh $initdir/
+
+        setup_testsuite
+    ) || return 1
+
+    ddebug "umount $TESTDIR/root"
+    umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-30-ONCLOCKCHANGE/testsuite.sh b/test/TEST-30-ONCLOCKCHANGE/testsuite.sh
new file mode 100755 (executable)
index 0000000..3f7c264
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -ex
+set -o pipefail
+
+systemd-analyze log-level debug
+systemd-analyze log-target console
+
+systemctl disable --now systemd-timesyncd.service
+
+timedatectl set-timezone Europe/Berlin
+timedatectl set-time 1980-10-15
+
+systemd-run --on-timezone-change touch /tmp/timezone-changed
+systemd-run --on-clock-change touch /tmp/clock-changed
+
+! test -f /tmp/timezone-changed
+! test -f /tmp/clock-changed
+
+timedatectl set-timezone Europe/Kiev
+
+while ! test -f /tmp/timezone-changed ; do sleep .5 ; done
+
+timedatectl set-time 2018-1-1
+
+while ! test -f /tmp/clock-changed ; do sleep .5 ; done
+
+systemd-analyze log-level info
+
+echo OK > /testok
+
+exit 0
diff --git a/test/TEST-31-DEVICE-ENUMERATION/Makefile b/test/TEST-31-DEVICE-ENUMERATION/Makefile
new file mode 120000 (symlink)
index 0000000..e9f93b1
--- /dev/null
@@ -0,0 +1 @@
+../TEST-01-BASIC/Makefile
\ No newline at end of file
diff --git a/test/TEST-31-DEVICE-ENUMERATION/test.sh b/test/TEST-31-DEVICE-ENUMERATION/test.sh
new file mode 100755 (executable)
index 0000000..d7cea73
--- /dev/null
@@ -0,0 +1,49 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -e
+TEST_DESCRIPTION="plugged -> dead -> plugged issue #11997"
+TEST_NO_NSPAWN=1
+
+. $TEST_BASE_DIR/test-functions
+QEMU_TIMEOUT=300
+
+test_setup() {
+    create_empty_image
+    mkdir -p $TESTDIR/root
+    mount ${LOOPDEV}p1 $TESTDIR/root
+
+    (
+        LOG_LEVEL=5
+        eval $(udevadm info --export --query=env --name=${LOOPDEV}p2)
+
+        setup_basic_environment
+
+        # 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
+
+        # setup the testsuite service
+        cat >$initdir/etc/systemd/system/testsuite.service <<EOF
+[Unit]
+Description=Testsuite service
+
+[Service]
+ExecStart=/bin/bash -x /testsuite.sh
+Type=oneshot
+StandardOutput=tty
+StandardError=tty
+EOF
+        cp testsuite.sh $initdir/
+
+        setup_testsuite
+    ) || return 1
+
+    ddebug "umount $TESTDIR/root"
+    umount $TESTDIR/root
+}
+
+do_test "$@"
diff --git a/test/TEST-31-DEVICE-ENUMERATION/testsuite.sh b/test/TEST-31-DEVICE-ENUMERATION/testsuite.sh
new file mode 100755 (executable)
index 0000000..cb12b51
--- /dev/null
@@ -0,0 +1,12 @@
+#!/bin/bash
+# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
+# ex: ts=8 sw=4 sts=4 et filetype=sh
+set -ex
+set -o pipefail
+
+if journalctl -b | grep -e '\.device: Changed plugged -> dead'; then
+    exit 1
+fi
+
+echo OK > /testok
+exit 0
diff --git a/test/fuzz/fuzz-bus-message/oss-fuzz-14016 b/test/fuzz/fuzz-bus-message/oss-fuzz-14016
new file mode 100644 (file)
index 0000000..c82d1ba
Binary files /dev/null and b/test/fuzz/fuzz-bus-message/oss-fuzz-14016 differ
diff --git a/test/fuzz/fuzz-calendarspec/oss-fuzz-14108 b/test/fuzz/fuzz-calendarspec/oss-fuzz-14108
new file mode 100644 (file)
index 0000000..6899c23
--- /dev/null
@@ -0,0 +1 @@
+@67767992554749550
\ No newline at end of file
diff --git a/test/fuzz/fuzz-dns-packet/oss-fuzz-13422 b/test/fuzz/fuzz-dns-packet/oss-fuzz-13422
new file mode 100644 (file)
index 0000000..439aec5
Binary files /dev/null and b/test/fuzz/fuzz-dns-packet/oss-fuzz-13422 differ
diff --git a/test/fuzz/fuzz-env-file/simple-env-file b/test/fuzz/fuzz-env-file/simple-env-file
new file mode 100644 (file)
index 0000000..2cad6f7
--- /dev/null
@@ -0,0 +1,5 @@
+VARIABLE="value"
+OPTION="--option=1234"
+NUMBER=1
+EMPTY=""
+PATH=/var/lib/xxx
diff --git a/test/fuzz/fuzz-journal-remote/oss-fuzz-9341 b/test/fuzz/fuzz-journal-remote/oss-fuzz-9341
new file mode 100644 (file)
index 0000000..3ddac6b
Binary files /dev/null and b/test/fuzz/fuzz-journal-remote/oss-fuzz-9341 differ
diff --git a/test/fuzz/fuzz-link-parser/99-default.link b/test/fuzz/fuzz-link-parser/99-default.link
new file mode 100644 (file)
index 0000000..92fcbe8
--- /dev/null
@@ -0,0 +1,12 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Link]
+NamePolicy=keep kernel database onboard slot path
+MACAddressPolicy=persistent
diff --git a/test/fuzz/fuzz-link-parser/advertise-segv.link b/test/fuzz/fuzz-link-parser/advertise-segv.link
new file mode 100644 (file)
index 0000000..305e846
--- /dev/null
@@ -0,0 +1,2 @@
+[Link]
+Advertise=hoge foo
diff --git a/test/fuzz/fuzz-link-parser/condition-memleak.link b/test/fuzz/fuzz-link-parser/condition-memleak.link
new file mode 100644 (file)
index 0000000..523e4ba
--- /dev/null
@@ -0,0 +1,7 @@
+[Match]
+OriginalName=eth0
+Host=hogehoge
+Virtualization=qemu
+KernelCommandLine=aaa
+KernelVersion=4.20.3
+Architecture=x86-64
diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link
new file mode 100644 (file)
index 0000000..5925e5a
--- /dev/null
@@ -0,0 +1,35 @@
+[Match]
+MACAddress=
+OriginalName=
+Path=
+Driver=
+Type=
+Host=
+Virtualization=
+KernelCommandLine=
+KernelVersion=
+Architecture=
+[Link]
+Description=
+MACAddressPolicy=
+MACAddress=
+NamePolicy=
+Name=
+Alias=
+MTUBytes=
+BitsPerSecond=
+Duplex=
+AutoNegotiation=
+WakeOnLan=
+Port=
+GenericSegmentationOffload=
+TCPSegmentationOffload=
+TCP6SegmentationOffload=
+UDPSegmentationOffload=
+GenericReceiveOffload=
+LargeReceiveOffload=
+RxChannels=
+TxChannels=
+OtherChannels=
+CombinedChannels=
+Advertise=
diff --git a/test/fuzz/fuzz-link-parser/oss-fuzz-13878 b/test/fuzz/fuzz-link-parser/oss-fuzz-13878
new file mode 100644 (file)
index 0000000..dbb2abe
--- /dev/null
@@ -0,0 +1,4 @@
+[Match]
+KernelVersion=t
+Virtualization=q
+KernelVersion=
\ No newline at end of file
diff --git a/test/fuzz/fuzz-link-parser/oss-fuzz-13882 b/test/fuzz/fuzz-link-parser/oss-fuzz-13882
new file mode 100644 (file)
index 0000000..7c56ec2
Binary files /dev/null and b/test/fuzz/fuzz-link-parser/oss-fuzz-13882 differ
index cd7c3aa..7da3955 100644 (file)
@@ -9,6 +9,7 @@ Mode=
 [WireGuard]
 ListenPort=
 PrivateKey=
+PrivateKeyFile=
 FwMark=
 [MACVTAP]
 Mode=
@@ -51,6 +52,7 @@ Name=
 [WireGuardPeer]
 Endpoint=
 PresharedKey=
+PresharedKeyFile=
 PersistentKeepalive=
 PublicKey=
 AllowedIPs=
@@ -156,3 +158,19 @@ MACAddress=
 MTUBytes=
 Description=
 Name=
+[L2TP]
+TunnelId=
+PeerTunnelId=
+UDPSourcePort=
+UDPDestinationPort=
+Local=
+Remote=
+EncapsulationType=
+UDPCheckSum=
+UDP6CheckSumRx=
+UDP6CheckSumTx=
+[L2TPSession]
+SessionId=
+PeerSessionId=
+Layer2SpecificHeader=
+Name=
diff --git a/test/fuzz/fuzz-netdev-parser/oss-fuzz-13719 b/test/fuzz/fuzz-netdev-parser/oss-fuzz-13719
new file mode 100644 (file)
index 0000000..adff4c1
--- /dev/null
@@ -0,0 +1,6 @@
+[NetDev]
+Name=w
+Kind=wireguard
+[WireGuardPeer]
+Endpoint=:0
+Endpoint=:8
\ No newline at end of file
diff --git a/test/fuzz/fuzz-netdev-parser/oss-fuzz-13884 b/test/fuzz/fuzz-netdev-parser/oss-fuzz-13884
new file mode 100644 (file)
index 0000000..ce8d713
Binary files /dev/null and b/test/fuzz/fuzz-netdev-parser/oss-fuzz-13884 differ
diff --git a/test/fuzz/fuzz-netdev-parser/oss-fuzz-13886 b/test/fuzz/fuzz-netdev-parser/oss-fuzz-13886
new file mode 100644 (file)
index 0000000..1230ffe
Binary files /dev/null and b/test/fuzz/fuzz-netdev-parser/oss-fuzz-13886 differ
diff --git a/test/fuzz/fuzz-netdev-parser/oss-fuzz-14157 b/test/fuzz/fuzz-netdev-parser/oss-fuzz-14157
new file mode 100644 (file)
index 0000000..d3a65e1
--- /dev/null
@@ -0,0 +1,5 @@
+[NetDev]
+Name=w
+Kind=wireguard
+[WireGuardPeer]
+PublicKey=e
\ No newline at end of file
diff --git a/test/fuzz/fuzz-netdev-parser/oss-fuzz-14158 b/test/fuzz/fuzz-netdev-parser/oss-fuzz-14158
new file mode 100644 (file)
index 0000000..6f6bf72
--- /dev/null
@@ -0,0 +1,5 @@
+[NetDev]
+Name=w
+Kind=wireguard
+[WireGuard]
+PrivateKey=E
\ No newline at end of file
index 209132f..ddc60a9 100644 (file)
@@ -7,6 +7,9 @@ FastLeave=
 Priority=
 AllowPortToBeRoot=
 MulticastToUnicast=
+MulticastFlood=
+NeighborSuppression=
+Learning=
 [Match]
 KernelVersion=
 Type=
@@ -60,6 +63,7 @@ Protocol=
 Table=
 Gateway=
 InitialAdvertisedReceiveWindow=
+GatewayOnLink=
 GatewayOnlink=
 Type=
 InitialCongestionWindow=
@@ -106,6 +110,7 @@ IPForward=
 IPv6Token=
 Description=
 VXLAN=
+L2TP=
 LinkLocalAddressing=
 ConfigureWithoutCarrier=
 NTP=
@@ -116,6 +121,7 @@ VLAN=
 DHCPServer=
 BindCarrier=
 VRF=
+IgnoreCarrierLoss=
 [IPv6Prefix]
 Prefix=
 OnLink=
@@ -130,6 +136,7 @@ PVID=
 SamplePoint=
 BitRate=
 RestartSec=
+TripleSampling=
 [Address]
 DuplicateAddressDetection=
 AutoJoin=
@@ -176,6 +183,8 @@ Prefix=
 UseDomains=
 RouteTable=
 UseDNS=
+UseAutonomousPrefix=
+UseOnLinkPrefix=
 [DHCPServer]
 EmitNTP=
 PoolSize=
diff --git a/test/fuzz/fuzz-network-parser/oss-fuzz-13059 b/test/fuzz/fuzz-network-parser/oss-fuzz-13059
new file mode 100644 (file)
index 0000000..d4267ff
Binary files /dev/null and b/test/fuzz/fuzz-network-parser/oss-fuzz-13059 differ
diff --git a/test/fuzz/fuzz-network-parser/oss-fuzz-13354 b/test/fuzz/fuzz-network-parser/oss-fuzz-13354
new file mode 100644 (file)
index 0000000..2274fa5
Binary files /dev/null and b/test/fuzz/fuzz-network-parser/oss-fuzz-13354 differ
diff --git a/test/fuzz/fuzz-network-parser/oss-fuzz-13433 b/test/fuzz/fuzz-network-parser/oss-fuzz-13433
new file mode 100644 (file)
index 0000000..1aef8b7
Binary files /dev/null and b/test/fuzz/fuzz-network-parser/oss-fuzz-13433 differ
diff --git a/test/fuzz/fuzz-network-parser/oss-fuzz-13888 b/test/fuzz/fuzz-network-parser/oss-fuzz-13888
new file mode 100644 (file)
index 0000000..c75fcb4
Binary files /dev/null and b/test/fuzz/fuzz-network-parser/oss-fuzz-13888 differ
diff --git a/test/fuzz/fuzz-nspawn-oci/basic.json b/test/fuzz/fuzz-nspawn-oci/basic.json
new file mode 100644 (file)
index 0000000..f42739e
--- /dev/null
@@ -0,0 +1,141 @@
+{
+    "ociVersion": "1.0.0",
+
+    "root": {
+        "path": "rootfs",
+        "readonly": true
+    },
+
+    "process": {
+        "terminal": false,
+        "consoleSize": {
+            "height":6667,
+            "width":6668
+        },
+
+        "user": {
+            "uid": 14,
+            "gid": 14,
+            "additionalGids": [59, 81]
+        },
+
+        "args": [
+            "/tmp/verify.sh"
+        ],
+
+        "env": [
+            "FOO=BAR",
+            "WITHSPACES=FOO BAR",
+            "WITHSHELLCHARS=$ASDF \\\"asdf asdf\\\" !",
+            "WITHCONTROLCHARS=\\123\\125\\010\\020",
+            "TERM=xterm"
+        ],
+
+        "cwd": "/tmp/src",
+
+        "rlimits": [
+            {
+                "type": "RLIMIT_NOFILE",
+                "hard": 1020,
+                "soft": 1020
+            }
+        ]
+    },
+
+    "mounts": [
+        {
+            "destination": "/tmp/src",
+            "source": "src",
+            "options": ["ro"]
+        },
+
+        {
+            "destination": "/tmp/verify.sh",
+            "source": "verify.sh",
+            "options": ["ro"]
+        },
+
+        {
+            "destination": "/proc",
+            "type": "proc",
+            "source": "proc"
+        },
+        {
+            "destination": "/dev",
+            "type": "tmpfs",
+            "source": "tmpfs",
+            "options": [
+                "mode=777"
+            ]
+        },
+        {
+            "destination": "/dev/pts",
+            "type": "devpts",
+            "source": "devpts",
+            "options": [
+                "mode=777"
+            ]
+        },
+        {
+            "destination": "/dev/shm",
+            "type": "tmpfs",
+            "source": "shm",
+            "options": [
+                "mode=777"
+            ]
+        },
+        {
+            "destination": "/dev/mqueue",
+            "type": "mqueue",
+            "source": "mqueue",
+            "options": [
+                "mode=777"
+            ]
+        },
+        {
+            "destination": "/sys",
+            "type": "sysfs",
+            "source": "sysfs",
+            "options": [
+                "mode=777"
+            ]
+        },
+        {
+            "destination": "/sys/fs/cgroup",
+            "type": "cgroup",
+            "source": "cgroup",
+            "options": [
+                "mode=777"
+            ]
+        }
+    ],
+
+    "hooks": {},
+
+    "linux": {
+        "resources": {
+            "devices": [
+                {
+                    "allow": false,
+                    "access": "rwm"
+                }
+            ]
+        },
+        "namespaces": [
+            {
+                "type": "pid"
+            },
+            {
+                "type": "ipc"
+            },
+            {
+                "type": "mount"
+            }
+        ]
+    },
+
+    "annotations": {
+        "com.example.key1": "value1",
+        "com.example.key2": "value2"
+    }
+}
diff --git a/test/fuzz/fuzz-nspawn-oci/crash-bffbd2085d4e95c47e9749b3f4a2dbc0580c20d3 b/test/fuzz/fuzz-nspawn-oci/crash-bffbd2085d4e95c47e9749b3f4a2dbc0580c20d3
new file mode 100644 (file)
index 0000000..22e42d3
--- /dev/null
@@ -0,0 +1,5 @@
+{"ociVersion": "1.0.0",
+"linux": {"devices": [     {  "access": "mmmw;r"}
+] }, "e": "}e"
+  }
\ No newline at end of file
diff --git a/test/fuzz/fuzz-nspawn-oci/crash-db0595479ee2e625fa5419a821009b5eb4d809b7 b/test/fuzz/fuzz-nspawn-oci/crash-db0595479ee2e625fa5419a821009b5eb4d809b7
new file mode 100644 (file)
index 0000000..0bf017c
--- /dev/null
@@ -0,0 +1,92 @@
+{
+    "ociVersion": "1.0.0",
+
+    "root": {
+        "path": "rootfs",
+        "readonly": true
+    },
+
+    "process": {
+        "terminal": false,
+        "consoleSize": {
+            "height":6667,
+            "width":6668
+        },
+
+        "user": {
+            "uid": 14,
+            "gid": 14,
+            "additionalGids": [59, 81]
+        },
+
+        "args": [
+            "/tmp/verify.sh"
+        ],
+
+        "env": [
+            "FOO=BAR",
+            "WITHSPACES=FOO BAR",
+            "WITHSHELLCHARS=$ASDF \\\"asdf asdf\\\" !",
+            "WITHCONTROLCHARS=\\123\\125\\010\\020",
+            "TERM=xterm"
+        ],
+
+        "cwd": "/tmp/src",
+
+        "rlimits": [
+            {
+                "type": "RLIMIT_NOFILE",
+                "hard": 1020,
+                "soft": 1020
+            }
+        ]
+    },
+
+    "mounts": [
+        {
+            "destination": "/tmp/src"       },
+        {
+       "source": "sysfs",
+            "options": [
+                "mode=777"
+            ]
+        },
+        {
+            "destination": "/sys/fs/cgroup",
+            "type": "cgroup",
+            "source": "cgroup",
+            "options": [
+                "mode=777"
+            ]
+        }
+    ],
+
+    "hooks": {},
+
+    "linux": {
+        "resources": {
+            "devices": [
+                {
+                    "allow": false,
+                    "access": "rwm"
+                }
+            ]
+        },
+        "namespaces": [
+            {
+                "type": "pid"
+            },
+            {
+                "type": "ipc"
+            },
+            {
+                "type": "mount"
+            }
+        ]
+    },
+
+    "annotations": {
+        "com.example.key1": "value1",
+        "com.example.key2": "value2"
+    }
+}
diff --git a/test/fuzz/fuzz-nspawn-settings/basic-config b/test/fuzz/fuzz-nspawn-settings/basic-config
new file mode 100644 (file)
index 0000000..be0d4e7
--- /dev/null
@@ -0,0 +1,36 @@
+[Exec]
+Boot=off
+ProcessTwo=off
+Parameters=/sbin/init -x=1
+Environment=THIS=that
+User=user
+WorkingDirectory=/cwd
+PivotRoot=/newroot
+Capability=CAP_NET
+DropCapability=CAP_ADMIN
+KillSignal=SIGTERM
+Personality=shy
+MachineID=edbfea3309ba41ea83e2318c58a8d498
+PrivateUser=1:2
+NotifyReady=no
+SystemCallFilters=write
+
+[Files]
+ReadOnly=no
+Volatile=no
+Bind=/bindthis
+BindReadOnly=/bindthisro
+TemporaryFileSystem=/thisismytmpfs:rw
+Overlay=/thisisanoverlay:/thisisanoverlaytoo
+PrivateUsersChown=no
+
+[Network]
+Private=off
+VirtualEthernet=yes
+VirtualEthernetExtra=veth1:veth2
+Interface=eth1 enp0s1
+MacVLAN=eno1 eno2
+IPVLAN=eno3 enp2s124
+Bridge=bridge123 bridge125
+Zone=myzone
+Port=1234 156 -1
diff --git a/test/fuzz/fuzz-nspawn-settings/leak-4ff0e2498f596a77ea68d185c61e9e9ff9bb657f b/test/fuzz/fuzz-nspawn-settings/leak-4ff0e2498f596a77ea68d185c61e9e9ff9bb657f
new file mode 100644 (file)
index 0000000..7be2d2c
Binary files /dev/null and b/test/fuzz/fuzz-nspawn-settings/leak-4ff0e2498f596a77ea68d185c61e9e9ff9bb657f differ
diff --git a/test/fuzz/fuzz-nspawn-settings/oss-fuzz-13691 b/test/fuzz/fuzz-nspawn-settings/oss-fuzz-13691
new file mode 100644 (file)
index 0000000..51f46e3
--- /dev/null
@@ -0,0 +1,2 @@
+[Files]
+Overlay=/::
\ No newline at end of file
diff --git a/test/fuzz/fuzz-udev-database/sample.txt b/test/fuzz/fuzz-udev-database/sample.txt
new file mode 100644 (file)
index 0000000..041c618
--- /dev/null
@@ -0,0 +1,500 @@
+E:ID_ATA=1
+E:ID_ATA_DOWNLOAD_MICROCODE=1
+E:ID_ATA_FEATURE_SET_HPA=1
+E:ID_ATA_FEATURE_SET_HPA_ENABLED=1
+E:ID_ATA_FEATURE_SET_PM=1
+E:ID_ATA_FEATURE_SET_PM_ENABLED=1
+E:ID_ATA_FEATURE_SET_SECURITY=1
+E:ID_ATA_FEATURE_SET_SECURITY_ENABLED=0
+E:ID_ATA_FEATURE_SET_SECURITY_ENHANCED_ERASE_UNIT_MIN=8
+E:ID_ATA_FEATURE_SET_SECURITY_ERASE_UNIT_MIN=2
+E:ID_ATA_FEATURE_SET_SECURITY_FROZEN=1
+E:ID_ATA_FEATURE_SET_SMART=1
+E:ID_ATA_FEATURE_SET_SMART_ENABLED=1
+E:ID_ATA_ROTATION_RATE_RPM=0
+E:ID_ATA_SATA=1
+E:ID_ATA_SATA_SIGNAL_RATE_GEN1=1
+E:ID_ATA_SATA_SIGNAL_RATE_GEN2=1
+E:ID_ATA_WRITE_CACHE=1
+E:ID_ATA_WRITE_CACHE_ENABLED=1
+E:ID_BTRFS_READY=1
+E:ID_BUS=ata
+E:ID_BUS=i8042
+E:ID_BUS=pci
+E:ID_BUS=usb
+E:ID_FOR_SEAT=drm-pci-0000_00_02_0
+E:ID_FOR_SEAT=graphics-pci-0000_00_02_0
+E:ID_FOR_SEAT=input-acpi-LNXVIDEO_00
+E:ID_FOR_SEAT=input-acpi-PNP0C0C_00
+E:ID_FOR_SEAT=input-acpi-PNP0C0D_00
+E:ID_FOR_SEAT=input-acpi-SNY5001_00
+E:ID_FOR_SEAT=input-pci-0000_00_03_0
+E:ID_FOR_SEAT=input-pci-0000_00_14_0-usb-0_5_1_0
+E:ID_FOR_SEAT=input-pci-0000_00_1b_0
+E:ID_FOR_SEAT=input-platform-i8042-serio-0
+E:ID_FOR_SEAT=input-platform-i8042-serio-1
+E:ID_FOR_SEAT=sound-pci-0000_00_03_0
+E:ID_FOR_SEAT=sound-pci-0000_00_1b_0
+E:ID_FOR_SEAT=usb-pci-0000_00_14_0
+E:ID_FOR_SEAT=usb-pci-0000_00_1d_0
+E:ID_FOR_SEAT=usb-pci-0000_00_1d_0-usb-0_1
+E:ID_FOR_SEAT=video4linux-pci-0000_00_14_0-usb-0_5_1_0
+E:ID_FS_LABEL_ENC=回復
+E:ID_FS_LABEL=回復
+E:ID_FS_TYPE=
+E:ID_FS_TYPE=btrfs
+E:ID_FS_TYPE=ext4
+E:ID_FS_TYPE=ntfs
+E:ID_FS_TYPE=swap
+E:ID_FS_TYPE=vfat
+E:ID_FS_USAGE=filesystem
+E:ID_FS_USAGE=other
+E:ID_FS_UUID=0f12f260-d308-49b4-9a9f-465a749937ce
+E:ID_FS_UUID=23451e06-2ec4-4ae0-86b1-36602653dd78
+E:ID_FS_UUID=5C1A-DCBA
+E:ID_FS_UUID=64A41A20A419F570
+E:ID_FS_UUID=9C12322A123209B2
+E:ID_FS_UUID=b95e2a35-09fd-493f-9be7-5616eb9ffc19
+E:ID_FS_UUID=beeb37c6-d4e2-494f-b329-3eb27452e469
+E:ID_FS_UUID=D60878D80878B8D7
+E:ID_FS_UUID_ENC=0f12f260-d308-49b4-9a9f-465a749937ce
+E:ID_FS_UUID_ENC=23451e06-2ec4-4ae0-86b1-36602653dd78
+E:ID_FS_UUID_ENC=5C1A-DCBA
+E:ID_FS_UUID_ENC=64A41A20A419F570
+E:ID_FS_UUID_ENC=9C12322A123209B2
+E:ID_FS_UUID_ENC=b95e2a35-09fd-493f-9be7-5616eb9ffc19
+E:ID_FS_UUID_ENC=beeb37c6-d4e2-494f-b329-3eb27452e469
+E:ID_FS_UUID_ENC=D60878D80878B8D7
+E:ID_FS_UUID_SUB=7f4127d5-2d4f-48a4-81ff-ddd959f2d653
+E:ID_FS_UUID_SUB_ENC=7f4127d5-2d4f-48a4-81ff-ddd959f2d653
+E:ID_FS_VERSION=1
+E:ID_FS_VERSION=1.0
+E:ID_FS_VERSION=FAT32
+E:ID_INPUT=1
+E:ID_INPUT_HEIGHT_MM=52
+E:ID_INPUT_JOYSTICK=1
+E:ID_INPUT_KEY=1
+E:ID_INPUT_KEYBOARD=1
+E:ID_INPUT_MOUSE=1
+E:ID_INPUT_SWITCH=1
+E:ID_INPUT_TOUCHPAD=1
+E:ID_INPUT_TOUCHPAD_INTEGRATION=internal
+E:ID_INPUT_WIDTH_MM=88
+E:ID_MODEL=07dc
+E:ID_MODEL=8000
+E:ID_MODEL=EHCI_Host_Controller
+E:ID_MODEL_ENC=07dc
+E:ID_MODEL_ENC=8000
+E:ID_MODEL_ENC=EHCI\x20Host\x20Controller
+E:ID_MODEL_ENC=Nexus\x205X
+E:ID_MODEL_ENC=SAMSUNG\x20MZNTD256HAGL-00000\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20
+E:ID_MODEL_ENC=USB\x202.0\x20Camera
+E:ID_MODEL_ENC=xHCI\x20Host\x20Controller
+E:ID_MODEL_FROM_DATABASE=2.0 root hub
+E:ID_MODEL_FROM_DATABASE=3.0 root hub
+E:ID_MODEL_FROM_DATABASE=8 Series HD Audio Controller
+E:ID_MODEL_FROM_DATABASE=8 Series HECI
+E:ID_MODEL_FROM_DATABASE=8 Series LPC Controller
+E:ID_MODEL_FROM_DATABASE=8 Series PCI Express Root Port 3
+E:ID_MODEL_FROM_DATABASE=8 Series PCI Express Root Port 4
+E:ID_MODEL_FROM_DATABASE=8 Series SATA Controller 1 [AHCI mode]
+E:ID_MODEL_FROM_DATABASE=8 Series SMBus Controller
+E:ID_MODEL_FROM_DATABASE=8 Series USB EHCI
+E:ID_MODEL_FROM_DATABASE=8 Series USB xHCI HC
+E:ID_MODEL_FROM_DATABASE=Haswell-ULT DRAM Controller
+E:ID_MODEL_FROM_DATABASE=Haswell-ULT HD Audio Controller
+E:ID_MODEL_FROM_DATABASE=Haswell-ULT Integrated Graphics Controller
+E:ID_MODEL_FROM_DATABASE=Nexus Device (MTP)
+E:ID_MODEL_FROM_DATABASE=Wireless 7260 (Dual Band Wireless-N 7260)
+E:ID_MODEL_ID=0002
+E:ID_MODEL_ID=0003
+E:ID_MODEL_ID=07dc
+E:ID_MODEL_ID=0x08b1
+E:ID_MODEL_ID=0x0a0c
+E:ID_MODEL_ID=0x9c20
+E:ID_MODEL_ID=4ee1
+E:ID_MODEL_ID=8000
+E:ID_MODEL_ID=b3be
+E:ID_MODEL=Nexus_5X
+E:ID_MODEL=SAMSUNG_MZNTD256HAGL-00000
+E:ID_MODEL=USB_2.0_Camera
+E:ID_MODEL=xHCI_Host_Controller
+E:ID_NET_DRIVER=bridge
+E:ID_NET_DRIVER=iwlwifi
+E:ID_NET_LINK_FILE=/usr/lib/systemd/network/99-default.link
+E:ID_NET_NAME_MAC=wlx00123456abcd
+E:ID_NET_NAME_MAC=wlx5c514f1383eb
+E:ID_NET_NAME_PATH=wlp1s0
+E:ID_NET_NAME=wlp1s0
+E:ID_NET_NAMING_SCHEME=v240
+E:ID_OUI_FROM_DATABASE=Intel Corporate
+E:ID_PART_ENTRY_DISK=8:0
+E:ID_PART_ENTRY_FLAGS=0x1
+E:ID_PART_ENTRY_FLAGS=0x8000000000000001
+E:ID_PART_ENTRY_NAME=Basic\x20data\x20partition
+E:ID_PART_ENTRY_NAME=EFI\x20System\x20Partition
+E:ID_PART_ENTRY_NAME=Microsoft\x20reserved\x20partition
+E:ID_PART_ENTRY_NUMBER=1
+E:ID_PART_ENTRY_NUMBER=2
+E:ID_PART_ENTRY_NUMBER=3
+E:ID_PART_ENTRY_NUMBER=4
+E:ID_PART_ENTRY_NUMBER=5
+E:ID_PART_ENTRY_NUMBER=6
+E:ID_PART_ENTRY_NUMBER=7
+E:ID_PART_ENTRY_NUMBER=8
+E:ID_PART_ENTRY_NUMBER=9
+E:ID_PART_ENTRY_OFFSET=1128448
+E:ID_PART_ENTRY_OFFSET=1161216
+E:ID_PART_ENTRY_OFFSET=132481024
+E:ID_PART_ENTRY_OFFSET=134219776
+E:ID_PART_ENTRY_OFFSET=135243776
+E:ID_PART_ENTRY_OFFSET=143372288
+E:ID_PART_ENTRY_OFFSET=2048
+E:ID_PART_ENTRY_OFFSET=248229888
+E:ID_PART_ENTRY_OFFSET=923648
+E:ID_PART_ENTRY_SCHEME=gpt
+E:ID_PART_ENTRY_SIZE=1024000
+E:ID_PART_ENTRY_SIZE=104857600
+E:ID_PART_ENTRY_SIZE=131319561
+E:ID_PART_ENTRY_SIZE=1738752
+E:ID_PART_ENTRY_SIZE=204800
+E:ID_PART_ENTRY_SIZE=251887616
+E:ID_PART_ENTRY_SIZE=32768
+E:ID_PART_ENTRY_SIZE=8128512
+E:ID_PART_ENTRY_SIZE=921600
+E:ID_PART_ENTRY_TYPE=0657fd6d-a4ab-43c4-84e5-0933c84b4f4f
+E:ID_PART_ENTRY_TYPE=0fc63daf-8483-4772-8e79-3d69d8477de4
+E:ID_PART_ENTRY_TYPE=c12a7328-f81f-11d2-ba4b-00a0c93ec93b
+E:ID_PART_ENTRY_TYPE=de94bba4-06d1-4d40-a16a-bfd50179d6ac
+E:ID_PART_ENTRY_TYPE=e3c9e316-0b5c-4db8-817d-f92df00215ae
+E:ID_PART_ENTRY_TYPE=ebd0a0a2-b9e5-4433-87c0-68b6b72699c7
+E:ID_PART_ENTRY_UUID=1d655759-7350-4d1e-b679-ae54e599c796
+E:ID_PART_ENTRY_UUID=55202025-f2e2-4b92-9b4b-7fa16d804a35
+E:ID_PART_ENTRY_UUID=611ffa59-e1da-4e0c-8b7e-83dd61edf945
+E:ID_PART_ENTRY_UUID=9e241958-b22d-4813-8504-791d45cbf0bc
+E:ID_PART_ENTRY_UUID=9ee3d84f-122d-4d5c-b62b-1006defbcbc1
+E:ID_PART_ENTRY_UUID=a4b0949c-5d61-499b-b336-592ef4e0d423
+E:ID_PART_ENTRY_UUID=b092dc67-d577-4c77-84c4-db681a69a200
+E:ID_PART_ENTRY_UUID=cc77a315-4305-4982-88e6-b52721460ce7
+E:ID_PART_ENTRY_UUID=f17bf199-921b-4cbd-bcbf-15b75ec80b21
+E:ID_PART_TABLE_TYPE=gpt
+E:ID_PART_TABLE_UUID=130de398-eb17-4bac-8a19-fe2e64163e91
+E:ID_PATH=acpi-LNXVIDEO:00
+E:ID_PATH=acpi-PNP0C0C:00
+E:ID_PATH=acpi-PNP0C0D:00
+E:ID_PATH=acpi-SNY5001:00
+E:ID_PATH=pci-0000:00:02.0
+E:ID_PATH=pci-0000:00:03.0
+E:ID_PATH=pci-0000:00:14.0
+E:ID_PATH=pci-0000:00:14.0-usb-0:5:1.0
+E:ID_PATH=pci-0000:00:14.0-usb-0:6:1.0
+E:ID_PATH=pci-0000:00:1b.0
+E:ID_PATH=pci-0000:00:1d.0
+E:ID_PATH=pci-0000:00:1d.0-usb-0:1
+E:ID_PATH=pci-0000:00:1f.2-ata-4
+E:ID_PATH=pci-0000:01:00.0
+E:ID_PATH=platform-i8042-serio-0
+E:ID_PATH=platform-i8042-serio-1
+E:ID_PATH_TAG=acpi-LNXVIDEO_00
+E:ID_PATH_TAG=acpi-PNP0C0C_00
+E:ID_PATH_TAG=acpi-PNP0C0D_00
+E:ID_PATH_TAG=acpi-SNY5001_00
+E:ID_PATH_TAG=pci-0000_00_02_0
+E:ID_PATH_TAG=pci-0000_00_03_0
+E:ID_PATH_TAG=pci-0000_00_14_0
+E:ID_PATH_TAG=pci-0000_00_14_0-usb-0_5_1_0
+E:ID_PATH_TAG=pci-0000_00_14_0-usb-0_6_1_0
+E:ID_PATH_TAG=pci-0000_00_1b_0
+E:ID_PATH_TAG=pci-0000_00_1d_0
+E:ID_PATH_TAG=pci-0000_00_1d_0-usb-0_1
+E:ID_PATH_TAG=pci-0000_00_1f_2-ata-4
+E:ID_PATH_TAG=pci-0000_01_00_0
+E:ID_PATH_TAG=platform-i8042-serio-0
+E:ID_PATH_TAG=platform-i8042-serio-1
+E:ID_PCI_CLASS_FROM_DATABASE=Bridge
+E:ID_PCI_CLASS_FROM_DATABASE=Communication controller
+E:ID_PCI_CLASS_FROM_DATABASE=Display controller
+E:ID_PCI_CLASS_FROM_DATABASE=Mass storage controller
+E:ID_PCI_CLASS_FROM_DATABASE=Multimedia controller
+E:ID_PCI_CLASS_FROM_DATABASE=Network controller
+E:ID_PCI_CLASS_FROM_DATABASE=Serial bus controller
+E:ID_PCI_INTERFACE_FROM_DATABASE=AHCI 1.0
+E:ID_PCI_INTERFACE_FROM_DATABASE=EHCI
+E:ID_PCI_INTERFACE_FROM_DATABASE=Normal decode
+E:ID_PCI_INTERFACE_FROM_DATABASE=VGA controller
+E:ID_PCI_INTERFACE_FROM_DATABASE=XHCI
+E:ID_PCI_SUBCLASS_FROM_DATABASE=Audio device
+E:ID_PCI_SUBCLASS_FROM_DATABASE=Communication controller
+E:ID_PCI_SUBCLASS_FROM_DATABASE=Host bridge
+E:ID_PCI_SUBCLASS_FROM_DATABASE=ISA bridge
+E:ID_PCI_SUBCLASS_FROM_DATABASE=Network controller
+E:ID_PCI_SUBCLASS_FROM_DATABASE=PCI bridge
+E:ID_PCI_SUBCLASS_FROM_DATABASE=SATA controller
+E:ID_PCI_SUBCLASS_FROM_DATABASE=SMBus
+E:ID_PCI_SUBCLASS_FROM_DATABASE=USB controller
+E:ID_PCI_SUBCLASS_FROM_DATABASE=VGA compatible controller
+E:ID_REVISION=0001
+E:ID_REVISION=0004
+E:ID_REVISION=0310
+E:ID_REVISION=0420
+E:ID_REVISION=5811
+E:ID_REVISION=DXT2300Q
+E:ID_SERIAL=8087_07dc
+E:ID_SERIAL=8087_8000
+E:ID_SERIAL=Chicony_Electronics_Co._Ltd._USB_2.0_Camera_0x0001
+E:ID_SERIAL=LGE_Nexus_5X_026442e0677ccae8
+E:ID_SERIAL=Linux_4.20.11-200.fc29.x86_64_ehci_hcd_EHCI_Host_Controller_0000:00:1d.0
+E:ID_SERIAL=Linux_4.20.11-200.fc29.x86_64_xhci-hcd_xHCI_Host_Controller_0000:00:14.0
+E:ID_SERIAL=noserial
+E:ID_SERIAL=SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616
+E:ID_SERIAL_SHORT=0000:00:14.0
+E:ID_SERIAL_SHORT=0000:00:1d.0
+E:ID_SERIAL_SHORT=026442e0677ccae8
+E:ID_SERIAL_SHORT=0x0001
+E:ID_SERIAL_SHORT=S15ZNYAD408616
+E:ID_TYPE=disk
+E:ID_TYPE=video
+E:ID_USB_CLASS_FROM_DATABASE=Hub
+E:ID_USB_CLASS_FROM_DATABASE=Miscellaneous Device
+E:ID_USB_CLASS_FROM_DATABASE=Wireless
+E:ID_USB_DRIVER=uvcvideo
+E:ID_USB_INTERFACE_NUM=00
+E:ID_USB_INTERFACES=:090000:
+E:ID_USB_INTERFACES=:0e0100:0e0200:
+E:ID_USB_INTERFACES=:e00101:
+E:ID_USB_INTERFACES=:ffff00:
+E:ID_USB_PROTOCOL_FROM_DATABASE=Bluetooth
+E:ID_USB_PROTOCOL_FROM_DATABASE=Full speed (or root) hub
+E:ID_USB_PROTOCOL_FROM_DATABASE=Interface Association
+E:ID_USB_PROTOCOL_FROM_DATABASE=Single TT
+E:ID_USB_SUBCLASS_FROM_DATABASE=Radio Frequency
+E:ID_V4L_CAPABILITIES=:capture:
+E:ID_V4L_PRODUCT=USB 2.0 Camera: USB 2.0 Camera
+E:ID_V4L_VERSION=2
+E:ID_VENDOR=8087
+E:ID_VENDOR=Chicony_Electronics_Co._Ltd.
+E:ID_VENDOR_ENC=8087
+E:ID_VENDOR_ENC=Chicony\x20Electronics\x20Co.\x2cLtd.
+E:ID_VENDOR_ENC=LGE
+E:ID_VENDOR_ENC=Linux\x204.20.11-200.fc29.x86_64\x20ehci_hcd
+E:ID_VENDOR_ENC=Linux\x204.20.11-200.fc29.x86_64\x20xhci-hcd
+E:ID_VENDOR_FROM_DATABASE=Chicony Electronics Co., Ltd
+E:ID_VENDOR_FROM_DATABASE=Google Inc.
+E:ID_VENDOR_FROM_DATABASE=Intel Corp.
+E:ID_VENDOR_FROM_DATABASE=Intel Corporation
+E:ID_VENDOR_FROM_DATABASE=Linux Foundation
+E:ID_VENDOR_FROM_DATABASE=NXP Semiconductors bv.
+E:ID_VENDOR_FROM_DATABASE=The Linux Foundation
+E:ID_VENDOR_ID=04f2
+E:ID_VENDOR_ID=0x8086
+E:ID_VENDOR_ID=18d1
+E:ID_VENDOR_ID=1d6b
+E:ID_VENDOR_ID=8087
+E:ID_VENDOR=LGE
+E:ID_VENDOR=Linux_4.20.11-200.fc29.x86_64_ehci_hcd
+E:ID_VENDOR=Linux_4.20.11-200.fc29.x86_64_xhci-hcd
+E:ID_WWN=0x500253850002aca7
+E:ID_WWN_WITH_EXTENSION=0x500253850002aca7
+E:KEYBOARD_KEY_06=mute
+E:KEYBOARD_KEY_07=volumedown
+E:KEYBOARD_KEY_08=volumeup
+E:KEYBOARD_KEY_09=brightnessdown
+E:KEYBOARD_KEY_0a=brightnessup
+E:KEYBOARD_KEY_0b=switchvideomode
+E:KEYBOARD_KEY_0e=zoom
+E:KEYBOARD_KEY_10=suspend
+E:LIBINPUT_DEVICE_GROUP=
+E:LIBINPUT_DEVICE_GROUP=0/0/0:ALSA
+E:LIBINPUT_DEVICE_GROUP=11/1/1:isa0060/serio0
+E:LIBINPUT_DEVICE_GROUP=11/2/7:isa0060/serio1
+E:LIBINPUT_DEVICE_GROUP=19/0/1:PNP0C0C/button
+E:LIBINPUT_DEVICE_GROUP=19/0/6:LNXVIDEO/video
+E:LIBINPUT_DEVICE_GROUP=3/4f2/b3be:usb-0000:00:14.0-5/button
+E:SOUND_FORM_FACTOR=internal
+E:SOUND_INITIALIZED=1
+E:SYSTEMD_ALIAS=/sys/subsystem/bluetooth/devices/hci0
+E:SYSTEMD_ALIAS=/sys/subsystem/net/devices/docker0
+E:SYSTEMD_ALIAS=/sys/subsystem/net/devices/wlp1s0 /sys/subsystem/net/devices/wlp1s0
+E:SYSTEMD_RFKILL=1
+E:SYSTEMD_WANTS=bluetooth.target
+E:SYSTEMD_WANTS=sound.target
+E:SYSTEMD_WANTS=sys-kernel-config.mount
+E:SYSTEMD_WANTS=systemd-backlight@backlight:intel_backlight.service
+E:SYSTEMD_WANTS=systemd-rfkill.socket
+G:master-of-seat
+G:power-switch
+G:seat
+G:systemd
+G:uaccess
+I:10305698
+I:10395221
+I:10782777
+I:10810535
+I:11197034
+I:11264776
+I:11840274
+I:11863672
+I:11921972
+I:12272821
+I:124311058
+I:124356828
+I:12608364
+I:12651337
+I:12666911
+I:12717449
+I:12737331
+I:12824659
+I:13034589
+I:13446543
+I:16700949
+I:16848532
+I:16854530
+I:16854680
+I:16943840
+I:17041135
+I:17125002
+I:17310738
+I:17346430
+I:17447492
+I:17523623
+I:17918119
+I:17925442
+I:18121723
+I:18140865
+I:18291271
+I:18306009
+I:18313790
+I:18351304
+I:18357657
+I:18398601
+I:18598995
+I:18618482
+I:18712164
+I:18723922
+I:18735577
+I:18740647
+I:18788491
+I:18944489
+I:19057658
+I:19100102
+I:19137360
+I:19562855
+I:19766580
+I:20762981
+I:20781206
+I:20800551
+I:20849301
+I:20875108
+I:20952531
+I:20973791
+I:5594028
+I:6515738
+I:8368250
+I:8459962
+I:8528809
+I:8529967
+I:8586056
+I:8593736
+I:8914299
+I:9003355
+I:9037102
+I:9042481
+I:9057797
+I:9117477
+I:9120365
+I:9208582
+I:9209296
+I:9244279
+I:9250754
+I:9257625
+I:9258871
+I:9317204
+I:9347715
+I:9358092
+I:9380474
+I:9450065
+I:9484613
+I:9495455
+I:9551757
+I:9706931
+I:9749967
+I:9876257
+L:-100
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616-part1
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616-part2
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616-part3
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616-part4
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616-part5
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616-part6
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616-part7
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616-part8
+S:disk/by-id/ata-SAMSUNG_MZNTD256HAGL-00000_S15ZNYAD408616-part9
+S:disk/by-id/wwn-0x500253850002aca7
+S:disk/by-id/wwn-0x500253850002aca7-part1
+S:disk/by-id/wwn-0x500253850002aca7-part2
+S:disk/by-id/wwn-0x500253850002aca7-part3
+S:disk/by-id/wwn-0x500253850002aca7-part4
+S:disk/by-id/wwn-0x500253850002aca7-part5
+S:disk/by-id/wwn-0x500253850002aca7-part6
+S:disk/by-id/wwn-0x500253850002aca7-part7
+S:disk/by-id/wwn-0x500253850002aca7-part8
+S:disk/by-id/wwn-0x500253850002aca7-part9
+S:disk/by-label/回復
+S:disk/by-partlabel/Basic\x20data\x20partition
+S:disk/by-partlabel/EFI\x20System\x20Partition
+S:disk/by-partlabel/Microsoft\x20reserved\x20partition
+S:disk/by-partuuid/1d655759-7350-4d1e-b679-ae54e599c796
+S:disk/by-partuuid/55202025-f2e2-4b92-9b4b-7fa16d804a35
+S:disk/by-partuuid/611ffa59-e1da-4e0c-8b7e-83dd61edf945
+S:disk/by-partuuid/9e241958-b22d-4813-8504-791d45cbf0bc
+S:disk/by-partuuid/9ee3d84f-122d-4d5c-b62b-1006defbcbc1
+S:disk/by-partuuid/a4b0949c-5d61-499b-b336-592ef4e0d423
+S:disk/by-partuuid/b092dc67-d577-4c77-84c4-db681a69a200
+S:disk/by-partuuid/cc77a315-4305-4982-88e6-b52721460ce7
+S:disk/by-partuuid/f17bf199-921b-4cbd-bcbf-15b75ec80b21
+S:disk/by-path/pci-0000:00:1f.2-ata-4
+S:disk/by-path/pci-0000:00:1f.2-ata-4-part1
+S:disk/by-path/pci-0000:00:1f.2-ata-4-part2
+S:disk/by-path/pci-0000:00:1f.2-ata-4-part3
+S:disk/by-path/pci-0000:00:1f.2-ata-4-part4
+S:disk/by-path/pci-0000:00:1f.2-ata-4-part5
+S:disk/by-path/pci-0000:00:1f.2-ata-4-part6
+S:disk/by-path/pci-0000:00:1f.2-ata-4-part7
+S:disk/by-path/pci-0000:00:1f.2-ata-4-part8
+S:disk/by-path/pci-0000:00:1f.2-ata-4-part9
+S:disk/by-uuid/0f12f260-d308-49b4-9a9f-465a749937ce
+S:disk/by-uuid/23451e06-2ec4-4ae0-86b1-36602653dd78
+S:disk/by-uuid/5C1A-DCBA
+S:disk/by-uuid/64A41A20A419F570
+S:disk/by-uuid/9C12322A123209B2
+S:disk/by-uuid/b95e2a35-09fd-493f-9be7-5616eb9ffc19
+S:disk/by-uuid/beeb37c6-d4e2-494f-b329-3eb27452e469
+S:disk/by-uuid/D60878D80878B8D7
+S:dri/by-path/pci-0000:00:02.0-card
+S:dri/by-path/pci-0000:00:02.0-render
+S:input/by-id/usb-Chicony_Electronics_Co._Ltd._USB_2.0_Camera_0x0001-event-if00
+S:input/by-path/acpi-SNY5001:00-event-joystick
+S:input/by-path/acpi-SNY5001:00-event-mouse
+S:input/by-path/acpi-SNY5001:00-mouse
+S:input/by-path/pci-0000:00:14.0-usb-0:5:1.0-event
+S:input/by-path/platform-i8042-serio-0-event-kbd
+S:input/by-path/platform-i8042-serio-1-event-mouse
+S:input/by-path/platform-i8042-serio-1-mouse
+S:rtc
+S:snd/by-path/pci-0000:00:03.0
+S:snd/by-path/pci-0000:00:1b.0
+S:v4l/by-id/usb-Chicony_Electronics_Co._Ltd._USB_2.0_Camera_0x0001-video-index0
+S:v4l/by-id/usb-Chicony_Electronics_Co._Ltd._USB_2.0_Camera_0x0001-video-index1
+S:v4l/by-path/pci-0000:00:14.0-usb-0:5:1.0-video-index0
+S:v4l/by-path/pci-0000:00:14.0-usb-0:5:1.0-video-index1
+W:1
+W:10
+W:2
+W:3
+W:4
+W:5
+W:6
+W:7
+W:8
+W:9
index 4d7526f..86e5918 100644 (file)
@@ -409,7 +409,7 @@ From=
 FwMark=
 GVRP=
 Gateway=
-GatewayOnlink=
+GatewayOnLink=
 GenericReceiveOffload=
 GenericSegmentationOffload=
 GratuitousARP=
@@ -851,6 +851,7 @@ ReserveVT=
 RestrictAddressFamilies=
 RestrictNamespaces=
 RestrictRealtime=
+RestrictSUIDSGID=
 RuntimeDirectory=
 RuntimeDirectoryMode=
 RuntimeDirectoryPreserve=
diff --git a/test/fuzz/fuzz-unit-file/oss-fuzz-13125 b/test/fuzz/fuzz-unit-file/oss-fuzz-13125
new file mode 100644 (file)
index 0000000..b671e11
--- /dev/null
@@ -0,0 +1,10 @@
+timer
+                   .                                                                     
+[Timer]
+OnCalendar=                                                                                                                                              CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%%H%H%CCH%L%H%L%H%H%L%H%H%H%H%C%L%HrH%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CL%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%%%H%HHH%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%HL%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%HeH%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%%H%%H%CLH%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%HH%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H.[ H/var/lH%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%HH%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H;C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%HeH%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%HH%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CLANG=C.%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%HeH%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%LH%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%%H%%H%CLH%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%HH%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H;C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%HeH%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%H%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%HeH%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%HeH%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%HeH%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%HH%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH󠁪%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%HeH%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%L%H%H%C%H%H%CH%L%H%L%HH%E%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H4,40,04,4..0,04,04,0,4..0,0,04,4,40,04,4..0,04,04,0,4..0,0,04,4,40,30,04,4..0,0,04,8,40,04,4..0=|w=s utc
+[Timer]
+OnCalendar=Wed utc
+
+OnCalendar=s%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%H%CH%L%H%L%HH%H%C%H%H%H%H%C%H%H%CH%S%H%L%H%H%L%H%H%H%H%C%L%H%H%H%H%H%H%C%H%H%CH%L%H%L%H%H%L%H%H%H%H%C%L%H%H%C%H%w=s utc
+[Timer]
+OnCHalend%CH%L%H%L%HH%H%ar0,4C%H.
\ No newline at end of file
index 448f062..70b627c 100644 (file)
@@ -15,6 +15,14 @@ Documentation=https://www.freedesktop.org/wiki/Software/systemd/machined
 Wants=machine.slice
 After=machine.slice
 RequiresMountsFor=/var/lib/machines
+ConditionNull=true
+ConditionNull=
+ConditionNull=|!false
+OnFailureIsolate=false
+FailureActionExitStatus=222
+FailureActionExitStatus=
+SuccessActionExitStatus=0
+SuccessActionExitStatus=
 
 [Service]
 ExecStart=/usr/lib/systemd/systemd-machined
@@ -32,3 +40,13 @@ IPAddressDeny=any
 # Note that machined cannot be placed in a mount namespace, since it
 # needs access to the host's mount namespace in order to implement the
 # "machinectl bind" operation.
+
+SELinuxContext=system_u:system_r:kernel_t:s0
+AppArmorProfile=profile
+SELinuxContext=-system_u:system_r:kernel_t:s22
+AppArmorProfile=-profile
+IODeviceLatencyTargetSec=/dev/sda 25ms
+IODeviceLatencyTargetSec=/dev/sdb 2h
+PIDFile=%t/mypid
+PIDFile=
+DisableControllers=
index daec2ea..c514f57 100644 (file)
@@ -4,7 +4,7 @@ sanitize_address = custom_target(
         'sanitize-address-fuzzers',
         output : 'sanitize-address-fuzzers',
         command : [meson_build_sh,
-                   meson.source_root(),
+                   project_source_root,
                    '@OUTPUT@',
                    'fuzzers',
                    '-Db_lundef=false -Db_sanitize=address',
@@ -16,11 +16,11 @@ sanitizers = [['address', sanitize_address]]
 if git.found()
         out = run_command(
                 git,
-                '--git-dir=@0@/.git'.format(meson.source_root()),
+                '--git-dir=@0@/.git'.format(project_source_root),
                  'ls-files', ':/test/fuzz/*/*')
 else
         out = run_command(
-                'sh', '-c', 'ls @0@/*/*'.format(meson.current_source_dir()))
+                'sh', '-c', 'ls @0@/test/fuzz/*/*'.format(project_source_root))
 endif
 
 fuzz_regression_tests = []
index 8b5bd4a..cd0070a 100644 (file)
@@ -62,6 +62,7 @@ test_data_files = '''
         test-execute/exec-dynamicuser-statedir-migrate-step2.service
         test-execute/exec-dynamicuser-statedir.service
         test-execute/exec-dynamicuser-supplementarygroups.service
+        test-execute/exec-environment-no-substitute.service
         test-execute/exec-environment-empty.service
         test-execute/exec-environment-multiple.service
         test-execute/exec-environment.service
@@ -73,7 +74,7 @@ test_data_files = '''
         test-execute/exec-ignoresigpipe-no.service
         test-execute/exec-ignoresigpipe-yes.service
         test-execute/exec-inaccessiblepaths-mount-propagation.service
-        test-execute/exec-inaccessiblepaths-proc.service
+        test-execute/exec-inaccessiblepaths-sys.service
         test-execute/exec-ioschedulingclass-best-effort.service
         test-execute/exec-ioschedulingclass-idle.service
         test-execute/exec-ioschedulingclass-none.service
@@ -100,6 +101,7 @@ test_data_files = '''
         test-execute/exec-privatenetwork-yes.service
         test-execute/exec-privatetmp-no.service
         test-execute/exec-privatetmp-yes.service
+        test-execute/exec-protecthome-tmpfs-vs-protectsystem-strict.service
         test-execute/exec-protectkernelmodules-no-capabilities.service
         test-execute/exec-protectkernelmodules-yes-capabilities.service
         test-execute/exec-protectkernelmodules-yes-mount-propagation.service
index 7011abc..8b1aeed 100755 (executable)
@@ -29,6 +29,7 @@ import time
 import unittest
 
 HAVE_DNSMASQ = shutil.which('dnsmasq') is not None
+IS_CONTAINER = subprocess.call(['systemd-detect-virt', '--quiet', '--container']) == 0
 
 NETWORK_UNITDIR = '/run/systemd/network'
 
@@ -282,11 +283,11 @@ class ClientTestBase(NetworkdTestingUtilities):
         klass.orig_log_level = subprocess.check_output(
             ['systemctl', 'show', '--value', '--property', 'LogLevel'],
             universal_newlines=True).strip()
-        subprocess.check_call(['systemd-analyze', 'set-log-level', 'debug'])
+        subprocess.check_call(['systemd-analyze', 'log-level', 'debug'])
 
     @classmethod
     def tearDownClass(klass):
-        subprocess.check_call(['systemd-analyze', 'set-log-level', klass.orig_log_level])
+        subprocess.check_call(['systemd-analyze', 'log-level', klass.orig_log_level])
 
     def setUp(self):
         self.iface = 'test_eth42'
@@ -335,13 +336,16 @@ class ClientTestBase(NetworkdTestingUtilities):
 
         raise NotImplementedError('must be implemented by a subclass')
 
-    def do_test(self, coldplug=True, ipv6=False, extra_opts='',
-                online_timeout=10, dhcp_mode='yes'):
+    def start_unit(self, unit):
         try:
-            subprocess.check_call(['systemctl', 'start', 'systemd-resolved'])
+            subprocess.check_call(['systemctl', 'start', unit])
         except subprocess.CalledProcessError:
-            self.show_journal('systemd-resolved.service')
+            self.show_journal(unit)
             raise
+
+    def do_test(self, coldplug=True, ipv6=False, extra_opts='',
+                online_timeout=10, dhcp_mode='yes'):
+        self.start_unit('systemd-resolved')
         self.write_network(self.config, '''\
 [Match]
 Name={}
@@ -352,14 +356,14 @@ DHCP={}
         if coldplug:
             # create interface first, then start networkd
             self.create_iface(ipv6=ipv6)
-            subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+            self.start_unit('systemd-networkd')
         elif coldplug is not None:
             # start networkd first, then create interface
-            subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+            self.start_unit('systemd-networkd')
             self.create_iface(ipv6=ipv6)
         else:
             # "None" means test sets up interface by itself
-            subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+            self.start_unit('systemd-networkd')
 
         try:
             subprocess.check_call([NETWORKD_WAIT_ONLINE, '--interface',
@@ -472,12 +476,19 @@ MACAddress=12:34:56:78:9a:bc''')
 [Match]
 Name=dummy0
 [Network]
-Address=192.168.42.100
+Address=192.168.42.100/24
 DNS=192.168.42.1
 Domains= ~company''')
 
-        self.do_test(coldplug=True, ipv6=False,
-                     extra_opts='IPv6AcceptRouterAdvertisements=False')
+        try:
+            self.do_test(coldplug=True, ipv6=False,
+                         extra_opts='IPv6AcceptRouterAdvertisements=False')
+        except subprocess.CalledProcessError as e:
+            # networkd often fails to start in LXC: https://github.com/systemd/systemd/issues/11848
+            if IS_CONTAINER and e.cmd == ['systemctl', 'start', 'systemd-networkd']:
+                raise unittest.SkipTest('https://github.com/systemd/systemd/issues/11848')
+            else:
+                raise
 
         with open(RESOLV_CONF) as f:
             contents = f.read()
@@ -496,12 +507,19 @@ MACAddress=12:34:56:78:9a:bc''')
         self.write_network('myvpn.network', '''[Match]
 Name=dummy0
 [Network]
-Address=192.168.42.100
+Address=192.168.42.100/24
 DNS=192.168.42.1
 Domains= ~company ~.''')
 
-        self.do_test(coldplug=True, ipv6=False,
-                     extra_opts='IPv6AcceptRouterAdvertisements=False')
+        try:
+            self.do_test(coldplug=True, ipv6=False,
+                         extra_opts='IPv6AcceptRouterAdvertisements=False')
+        except subprocess.CalledProcessError as e:
+            # networkd often fails to start in LXC: https://github.com/systemd/systemd/issues/11848
+            if IS_CONTAINER and e.cmd == ['systemctl', 'start', 'systemd-networkd']:
+                raise unittest.SkipTest('https://github.com/systemd/systemd/issues/11848')
+            else:
+                raise
 
         with open(RESOLV_CONF) as f:
             contents = f.read()
@@ -575,6 +593,13 @@ class DnsmasqClientTest(ClientTestBase, unittest.TestCase):
     def test_resolved_domain_restricted_dns(self):
         '''resolved: domain-restricted DNS servers'''
 
+        # FIXME: resolvectl query fails with enabled DNSSEC against our dnsmasq
+        conf = '/run/systemd/resolved.conf.d/test-disable-dnssec.conf'
+        os.makedirs(os.path.dirname(conf), exist_ok=True)
+        with open(conf, 'w') as f:
+            f.write('[Resolve]\nDNSSEC=no\n')
+        self.addCleanup(os.remove, conf)
+
         # create interface for generic connections; this will map all DNS names
         # to 192.168.42.1
         self.create_iface(dnsmasq_opts=['--address=/#/192.168.42.1'])
@@ -611,7 +636,7 @@ Address=10.241.3.2/24
 DNS=10.241.3.1
 Domains= ~company ~lab''')
 
-        subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+        self.start_unit('systemd-networkd')
         subprocess.check_call([NETWORKD_WAIT_ONLINE, '--interface', self.iface,
                                '--interface=testvpnclient', '--timeout=20'])
 
@@ -648,52 +673,52 @@ Domains= ~company ~lab''')
         '''resolved queries to /etc/hosts'''
 
         # FIXME: -t MX query fails with enabled DNSSEC (even when using
-        # the known negative trust anchor .internal instead of .example)
+        # the known negative trust anchor .internal instead of .example.com)
         conf = '/run/systemd/resolved.conf.d/test-disable-dnssec.conf'
         os.makedirs(os.path.dirname(conf), exist_ok=True)
         with open(conf, 'w') as f:
             f.write('[Resolve]\nDNSSEC=no\nLLMNR=no\nMulticastDNS=no\n')
         self.addCleanup(os.remove, conf)
 
-        # create /etc/hosts bind mount which resolves my.example for IPv4
+        # create /etc/hosts bind mount which resolves my.example.com for IPv4
         hosts = os.path.join(self.workdir, 'hosts')
         with open(hosts, 'w') as f:
-            f.write('172.16.99.99  my.example\n')
+            f.write('172.16.99.99  my.example.com\n')
         subprocess.check_call(['mount', '--bind', hosts, '/etc/hosts'])
         self.addCleanup(subprocess.call, ['umount', '/etc/hosts'])
         subprocess.check_call(['systemctl', 'stop', 'systemd-resolved.service'])
 
         # note: different IPv4 address here, so that it's easy to tell apart
         # what resolved the query
-        self.create_iface(dnsmasq_opts=['--host-record=my.example,172.16.99.1,2600::99:99',
-                                        '--host-record=other.example,172.16.0.42,2600::42',
-                                        '--mx-host=example,mail.example'],
+        self.create_iface(dnsmasq_opts=['--host-record=my.example.com,172.16.99.1,2600::99:99',
+                                        '--host-record=other.example.com,172.16.0.42,2600::42',
+                                        '--mx-host=example.com,mail.example.com'],
                           ipv6=True)
         self.do_test(coldplug=None, ipv6=True)
 
         try:
             # family specific queries
-            out = subprocess.check_output(['resolvectl', 'query', '-4', 'my.example'])
-            self.assertIn(b'my.example: 172.16.99.99', out)
+            out = subprocess.check_output(['resolvectl', 'query', '-4', 'my.example.com'])
+            self.assertIn(b'my.example.com: 172.16.99.99', out)
             # we don't expect an IPv6 answer; if /etc/hosts has any IP address,
             # it's considered a sufficient source
-            self.assertNotEqual(subprocess.call(['resolvectl', 'query', '-6', 'my.example']), 0)
+            self.assertNotEqual(subprocess.call(['resolvectl', 'query', '-6', 'my.example.com']), 0)
             # "any family" query; IPv4 should come from /etc/hosts
-            out = subprocess.check_output(['resolvectl', 'query', 'my.example'])
-            self.assertIn(b'my.example: 172.16.99.99', out)
+            out = subprocess.check_output(['resolvectl', 'query', 'my.example.com'])
+            self.assertIn(b'my.example.com: 172.16.99.99', out)
             # IP → name lookup; again, takes the /etc/hosts one
             out = subprocess.check_output(['resolvectl', 'query', '172.16.99.99'])
-            self.assertIn(b'172.16.99.99: my.example', out)
+            self.assertIn(b'172.16.99.99: my.example.com', out)
 
             # non-address RRs should fall back to DNS
-            out = subprocess.check_output(['resolvectl', 'query', '--type=MX', 'example'])
-            self.assertIn(b'example IN MX 1 mail.example', out)
+            out = subprocess.check_output(['resolvectl', 'query', '--type=MX', 'example.com'])
+            self.assertIn(b'example.com IN MX 1 mail.example.com', out)
 
             # other domains query DNS
-            out = subprocess.check_output(['resolvectl', 'query', 'other.example'])
+            out = subprocess.check_output(['resolvectl', 'query', 'other.example.com'])
             self.assertIn(b'172.16.0.42', out)
             out = subprocess.check_output(['resolvectl', 'query', '172.16.0.42'])
-            self.assertIn(b'172.16.0.42: other.example', out)
+            self.assertIn(b'172.16.0.42: other.example.com', out)
         except (AssertionError, subprocess.CalledProcessError):
             self.show_journal('systemd-resolved.service')
             self.print_server_log()
@@ -877,11 +902,11 @@ MACAddress=12:34:56:78:9a:bc''')
 [Match]
 Name=dummy0
 [Network]
-Address=192.168.42.100
+Address=192.168.42.100/24
 DNS=192.168.42.1
 Domains= one two three four five six seven eight nine ten''')
 
-        subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+        self.start_unit('systemd-networkd')
 
         for timeout in range(50):
             with open(RESOLV_CONF) as f:
@@ -909,11 +934,11 @@ MACAddress=12:34:56:78:9a:bc''')
 [Match]
 Name=dummy0
 [Network]
-Address=192.168.42.100
+Address=192.168.42.100/24
 DNS=192.168.42.1
 Domains={p}0 {p}1 {p}2 {p}3 {p}4'''.format(p=name_prefix))
 
-        subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+        self.start_unit('systemd-networkd')
 
         for timeout in range(50):
             with open(RESOLV_CONF) as f:
@@ -937,18 +962,19 @@ MACAddress=12:34:56:78:9a:bc''')
 [Match]
 Name=dummy0
 [Network]
-Address=192.168.42.100
+Address=192.168.42.100/24
 DNS=192.168.42.1''')
         self.write_network_dropin('test.network', 'dns', '''\
 [Network]
 DNS=127.0.0.1''')
 
-        subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
+        self.start_unit('systemd-resolved')
+        self.start_unit('systemd-networkd')
 
         for timeout in range(50):
             with open(RESOLV_CONF) as f:
                 contents = f.read()
-            if ' 127.0.0.1' in contents:
+            if ' 127.0.0.1' in contents and '192.168.42.1' in contents:
                 break
             time.sleep(0.1)
         self.assertIn('nameserver 192.168.42.1\n', contents)
diff --git a/test/test-execute/exec-environment-no-substitute.service b/test/test-execute/exec-environment-no-substitute.service
new file mode 100644 (file)
index 0000000..6a2e60e
--- /dev/null
@@ -0,0 +1,8 @@
+[Unit]
+Description=Test for No Environment Variable Substitution
+
+[Service]
+ExecStart=/bin/sh -x -c 'test "$${VAR1-unset}" = "unset" && test "$${VAR2}" = "word3" && test "$${VAR3-unset}" = \'$word 5 6\''
+ExecStart=:/bin/sh -x -c 'test "$${VAR1-unset}" != "unset" && test "$${VAR2}" != "word3" && test "$${VAR3-unset}" != \'$word 5 6\''
+Type=oneshot
+Environment="VAR2=word3" "VAR3=$word 5 6"
@@ -2,6 +2,6 @@
 Description=Test to make sure that mount namespace setup works properly with the 'InaccessiblePaths=/proc' option
 
 [Service]
-InaccessiblePaths=/proc
-ExecStart=/bin/sh -x -c 'test "$$(stat -c %%a /proc)" = "0"'
+InaccessiblePaths=/sys
+ExecStart=/bin/sh -x -c 'test "$$(stat -c %%a /sys)" = "0"'
 Type=oneshot
diff --git a/test/test-execute/exec-protecthome-tmpfs-vs-protectsystem-strict.service b/test/test-execute/exec-protecthome-tmpfs-vs-protectsystem-strict.service
new file mode 100644 (file)
index 0000000..1522ff8
--- /dev/null
@@ -0,0 +1,9 @@
+[Unit]
+Description=Test ProtectHome=tmpfs vs ProtectSystem=strict
+# Test for #11276
+
+[Service]
+ProtectHome=tmpfs
+ProtectSystem=strict
+Type=oneshot
+ExecStart=/bin/sh -x -c 'test "$$(stat -fc %%T /home)" = "tmpfs"'
index f1afc14..6258a62 100644 (file)
@@ -24,8 +24,8 @@ fi
 
 PATH_TO_INIT=$ROOTLIBDIR/systemd
 
-BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs"
-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"
+BASICTOOLS="test sh bash setsid loadkeys setfont login sulogin gzip sleep echo head tail cat mount umount cryptsetup date dmsetup modprobe sed cmp tee rm true false chmod chown ln xargs"
+DEBUGTOOLS="df free ls stty ps ln ip route dmesg dhclient mkdir cp ping dhclient strace less grep id tty touch du sort hostname find vi mv"
 
 STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(readlink -f $0)))"
 STATEFILE="$STATEDIR/.testdir"
@@ -60,7 +60,7 @@ function find_qemu_bin() {
     # SUSE and Red Hat call the binary qemu-kvm. Debian and Gentoo call it kvm.
     # Either way, only use this version if we aren't running in KVM, because
     # nested KVM is flaky still.
-    if [ `systemd-detect-virt -v` != kvm ] ; then
+    if [[ $(systemd-detect-virt -v) != kvm && -z $TEST_NO_KVM ]] ; then
         [ "$QEMU_BIN" ] || QEMU_BIN=$(which -a kvm qemu-kvm 2>/dev/null | grep '^/' -m1)
     fi
 
@@ -134,7 +134,16 @@ run_qemu() {
         fi
     fi
 
-    [ "$QEMU_SMP" ]   || QEMU_SMP=1
+    # If QEMU_SMP was not explicitly set, try to determine the value 'dynamically'
+    # i.e. use the number of online CPUs on the host machine. If the nproc utility
+    # is not installed or there's some other error when calling it, fall back
+    # to the original value (QEMU_SMP=1).
+    if ! [ "$QEMU_SMP" ]; then
+        if ! QEMU_SMP=$(nproc); then
+            dwarn "nproc utility is not installed, falling back to QEMU_SMP=1"
+            QEMU_SMP=1
+        fi
+    fi
 
     find_qemu_bin || return 1
 
@@ -152,6 +161,8 @@ run_qemu() {
 
 if [[ "$LOOKS_LIKE_SUSE" ]]; then
     PARAMS+="rd.hostonly=0"
+elif [[ "$LOOKS_LIKE_ARCH" ]]; then
+    PARAMS+="rw"
 else
     PARAMS+="ro"
 fi
@@ -181,7 +192,7 @@ $KERNEL_APPEND \
     fi
 
     # Let's use KVM if it is available, but let's avoid using nested KVM as that is still flaky
-    if [ -c /dev/kvm -a `systemd-detect-virt -v` != kvm ]; then
+    if [[ -c /dev/kvm && $(systemd-detect-virt -v) != kvm && -z $TEST_NO_KVM ]] ; then
         QEMU_OPTIONS="$QEMU_OPTIONS -machine accel=kvm -enable-kvm -cpu host"
     fi
 
@@ -459,7 +470,7 @@ create_empty_image() {
     [ -b "$LOOPDEV" ] || return 1
     echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
     sfdisk "$LOOPDEV" <<EOF
-,$((_size-10))M
+,$((_size-50))M
 ,
 EOF
 
@@ -498,7 +509,7 @@ check_asan_reports() {
                          "dbus-daemon" => undef,
                      );
                  }
-                print $2 if /\s(\S*)\[(\d+)\]:\s*SUMMARY:\s+\w+Sanitizer/ && !exists $services_to_ignore{$1}'
+                 print $2 if /\s(\S*)\[(\d+)\]:\s*SUMMARY:\s+\w+Sanitizer/ && !exists $services_to_ignore{$1}'
         )
         if [[ ! -z "$pids" ]]; then
             ret=$(($ret+1))
@@ -644,6 +655,21 @@ install_basic_tools() {
 
 install_debug_tools() {
     [[ $DEBUGTOOLS ]] && dracut_install $DEBUGTOOLS
+
+    if [[ $INTERACTIVE_DEBUG ]]; then
+        # Set default TERM from vt220 to linux, so at least basic key shortcuts work
+        local _getty_override="$initdir/etc/systemd/system/serial-getty@.service.d"
+        mkdir -p "$_getty_override"
+        echo -e "[Service]\nEnvironment=TERM=linux" > "$_getty_override/default-TERM.conf"
+
+        cat > "$initdir/etc/motd" << EOF
+To adjust the terminal size use:
+    export COLUMNS=xx
+    export LINES=yy
+or
+    stty cols xx rows yy
+EOF
+    fi
 }
 
 install_libnss() {
@@ -663,6 +689,9 @@ install_dbus() {
     else
         inst $ROOTLIBDIR/system/dbus.service
     fi
+    # Newer Fedora versions use dbus-broker by default. Let's install it is available.
+    [ -f /usr/bin/dbus-broker ] && inst /usr/bin/dbus-broker
+    [ -f /usr/bin/dbus-broker-launch ] && inst /usr/bin/dbus-broker-launch
 
     find \
         /etc/dbus-1 /usr/share/dbus-1 -xtype f \
@@ -747,7 +776,8 @@ setup_testsuite() {
 
     mkdir -p $initdir/etc/systemd/system/testsuite.target.wants
     ln -fs $TEST_BASE_DIR/testsuite.service $initdir/etc/systemd/system/testsuite.target.wants/testsuite.service
-    ln -fs $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/testsuite.target.wants/end.service
+    # Don't shutdown the machine after running the test when INTERACTIVE_DEBUG is set
+    [[ -z $INTERACTIVE_DEBUG ]] && ln -fs $TEST_BASE_DIR/end.service $initdir/etc/systemd/system/testsuite.target.wants/end.service
 
     # make the testsuite the default target
     ln -fs testsuite.target $initdir/etc/systemd/system/default.target
@@ -808,8 +838,13 @@ inst_libs() {
 
 import_testdir() {
     [[ -e $STATEFILE ]] && . $STATEFILE
-    if [[ -z "$TESTDIR" ]] || [[ ! -d "$TESTDIR" ]]; then
-        TESTDIR=$(mktemp --tmpdir=/var/tmp -d -t systemd-test.XXXXXX)
+    if [[ ! -d "$TESTDIR" ]]; then
+        if [[ -z "$TESTDIR" ]]; then
+            TESTDIR=$(mktemp --tmpdir=/var/tmp -d -t systemd-test.XXXXXX)
+        else
+            mkdir -p "$TESTDIR"
+        fi
+
         echo "TESTDIR=\"$TESTDIR\"" > $STATEFILE
         export TESTDIR
     fi
diff --git a/test/test-network/conf/11-dummy.network b/test/test-network/conf/11-dummy.network
new file mode 100644 (file)
index 0000000..b117028
--- /dev/null
@@ -0,0 +1,5 @@
+[Match]
+Name=test1
+
+[Network]
+IPv6AcceptRA=no
diff --git a/test/test-network/conf/15-name-conflict-test.netdev b/test/test-network/conf/15-name-conflict-test.netdev
new file mode 100644 (file)
index 0000000..c9d18d7
--- /dev/null
@@ -0,0 +1,4 @@
+[NetDev]
+Name=dropin-test
+Kind=dummy
+MACAddress=00:50:56:c0:00:38
diff --git a/test/test-network/conf/21-vlan-test1.network b/test/test-network/conf/21-vlan-test1.network
new file mode 100644 (file)
index 0000000..afe1deb
--- /dev/null
@@ -0,0 +1,2 @@
+[Match]
+Name=test1
diff --git a/test/test-network/conf/21-vlan-test1.network.d/override.conf b/test/test-network/conf/21-vlan-test1.network.d/override.conf
new file mode 100644 (file)
index 0000000..06307ff
--- /dev/null
@@ -0,0 +1,5 @@
+[Network]
+VLAN=vlan99
+Address=192.168.24.5/24
+Address=192.168.25.5/24
+IPv6AcceptRA=false
index afe1deb..0cd901d 100644 (file)
@@ -1,2 +1,6 @@
 [Match]
-Name=test1
+Name=vlan99
+
+[Network]
+IPv6AcceptRA=false
+Address=192.168.23.5/24
diff --git a/test/test-network/conf/21-vlan.network.d/override.conf b/test/test-network/conf/21-vlan.network.d/override.conf
deleted file mode 100644 (file)
index 363fc90..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-[Network]
-VLAN=vlan99
diff --git a/test/test-network/conf/25-address-preferred-lifetime-zero-ipv6.network b/test/test-network/conf/25-address-preferred-lifetime-zero-ipv6.network
new file mode 100644 (file)
index 0000000..bfb278f
--- /dev/null
@@ -0,0 +1,27 @@
+[Match]
+Name=dummy98
+
+[Network]
+# these lines are ignored
+Address=hogehoge
+Address=foofoo
+
+[Address]
+Address=10.2.3.4/16
+PreferredLifetime=0
+Scope=link
+
+[Address]
+Address=2001:0db8:0:f101::1/64
+
+[Address]
+# this section must be ignored
+Peer=hoge
+Address=10.10.0.1/16
+Label=30
+
+[Address]
+# this section must be ignored
+Label=30
+Peer=hoge
+Address=10.10.0.2/16
diff --git a/test/test-network/conf/25-address-section-miscellaneous.network b/test/test-network/conf/25-address-section-miscellaneous.network
deleted file mode 100644 (file)
index 3a37d03..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Match]
-Name=dummy98
-
-[Address]
-Address=10.2.3.4/16
-PreferredLifetime=0
-Scope=link
-
-[Address]
-Address=2001:0db8:0:f101::1/64
diff --git a/test/test-network/conf/25-address-section.network b/test/test-network/conf/25-address-section.network
deleted file mode 100644 (file)
index 3904953..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-[Match]
-Name=dummy98
-
-[Network]
-IPv6AcceptRA=no
-
-[Address]
-Address=10.2.3.4/16
-Peer=10.2.3.5/16
-Label=32
-
-[Address]
-Address=10.6.7.8/16
-Label=33
-
-[Address]
-Address=2001:db8::20
-Peer=2001:db8::10/128
diff --git a/test/test-network/conf/25-address-static.network b/test/test-network/conf/25-address-static.network
new file mode 100644 (file)
index 0000000..e9780f2
--- /dev/null
@@ -0,0 +1,53 @@
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.1.2.3/16
+Address=10.1.2.4/16
+Address=10.2.2.4/16
+Address=2001:db8:0:f101::15/64
+Address=2001:db8:0:f101::16/64
+Address=2001:db8:0:f102::15/64
+# these lines are ignored
+Address=hogehoge
+Address=foofoo
+
+[Address]
+Address=10.3.2.3/16
+Label=32
+
+[Address]
+Address=10.4.2.3/16
+Peer=10.4.2.4/16
+Label=33
+
+[Address]
+Address=0.0.0.0/24
+Label=34
+
+[Address]
+Address=0.0.0.0/16
+Label=35
+
+[Address]
+# this section must be ignored
+Peer=hoge
+Address=10.10.0.1/16
+Label=30
+
+[Address]
+# this section must be ignored
+Label=30
+Peer=hoge
+Address=10.10.0.2/16
+
+[Address]
+Address=2001:db8:0:f102::16/64
+
+[Address]
+Address=2001:db8:0:f103::20/128
+Peer=2001:db8:0:f103::10/128
+
+[Address]
+Address=::/64
diff --git a/test/test-network/conf/25-bind-carrier.network b/test/test-network/conf/25-bind-carrier.network
new file mode 100644 (file)
index 0000000..cf854d3
--- /dev/null
@@ -0,0 +1,8 @@
+[Match]
+Name=test1
+
+[Network]
+BindCarrier=dummy99 dummy98
+Address=192.168.10.30/24
+Gateway=192.168.10.1
+IPv6AcceptRA=no
diff --git a/test/test-network/conf/25-bridge.network b/test/test-network/conf/25-bridge.network
new file mode 100644 (file)
index 0000000..d2f3463
--- /dev/null
@@ -0,0 +1,5 @@
+[Match]
+Name=bridge99
+
+[Network]
+IPv6AcceptRA=no
diff --git a/test/test-network/conf/25-erspan-tunnel-local-any.netdev b/test/test-network/conf/25-erspan-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..e9eb1c1
--- /dev/null
@@ -0,0 +1,10 @@
+[NetDev]
+Name=erspan98
+Kind=erspan
+
+[Tunnel]
+ERSPANIndex=124
+Local = any
+Remote = 172.16.1.100
+Key=102
+SerializeTunneledPackets=true
index 746b7ac..86935e9 100644 (file)
@@ -1,9 +1,8 @@
 [NetDev]
-Name=erspan-test
+Name=erspan99
 Kind=erspan
 
 [Tunnel]
-Independent=true
 ERSPANIndex=123
 Local = 172.16.1.200
 Remote = 172.16.1.100
diff --git a/test/test-network/conf/25-fou-gre.netdev b/test/test-network/conf/25-fou-gre.netdev
new file mode 100644 (file)
index 0000000..6ace606
--- /dev/null
@@ -0,0 +1,14 @@
+[NetDev]
+Name=gretun96
+Kind=gre
+
+[Tunnel]
+Local=10.65.223.238
+Remote=10.65.223.239
+Key=1.2.5.103
+SerializeTunneledPackets=true
+Independent=true
+
+FooOverUDP=yes
+FOUDestinationPort=55556
+FOUSourcePort=1001
diff --git a/test/test-network/conf/25-fou-gretap.netdev b/test/test-network/conf/25-fou-gretap.netdev
new file mode 100644 (file)
index 0000000..97fbc13
--- /dev/null
@@ -0,0 +1,13 @@
+[NetDev]
+Name=gretap96
+Kind=gretap
+
+[Tunnel]
+Local=10.65.223.238
+Remote=10.65.223.239
+Key=1.2.5.106
+SerializeTunneledPackets=true
+Independent=true
+
+FooOverUDP=yes
+FOUDestinationPort=55556
diff --git a/test/test-network/conf/25-fou-ipip.netdev b/test/test-network/conf/25-fou-ipip.netdev
new file mode 100644 (file)
index 0000000..2f52157
--- /dev/null
@@ -0,0 +1,12 @@
+[NetDev]
+Name=ipiptun96
+Kind=ipip
+MTUBytes=1480
+
+[Tunnel]
+Local=192.168.223.238
+Remote=192.169.224.239
+Independent=true
+
+FooOverUDP=yes
+FOUDestinationPort=55555
diff --git a/test/test-network/conf/25-fou-ipproto-gre.netdev b/test/test-network/conf/25-fou-ipproto-gre.netdev
new file mode 100644 (file)
index 0000000..09ecd9e
--- /dev/null
@@ -0,0 +1,8 @@
+[NetDev]
+Name=fou98
+Kind=fou
+
+[FooOverUDP]
+Encapsulation=FooOverUDP
+Port=55556
+Protocol=GRE
diff --git a/test/test-network/conf/25-fou-ipproto-ipip.netdev b/test/test-network/conf/25-fou-ipproto-ipip.netdev
new file mode 100644 (file)
index 0000000..b00d5ce
--- /dev/null
@@ -0,0 +1,8 @@
+[NetDev]
+Name=fou99
+Kind=fou
+
+[FooOverUDP]
+Encapsulation=FooOverUDP
+Port=55555
+Protocol=ipip
diff --git a/test/test-network/conf/25-fou-sit.netdev b/test/test-network/conf/25-fou-sit.netdev
new file mode 100644 (file)
index 0000000..f1b4f32
--- /dev/null
@@ -0,0 +1,11 @@
+[NetDev]
+Name=sittun96
+Kind=sit
+
+[Tunnel]
+Local=10.65.223.238
+Remote=10.65.223.239
+Independent=true
+
+FooOverUDP=yes
+FOUDestinationPort=55555
diff --git a/test/test-network/conf/25-gre-tunnel-local-any.netdev b/test/test-network/conf/25-gre-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..36bc556
--- /dev/null
@@ -0,0 +1,9 @@
+[NetDev]
+Name=gretun98
+Kind=gre
+
+[Tunnel]
+Local=any
+Remote=10.65.223.239
+Key=104
+SerializeTunneledPackets=false
diff --git a/test/test-network/conf/25-gre-tunnel-remote-any.netdev b/test/test-network/conf/25-gre-tunnel-remote-any.netdev
new file mode 100644 (file)
index 0000000..74c02c9
--- /dev/null
@@ -0,0 +1,9 @@
+[NetDev]
+Name=gretun97
+Kind=gre
+
+[Tunnel]
+Local=10.65.223.238
+Remote=any
+Key=105
+SerializeTunneledPackets=false
index 94d9320..89c7fe1 100644 (file)
@@ -5,3 +5,6 @@ Kind=gre
 [Tunnel]
 Local=10.65.223.238
 Remote=10.65.223.239
+InputKey=1.2.3.103
+OutputKey=1.2.4.103
+SerializeTunneledPackets=true
diff --git a/test/test-network/conf/25-gretap-tunnel-local-any.netdev b/test/test-network/conf/25-gretap-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..17abcf6
--- /dev/null
@@ -0,0 +1,9 @@
+[NetDev]
+Name=gretap98
+Kind=gretap
+
+[Tunnel]
+Local=any
+Remote=10.65.223.239
+Key=107
+SerializeTunneledPackets=true
index 769e765..912daf5 100644 (file)
@@ -5,3 +5,5 @@ Kind=gretap
 [Tunnel]
 Local=10.65.223.238
 Remote=10.65.223.239
+Key=106
+SerializeTunneledPackets=true
diff --git a/test/test-network/conf/25-ip6gre-tunnel-local-any.netdev b/test/test-network/conf/25-ip6gre-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..b3781f0
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=ip6gretun98
+Kind=ip6gre
+
+[Tunnel]
+Local=any
+Remote=2001:473:fece:cafe::5179
diff --git a/test/test-network/conf/25-ip6gre-tunnel-remote-any.netdev b/test/test-network/conf/25-ip6gre-tunnel-remote-any.netdev
new file mode 100644 (file)
index 0000000..828c17f
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=ip6gretun97
+Kind=ip6gre
+
+[Tunnel]
+Local=2a00:ffde:4567:edde::4987
+Remote=any
index b16e0b4..ba7d2bc 100644 (file)
@@ -1,6 +1,6 @@
 [NetDev]
-Name=ip6gretap99
-Kind=ip6gretap
+Name=ip6gretun99
+Kind=ip6gre
 
 [Tunnel]
 Local=2a00:ffde:4567:edde::4987
diff --git a/test/test-network/conf/25-ip6gretap-tunnel-local-any.netdev b/test/test-network/conf/25-ip6gretap-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..7a962e8
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=ip6gretap98
+Kind=ip6gretap
+
+[Tunnel]
+Local=any
+Remote=2001:473:fece:cafe::5179
diff --git a/test/test-network/conf/25-ip6gretap-tunnel.netdev b/test/test-network/conf/25-ip6gretap-tunnel.netdev
new file mode 100644 (file)
index 0000000..b16e0b4
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=ip6gretap99
+Kind=ip6gretap
+
+[Tunnel]
+Local=2a00:ffde:4567:edde::4987
+Remote=2001:473:fece:cafe::5179
diff --git a/test/test-network/conf/25-ip6tnl-tunnel-local-any.netdev b/test/test-network/conf/25-ip6tnl-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..7732eb8
--- /dev/null
@@ -0,0 +1,8 @@
+[NetDev]
+Name=ip6tnl98
+Kind=ip6tnl
+
+[Tunnel]
+Mode=ip6ip6
+Local=any
+Remote=2001:473:fece:cafe::5179
diff --git a/test/test-network/conf/25-ip6tnl-tunnel-remote-any.netdev b/test/test-network/conf/25-ip6tnl-tunnel-remote-any.netdev
new file mode 100644 (file)
index 0000000..0d9d1e9
--- /dev/null
@@ -0,0 +1,8 @@
+[NetDev]
+Name=ip6tnl97
+Kind=ip6tnl
+
+[Tunnel]
+Mode=ip6ip6
+Local=2a00:ffde:4567:edde::4987
+Remote=any
diff --git a/test/test-network/conf/25-ipip-tunnel-local-any.netdev b/test/test-network/conf/25-ipip-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..8fa27e8
--- /dev/null
@@ -0,0 +1,8 @@
+[NetDev]
+Name=ipiptun98
+Kind=ipip
+MTUBytes=1480
+
+[Tunnel]
+Local=any
+Remote=192.169.224.239
diff --git a/test/test-network/conf/25-ipip-tunnel-remote-any.netdev b/test/test-network/conf/25-ipip-tunnel-remote-any.netdev
new file mode 100644 (file)
index 0000000..58d7feb
--- /dev/null
@@ -0,0 +1,8 @@
+[NetDev]
+Name=ipiptun97
+Kind=ipip
+MTUBytes=1480
+
+[Tunnel]
+Local=192.168.223.238
+Remote=any
diff --git a/test/test-network/conf/25-l2tp-dummy.network b/test/test-network/conf/25-l2tp-dummy.network
new file mode 100644 (file)
index 0000000..9f2eb90
--- /dev/null
@@ -0,0 +1,7 @@
+[Match]
+Name=test1
+
+[Network]
+Address=192.168.30.100/24
+IPv6AcceptRA=false
+L2TP=l2tp99
diff --git a/test/test-network/conf/25-l2tp-ip.netdev b/test/test-network/conf/25-l2tp-ip.netdev
new file mode 100644 (file)
index 0000000..ceae25f
--- /dev/null
@@ -0,0 +1,20 @@
+[NetDev]
+Kind=l2tp
+Name=l2tp99
+
+[L2TP]
+TunnelId=10
+PeerTunnelId=12
+Local=static
+Remote=192.168.30.101
+EncapsulationType=ip
+
+[L2TPSession]
+SessionId=25
+PeerSessionId=26
+Name=l2tp-ses3
+
+[L2TPSession]
+SessionId=27
+PeerSessionId=28
+Name=l2tp-ses4
diff --git a/test/test-network/conf/25-l2tp-udp.netdev b/test/test-network/conf/25-l2tp-udp.netdev
new file mode 100644 (file)
index 0000000..84589b0
--- /dev/null
@@ -0,0 +1,25 @@
+[NetDev]
+Kind=l2tp
+Name=l2tp99
+
+[L2TP]
+TunnelId=10
+PeerTunnelId=11
+UDPSourcePort=3000
+UDPDestinationPort=4000
+Local=static
+Remote=192.168.30.101
+EncapsulationType=udp
+UDPCheckSum=true
+UDP6CheckSumRx=true
+UDP6CheckSumTx=true
+
+[L2TPSession]
+SessionId=15
+PeerSessionId=16
+Name=l2tp-ses1
+
+[L2TPSession]
+SessionId=17
+PeerSessionId=18
+Name=l2tp-ses2
diff --git a/test/test-network/conf/25-route-gateway-on-link.network b/test/test-network/conf/25-route-gateway-on-link.network
deleted file mode 100644 (file)
index aa64c25..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-[Match]
-Name=dummy98
-
-[Address]
-Address=149.10.124.58/28
-
-[Route]
-Destination=149.10.124.64
-Scope=link
-
-[Route]
-Gateway=149.10.125.65
-GatewayOnlink=true
diff --git a/test/test-network/conf/25-route-gateway.network b/test/test-network/conf/25-route-gateway.network
deleted file mode 100644 (file)
index 29d07f1..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-# test for issue #5430
-
-[Match]
-Name=dummy98
-
-[Address]
-Address=149.10.124.58/28
-
-[Route]
-Destination=149.10.124.64
-Scope=link
-
-[Route]
-Gateway=149.10.124.64
diff --git a/test/test-network/conf/25-route-reverse-order.network b/test/test-network/conf/25-route-reverse-order.network
deleted file mode 100644 (file)
index d1b47ad..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-[Match]
-Name=dummy98
-
-[Network]
-LinkLocalAddressing=ipv6
-Address=2001:1234:5:8f63::1/128
-IPv6AcceptRA=no
-
-[Route]
-Destination=2001:1234:5:8fff:ff:ff:ff:ff/128
-Scope=link
-
-[Route]
-Destination=::/0
-Gateway=2001:1234:5:8fff:ff:ff:ff:ff
diff --git a/test/test-network/conf/25-route-section.network b/test/test-network/conf/25-route-section.network
deleted file mode 100644 (file)
index c9c7a72..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-[Match]
-Name=dummy98
-
-[Network]
-Address=192.168.0.15/24
-
-[Route]
-Gateway=192.168.0.1
diff --git a/test/test-network/conf/25-route-static.network b/test/test-network/conf/25-route-static.network
new file mode 100644 (file)
index 0000000..50b2ce0
--- /dev/null
@@ -0,0 +1,46 @@
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=2001:1234:5:8f63::1/128
+Address=149.10.124.58/28
+
+[Route]
+Destination=2001:1234:5:8fff:ff:ff:ff:ff/128
+Scope=link
+
+[Route]
+Destination=::/0
+Gateway=2001:1234:5:8fff:ff:ff:ff:ff
+
+[Route]
+Destination=149.10.124.64
+Scope=link
+
+[Route]
+Gateway=149.10.124.64
+
+[Route]
+Gateway=149.10.125.65
+GatewayOnLink=yes
+
+[Route]
+Destination=192.168.1.1
+InitialCongestionWindow=20
+
+[Route]
+Destination=192.168.1.2
+InitialAdvertisedReceiveWindow=30
+
+[Route]
+Type=blackhole
+Destination=202.54.1.2
+
+[Route]
+Type=unreachable
+Destination=202.54.1.3
+
+[Route]
+Type=prohibit
+Destination=202.54.1.4
diff --git a/test/test-network/conf/25-route-tcp-window-settings.network b/test/test-network/conf/25-route-tcp-window-settings.network
deleted file mode 100644 (file)
index e77a721..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[Match]
-Name=test1
-
-[Route]
-Destination=192.168.1.1
-InitialCongestionWindow=20
-
-[Route]
-Destination=192.168.1.2
-InitialAdvertisedReceiveWindow=30
diff --git a/test/test-network/conf/25-route-type.network b/test/test-network/conf/25-route-type.network
deleted file mode 100644 (file)
index 9a10413..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-[Match]
-Name=dummy98
-
-[Route]
-Type=blackhole
-Destination=202.54.1.2
-
-[Route]
-Type=unreachable
-Destination=202.54.1.3
-
-[Route]
-Type=prohibit
-Destination=202.54.1.4
diff --git a/test/test-network/conf/25-sit-tunnel-local-any.netdev b/test/test-network/conf/25-sit-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..20c1a33
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=sittun98
+Kind=sit
+
+[Tunnel]
+Local=any
+Remote=10.65.223.239
diff --git a/test/test-network/conf/25-sit-tunnel-remote-any.netdev b/test/test-network/conf/25-sit-tunnel-remote-any.netdev
new file mode 100644 (file)
index 0000000..ed7b9b7
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=sittun97
+Kind=sit
+
+[Tunnel]
+Local=10.65.223.238
+Remote=any
diff --git a/test/test-network/conf/25-sysctl-disable-ipv6.network b/test/test-network/conf/25-sysctl-disable-ipv6.network
new file mode 100644 (file)
index 0000000..e52078e
--- /dev/null
@@ -0,0 +1,6 @@
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.2.3.4/16
index 2452fb7..68be305 100644 (file)
@@ -8,3 +8,4 @@ IPv6DuplicateAddressDetection=3
 IPv6HopLimit=5
 IPv4ProxyARP=true
 IPv6ProxyNDP=true
+IPv6AcceptRA=no
diff --git a/test/test-network/conf/25-vrf.network b/test/test-network/conf/25-vrf.network
new file mode 100644 (file)
index 0000000..42ce5b1
--- /dev/null
@@ -0,0 +1,2 @@
+[Match]
+Name=vrf99
diff --git a/test/test-network/conf/25-vti-tunnel-local-any.netdev b/test/test-network/conf/25-vti-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..cab3886
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=vtitun98
+Kind=vti
+
+[Tunnel]
+Local=remote
+Remote=10.65.223.239
diff --git a/test/test-network/conf/25-vti-tunnel-remote-any.netdev b/test/test-network/conf/25-vti-tunnel-remote-any.netdev
new file mode 100644 (file)
index 0000000..b8bedff
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=vtitun97
+Kind=vti
+
+[Tunnel]
+Local=10.65.223.238
+Remote=any
diff --git a/test/test-network/conf/25-vti6-tunnel-local-any.netdev b/test/test-network/conf/25-vti6-tunnel-local-any.netdev
new file mode 100644 (file)
index 0000000..c3d05b4
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=vti6tun98
+Kind=vti6
+
+[Tunnel]
+Local=any
+Remote=2001:473:fece:cafe::5179
diff --git a/test/test-network/conf/25-vti6-tunnel-remote-any.netdev b/test/test-network/conf/25-vti6-tunnel-remote-any.netdev
new file mode 100644 (file)
index 0000000..b86c628
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=vti6tun97
+Kind=vti6
+
+[Tunnel]
+Local=2a00:ffde:4567:edde::4987
+Remote=any
index 7f77dc1..61a75e5 100644 (file)
@@ -7,7 +7,9 @@ Description=For issue #11404
 [WireGuard]
 # 51820 is common port for Wireguard, 4500 is IPSec/UDP
 ListenPort=4500
-PrivateKey=CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=
+# The key below should be overridden by PrivateKeyFile=
+PrivateKey=EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=
+PrivateKeyFile=/run/systemd/network/25-wireguard-private-key.txt
 
 # peer 1
 [WireGuardPeer]
diff --git a/test/test-network/conf/25-wireguard-preshared-key.txt b/test/test-network/conf/25-wireguard-preshared-key.txt
new file mode 100644 (file)
index 0000000..021c443
--- /dev/null
@@ -0,0 +1,3 @@
+cPLOy1YUrEI0EM
+  MIycPJmOo0aTu3RZnw8bL5
+        meVD6m0=
diff --git a/test/test-network/conf/25-wireguard-private-key.txt b/test/test-network/conf/25-wireguard-private-key.txt
new file mode 100644 (file)
index 0000000..469acd0
--- /dev/null
@@ -0,0 +1,6 @@
+CJQUtcS9emY2fLY
+   qDlpSZiE/QJyHkP
+          Wr+WHtZ
+
+
+LZ90FU=
diff --git a/test/test-network/conf/25-wireguard.netdev.d/peer.conf b/test/test-network/conf/25-wireguard.netdev.d/peer.conf
new file mode 100644 (file)
index 0000000..f559ea6
--- /dev/null
@@ -0,0 +1,5 @@
+[WireGuardPeer]
+PublicKey=lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=
+AllowedIPs=fdbc:bae2:7871:0500:e1fe:0793:8636:dad1/128
+AllowedIPs=fdbc:bae2:7871:e1fe:0793:8636::/96
+PresharedKeyFile=/run/systemd/network/25-wireguard-preshared-key.txt
diff --git a/test/test-network/conf/25-wireguard.network b/test/test-network/conf/25-wireguard.network
new file mode 100644 (file)
index 0000000..ab30523
--- /dev/null
@@ -0,0 +1,2 @@
+[Match]
+Name=wg99
index 81b372f..1f8c5b5 100644 (file)
@@ -9,4 +9,7 @@ Cost=400
 HairPin = true
 FastLeave = true
 UnicastFlood = true
+MulticastFlood = false
 MulticastToUnicast = true
+NeighborSuppression = true
+Learning = false
diff --git a/test/test-network/conf/bond-slave.network b/test/test-network/conf/bond-slave.network
new file mode 100644 (file)
index 0000000..4eeeae2
--- /dev/null
@@ -0,0 +1,12 @@
+[Match]
+Name=dummy98 test1
+
+[Network]
+Bond=bond99
+
+# Settings below should be ignored
+IPv6AcceptRA=yes
+LinkLocalAddressing=yes
+DHCP=yes
+Address=192.168.25.3/24
+Gateway=192.168.25.1
diff --git a/test/test-network/conf/bond99.network b/test/test-network/conf/bond99.network
new file mode 100644 (file)
index 0000000..c5b417a
--- /dev/null
@@ -0,0 +1,6 @@
+[Match]
+Name=bond99
+
+[Network]
+IPv6AcceptRA=no
+Address=192.168.123.45/24
diff --git a/test/test-network/conf/bridge99-ignore-carrier-loss.network b/test/test-network/conf/bridge99-ignore-carrier-loss.network
new file mode 100644 (file)
index 0000000..d4741d6
--- /dev/null
@@ -0,0 +1,12 @@
+[Match]
+Name=bridge99
+
+[Network]
+Address=192.168.0.15/24
+Gateway=192.168.0.1
+IPv6AcceptRA=no
+IgnoreCarrierLoss=true
+
+[RoutingPolicyRule]
+To=8.8.8.8
+Table=100
index 39e48ce..1a00ec1 100644 (file)
@@ -4,3 +4,4 @@ Name=bridge99
 [Network]
 Address=192.168.0.15/24
 Gateway=192.168.0.1
+IPv6AcceptRA=no
diff --git a/test/test-network/conf/dhcp-client-gateway-onlink-implicit.network b/test/test-network/conf/dhcp-client-gateway-onlink-implicit.network
new file mode 100644 (file)
index 0000000..35aa8e7
--- /dev/null
@@ -0,0 +1,13 @@
+[Match]
+Name=veth99
+
+[Network]
+DHCP=ipv4
+
+[Route]
+Gateway=192.168.0.1
+Destination=10.0.0.0/8
+
+[Route]
+Gateway=192.168.0.1
+Destination=192.168.100.0/24
index 5c4ca22..ebe3b7c 100644 (file)
@@ -13,3 +13,4 @@ UseHostname=true
 Hostname=test-hostname
 ClientIdentifier=mac
 VendorClassIdentifier=SusantVendorTest
+RouteTable=211
diff --git a/test/test-network/conf/dhcp-client-vrf.network b/test/test-network/conf/dhcp-client-vrf.network
new file mode 100644 (file)
index 0000000..bb1d2e0
--- /dev/null
@@ -0,0 +1,8 @@
+[Match]
+Name=veth99
+
+[Network]
+DHCP=yes
+IPv6AcceptRA=yes
+LinkLocalAddressing=yes
+VRF=vrf99
index 9e49691..439258a 100644 (file)
@@ -3,6 +3,7 @@ Name=veth-peer
 
 [Network]
 Address=192.168.5.1/24
+IPv6AcceptRA=false
 DHCPServer=yes
 
 [DHCPServer]
diff --git a/test/test-network/conf/erspan.network b/test/test-network/conf/erspan.network
new file mode 100644 (file)
index 0000000..49364c5
--- /dev/null
@@ -0,0 +1,6 @@
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=erspan99
+Tunnel=erspan98
index 88b9250..1493fcf 100644 (file)
@@ -3,3 +3,4 @@ Name=dummy98
 
 [Network]
 Tunnel=gretap99
+Tunnel=gretap98
index 376074c..00bb03c 100644 (file)
@@ -3,3 +3,5 @@ Name=dummy98
 
 [Network]
 Tunnel=gretun99
+Tunnel=gretun98
+Tunnel=gretun97
index cad0bae..7ae4e3a 100644 (file)
@@ -3,3 +3,4 @@ Name=dummy98
 
 [Network]
 Tunnel=ip6gretap99
+Tunnel=ip6gretap98
diff --git a/test/test-network/conf/ip6gretun.network b/test/test-network/conf/ip6gretun.network
new file mode 100644 (file)
index 0000000..6d39bbd
--- /dev/null
@@ -0,0 +1,7 @@
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=ip6gretun99
+Tunnel=ip6gretun98
+Tunnel=ip6gretun97
index 41e3448..15c6d15 100644 (file)
@@ -3,3 +3,5 @@ Name=dummy98
 
 [Network]
 Tunnel=ip6tnl99
+Tunnel=ip6tnl98
+Tunnel=ip6tnl97
index 4ce6714..ec6c958 100644 (file)
@@ -3,3 +3,5 @@ Name=dummy98
 
 [Network]
 Tunnel=ipiptun99
+Tunnel=ipiptun98
+Tunnel=ipiptun97
diff --git a/test/test-network/conf/routing-policy-rule-dummy98.network b/test/test-network/conf/routing-policy-rule-dummy98.network
new file mode 100644 (file)
index 0000000..8136c20
--- /dev/null
@@ -0,0 +1,10 @@
+[Match]
+Name=dummy98
+
+[RoutingPolicyRule]
+TypeOfService=0x08
+Table=8
+From= 192.168.101.18
+Priority=112
+IncomingInterface=dummy98
+OutgoingInterface=dummy98
index 84e5af0..8d97823 100644 (file)
@@ -3,3 +3,5 @@ Name=dummy98
 
 [Network]
 Tunnel=sittun99
+Tunnel=sittun98
+Tunnel=sittun97
diff --git a/test/test-network/conf/test-static.network b/test/test-network/conf/test-static.network
deleted file mode 100644 (file)
index 636c55c..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-[Match]
-Name=dummy98
-
-[Network]
-Address=192.168.0.15/24
-Gateway=192.168.0.1
diff --git a/test/test-network/conf/vlan6.netdev b/test/test-network/conf/vlan6.netdev
new file mode 100644 (file)
index 0000000..310be91
--- /dev/null
@@ -0,0 +1,7 @@
+[NetDev]
+Name=vlan6
+Kind=vlan
+MTUBytes=1500
+
+[VLAN]
+Id=6
diff --git a/test/test-network/conf/vlan6.network b/test/test-network/conf/vlan6.network
new file mode 100644 (file)
index 0000000..64e9db5
--- /dev/null
@@ -0,0 +1,6 @@
+[Match]
+Name=vlan6
+
+[Network]
+IPv6AcceptRA=false
+Address=100.100.100.2/24
index 7fbad6a..1e0b840 100644 (file)
@@ -3,3 +3,5 @@ Name=dummy98
 
 [Network]
 Tunnel=vtitun99
+Tunnel=vtitun98
+Tunnel=vtitun97
index 49a9d11..60ccb77 100644 (file)
@@ -3,3 +3,5 @@ Name=dummy98
 
 [Network]
 Tunnel=vti6tun99
+Tunnel=vti6tun98
+Tunnel=vti6tun97
index 1fc7094..b44cfe8 100755 (executable)
@@ -22,6 +22,8 @@ network_sysctl_ipv4_path='/proc/sys/net/ipv4/conf'
 dnsmasq_pid_file='/run/networkd-ci/test-test-dnsmasq.pid'
 dnsmasq_log_file='/run/networkd-ci/test-dnsmasq-log-file'
 
+wait_online_bin='/usr/lib/systemd/systemd-networkd-wait-online'
+
 def is_module_available(module_name):
     lsmod_output = subprocess.check_output('lsmod', universal_newlines=True)
     module_re = re.compile(r'^{0}\b'.format(re.escape(module_name)), re.MULTILINE)
@@ -69,7 +71,6 @@ def expectedFailureIfRoutingPolicyIPProtoIsNotAvailable():
     return f
 
 def setUpModule():
-
     os.makedirs(network_unit_file_path, exist_ok=True)
     os.makedirs(networkd_ci_path, exist_ok=True)
 
@@ -86,8 +87,6 @@ def tearDownModule():
     subprocess.check_call('systemctl start systemd-networkd.service', shell=True)
 
 class Utilities():
-    dhcp_server_data = []
-
     def read_link_attr(self, link, dev, attribute):
         with open(os.path.join(os.path.join(os.path.join('/sys/class/net/', link), dev), attribute)) as f:
             return f.readline().strip()
@@ -110,6 +109,14 @@ class Utilities():
                 subprocess.call(['ip', 'link', 'del', 'dev', link])
         time.sleep(1)
 
+    def l2tp_tunnel_remove(self, tunnel_ids):
+        output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel']).rstrip().decode('utf-8')
+        for tid in tunnel_ids:
+            words='Tunnel ' + tid + ', encap'
+            if words in output:
+                subprocess.call(['ip', 'l2tp', 'del', 'tunnel', 'tid', tid])
+        time.sleep(1)
+
     def read_ipv6_sysctl_attr(self, link, attribute):
         with open(os.path.join(os.path.join(network_sysctl_ipv6_path, link), attribute)) as f:
             return f.readline().strip()
@@ -119,6 +126,7 @@ class Utilities():
             return f.readline().strip()
 
     def copy_unit_to_networkd_unit_path(self, *units):
+        print()
         for unit in units:
             shutil.copy(os.path.join(networkd_ci_path, unit), network_unit_file_path)
             if (os.path.exists(os.path.join(networkd_ci_path, unit + '.d'))):
@@ -166,15 +174,22 @@ class Utilities():
         if os.path.exists(dnsmasq_log_file):
             os.remove(dnsmasq_log_file)
 
-    def start_networkd(self):
-        if (os.path.exists(os.path.join(networkd_runtime_directory, 'state'))):
+    def start_networkd(self, sleep_sec=5, remove_state_files=True):
+        if (remove_state_files and
+            os.path.exists(os.path.join(networkd_runtime_directory, 'state'))):
             subprocess.check_call('systemctl stop systemd-networkd', shell=True)
             os.remove(os.path.join(networkd_runtime_directory, 'state'))
             subprocess.check_call('systemctl start systemd-networkd', shell=True)
         else:
             subprocess.check_call('systemctl restart systemd-networkd', shell=True)
-        time.sleep(5)
-        print()
+        if sleep_sec > 0:
+            time.sleep(sleep_sec)
+
+    def wait_online(self, links_with_operstate, timeout='20s', bool_any=False):
+        args = [wait_online_bin, f'--timeout={timeout}'] + [f'--interface={link}' for link in links_with_operstate]
+        if bool_any:
+            args += ['--any']
+        subprocess.check_call(args)
 
 class NetworkdNetDevTests(unittest.TestCase, Utilities):
 
@@ -184,17 +199,35 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         'bridge99',
         'dropin-test',
         'dummy98',
-        'erspan-test',
+        'erspan98',
+        'erspan99',
         'geneve99',
+        'gretap96',
+        'gretap98',
         'gretap99',
+        'gretun96',
+        'gretun97',
+        'gretun98',
         'gretun99',
+        'ip6gretap98',
         'ip6gretap99',
+        'ip6gretun97',
+        'ip6gretun98',
+        'ip6gretun99',
+        'ip6tnl97',
+        'ip6tnl98',
         'ip6tnl99',
+        'ipiptun96',
+        'ipiptun97',
+        'ipiptun98',
         'ipiptun99',
         'ipvlan99',
         'isataptun99',
         'macvlan99',
         'macvtap99',
+        'sittun96',
+        'sittun97',
+        'sittun98',
         'sittun99',
         'tap99',
         'test1',
@@ -203,7 +236,11 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         'veth99',
         'vlan99',
         'vrf99',
+        'vti6tun97',
+        'vti6tun98',
         'vti6tun99',
+        'vtitun97',
+        'vtitun98',
         'vtitun99',
         'vxlan99',
         'wg98',
@@ -212,42 +249,75 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
     units = [
         '10-dropin-test.netdev',
         '11-dummy.netdev',
+        '11-dummy.network',
         '12-dummy.netdev',
+        '15-name-conflict-test.netdev',
         '21-macvlan.netdev',
         '21-macvtap.netdev',
+        '21-vlan-test1.network',
         '21-vlan.netdev',
         '21-vlan.network',
         '25-6rd-tunnel.netdev',
         '25-bond.netdev',
         '25-bond-balanced-tlb.netdev',
         '25-bridge.netdev',
+        '25-bridge.network',
+        '25-erspan-tunnel-local-any.netdev',
         '25-erspan-tunnel.netdev',
+        '25-fou-gretap.netdev',
+        '25-fou-gre.netdev',
+        '25-fou-ipip.netdev',
+        '25-fou-ipproto-gre.netdev',
+        '25-fou-ipproto-ipip.netdev',
+        '25-fou-sit.netdev',
         '25-geneve.netdev',
+        '25-gretap-tunnel-local-any.netdev',
         '25-gretap-tunnel.netdev',
+        '25-gre-tunnel-local-any.netdev',
+        '25-gre-tunnel-remote-any.netdev',
         '25-gre-tunnel.netdev',
+        '25-ip6gretap-tunnel-local-any.netdev',
+        '25-ip6gretap-tunnel.netdev',
+        '25-ip6gre-tunnel-local-any.netdev',
+        '25-ip6gre-tunnel-remote-any.netdev',
         '25-ip6gre-tunnel.netdev',
+        '25-ip6tnl-tunnel-remote-any.netdev',
+        '25-ip6tnl-tunnel-local-any.netdev',
         '25-ip6tnl-tunnel.netdev',
         '25-ipip-tunnel-independent.netdev',
+        '25-ipip-tunnel-local-any.netdev',
+        '25-ipip-tunnel-remote-any.netdev',
         '25-ipip-tunnel.netdev',
         '25-ipvlan.netdev',
         '25-isatap-tunnel.netdev',
+        '25-sit-tunnel-local-any.netdev',
+        '25-sit-tunnel-remote-any.netdev',
         '25-sit-tunnel.netdev',
         '25-tap.netdev',
         '25-tun.netdev',
         '25-vcan.netdev',
         '25-veth.netdev',
         '25-vrf.netdev',
+        '25-vti6-tunnel-local-any.netdev',
+        '25-vti6-tunnel-remote-any.netdev',
         '25-vti6-tunnel.netdev',
+        '25-vti-tunnel-local-any.netdev',
+        '25-vti-tunnel-remote-any.netdev',
         '25-vti-tunnel.netdev',
         '25-vxlan.netdev',
         '25-wireguard-23-peers.netdev',
         '25-wireguard-23-peers.network',
+        '25-wireguard-preshared-key.txt',
+        '25-wireguard-private-key.txt',
         '25-wireguard.netdev',
+        '25-wireguard.network',
         '6rd.network',
+        'erspan.network',
         'gre.network',
         'gretap.network',
         'gretun.network',
         'ip6gretap.network',
+        'ip6gretun.network',
         'ip6tnl.network',
         'ipip.network',
         'ipvlan.network',
@@ -267,15 +337,56 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         self.remove_unit_from_networkd_path(self.units)
 
     def test_dropin(self):
-        self.copy_unit_to_networkd_unit_path('10-dropin-test.netdev')
+        self.copy_unit_to_networkd_unit_path('10-dropin-test.netdev', '15-name-conflict-test.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dropin-test'))
 
+        # This also tests NetDev.Name= conflict and basic networkctl functionalities
+
         output = subprocess.check_output(['ip', 'link', 'show', 'dropin-test']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, '00:50:56:c0:00:28')
 
+        output = subprocess.check_output(['networkctl', 'list']).rstrip().decode('utf-8')
+        self.assertRegex(output, '1 lo ')
+        self.assertRegex(output, 'dropin-test')
+
+        output = subprocess.check_output(['networkctl', 'list', 'dropin-test']).rstrip().decode('utf-8')
+        self.assertNotRegex(output, '1 lo ')
+        self.assertRegex(output, 'dropin-test')
+
+        output = subprocess.check_output(['networkctl', 'list', 'dropin-*']).rstrip().decode('utf-8')
+        self.assertNotRegex(output, '1 lo ')
+        self.assertRegex(output, 'dropin-test')
+
+        output = subprocess.check_output(['networkctl', 'status', 'dropin-*']).rstrip().decode('utf-8')
+        self.assertNotRegex(output, '1: lo ')
+        self.assertRegex(output, 'dropin-test')
+
+        ret = subprocess.run(['ethtool', '--driver', 'dropin-test'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+        print(ret.stdout.rstrip().decode('utf-8'))
+        if ret.returncode == 0 and re.search('driver: dummy', ret.stdout.rstrip().decode('utf-8')) != None:
+            self.assertRegex(output, 'Driver: dummy')
+        else:
+            print('ethtool does not support driver field at least for dummy interfaces, skipping test for Driver field of networkctl.')
+
+    def test_wait_online_any(self):
+        self.copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge.network', '11-dummy.netdev', '11-dummy.network')
+        self.start_networkd(0)
+
+        self.wait_online(['bridge99', 'test1:degraded'], bool_any=True)
+        self.assertTrue(self.link_exits('bridge99'))
+        self.assertTrue(self.link_exits('test1'))
+
+        output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: (?:off|no-carrier) \(configuring\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: degraded \(configured\)')
+
     def test_bridge(self):
         self.copy_unit_to_networkd_unit_path('25-bridge.netdev')
         self.start_networkd()
@@ -319,18 +430,34 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         self.assertEqual('1',             self.read_link_attr('bond99', 'bonding', 'tlb_dynamic_lb'))
 
     def test_vlan(self):
-        self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev', '21-vlan.network')
+        self.copy_unit_to_networkd_unit_path('21-vlan.netdev', '11-dummy.netdev',
+                                             '21-vlan.network', '21-vlan-test1.network')
         self.start_networkd()
 
+        self.assertTrue(self.link_exits('test1'))
         self.assertTrue(self.link_exits('vlan99'))
 
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertTrue(output, ' mtu 2004 ')
+
         output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99']).rstrip().decode('utf-8')
         print(output)
+        self.assertTrue(output, ' mtu 2000 ')
         self.assertTrue(output, 'REORDER_HDR')
         self.assertTrue(output, 'LOOSE_BINDING')
         self.assertTrue(output, 'GVRP')
         self.assertTrue(output, 'MVRP')
-        self.assertTrue(output, '99')
+        self.assertTrue(output, ' id 99 ')
+
+        output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'inet 192.168.24.5/24 brd 192.168.24.255 scope global test1')
+        self.assertRegex(output, 'inet 192.168.25.5/24 brd 192.168.25.255 scope global test1')
+
+        output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'vlan99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'inet 192.168.23.5/24 brd 192.168.23.255 scope global vlan99')
 
     def test_macvtap(self):
         self.copy_unit_to_networkd_unit_path('21-macvtap.netdev', '11-dummy.netdev', 'macvtap.network')
@@ -342,8 +469,17 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         self.copy_unit_to_networkd_unit_path('21-macvlan.netdev', '11-dummy.netdev', 'macvlan.network')
         self.start_networkd()
 
+        self.assertTrue(self.link_exits('test1'))
         self.assertTrue(self.link_exits('macvlan99'))
 
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertTrue(output, ' mtu 2000 ')
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macvlan99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertTrue(output, ' mtu 2000 ')
+
     @expectedFailureIfModuleIsNotAvailable('ipvlan')
     def test_ipvlan(self):
         self.copy_unit_to_networkd_unit_path('25-ipvlan.netdev', '11-dummy.netdev', 'ipvlan.network')
@@ -391,33 +527,37 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
 
     @expectedFailureIfModuleIsNotAvailable('wireguard')
     def test_wireguard(self):
-        self.copy_unit_to_networkd_unit_path('25-wireguard.netdev')
-        self.start_networkd()
+        self.copy_unit_to_networkd_unit_path('25-wireguard.netdev', '25-wireguard.network',
+                                             '25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network',
+                                             '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt')
+        self.start_networkd(0)
+        self.wait_online(['wg99:carrier', 'wg98:routable'])
+
+        self.assertTrue(self.link_exits('wg99'))
+        self.assertTrue(self.link_exits('wg98'))
 
         if shutil.which('wg'):
             subprocess.call('wg')
+
             output = subprocess.check_output(['wg', 'show', 'wg99', 'listen-port']).rstrip().decode('utf-8')
             self.assertTrue(output, '51820')
             output = subprocess.check_output(['wg', 'show', 'wg99', 'fwmark']).rstrip().decode('utf-8')
             self.assertTrue(output, '0x4d2')
             output = subprocess.check_output(['wg', 'show', 'wg99', 'allowed-ips']).rstrip().decode('utf-8')
             self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
+            self.assertTrue(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
             output = subprocess.check_output(['wg', 'show', 'wg99', 'persistent-keepalive']).rstrip().decode('utf-8')
             self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20')
             output = subprocess.check_output(['wg', 'show', 'wg99', 'endpoints']).rstrip().decode('utf-8')
             self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820')
+            output = subprocess.check_output(['wg', 'show', 'wg99', 'private-key']).rstrip().decode('utf-8')
+            self.assertTrue(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=')
+            output = subprocess.check_output(['wg', 'show', 'wg99', 'preshared-keys']).rstrip().decode('utf-8')
+            self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=      IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
+            self.assertTrue(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=      cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
 
-        self.assertTrue(self.link_exits('wg99'))
-
-    @expectedFailureIfModuleIsNotAvailable('wireguard')
-    def test_wireguard_23_peers(self):
-        self.copy_unit_to_networkd_unit_path('25-wireguard-23-peers.netdev', '25-wireguard-23-peers.network')
-        self.start_networkd()
-
-        if shutil.which('wg'):
-            subprocess.call('wg')
-
-        self.assertTrue(self.link_exits('wg98'))
+            output = subprocess.check_output(['wg', 'show', 'wg98', 'private-key']).rstrip().decode('utf-8')
+            self.assertTrue(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=')
 
     def test_geneve(self):
         self.copy_unit_to_networkd_unit_path('25-geneve.netdev')
@@ -433,60 +573,197 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         self.assertTrue(output, 'udp6zerocsumrx')
 
     def test_ipip_tunnel(self):
-        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ipip-tunnel.netdev', 'ipip.network')
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ipip-tunnel.netdev', 'ipip.network',
+                                             '25-ipip-tunnel-local-any.netdev', '25-ipip-tunnel-remote-any.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('ipiptun99'))
+        self.assertTrue(self.link_exits('ipiptun98'))
+        self.assertTrue(self.link_exits('ipiptun97'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local 192.168.223.238 dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ipip (?:ipip |)remote 192.169.224.239 local any dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun97']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ipip (?:ipip |)remote any local 192.168.223.238 dev dummy98')
 
     def test_gre_tunnel(self):
-        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gre-tunnel.netdev', 'gretun.network')
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gre-tunnel.netdev', 'gretun.network',
+                                             '25-gre-tunnel-local-any.netdev', '25-gre-tunnel-remote-any.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('gretun99'))
+        self.assertTrue(self.link_exits('gretun98'))
+        self.assertTrue(self.link_exits('gretun97'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'gre remote 10.65.223.239 local 10.65.223.238 dev dummy98')
+        self.assertRegex(output, 'ikey 1.2.3.103')
+        self.assertRegex(output, 'okey 1.2.4.103')
+        self.assertRegex(output, 'iseq')
+        self.assertRegex(output, 'oseq')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'gre remote 10.65.223.239 local any dev dummy98')
+        self.assertRegex(output, 'ikey 0.0.0.104')
+        self.assertRegex(output, 'okey 0.0.0.104')
+        self.assertNotRegex(output, 'iseq')
+        self.assertNotRegex(output, 'oseq')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun97']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'gre remote any local 10.65.223.238 dev dummy98')
+        self.assertRegex(output, 'ikey 0.0.0.105')
+        self.assertRegex(output, 'okey 0.0.0.105')
+        self.assertNotRegex(output, 'iseq')
+        self.assertNotRegex(output, 'oseq')
+
+    def test_ip6gre_tunnel(self):
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6gre-tunnel.netdev', 'ip6gretun.network',
+                                             '25-ip6gre-tunnel-local-any.netdev', '25-ip6gre-tunnel-remote-any.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('dummy98'))
+        self.assertTrue(self.link_exits('ip6gretun99'))
+        self.assertTrue(self.link_exits('ip6gretun98'))
+        self.assertTrue(self.link_exits('ip6gretun97'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ip6gre remote 2001:473:fece:cafe::5179 local any dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretun97']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ip6gre remote any local 2a00:ffde:4567:edde::4987 dev dummy98')
 
     def test_gretap_tunnel(self):
-        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gretap-tunnel.netdev', 'gretap.network')
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-gretap-tunnel.netdev', 'gretap.network',
+                                             '25-gretap-tunnel-local-any.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('gretap99'))
+        self.assertTrue(self.link_exits('gretap98'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'gretap remote 10.65.223.239 local 10.65.223.238 dev dummy98')
+        self.assertRegex(output, 'ikey 0.0.0.106')
+        self.assertRegex(output, 'okey 0.0.0.106')
+        self.assertRegex(output, 'iseq')
+        self.assertRegex(output, 'oseq')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'gretap remote 10.65.223.239 local any dev dummy98')
+        self.assertRegex(output, 'ikey 0.0.0.107')
+        self.assertRegex(output, 'okey 0.0.0.107')
+        self.assertRegex(output, 'iseq')
+        self.assertRegex(output, 'oseq')
 
     def test_ip6gretap_tunnel(self):
-        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6gre-tunnel.netdev', 'ip6gretap.network')
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6gretap-tunnel.netdev', 'ip6gretap.network',
+                                             '25-ip6gretap-tunnel-local-any.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('ip6gretap99'))
+        self.assertTrue(self.link_exits('ip6gretap98'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretap99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6gretap98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ip6gretap remote 2001:473:fece:cafe::5179 local any dev dummy98')
 
     def test_vti_tunnel(self):
-        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti-tunnel.netdev', 'vti.network')
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti-tunnel.netdev', 'vti.network',
+                                             '25-vti-tunnel-local-any.netdev', '25-vti-tunnel-remote-any.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('vtitun99'))
+        self.assertTrue(self.link_exits('vtitun98'))
+        self.assertTrue(self.link_exits('vtitun97'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'vti remote 10.65.223.239 local 10.65.223.238 dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'vti remote 10.65.223.239 local any dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vtitun97']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'vti remote any local 10.65.223.238 dev dummy98')
 
     def test_vti6_tunnel(self):
-        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti6-tunnel.netdev', 'vti6.network')
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-vti6-tunnel.netdev', 'vti6.network',
+                                             '25-vti6-tunnel-local-any.netdev', '25-vti6-tunnel-remote-any.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('vti6tun99'))
+        self.assertTrue(self.link_exits('vti6tun98'))
+        self.assertTrue(self.link_exits('vti6tun97'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'vti6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vti6tun97']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'vti6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
 
     def test_ip6tnl_tunnel(self):
-        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6tnl-tunnel.netdev', 'ip6tnl.network')
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ip6tnl-tunnel.netdev', 'ip6tnl.network',
+                                             '25-ip6tnl-tunnel-local-any.netdev', '25-ip6tnl-tunnel-remote-any.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('ip6tnl99'))
+        self.assertTrue(self.link_exits('ip6tnl98'))
+        self.assertTrue(self.link_exits('ip6tnl97'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (?:any|::) dev dummy98')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ip6tnl97']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'ip6tnl ip6ip6 remote (?:any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
 
     def test_sit_tunnel(self):
-        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-sit-tunnel.netdev', 'sit.network')
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-sit-tunnel.netdev', 'sit.network',
+                                             '25-sit-tunnel-local-any.netdev',
+                                             '25-sit-tunnel-remote-any.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('sittun99'))
+        self.assertTrue(self.link_exits('sittun98'))
+        self.assertTrue(self.link_exits('sittun97'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local 10.65.223.238 dev dummy98")
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "sit (?:ip6ip |)remote 10.65.223.239 local any dev dummy98")
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun97']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "sit (?:ip6ip |)remote any local 10.65.223.238 dev dummy98")
 
     def test_isatap_tunnel(self):
         self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-isatap-tunnel.netdev', 'isatap.network')
@@ -506,18 +783,35 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         self.assertTrue(self.link_exits('dummy98'))
         self.assertTrue(self.link_exits('sittun99'))
 
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, '6rd-prefix 2602::/24')
+
     @expectedFailureIfERSPANModuleIsNotAvailable()
     def test_erspan_tunnel(self):
-        self.copy_unit_to_networkd_unit_path('25-erspan-tunnel.netdev')
+        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'erspan.network',
+                                             '25-erspan-tunnel.netdev', '25-erspan-tunnel-local-any.netdev')
         self.start_networkd()
 
-        self.assertTrue(self.link_exits('erspan-test'))
+        self.assertTrue(self.link_exits('dummy98'))
+        self.assertTrue(self.link_exits('erspan99'))
+        self.assertTrue(self.link_exits('erspan98'))
 
-        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan-test']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan99']).rstrip().decode('utf-8')
         print(output)
-        self.assertTrue(output, '172.16.1.200')
-        self.assertTrue(output, '172.16.1.100')
-        self.assertTrue(output, '101')
+        self.assertRegex(output, 'erspan remote 172.16.1.100 local 172.16.1.200')
+        self.assertRegex(output, 'ikey 0.0.0.101')
+        self.assertRegex(output, 'okey 0.0.0.101')
+        self.assertRegex(output, 'iseq')
+        self.assertRegex(output, 'oseq')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'erspan98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'erspan remote 172.16.1.100 local any')
+        self.assertRegex(output, '102')
+        self.assertRegex(output, 'ikey 0.0.0.102')
+        self.assertRegex(output, 'okey 0.0.0.102')
+        self.assertRegex(output, 'iseq')
+        self.assertRegex(output, 'oseq')
 
     def test_tunnel_independent(self):
         self.copy_unit_to_networkd_unit_path('25-ipip-tunnel-independent.netdev')
@@ -525,8 +819,45 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
 
         self.assertTrue(self.link_exits('ipiptun99'))
 
+    @expectedFailureIfModuleIsNotAvailable('fou')
+    def test_fou(self):
+        # The following redundant check is necessary for CentOS CI.
+        # Maybe, error handling in lookup_id() in sd-netlink/generic-netlink.c needs to be updated.
+        self.assertTrue(is_module_available('fou'))
+
+        self.copy_unit_to_networkd_unit_path('25-fou-ipproto-ipip.netdev', '25-fou-ipproto-gre.netdev',
+                                             '25-fou-ipip.netdev', '25-fou-sit.netdev',
+                                             '25-fou-gre.netdev', '25-fou-gretap.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('ipiptun96'))
+        self.assertTrue(self.link_exits('sittun96'))
+        self.assertTrue(self.link_exits('gretun96'))
+        self.assertTrue(self.link_exits('gretap96'))
+
+        output = subprocess.check_output(['ip', 'fou', 'show']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'port 55555 ipproto 4')
+        self.assertRegex(output, 'port 55556 ipproto 47')
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'ipiptun96']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'sittun96']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55555')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretun96']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'encap fou encap-sport 1001 encap-dport 55556')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'gretap96']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'encap fou encap-sport auto encap-dport 55556')
+
+        subprocess.call(['ip', 'fou', 'del', 'port', '55555'])
+        subprocess.call(['ip', 'fou', 'del', 'port', '55556'])
+
     def test_vxlan(self):
-        self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network','11-dummy.netdev')
+        self.copy_unit_to_networkd_unit_path('25-vxlan.netdev', 'vxlan.network', '11-dummy.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('vxlan99'))
@@ -544,22 +875,103 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'remcsumrx')
         self.assertRegex(output, 'gbp')
 
+class NetworkdL2TPTests(unittest.TestCase, Utilities):
+
+    links =[
+        'l2tp-ses1',
+        'l2tp-ses2',
+        'l2tp-ses3',
+        'l2tp-ses4',
+        'test1']
+
+    units = [
+        '11-dummy.netdev',
+        '25-l2tp-dummy.network',
+        '25-l2tp-ip.netdev',
+        '25-l2tp-udp.netdev']
+
+    l2tp_tunnel_ids = [ '10' ]
+
+    def setUp(self):
+        self.l2tp_tunnel_remove(self.l2tp_tunnel_ids)
+        self.link_remove(self.links)
+
+    def tearDown(self):
+        self.l2tp_tunnel_remove(self.l2tp_tunnel_ids)
+        self.link_remove(self.links)
+        self.remove_unit_from_networkd_path(self.units)
+
+    @expectedFailureIfModuleIsNotAvailable('l2tp_eth')
+    def test_l2tp_udp(self):
+        self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-udp.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('test1'))
+        self.assertTrue(self.link_exits('l2tp-ses1'))
+        self.assertTrue(self.link_exits('l2tp-ses2'))
+
+        output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel', 'tunnel_id', '10']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "Tunnel 10, encap UDP")
+        self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
+        self.assertRegex(output, "Peer tunnel 11")
+        self.assertRegex(output, "UDP source / dest ports: 3000/4000")
+        self.assertRegex(output, "UDP checksum: enabled")
+
+        output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '15']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "Session 15 in tunnel 10")
+        self.assertRegex(output, "Peer session 16, tunnel 11")
+        self.assertRegex(output, "interface name: l2tp-ses1")
+
+        output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '17']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "Session 17 in tunnel 10")
+        self.assertRegex(output, "Peer session 18, tunnel 11")
+        self.assertRegex(output, "interface name: l2tp-ses2")
+
+    @expectedFailureIfModuleIsNotAvailable('l2tp_ip')
+    def test_l2tp_ip(self):
+        self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '25-l2tp-dummy.network', '25-l2tp-ip.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('test1'))
+        self.assertTrue(self.link_exits('l2tp-ses3'))
+        self.assertTrue(self.link_exits('l2tp-ses4'))
+
+        output = subprocess.check_output(['ip', 'l2tp', 'show', 'tunnel', 'tunnel_id', '10']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "Tunnel 10, encap IP")
+        self.assertRegex(output, "From 192.168.30.100 to 192.168.30.101")
+        self.assertRegex(output, "Peer tunnel 12")
+
+        output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '25']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "Session 25 in tunnel 10")
+        self.assertRegex(output, "Peer session 26, tunnel 12")
+        self.assertRegex(output, "interface name: l2tp-ses3")
+
+        output = subprocess.check_output(['ip', 'l2tp', 'show', 'session', 'tid', '10', 'session_id', '27']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, "Session 27 in tunnel 10")
+        self.assertRegex(output, "Peer session 28, tunnel 12")
+        self.assertRegex(output, "interface name: l2tp-ses4")
+
 class NetworkdNetWorkTests(unittest.TestCase, Utilities):
     links = [
         'bond199',
         'dummy98',
+        'dummy99',
         'test1']
 
     units = [
         '11-dummy.netdev',
         '12-dummy.netdev',
         '23-active-slave.network',
-        '23-bond199.network',
-        '23-primary-slave.network',
-        '23-test1-bond199.network',
         '25-address-link-section.network',
-        '25-address-section-miscellaneous.network',
-        '25-address-section.network',
+        '25-address-preferred-lifetime-zero-ipv6.network',
+        '25-address-static.network',
+        '25-bind-carrier.network',
         '25-bond-active-backup-slave.netdev',
         '25-fibrule-invert.network',
         '25-fibrule-port-range.network',
@@ -568,17 +980,13 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         '25-link-local-addressing-no.network',
         '25-link-local-addressing-yes.network',
         '25-link-section-unmanaged.network',
-        '25-route-gateway.network',
-        '25-route-gateway-on-link.network',
         '25-route-ipv6-src.network',
-        '25-route-reverse-order.network',
-        '25-route-section.network',
-        '25-route-tcp-window-settings.network',
-        '25-route-type.network',
+        '25-route-static.network',
+        '25-sysctl-disable-ipv6.network',
         '25-sysctl.network',
         'configure-without-carrier.network',
-        'routing-policy-rule.network',
-        'test-static.network']
+        'routing-policy-rule-dummy98.network',
+        'routing-policy-rule-test1.network']
 
     def setUp(self):
         self.link_remove(self.links)
@@ -587,54 +995,75 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.link_remove(self.links)
         self.remove_unit_from_networkd_path(self.units)
 
-    def test_static_address(self):
-        self.copy_unit_to_networkd_unit_path('12-dummy.netdev', 'test-static.network')
-        self.start_networkd()
+    def test_address_static(self):
+        self.copy_unit_to_networkd_unit_path('25-address-static.network', '12-dummy.netdev')
+        self.start_networkd(0)
 
-        self.assertTrue(self.link_exits('dummy98'))
+        self.wait_online(['dummy98:routable'])
 
-        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, '192.168.0.15')
-        self.assertRegex(output, '192.168.0.1')
-        self.assertRegex(output, 'routable')
+        self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98')
+        self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98')
+        self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98')
 
-    def test_configure_without_carrier(self):
-        self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
-        self.start_networkd()
+        # invalid sections
+        self.assertNotRegex(output, '10.10.0.1/16')
+        self.assertNotRegex(output, '10.10.0.2/16')
 
-        self.assertTrue(self.link_exits('test1'))
+        output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '32']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32')
 
-        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '33']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33')
+
+        output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '34']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34')
+
+        output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'dummy98', 'label', '35']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35')
+
+        output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, '192.168.0.15')
-        self.assertRegex(output, '192.168.0.1')
-        self.assertRegex(output, 'routable')
+        self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global')
+        self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global')
+        self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global')
+        self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global')
+        self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global')
+        self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global')
 
-    def test_bond_active_slave(self):
-        self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
+    def test_address_preferred_lifetime_zero_ipv6(self):
+        self.copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero-ipv6.network', '12-dummy.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('dummy98'))
-        self.assertTrue(self.link_exits('bond199'))
 
-        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, 'active_slave dummy98')
+        self.assertRegex(output, 'State: routable \(configuring\)')
 
-    def test_bond_primary_slave(self):
-        self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
+        output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
+        self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
+
+    def test_configure_without_carrier(self):
+        self.copy_unit_to_networkd_unit_path('configure-without-carrier.network', '11-dummy.netdev')
         self.start_networkd()
 
         self.assertTrue(self.link_exits('test1'))
-        self.assertTrue(self.link_exits('bond199'))
 
-        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, 'primary test1')
+        self.assertRegex(output, '192.168.0.15')
+        self.assertRegex(output, '192.168.0.1')
+        self.assertRegex(output, 'routable')
 
     def test_routing_policy_rule(self):
-        self.copy_unit_to_networkd_unit_path('routing-policy-rule.network', '11-dummy.netdev')
+        self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '7'])
+
         self.start_networkd()
 
         self.assertTrue(self.link_exits('test1'))
@@ -650,9 +1079,37 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
 
         subprocess.call(['ip', 'rule', 'del', 'table', '7'])
 
+    def test_routing_policy_rule_issue_11280(self):
+        self.copy_unit_to_networkd_unit_path('routing-policy-rule-test1.network', '11-dummy.netdev',
+                                             'routing-policy-rule-dummy98.network', '12-dummy.netdev')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '7'])
+        subprocess.call(['ip', 'rule', 'del', 'table', '8'])
+
+        for trial in range(3):
+            # Remove state files only first time
+            self.start_networkd(remove_state_files=(trial == 0))
+
+            self.assertTrue(self.link_exits('test1'))
+            self.assertTrue(self.link_exits('dummy98'))
+
+            output = subprocess.check_output(['ip', 'rule', 'list', 'table', '7']).rstrip().decode('utf-8')
+            print(output)
+            self.assertRegex(output, '111:     from 192.168.100.18 tos (?:0x08|throughput) iif test1 oif test1 lookup 7')
+
+            output = subprocess.check_output(['ip', 'rule', 'list', 'table', '8']).rstrip().decode('utf-8')
+            print(output)
+            self.assertRegex(output, '112:     from 192.168.101.18 tos (?:0x08|throughput) iif dummy98 oif dummy98 lookup 8')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '7'])
+        subprocess.call(['ip', 'rule', 'del', 'table', '8'])
+
     @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable()
     def test_routing_policy_rule_port_range(self):
         self.copy_unit_to_networkd_unit_path('25-fibrule-port-range.network', '11-dummy.netdev')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '7'])
+
         self.start_networkd()
 
         self.assertTrue(self.link_exits('test1'))
@@ -671,6 +1128,9 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
     @expectedFailureIfRoutingPolicyIPProtoIsNotAvailable()
     def test_routing_policy_rule_invert(self):
         self.copy_unit_to_networkd_unit_path('25-fibrule-invert.network', '11-dummy.netdev')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '7'])
+
         self.start_networkd()
 
         self.assertTrue(self.link_exits('test1'))
@@ -684,128 +1144,47 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
 
         subprocess.call(['ip', 'rule', 'del', 'table', '7'])
 
-    def test_address_peer(self):
-        self.copy_unit_to_networkd_unit_path('25-address-section.network', '12-dummy.netdev')
-        self.start_networkd()
+    def test_route_static(self):
+        self.copy_unit_to_networkd_unit_path('25-route-static.network', '12-dummy.netdev')
+        self.start_networkd(0)
 
-        self.assertTrue(self.link_exits('dummy98'))
+        self.wait_online(['dummy98:routable'])
 
-        output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, 'inet 10.2.3.4 peer 10.2.3.5/16 scope global 32')
-        self.assertRegex(output, 'inet 10.6.7.8/16 brd 10.6.255.255 scope global 33')
-        self.assertRegex(output, 'inet6 2001:db8::20 peer 2001:db8::10/128 scope global')
+        self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static')
+        self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel')
 
-        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
-        print(output)
-        self.assertRegex(output, 'State: routable \(configured\)')
+        output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'default via 2001:1234:5:8fff:ff:ff:ff:ff proto static metric 1024 pref medium')
 
-    def test_address_preferred_lifetime_zero_ipv6(self):
-        self.copy_unit_to_networkd_unit_path('25-address-section-miscellaneous.network', '12-dummy.netdev')
-        self.start_networkd()
-
-        self.assertTrue(self.link_exits('dummy98'))
-
-        output = subprocess.check_output(['ip', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98')
-        self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global')
-
-    def test_ip_route(self):
-        self.copy_unit_to_networkd_unit_path('25-route-section.network', '12-dummy.netdev')
-        self.start_networkd()
+        self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58')
+        self.assertRegex(output, '149.10.124.64 proto static scope link')
+        self.assertRegex(output, '192.168.1.1 proto static initcwnd 20')
+        self.assertRegex(output, '192.168.1.2 proto static initrwnd 30')
 
-        self.assertTrue(self.link_exits('dummy98'))
+        output = subprocess.check_output(['ip', '-4', 'route', 'show', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'default via 149.10.125.65 proto static onlink')
+        self.assertRegex(output, 'default via 149.10.124.64 proto static')
 
-        output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['ip', 'route', 'show', 'type', 'blackhole']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, '192.168.0.1')
-        self.assertRegex(output, 'static')
-        self.assertRegex(output, '192.168.0.0/24')
-
-    def test_ip_route_reverse(self):
-        self.copy_unit_to_networkd_unit_path('25-route-reverse-order.network', '12-dummy.netdev')
-        self.start_networkd()
-
-        self.assertTrue(self.link_exits('dummy98'))
+        self.assertRegex(output, 'blackhole 202.54.1.2 proto static')
 
-        output = subprocess.check_output(['ip', '-6', 'route', 'show', 'dev', 'dummy98']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['ip', 'route', 'show', 'type', 'unreachable']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff')
-        self.assertRegex(output, '2001:1234:5:8f63::1')
+        self.assertRegex(output, 'unreachable 202.54.1.3 proto static')
 
-    def test_ip_route_blackhole_unreachable_prohibit(self):
-        self.copy_unit_to_networkd_unit_path('25-route-type.network', '12-dummy.netdev')
-        self.start_networkd()
-
-        self.assertTrue(self.link_exits('dummy98'))
-
-        output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
+        output = subprocess.check_output(['ip', 'route', 'show', 'type', 'prohibit']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, 'blackhole')
-        self.assertRegex(output, 'unreachable')
-        self.assertRegex(output, 'prohibit')
+        self.assertRegex(output, 'prohibit 202.54.1.4 proto static')
 
         subprocess.call(['ip', 'route', 'del', 'blackhole', '202.54.1.2'])
         subprocess.call(['ip', 'route', 'del', 'unreachable', '202.54.1.3'])
         subprocess.call(['ip', 'route', 'del', 'prohibit', '202.54.1.4'])
 
-    def test_ip_route_tcp_window(self):
-        self.copy_unit_to_networkd_unit_path('25-route-tcp-window-settings.network', '11-dummy.netdev')
-        self.start_networkd()
-
-        self.assertTrue(self.link_exits('test1'))
-
-        output = subprocess.check_output(['ip', 'route', 'list']).rstrip().decode('utf-8')
-        print(output)
-        self.assertRegex(output, 'initcwnd 20')
-        self.assertRegex(output, 'initrwnd 30')
-
-    def test_ip_route_gateway(self):
-        self.copy_unit_to_networkd_unit_path('25-route-gateway.network', '12-dummy.netdev')
-        self.start_networkd()
-
-        self.assertTrue(self.link_exits('dummy98'))
-
-        output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
-        print(output)
-        self.assertRegex(output, 'default')
-        self.assertRegex(output, 'via')
-        self.assertRegex(output, '149.10.124.64')
-        self.assertRegex(output, 'proto')
-        self.assertRegex(output, 'static')
-
-        output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
-        print(output)
-        self.assertRegex(output, '149.10.124.48/28')
-        self.assertRegex(output, 'proto')
-        self.assertRegex(output, 'kernel')
-        self.assertRegex(output, 'scope')
-        self.assertRegex(output, 'link')
-
-    def test_ip_route_gateway_on_link(self):
-        self.copy_unit_to_networkd_unit_path('25-route-gateway-on-link.network', '12-dummy.netdev')
-        self.start_networkd()
-
-        self.assertTrue(self.link_exits('dummy98'))
-
-        output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'default']).rstrip().decode('utf-8')
-        print(output)
-        self.assertRegex(output, 'default')
-        self.assertRegex(output, 'via')
-        self.assertRegex(output, '149.10.125.65')
-        self.assertRegex(output, 'proto')
-        self.assertRegex(output, 'static')
-        self.assertRegex(output, 'onlink')
-
-        output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'dummy98', 'src', '149.10.124.58']).rstrip().decode('utf-8')
-        print(output)
-        self.assertRegex(output, '149.10.124.48/28')
-        self.assertRegex(output, 'proto')
-        self.assertRegex(output, 'kernel')
-        self.assertRegex(output, 'scope')
-        self.assertRegex(output, 'link')
-
     def test_ip_route_ipv6_src_route(self):
         # a dummy device does not make the addresses go through tentative state, so we
         # reuse a bond from an earlier test, which does make the addresses go through
@@ -866,13 +1245,12 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
     def test_link_local_addressing(self):
         self.copy_unit_to_networkd_unit_path('25-link-local-addressing-yes.network', '11-dummy.netdev',
                                              '25-link-local-addressing-no.network', '12-dummy.netdev')
-        self.start_networkd()
+        self.start_networkd(0)
+        self.wait_online(['test1:degraded', 'dummy98:carrier'])
 
         self.assertTrue(self.link_exits('test1'))
         self.assertTrue(self.link_exits('dummy98'))
 
-        time.sleep(10)
-
         output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'test1']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, 'inet .* scope link')
@@ -918,14 +1296,15 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
             test1_addr_gen_mode = '0'
 
         if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'test1'), 'addr_gen_mode')):
-            self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), '0')
+            self.assertEqual(self.read_ipv6_sysctl_attr('test1', 'addr_gen_mode'), test1_addr_gen_mode)
 
         if os.path.exists(os.path.join(os.path.join(network_sysctl_ipv6_path, 'dummy98'), 'addr_gen_mode')):
             self.assertEqual(self.read_ipv6_sysctl_attr('dummy98', 'addr_gen_mode'), '1')
 
     def test_sysctl(self):
         self.copy_unit_to_networkd_unit_path('25-sysctl.network', '12-dummy.netdev')
-        self.start_networkd()
+        self.start_networkd(0)
+        self.wait_online(['dummy98:degraded'])
 
         self.assertTrue(self.link_exits('dummy98'))
 
@@ -937,6 +1316,229 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'forwarding'),'1')
         self.assertEqual(self.read_ipv4_sysctl_attr('dummy98', 'proxy_arp'), '1')
 
+    def test_sysctl_disable_ipv6(self):
+        self.copy_unit_to_networkd_unit_path('25-sysctl-disable-ipv6.network', '12-dummy.netdev')
+
+        print('## Disable ipv6')
+        self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=1']), 0)
+        self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=1']), 0)
+
+        self.start_networkd(0)
+        self.wait_online(['dummy98:routable'])
+
+        self.assertTrue(self.link_exits('dummy98'))
+
+        output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
+        output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertEqual(output, '')
+        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
+
+        print('## Enable ipv6')
+        self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.all.disable_ipv6=0']), 0)
+        self.assertEqual(subprocess.call(['sysctl', 'net.ipv6.conf.default.disable_ipv6=0']), 0)
+
+        self.start_networkd(0)
+        self.wait_online(['dummy98:routable'])
+
+        self.assertTrue(self.link_exits('dummy98'))
+
+        output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope global dummy98')
+        output = subprocess.check_output(['ip', '-6', 'address', 'show', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'inet6 .* scope link')
+        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+    def test_bind_carrier(self):
+        self.copy_unit_to_networkd_unit_path('25-bind-carrier.network', '11-dummy.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('test1'))
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy99', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy99', 'up']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy99']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertNotRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'DOWN')
+        self.assertNotRegex(output, '192.168.10')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: off \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
+        time.sleep(2)
+        output = subprocess.check_output(['ip', 'address', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'UP,LOWER_UP')
+        self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1')
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+class NetworkdNetWorkBondTests(unittest.TestCase, Utilities):
+    links = [
+        'bond199',
+        'bond99',
+        'dummy98',
+        'test1']
+
+    units = [
+        '11-dummy.netdev',
+        '12-dummy.netdev',
+        '23-active-slave.network',
+        '23-bond199.network',
+        '23-primary-slave.network',
+        '23-test1-bond199.network',
+        '25-bond-active-backup-slave.netdev',
+        '25-bond.netdev',
+        'bond99.network',
+        'bond-slave.network']
+
+    def setUp(self):
+        self.link_remove(self.links)
+
+    def tearDown(self):
+        self.link_remove(self.links)
+        self.remove_unit_from_networkd_path(self.units)
+
+    def test_bond_active_slave(self):
+        self.copy_unit_to_networkd_unit_path('23-active-slave.network', '23-bond199.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('dummy98'))
+        self.assertTrue(self.link_exits('bond199'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'active_slave dummy98')
+
+    def test_bond_primary_slave(self):
+        self.copy_unit_to_networkd_unit_path('23-primary-slave.network', '23-test1-bond199.network', '25-bond-active-backup-slave.netdev', '11-dummy.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('test1'))
+        self.assertTrue(self.link_exits('bond199'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond199']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'primary test1')
+
+    def test_bond_operstate(self):
+        self.copy_unit_to_networkd_unit_path('25-bond.netdev', '11-dummy.netdev', '12-dummy.netdev',
+                                             'bond99.network','bond-slave.network')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('bond99'))
+        self.assertTrue(self.link_exits('dummy98'))
+        self.assertTrue(self.link_exits('test1'))
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'SLAVE,UP,LOWER_UP')
+
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'bond99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'MASTER,UP,LOWER_UP')
+
+        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: enslaved \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: enslaved \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
+        time.sleep(2)
+
+        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: off \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: enslaved \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: degraded-carrier \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
+        time.sleep(2)
+
+        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: enslaved \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: enslaved \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'down']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'test1', 'down']), 0)
+        time.sleep(5)
+
+        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: off \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: off \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'bond99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: no-carrier \(configured\)')
+
 class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
     links = [
         'bridge99',
@@ -949,6 +1551,7 @@ class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
         '26-bridge.netdev',
         '26-bridge-slave-interface-1.network',
         '26-bridge-slave-interface-2.network',
+        'bridge99-ignore-carrier-loss.network',
         'bridge99.network']
 
     def setUp(self):
@@ -980,20 +1583,131 @@ class NetworkdNetWorkBridgeTests(unittest.TestCase, Utilities):
 
         output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, '192.168.0.15')
-        self.assertRegex(output, '192.168.0.1')
+        self.assertRegex(output, '192.168.0.15/24')
 
         output = subprocess.check_output(['bridge', '-d', 'link', 'show', 'dummy98']).rstrip().decode('utf-8')
         print(output)
         self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'hairpin_mode'), '1')
         self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'path_cost'), '400')
         self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'unicast_flood'), '1')
+        self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_flood'), '0')
         self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_fast_leave'), '1')
+        if (os.path.exists('/sys/devices/virtual/net/bridge99/lower_dummy98/brport/neigh_suppress')):
+            self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'neigh_suppress'), '1')
+        self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'learning'), '0')
 
         # CONFIG_BRIDGE_IGMP_SNOOPING=y
         if (os.path.exists('/sys/devices/virtual/net/bridge00/lower_dummy98/brport/multicast_to_unicast')):
             self.assertEqual(self.read_bridge_port_attr('bridge99', 'dummy98', 'multicast_to_unicast'), '1')
 
+        output = subprocess.check_output(['networkctl', 'status', 'test1']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: enslaved \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: enslaved \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
+        time.sleep(1)
+
+        output = subprocess.check_output(['ip', 'addr', 'show', 'bridge99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, '192.168.0.16/24')
+
+        output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
+        time.sleep(3)
+
+        output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: degraded-carrier \(configured\)')
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
+        time.sleep(3)
+
+        output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: no-carrier \(configured\)')
+
+        output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'NO-CARRIER')
+        self.assertNotRegex(output, '192.168.0.15/24')
+        self.assertNotRegex(output, '192.168.0.16/24')
+
+    def test_bridge_ignore_carrier_loss(self):
+        self.copy_unit_to_networkd_unit_path('11-dummy.netdev', '12-dummy.netdev', '26-bridge.netdev',
+                                             '26-bridge-slave-interface-1.network', '26-bridge-slave-interface-2.network',
+                                             'bridge99-ignore-carrier-loss.network')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '100'])
+
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('dummy98'))
+        self.assertTrue(self.link_exits('test1'))
+        self.assertTrue(self.link_exits('bridge99'))
+
+        self.assertEqual(subprocess.call(['ip', 'address', 'add', '192.168.0.16/24', 'dev', 'bridge99']), 0)
+        time.sleep(1)
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'test1']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
+        time.sleep(3)
+
+        output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'NO-CARRIER')
+        self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
+        self.assertRegex(output, 'inet 192.168.0.16/24 scope global secondary bridge99')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '100'])
+
+    def test_bridge_ignore_carrier_loss_frequent_loss_and_gain(self):
+        self.copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-slave-interface-1.network',
+                                             'bridge99-ignore-carrier-loss.network')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '100'])
+
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('bridge99'))
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'del', 'dummy98']), 0)
+
+        self.assertEqual(subprocess.call(['ip', 'link', 'add', 'dummy98', 'type', 'dummy']), 0)
+        self.assertEqual(subprocess.call(['ip', 'link', 'set', 'dummy98', 'up']), 0)
+
+        time.sleep(3)
+
+        output = subprocess.check_output(['ip', 'address', 'show', 'bridge99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'inet 192.168.0.15/24 brd 192.168.0.255 scope global bridge99')
+
+        output = subprocess.check_output(['networkctl', 'status', 'bridge99']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'dummy98']).rstrip().decode('utf-8')
+        self.assertRegex(output, 'State: enslaved \(configured\)')
+
+        output = subprocess.check_output(['ip', 'rule', 'list', 'table', '100']).rstrip().decode('utf-8')
+        print(output)
+        self.assertEqual(output, '0:   from all to 8.8.8.8 lookup 100')
+
+        subprocess.call(['ip', 'rule', 'del', 'table', '100'])
+
 class NetworkdNetWorkLLDPTests(unittest.TestCase, Utilities):
     links = ['veth99']
 
@@ -1106,12 +1820,16 @@ class NetworkdNetworkDHCPServerTests(unittest.TestCase, Utilities):
 class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
     links = [
         'dummy98',
-        'veth99']
+        'veth99',
+        'vrf99']
 
     units = [
         '25-veth.netdev',
+        '25-vrf.netdev',
+        '25-vrf.network',
         'dhcp-client-anonymize.network',
         'dhcp-client-critical-connection.network',
+        'dhcp-client-gateway-onlink-implicit.network',
         'dhcp-client-ipv4-dhcp-settings.network',
         'dhcp-client-ipv4-only-ipv6-disabled.network',
         'dhcp-client-ipv4-only.network',
@@ -1120,6 +1838,7 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
         'dhcp-client-listen-port.network',
         'dhcp-client-route-metric.network',
         'dhcp-client-route-table.network',
+        'dhcp-client-vrf.network',
         'dhcp-client.network',
         'dhcp-server-veth-peer.network',
         'dhcp-v4-server-veth-peer.network',
@@ -1184,16 +1903,27 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
 
         self.start_dnsmasq()
 
+        print('## ip address show dev veth99')
         output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
         print(output)
         self.assertRegex(output, '12:34:56:78:9a:bc')
         self.assertRegex(output, '192.168.5')
         self.assertRegex(output, '1492')
 
-        output = subprocess.check_output(['ip', 'route']).rstrip().decode('utf-8')
+        # issue #8726
+        print('## ip route show table main dev veth99')
+        output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99']).rstrip().decode('utf-8')
         print(output)
-        self.assertRegex(output, 'default.*dev veth99 proto dhcp')
+        self.assertNotRegex(output, 'proto dhcp')
 
+        print('## ip route show table 211 dev veth99')
+        output = subprocess.check_output(['ip', 'route', 'show', 'table', '211', 'dev', 'veth99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'default via 192.168.5.1 proto dhcp')
+        self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 proto dhcp')
+        self.assertRegex(output, '192.168.5.1 proto dhcp scope link')
+
+        print('## dnsmasq log')
         self.assertTrue(self.search_words_in_dnsmasq_log('vendor class: SusantVendorTest', True))
         self.assertTrue(self.search_words_in_dnsmasq_log('DHCPDISCOVER(veth-peer) 12:34:56:78:9a:bc'))
         self.assertTrue(self.search_words_in_dnsmasq_log('client provides name: test-hostname'))
@@ -1333,6 +2063,78 @@ class NetworkdNetworkDHCPClientTests(unittest.TestCase, Utilities):
         self.assertRegex(output, '2600::')
         self.assertRegex(output, 'valid_lft forever preferred_lft forever')
 
+    @expectedFailureIfModuleIsNotAvailable('vrf')
+    def test_dhcp_client_vrf(self):
+        self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', 'dhcp-client-vrf.network',
+                                             '25-vrf.netdev', '25-vrf.network')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('veth99'))
+        self.assertTrue(self.link_exits('vrf99'))
+
+        self.start_dnsmasq()
+
+        print('## ip -d link show dev vrf99')
+        output = subprocess.check_output(['ip', '-d', 'link', 'show', 'dev', 'vrf99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'vrf table 42')
+
+        print('## ip address show vrf vrf99')
+        output_ip_vrf = subprocess.check_output(['ip', 'address', 'show', 'vrf', 'vrf99']).rstrip().decode('utf-8')
+        print(output_ip_vrf)
+
+        print('## ip address show dev veth99')
+        output = subprocess.check_output(['ip', 'address', 'show', 'dev', 'veth99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertEqual(output, output_ip_vrf)
+        self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99')
+        self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99')
+        self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic noprefixroute')
+        self.assertRegex(output, 'inet6 .* scope link')
+
+        print('## ip route show vrf vrf99')
+        output = subprocess.check_output(['ip', 'route', 'show', 'vrf', 'vrf99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.')
+        self.assertRegex(output, 'default dev veth99 proto static scope link')
+        self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254')
+        self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5')
+        self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp')
+        self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5')
+
+        print('## ip route show table main dev veth99')
+        output = subprocess.check_output(['ip', 'route', 'show', 'table', 'main', 'dev', 'veth99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertEqual(output, '')
+
+        output = subprocess.check_output(['networkctl', 'status', 'vrf99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: carrier \(configured\)')
+
+        output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'State: routable \(configured\)')
+
+    def test_dhcp_client_gateway_onlink_implicit(self):
+        self.copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network',
+                                             'dhcp-client-gateway-onlink-implicit.network')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('veth99'))
+
+        self.start_dnsmasq()
+
+        output = subprocess.check_output(['networkctl', 'status', 'veth99']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, '192.168.5')
+
+        output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '10.0.0.0/8']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'onlink')
+        output = subprocess.check_output(['ip', 'route', 'list', 'dev', 'veth99', '192.168.100.0/24']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'onlink')
+
 if __name__ == '__main__':
     unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout,
                                                      verbosity=3))
index 957cda5..122359e 100755 (executable)
@@ -39,11 +39,17 @@ for (my $i = 1; $i <= 10000; ++$i) {
         $rules_10k_tags .= 'KERNEL=="sda", TAG+="test' . $i . "\"\n";
 }
 
+my $rules_10k_tags_continuation = "KERNEL==\"sda\", \\\n";
+for (my $i = 1; $i < 10000; ++$i) {
+        $rules_10k_tags_continuation .= 'TAG+="test' . $i . "\",\\\n";
+}
+$rules_10k_tags_continuation .= "TAG+=\"test10000\"\\n";
+
 my @tests = (
         {
                 desc            => "no rules",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
-                exp_name        => "sda" ,
+                exp_name        => "sda",
                 exp_rem_error   => "yes",
                 rules           => <<EOF
 #
@@ -52,7 +58,7 @@ EOF
         {
                 desc            => "label test of scsi disc",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
-                exp_name        => "boot_disk" ,
+                exp_name        => "boot_disk",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
 KERNEL=="ttyACM0", SYMLINK+="modem"
@@ -61,7 +67,7 @@ EOF
         {
                 desc            => "label test of scsi disc",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
-                exp_name        => "boot_disk" ,
+                exp_name        => "boot_disk",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
 KERNEL=="ttyACM0", SYMLINK+="modem"
@@ -70,7 +76,7 @@ EOF
         {
                 desc            => "label test of scsi disc",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
-                exp_name        => "boot_disk" ,
+                exp_name        => "boot_disk",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
 KERNEL=="ttyACM0", SYMLINK+="modem"
@@ -79,7 +85,7 @@ EOF
         {
                 desc            => "label test of scsi partition",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
-                exp_name        => "boot_disk1" ,
+                exp_name        => "boot_disk1",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
 EOF
@@ -87,7 +93,7 @@ EOF
         {
                 desc            => "label test of pattern match",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
-                exp_name        => "boot_disk1" ,
+                exp_name        => "boot_disk1",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1"
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2"
@@ -98,7 +104,7 @@ EOF
         {
                 desc            => "label test of multiple sysfs files",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
-                exp_name        => "boot_disk1" ,
+                exp_name        => "boot_disk1",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n"
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="boot_disk%n"
@@ -107,7 +113,7 @@ EOF
         {
                 desc            => "label test of max sysfs files (skip invalid rule)",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
-                exp_name        => "boot_disk1" ,
+                exp_name        => "boot_disk1",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="32", SYMLINK+="boot_diskXX%n"
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
@@ -116,7 +122,7 @@ EOF
         {
                 desc            => "catch device by *",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem/0" ,
+                exp_name        => "modem/0",
                 rules           => <<EOF
 KERNEL=="ttyACM*", SYMLINK+="modem/%n"
 EOF
@@ -124,7 +130,7 @@ EOF
         {
                 desc            => "catch device by * - take 2",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem/0" ,
+                exp_name        => "modem/0",
                 rules           => <<EOF
 KERNEL=="*ACM1", SYMLINK+="bad"
 KERNEL=="*ACM0", SYMLINK+="modem/%n"
@@ -133,7 +139,7 @@ EOF
         {
                 desc            => "catch device by ?",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem/0" ,
+                exp_name        => "modem/0",
                 rules           => <<EOF
 KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1"
 KERNEL=="ttyACM??", SYMLINK+="modem/%n-2"
@@ -143,7 +149,7 @@ EOF
         {
                 desc            => "catch device by character class",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem/0" ,
+                exp_name        => "modem/0",
                 rules           => <<EOF
 KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1"
 KERNEL=="ttyACM?[0-9]", SYMLINK+="modem/%n-2"
@@ -153,7 +159,7 @@ EOF
         {
                 desc            => "replace kernel name",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem" ,
+                exp_name        => "modem",
                 rules           => <<EOF
 KERNEL=="ttyACM0", SYMLINK+="modem"
 EOF
@@ -161,7 +167,7 @@ EOF
         {
                 desc            => "Handle comment lines in config file (and replace kernel name)",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem" ,
+                exp_name        => "modem",
                 rules           => <<EOF
 # this is a comment
 KERNEL=="ttyACM0", SYMLINK+="modem"
@@ -171,7 +177,7 @@ EOF
         {
                 desc            => "Handle comment lines in config file with whitespace (and replace kernel name)",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem" ,
+                exp_name        => "modem",
                 rules           => <<EOF
  # this is a comment with whitespace before the comment
 KERNEL=="ttyACM0", SYMLINK+="modem"
@@ -181,7 +187,7 @@ EOF
         {
                 desc            => "Handle whitespace only lines (and replace kernel name)",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "whitespace" ,
+                exp_name        => "whitespace",
                 rules           => <<EOF
 
 
@@ -196,7 +202,7 @@ EOF
         {
                 desc            => "Handle empty lines in config file (and replace kernel name)",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem" ,
+                exp_name        => "modem",
                 rules           => <<EOF
 
 KERNEL=="ttyACM0", SYMLINK+="modem"
@@ -206,7 +212,7 @@ EOF
         {
                 desc            => "Handle backslashed multi lines in config file (and replace kernel name)",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem" ,
+                exp_name        => "modem",
                 rules           => <<EOF
 KERNEL=="ttyACM0", \\
 SYMLINK+="modem"
@@ -224,7 +230,7 @@ EOF
         {
                 desc            => "Handle stupid backslashed multi lines in config file (and replace kernel name)",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem" ,
+                exp_name        => "modem",
                 rules           => <<EOF
 
 #
@@ -242,7 +248,7 @@ EOF
         {
                 desc            => "subdirectory handling",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "sub/direct/ory/modem" ,
+                exp_name        => "sub/direct/ory/modem",
                 rules           => <<EOF
 KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem"
 EOF
@@ -250,7 +256,7 @@ EOF
         {
                 desc            => "parent device name match of scsi partition",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "first_disk5" ,
+                exp_name        => "first_disk5",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n"
 EOF
@@ -258,7 +264,7 @@ EOF
         {
                 desc            => "test substitution chars",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "Major:8:minor:5:kernelnumber:5:id:0:0:0:0" ,
+                exp_name        => "Major:8:minor:5:kernelnumber:5:id:0:0:0:0",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b"
 EOF
@@ -275,7 +281,7 @@ EOF
         {
                 desc            => "sustitution of sysfs value (%s{file})",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
-                exp_name        => "disk-ATA-sda" ,
+                exp_name        => "disk-ATA-sda",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k"
 KERNEL=="ttyACM0", SYMLINK+="modem"
@@ -284,8 +290,8 @@ EOF
         {
                 desc            => "program result substitution",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "special-device-5" ,
-                not_exp_name    => "not" ,
+                exp_name        => "special-device-5",
+                not_exp_name    => "not",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n"
@@ -294,7 +300,7 @@ EOF
         {
                 desc            => "program result substitution (newline removal)",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "newline_removed" ,
+                exp_name        => "newline_removed",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed"
 EOF
@@ -302,7 +308,7 @@ EOF
         {
                 desc            => "program result substitution",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "test-0:0:0:0" ,
+                exp_name        => "test-0:0:0:0",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c"
 EOF
@@ -310,7 +316,7 @@ EOF
         {
                 desc            => "program with lots of arguments",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "foo9" ,
+                exp_name        => "foo9",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}"
 EOF
@@ -318,7 +324,7 @@ EOF
         {
                 desc            => "program with subshell",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "bar9" ,
+                exp_name        => "bar9",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed  s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}"
 EOF
@@ -326,7 +332,7 @@ EOF
         {
                 desc            => "program arguments combined with apostrophes",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "foo7" ,
+                exp_name        => "foo7",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4'   'foo5   foo6   foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}"
 EOF
@@ -334,7 +340,7 @@ EOF
         {
                 desc            => "program arguments combined with escaped double quotes, part 1",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "foo2" ,
+                exp_name        => "foo2",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf %%s \\\"foo1 foo2\\\" | grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
 EOF
@@ -342,7 +348,7 @@ EOF
         {
                 desc            => "program arguments combined with escaped double quotes, part 2",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "foo2" ,
+                exp_name        => "foo2",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \\\"printf %%s 'foo1 foo2' | grep 'foo1 foo2'\\\"", KERNEL=="sda5", SYMLINK+="%c{2}"
 EOF
@@ -350,7 +356,7 @@ EOF
         {
                 desc            => "program arguments combined with escaped double quotes, part 3",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "foo2" ,
+                exp_name        => "foo2",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf \\\"%%s %%s\\\" \\\"foo1 foo2\\\" \\\"foo3\\\"| grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
 EOF
@@ -358,7 +364,7 @@ EOF
         {
                 desc            => "characters before the %c{N} substitution",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "my-foo9" ,
+                exp_name        => "my-foo9",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}"
 EOF
@@ -366,7 +372,7 @@ EOF
         {
                 desc            => "substitute the second to last argument",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "my-foo8" ,
+                exp_name        => "my-foo8",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}"
 EOF
@@ -390,7 +396,7 @@ EOF
         {
                 desc            => "test substitution by variable name 3",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "850:0:0:05" ,
+                exp_name        => "850:0:0:05",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n"
 EOF
@@ -398,7 +404,7 @@ EOF
         {
                 desc            => "test substitution by variable name 4",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "855" ,
+                exp_name        => "855",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number"
 EOF
@@ -406,7 +412,7 @@ EOF
         {
                 desc            => "test substitution by variable name 5",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
-                exp_name        => "8550:0:0:0" ,
+                exp_name        => "8550:0:0:0",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id"
 EOF
@@ -423,7 +429,7 @@ EOF
         {
                 desc            => "non matching SUBSYSTEMS",
                 devpath         => "/devices/virtual/tty/console",
-                exp_name        => "TTY" ,
+                exp_name        => "TTY",
                 rules                => <<EOF
 SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo"
 KERNEL=="console", SYMLINK+="TTY"
@@ -432,7 +438,7 @@ EOF
         {
                 desc            => "ATTRS match",
                 devpath         => "/devices/virtual/tty/console",
-                exp_name        => "foo" ,
+                exp_name        => "foo",
                 rules           => <<EOF
 KERNEL=="console", SYMLINK+="TTY"
 ATTRS{dev}=="5:1", SYMLINK+="foo"
@@ -441,7 +447,7 @@ EOF
         {
                 desc            => "ATTR (empty file)",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
-                exp_name        => "empty" ,
+                exp_name        => "empty",
                 rules           => <<EOF
 KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something"
 KERNEL=="sda", ATTR{test_empty_file}!="", SYMLINK+="not-empty"
@@ -452,7 +458,7 @@ EOF
         {
                 desc            => "ATTR (non-existent file)",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
-                exp_name        => "non-existent" ,
+                exp_name        => "non-existent",
                 rules           => <<EOF
 KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something"
 KERNEL=="sda", ATTR{nofile}!="", SYMLINK+="not-empty"
@@ -465,7 +471,7 @@ EOF
         {
                 desc            => "program and bus type match",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
-                exp_name        => "scsi-0:0:0:0" ,
+                exp_name        => "scsi-0:0:0:0",
                 rules           => <<EOF
 SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c"
 SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", SYMLINK+="%c"
@@ -475,7 +481,7 @@ EOF
         {
                 desc            => "sysfs parent hierarchy",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "modem" ,
+                exp_name        => "modem",
                 rules           => <<EOF
 ATTRS{idProduct}=="007b", SYMLINK+="modem"
 EOF
@@ -483,7 +489,7 @@ EOF
         {
                 desc            => "name test with ! in the name",
                 devpath         => "/devices/virtual/block/fake!blockdev0",
-                exp_name        => "is/a/fake/blockdev0" ,
+                exp_name        => "is/a/fake/blockdev0",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k"
 SUBSYSTEM=="block", SYMLINK+="is/a/%k"
@@ -493,7 +499,7 @@ EOF
         {
                 desc            => "name test with ! in the name, but no matching rule",
                 devpath         => "/devices/virtual/block/fake!blockdev0",
-                exp_name        => "fake/blockdev0" ,
+                exp_name        => "fake/blockdev0",
                 exp_rem_error   => "yes",
                 rules           => <<EOF
 KERNEL=="ttyACM0", SYMLINK+="modem"
@@ -536,7 +542,7 @@ EOF
                 desc            => "KERNELS wildcard partial 2",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
                 exp_name        => "scsi-0:0:0:0",
-                rules                => <<EOF
+                rules           => <<EOF
 SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
 SUBSYSTEMS=="scsi", KERNELS=="*:0:0:0", SYMLINK+="scsi-0:0:0:0"
 EOF
@@ -733,7 +739,7 @@ EOF
                 devpath         => "/devices/virtual/misc/misc-fake1",
                 exp_name        => "node",
                 exp_majorminor  => "4095:1",
-                rules                => <<EOF
+                rules           => <<EOF
 KERNEL=="misc-fake1", SYMLINK+="node"
 EOF
         },
@@ -758,7 +764,7 @@ EOF
                 desc            => "multiple symlinks with a lot of s p a c e s",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
                 exp_name        => "one",
-                not_exp_name        => " ",
+                not_exp_name    => " ",
                 rules           => <<EOF
 KERNEL=="ttyACM[0-9]*", SYMLINK="  one     two        "
 EOF
@@ -854,7 +860,7 @@ EOF
         {
                 desc            => "multiple symlinks",
                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
-                exp_name        => "second-0" ,
+                exp_name        => "second-0",
                 rules           => <<EOF
 KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n"
 EOF
@@ -863,8 +869,8 @@ EOF
                 desc            => "symlink name '.'",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
                 exp_name        => ".",
-                exp_add_error        => "yes",
-                exp_rem_error        => "yes",
+                exp_add_error   => "yes",
+                exp_rem_error   => "yes",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="."
 EOF
@@ -873,9 +879,9 @@ EOF
                 desc            => "symlink node to itself",
                 devpath         => "/devices/virtual/tty/tty0",
                 exp_name        => "link",
-                exp_add_error        => "yes",
-                exp_rem_error        => "yes",
-                option                => "clean",
+                exp_add_error   => "yes",
+                exp_rem_error   => "yes",
+                option          => "clean",
                 rules           => <<EOF
 KERNEL=="tty0", SYMLINK+="tty0"
 EOF
@@ -1431,7 +1437,7 @@ EOF
                 desc            => "add and match tag",
                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
                 exp_name        => "found",
-                not_exp_name    => "bad" ,
+                not_exp_name    => "bad",
                 rules           => <<EOF
 SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green"
 TAGS=="green", SYMLINK+="found"
@@ -1446,6 +1452,58 @@ EOF
 TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
 EOF
         },
+        {
+                desc            => "continuations",
+                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                exp_name        => "found",
+                not_exp_name    => "bad",
+                rules           => $rules_10k_tags_continuation . <<EOF
+TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="bad"
+KERNEL=="sda",\\
+# comment in continuation
+TAG+="hoge1",\\
+  # space before comment
+TAG+="hoge2",\\
+# spaces before and after token are dropped
+  TAG+="hoge3",   \\
+\\
+ \\
+TAG+="hoge4"
+TAGS=="hoge1", TAGS=="hoge2", TAGS=="hoge3", TAGS=="hoge4", SYMLINK+="found"
+EOF
+        },
+        {
+                desc            => "continuations with empty line",
+                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                exp_name        => "found",
+                not_exp_name    => "bad",
+                rules           => <<EOF
+# empty line finishes continuation
+KERNEL=="sda", TAG+="foo" \\
+
+KERNEL=="sdb", TAG+="hoge"
+KERNEL=="sda", TAG+="aaa" \\
+KERNEL=="sdb", TAG+="bbb"
+TAGS=="foo", SYMLINK+="found"
+TAGS=="aaa", SYMLINK+="bad"
+EOF
+        },
+        {
+                desc            => "continuations with white only line",
+                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                exp_name        => "found",
+                not_exp_name    => "bad",
+                rules           => <<EOF
+# space only line finishes continuation
+KERNEL=="sda", TAG+="foo" \\
+   \t
+KERNEL=="sdb", TAG+="hoge"
+KERNEL=="sda", TAG+="aaa" \\
+KERNEL=="sdb", TAG+="bbb"
+TAGS=="foo", SYMLINK+="found"
+TAGS=="aaa", SYMLINK+="bad"
+EOF
+        },
 );
 
 sub udev {
index e2fd388..99f8f9d 100755 (executable)
@@ -10,12 +10,20 @@ function generate_directives() {
         }}' "$1"
 }
 
+ret=0
 if [[ $(generate_directives src/network/networkd-network-gperf.gperf | wc -l) -ne $(wc -l <test/fuzz/fuzz-network-parser/directives.network) ]]; then
        echo "Looks like test/fuzz/fuzz-network-parser/directives.network hasn't been updated"
-       exit 1
+        ret=1
 fi
 
 if [[ $(generate_directives src/network/netdev/netdev-gperf.gperf | wc -l) -ne $(wc -l <test/fuzz/fuzz-netdev-parser/directives.netdev) ]]; then
        echo "Looks like test/fuzz/fuzz-netdev-parser/directives.netdev hasn't been updated"
-       exit 1
+       ret=1
 fi
+
+if [[ $(generate_directives src/udev/net/link-config-gperf.gperf | wc -l) -ne $(wc -l <test/fuzz/fuzz-link-parser/directives.link) ]]; then
+       echo "Looks like test/fuzz/fuzz-link-parser/directives.link hasn't been updated"
+       ret=1
+fi
+
+exit $ret
index f9ef241..8bdc58a 100755 (executable)
@@ -20,8 +20,8 @@ if [ "${2:-}" != "-n" ]; then (
         curl -L -o ma-large.txt 'http://standards-oui.ieee.org/oui/oui.txt'
         curl -L -o ma-medium.txt 'http://standards-oui.ieee.org/oui28/mam.txt'
         curl -L -o ma-small.txt 'http://standards-oui.ieee.org/oui36/oui36.txt'
-        curl -L -o pnp_id_registry.html 'http://www.uefi.org/uefi-pnp-export'
-        curl -L -o acpi_id_registry.html 'http://www.uefi.org/uefi-acpi-export'
+        curl -L -o pnp_id_registry.html 'https://uefi.org/uefi-pnp-export'
+        curl -L -o acpi_id_registry.html 'https://uefi.org/uefi-acpi-export'
 ) fi
 
 set -x
index dbd12c4..72ffcee 100755 (executable)
@@ -34,7 +34,7 @@ for phase in "${PHASES[@]}"; do
             info "Starting container $CONT_NAME"
             $DOCKER_RUN -v $REPO_ROOT:/build:rw \
                         -w /build --privileged=true --name $CONT_NAME \
-                        -dit --net=host debian-with-systemd/latest /usr/bin/systemd
+                        -dit --net=host debian-with-systemd/latest /bin/systemd
             $DOCKER_EXEC bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list"
             $DOCKER_EXEC apt-get -y update
             $DOCKER_EXEC apt-get -y build-dep systemd
index be32433..0114ad3 100644 (file)
@@ -20,3 +20,4 @@ ConditionCapability=CAP_SYS_ADMIN
 What=mqueue
 Where=/dev/mqueue
 Type=mqueue
+Options=nosuid,nodev,noexec
index 7916ec6..e862ceb 100644 (file)
@@ -21,7 +21,7 @@ units = [
         ['halt.target',                         ''],
         ['hibernate.target',                    'ENABLE_HIBERNATE'],
         ['hybrid-sleep.target',                 'ENABLE_HIBERNATE'],
-        ['suspend-then-hibernate.target',         'ENABLE_HIBERNATE'],
+        ['suspend-then-hibernate.target',       'ENABLE_HIBERNATE'],
         ['initrd-fs.target',                    ''],
         ['initrd-root-device.target',           ''],
         ['initrd-root-fs.target',               ''],
@@ -33,8 +33,7 @@ units = [
         ['local-fs-pre.target',                 ''],
         ['local-fs.target',                     ''],
         ['machine.slice',                       'ENABLE_MACHINED'],
-        ['machines.target',                     'ENABLE_MACHINED',
-         join_paths(pkgsysconfdir, 'system/multi-user.target.wants/')],
+        ['machines.target',                     'ENABLE_MACHINED'],
         ['multi-user.target',                   '',
          'runlevel2.target runlevel3.target runlevel4.target'],
         ['network-online.target',               ''],
@@ -51,11 +50,9 @@ units = [
         ['proc-sys-fs-binfmt_misc.mount',       'ENABLE_BINFMT'],
         ['reboot.target',                       '',
          'runlevel6.target ctrl-alt-del.target'],
-        ['remote-cryptsetup.target',            'HAVE_LIBCRYPTSETUP',
-         join_paths(pkgsysconfdir, 'system/multi-user.target.wants/')],
+        ['remote-cryptsetup.target',            'HAVE_LIBCRYPTSETUP'],
         ['remote-fs-pre.target',                ''],
-        ['remote-fs.target',                    '',
-         join_paths(pkgsysconfdir, 'system/multi-user.target.wants/')],
+        ['remote-fs.target',                    ''],
         ['rescue.target',                       '',
          'runlevel1.target'],
         ['rpcbind.target',                      ''],
@@ -97,8 +94,7 @@ units = [
          'sockets.target.wants/'],
         ['systemd-journald.socket',             '',
          'sockets.target.wants/'],
-        ['systemd-networkd.socket',             'ENABLE_NETWORKD',
-         join_paths(pkgsysconfdir, 'system/sockets.target.wants/')],
+        ['systemd-networkd.socket',             'ENABLE_NETWORKD'],
         ['systemd-poweroff.service',             ''],
         ['systemd-reboot.service',               ''],
         ['systemd-rfkill.socket',               'ENABLE_RFKILL'],
@@ -108,6 +104,7 @@ units = [
          'sockets.target.wants/'],
         ['systemd-udevd-kernel.socket',         '',
          'sockets.target.wants/'],
+        ['time-set.target',                     ''],
         ['time-sync.target',                    ''],
         ['timers.target',                       ''],
         ['umount.target',                       ''],
@@ -177,22 +174,16 @@ in_units = [
          'dbus-org.freedesktop.machine1.service'],
         ['systemd-modules-load.service',         'HAVE_KMOD',
          'sysinit.target.wants/'],
-        ['systemd-networkd.service',             'ENABLE_NETWORKD',
-         join_paths(pkgsysconfdir, 'system/dbus-org.freedesktop.network1.service') + ' ' +
-         join_paths(pkgsysconfdir, 'system/multi-user.target.wants/')],
-        ['systemd-networkd-wait-online.service', 'ENABLE_NETWORKD',
-         join_paths(pkgsysconfdir, 'system/network-online.target.wants/')],
+        ['systemd-networkd.service',             'ENABLE_NETWORKD'],
+        ['systemd-networkd-wait-online.service', 'ENABLE_NETWORKD'],
         ['systemd-nspawn@.service',              ''],
         ['systemd-portabled.service',            'ENABLE_PORTABLED',
          'dbus-org.freedesktop.portable1.service'],
         ['systemd-quotacheck.service',           'ENABLE_QUOTACHECK'],
         ['systemd-random-seed.service',          'ENABLE_RANDOMSEED',
          'sysinit.target.wants/'],
-        ['systemd-remount-fs.service',           '',
-         'local-fs.target.wants/'],
-        ['systemd-resolved.service',             'ENABLE_RESOLVE',
-         join_paths(pkgsysconfdir, 'system/dbus-org.freedesktop.resolve1.service') + ' ' +
-         join_paths(pkgsysconfdir, 'system/multi-user.target.wants/')],
+        ['systemd-remount-fs.service',           ''],
+        ['systemd-resolved.service',             'ENABLE_RESOLVE'],
         ['systemd-rfkill.service',               'ENABLE_RFKILL'],
         ['systemd-suspend.service',              ''],
         ['systemd-sysctl.service',               '',
@@ -201,8 +192,7 @@ in_units = [
          'sysinit.target.wants/'],
         ['systemd-timedated.service',            'ENABLE_TIMEDATED',
          'dbus-org.freedesktop.timedate1.service'],
-        ['systemd-timesyncd.service',            'ENABLE_TIMESYNCD',
-         join_paths(pkgsysconfdir, 'system/sysinit.target.wants/')],
+        ['systemd-timesyncd.service',            'ENABLE_TIMESYNCD'],
         ['systemd-time-wait-sync.service',       'ENABLE_TIMESYNCD'],
         ['systemd-tmpfiles-clean.service',       'ENABLE_TMPFILES'],
         ['systemd-tmpfiles-setup-dev.service',   'ENABLE_TMPFILES',
@@ -239,8 +229,7 @@ m4_units = [
         ['console-getty.service',              ''],
         ['container-getty@.service',           ''],
         ['getty@.service',                     '',
-         'autovt@.service ' +
-         join_paths(pkgsysconfdir, 'system/getty.target.wants/getty@tty1.service')],
+         'autovt@.service '],
         ['serial-getty@.service',              ''],
         ['tmp.mount',                           '',
          'local-fs.target.wants/'],
index 091191e..66229ec 100644 (file)
@@ -17,3 +17,4 @@ DefaultDependencies=no
 What=binfmt_misc
 Where=/proc/sys/fs/binfmt_misc
 Type=binfmt_misc
+Options=nosuid,nodev,noexec
index 7e7b05c..7bbc342 100644 (file)
@@ -22,3 +22,4 @@ Before=sysinit.target
 What=fusectl
 Where=/sys/fs/fuse/connections
 Type=fusectl
+Options=nosuid,nodev,noexec
index e213ca5..e699788 100644 (file)
@@ -21,3 +21,4 @@ Before=sysinit.target
 What=configfs
 Where=/sys/kernel/config
 Type=configfs
+Options=nosuid,nodev,noexec
index 53ce820..618270d 100644 (file)
@@ -20,3 +20,4 @@ Before=sysinit.target
 What=debugfs
 Where=/sys/kernel/debug
 Type=debugfs
+Options=nosuid,nodev,noexec
index 58baab3..d5eca25 100644 (file)
@@ -9,7 +9,7 @@
 
 [Unit]
 Description=Remove the Offline System Updates symlink
-Documentation=man:systemd.special(5) man:systemd.offline-updates(7)
+Documentation=man:systemd.special(7) man:systemd.offline-updates(7)
 After=system-update.target
 DefaultDependencies=no
 Conflicts=shutdown.target
index ffcb5f3..afb2ab9 100644 (file)
@@ -29,12 +29,14 @@ PrivateNetwork=yes
 PrivateTmp=yes
 ProtectControlGroups=yes
 ProtectHome=yes
+ProtectHostname=yes
 ProtectKernelModules=yes
 ProtectKernelTunables=yes
 ProtectSystem=strict
 RestrictAddressFamilies=AF_UNIX
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
 RuntimeMaxSec=5min
 StateDirectory=systemd/coredump
 SystemCallArchitectures=native
index 6cdbe1b..d9646c9 100644 (file)
@@ -32,6 +32,7 @@ ReadWritePaths=/etc
 RestrictAddressFamilies=AF_UNIX
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
 SmackProcessLabel=System
 SystemCallArchitectures=native
 SystemCallErrorNumber=EPERM
index 20704a8..38b7d7e 100644 (file)
@@ -20,6 +20,7 @@ KillMode=mixed
 CapabilityBoundingSet=CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD CAP_SETFCAP CAP_SYS_ADMIN CAP_SETPCAP CAP_DAC_OVERRIDE
 NoNewPrivileges=yes
 MemoryDenyWriteExecute=yes
+ProtectHostname=yes
 RestrictRealtime=yes
 RestrictNamespaces=net
 RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
index f735cd0..cc3cdca 100644 (file)
@@ -12,7 +12,7 @@ Description=Rebuild Journal Catalog
 Documentation=man:systemd-journald.service(8) man:journald.conf(5)
 DefaultDependencies=no
 Conflicts=shutdown.target
-After=local-fs.target
+After=local-fs.target systemd-tmpfiles-setup.service
 Before=sysinit.target shutdown.target systemd-update-done.service
 ConditionNeedsUpdate=/var
 
index ebc8bf9..50f7745 100644 (file)
@@ -17,11 +17,11 @@ DynamicUser=yes
 ExecStart=@rootlibexecdir@/systemd-journal-gatewayd
 LockPersonality=yes
 MemoryDenyWriteExecute=yes
-NoNewPrivileges=yes
 PrivateDevices=yes
 PrivateNetwork=yes
 ProtectControlGroups=yes
 ProtectHome=yes
+ProtectHostname=yes
 ProtectKernelModules=yes
 ProtectKernelTunables=yes
 RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
index 29a99aa..dd6322e 100644 (file)
@@ -23,12 +23,14 @@ PrivateNetwork=yes
 PrivateTmp=yes
 ProtectControlGroups=yes
 ProtectHome=yes
+ProtectHostname=yes
 ProtectKernelModules=yes
 ProtectKernelTunables=yes
 ProtectSystem=strict
 RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
 SystemCallArchitectures=native
 User=systemd-journal-remote
 WatchdogSec=3min
index 92cd4e5..e380047 100644 (file)
@@ -18,10 +18,10 @@ DynamicUser=yes
 ExecStart=@rootlibexecdir@/systemd-journal-upload --save-state
 LockPersonality=yes
 MemoryDenyWriteExecute=yes
-NoNewPrivileges=yes
 PrivateDevices=yes
 ProtectControlGroups=yes
 ProtectHome=yes
+ProtectHostname=yes
 ProtectKernelModules=yes
 ProtectKernelTunables=yes
 RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
index 3a3153e..9c2ebf0 100644 (file)
@@ -28,6 +28,7 @@ RestartSec=0
 RestrictAddressFamilies=AF_UNIX AF_NETLINK
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
 SmackProcessLabel=System
 Sockets=systemd-journald.socket systemd-journald-dev-log.socket systemd-journald-audit.socket
 StandardOutput=null
index 32ead88..e8ab03f 100644 (file)
@@ -25,6 +25,7 @@ PrivateNetwork=yes
 PrivateTmp=yes
 ProtectControlGroups=yes
 ProtectHome=yes
+ProtectHostname=yes
 ProtectKernelModules=yes
 ProtectKernelTunables=yes
 ProtectSystem=strict
@@ -32,6 +33,7 @@ ReadWritePaths=/etc
 RestrictAddressFamilies=AF_UNIX
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
 SmackProcessLabel=System
 SystemCallArchitectures=native
 SystemCallErrorNumber=EPERM
index 566b807..7b00a08 100644 (file)
@@ -22,18 +22,28 @@ After=dbus.socket
 
 [Service]
 BusName=org.freedesktop.login1
-CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_KILL CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER CAP_SYS_TTY_CONFIG
+CapabilityBoundingSet=CAP_SYS_ADMIN CAP_MAC_ADMIN CAP_AUDIT_CONTROL CAP_CHOWN CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_FOWNER CAP_SYS_TTY_CONFIG CAP_LINUX_IMMUTABLE
 ExecStart=@rootlibexecdir@/systemd-logind
 FileDescriptorStoreMax=512
 IPAddressDeny=any
 LockPersonality=yes
 MemoryDenyWriteExecute=yes
 NoNewPrivileges=yes
+PrivateTmp=yes
+ProtectControlGroups=yes
+ProtectHome=yes
+ProtectHostname=yes
+ProtectKernelModules=yes
+ProtectSystem=strict
+ReadWritePaths=/etc /run
 Restart=always
 RestartSec=0
 RestrictAddressFamilies=AF_UNIX AF_NETLINK
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
+RuntimeDirectory=systemd/sessions systemd/seats systemd/users systemd/inhibit systemd/shutdown
+RuntimeDirectoryPreserve=yes
 SmackProcessLabel=System::Privileged
 SystemCallArchitectures=native
 SystemCallErrorNumber=EPERM
index 6e64be1..e7f9859 100644 (file)
@@ -23,6 +23,7 @@ IPAddressDeny=any
 LockPersonality=yes
 MemoryDenyWriteExecute=yes
 NoNewPrivileges=yes
+ProtectHostname=yes
 RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
 RestrictRealtime=yes
 SmackProcessLabel=System
index c4dc679..d296ccb 100644 (file)
@@ -39,6 +39,7 @@ RestartSec=0
 RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 AF_PACKET
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
 RuntimeDirectory=systemd/netif
 RuntimeDirectoryPreserve=yes
 SystemCallArchitectures=native
index a44cdb3..a8eab94 100644 (file)
@@ -18,6 +18,7 @@ BusName=org.freedesktop.portable1
 WatchdogSec=3min
 CapabilityBoundingSet=CAP_KILL CAP_SYS_PTRACE CAP_SYS_ADMIN CAP_SETGID CAP_SYS_CHROOT CAP_DAC_READ_SEARCH CAP_DAC_OVERRIDE CAP_CHOWN CAP_FOWNER CAP_FSETID CAP_MKNOD
 MemoryDenyWriteExecute=yes
+ProtectHostname=yes
 RestrictRealtime=yes
 RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
 SystemCallFilter=@system-service @mount
index fd645e0..8c736b8 100644 (file)
@@ -16,7 +16,6 @@ Conflicts=shutdown.target
 After=systemd-fsck-root.service
 Before=local-fs-pre.target local-fs.target shutdown.target
 Wants=local-fs-pre.target
-ConditionPathExists=/etc/fstab
 
 [Service]
 Type=oneshot
index c2c783c..26e0f5b 100644 (file)
@@ -43,6 +43,7 @@ RestartSec=0
 RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
 RuntimeDirectory=systemd/resolve
 RuntimeDirectoryPreserve=yes
 SystemCallArchitectures=native
index 6d53024..df546f4 100644 (file)
@@ -23,6 +23,7 @@ NoNewPrivileges=yes
 PrivateTmp=yes
 ProtectControlGroups=yes
 ProtectHome=yes
+ProtectHostname=yes
 ProtectKernelModules=yes
 ProtectKernelTunables=yes
 ProtectSystem=strict
@@ -30,6 +31,7 @@ ReadWritePaths=/etc
 RestrictAddressFamilies=AF_UNIX
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
 SystemCallArchitectures=native
 SystemCallErrorNumber=EPERM
 SystemCallFilter=@system-service @clock
index 03ade45..2d8d14f 100644 (file)
@@ -14,9 +14,9 @@ ConditionCapability=CAP_SYS_TIME
 ConditionVirtualization=!container
 DefaultDependencies=no
 After=systemd-remount-fs.service systemd-sysusers.service
-Before=time-sync.target sysinit.target shutdown.target
+Before=time-set.target sysinit.target shutdown.target
 Conflicts=shutdown.target
-Wants=time-sync.target
+Wants=time-set.target time-sync.target
 
 [Service]
 AmbientCapabilities=CAP_SYS_TIME
@@ -29,6 +29,7 @@ PrivateDevices=yes
 PrivateTmp=yes
 ProtectControlGroups=yes
 ProtectHome=yes
+ProtectHostname=yes
 ProtectKernelModules=yes
 ProtectKernelTunables=yes
 ProtectSystem=strict
@@ -37,6 +38,7 @@ RestartSec=0
 RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
 RestrictNamespaces=yes
 RestrictRealtime=yes
+RestrictSUIDSGID=yes
 RuntimeDirectory=systemd/timesync
 StateDirectory=systemd/timesync
 SystemCallArchitectures=native
index 7c2a563..485c9bb 100644 (file)
@@ -12,7 +12,7 @@ Description=Cleanup of Temporary Directories
 Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
 DefaultDependencies=no
 Conflicts=shutdown.target
-After=local-fs.target time-sync.target
+After=local-fs.target time-set.target
 Before=shutdown.target
 
 [Service]
index 369e6da..cba1336 100644 (file)
@@ -27,9 +27,11 @@ WatchdogSec=3min
 TasksMax=infinity
 SmackProcessLabel=System::Privileged
 PrivateMounts=yes
+ProtectHostname=yes
 MemoryDenyWriteExecute=yes
-RestrictRealtime=yes
 RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
+RestrictRealtime=yes
+RestrictSUIDSGID=yes
 SystemCallFilter=@system-service @module @raw-io
 SystemCallErrorNumber=EPERM
 SystemCallArchitectures=native
diff --git a/units/time-set.target b/units/time-set.target
new file mode 100644 (file)
index 0000000..6b40033
--- /dev/null
@@ -0,0 +1,13 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=System Time Set
+Documentation=man:systemd.special(7)
+RefuseManualStart=yes
index 1533c7c..9106502 100644 (file)
@@ -11,3 +11,5 @@
 Description=System Time Synchronized
 Documentation=man:systemd.special(7)
 RefuseManualStart=yes
+After=time-set.target
+Wants=time-set.target
index 3025e91..6ef46d3 100644 (file)
@@ -9,7 +9,8 @@
 
 [Unit]
 Description=Temporary Directory (/tmp)
-Documentation=man:hier(7)
+Documentation=https://systemd.io/TEMPORARY_DIRECTORIES
+Documentation=man:file-hierarchy(7)
 Documentation=https://www.freedesktop.org/wiki/Software/systemd/APIFileSystems
 ConditionPathIsSymbolicLink=!/tmp
 DefaultDependencies=no
diff --git a/units/usb-gadget.target b/units/usb-gadget.target
new file mode 100644 (file)
index 0000000..c666683
--- /dev/null
@@ -0,0 +1,12 @@
+#  SPDX-License-Identifier: LGPL-2.1+
+#
+#  This file is part of systemd.
+#
+#  systemd is free software; you can redistribute it and/or modify it
+#  under the terms of the GNU Lesser General Public License as published by
+#  the Free Software Foundation; either version 2.1 of the License, or
+#  (at your option) any later version.
+
+[Unit]
+Description=Hardware activated USB gadget
+Documentation=man:systemd.special(7)
index da319ce..c50638c 100644 (file)
@@ -8,7 +8,7 @@
 #  (at your option) any later version.
 
 [Unit]
-Description=Default
+Description=Main User Target
 Documentation=man:systemd.special(7)
 Requires=basic.target
 After=basic.target
index f661e79..fe6603b 100644 (file)
@@ -31,3 +31,4 @@ Capabilities=cap_sys_admin,cap_mac_admin,cap_setgid,cap_dac_override=i
 SecureBits=keep-caps
 TimeoutStartSec=infinity
 TimeoutStopSec=120s
+KeyringMode=inherit