--- /dev/null
+--links=no
(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)))
--- /dev/null
+/**
+ * @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
+++ /dev/null
-/**
- * @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"
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>
Bootable=yes
[Partitions]
-RootSize=2G
+RootSize=3G
[Packages]
Cache=/var/cache/pacman/pkg/
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,
* 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
Miettinen, YiFei Zhu, YmrDtnJu, YunQiang Su, Yu Watanabe, Zbigniew
Jędrzejewski-Szmek, zsergeant77, Дамјан Георгиевски
- — Berlin, 2018-02-14
+ — Berlin, 2019-02-14
CHANGES WITH 240:
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
* 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
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.
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).
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)
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.
<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/>
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.
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.
* 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
* 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
* 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.
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
* 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.
* 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.
* 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
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
* 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
- 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?
- 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
- 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
* 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
--- /dev/null
+@@
+expression s;
+@@
+- (isempty(s) || streq(s, "-"))
++ empty_or_dash(s)
--- /dev/null
+@@
+expression e, v, flags;
+expression list args;
+@@
++ return
+- json_log(v, flags, 0, args);
++ json_log(v, flags, SYNTHETIC_ERRNO(e), args);
+- return -e;
# 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.
## 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.
* 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
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`.
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).
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
## 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
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
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
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.
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
# 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).
--- /dev/null
+---
+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.)
✓ MemoryDenyWriteExecute=
✓ RestrictNamespaces=
✓ RestrictRealtime=
+✓ RestrictSUIDSGID=
✓ RestrictAddressFamilies=
✓ LockPersonality=
✓ LimitCPU=
✓ CPUShares=
✓ StartupCPUShares=
✓ CPUQuota=
+✓ CPUQuotaPeriodSec=
✓ MemoryAccounting=
✓ MemoryMin=
✓ MemoryLow=
Most timer unit settings are available to transient units.
```
-✓ OnCalendar=
✓ OnActiveSec=
✓ OnBootSec=
+✓ OnCalendar=
+✓ OnClockChange=
✓ OnStartupSec=
+✓ OnTimezoneChange
✓ OnUnitActiveSec=
✓ OnUnitInactiveSec=
✓ Persistent=
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
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
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.
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.
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.
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
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.
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.
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
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.
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
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
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
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
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
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
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
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
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
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)
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
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.
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.
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
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.
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.
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
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
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
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)
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.
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
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.
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
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
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
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
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
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.
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
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
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
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.
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
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
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)
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.
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.
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
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
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.
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
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
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.
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
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
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
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
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.
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
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
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
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
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.
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
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.
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
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
OUI:487604*
ID_OUI_FROM_DATABASE=Private
+OUI:487746*
+ ID_OUI_FROM_DATABASE=Calix Inc.
+
OUI:487A55*
ID_OUI_FROM_DATABASE=ALE International
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
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.
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
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
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
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.
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.
OUI:50DF95*
ID_OUI_FROM_DATABASE=Lytx
+OUI:50E085*
+ ID_OUI_FROM_DATABASE=Intel Corporate
+
OUI:50E0C7*
ID_OUI_FROM_DATABASE=TurControlSystme AG
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.
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
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
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
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
OUI:5C5948*
ID_OUI_FROM_DATABASE=Apple, Inc.
+OUI:5C5AC7*
+ ID_OUI_FROM_DATABASE=Cisco Systems, Inc
+
OUI:5C5AEA*
ID_OUI_FROM_DATABASE=FORD
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
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
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.
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.
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
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
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
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.
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
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
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
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
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
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.
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
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
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)
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
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
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.
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
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
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
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
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
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
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
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
OUI:70B3D5236*
ID_OUI_FROM_DATABASE=Monnit Corporation
+OUI:70B3D5237*
+ ID_OUI_FROM_DATABASE=Sikom AS
+
OUI:70B3D5238*
ID_OUI_FROM_DATABASE=Arete Associates
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
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.
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
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
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.
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
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
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
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.
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
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
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
OUI:70B3D5462*
ID_OUI_FROM_DATABASE=EarTex
+OUI:70B3D5463*
+ ID_OUI_FROM_DATABASE=WARECUBE,INC
+
OUI:70B3D5465*
ID_OUI_FROM_DATABASE=ENERGISME
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.
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
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.
OUI:70B3D54F9*
ID_OUI_FROM_DATABASE=OptoPrecision GmbH
+OUI:70B3D54FA*
+ ID_OUI_FROM_DATABASE=Thruvision Limited
+
OUI:70B3D54FC*
ID_OUI_FROM_DATABASE=Mettler Toledo
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
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
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
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.
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.
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
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
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
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
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.
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.
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
OUI:70B3D5821*
ID_OUI_FROM_DATABASE=HL2 group
+OUI:70B3D5822*
+ ID_OUI_FROM_DATABASE=Angora Networks
+
OUI:70B3D5823*
ID_OUI_FROM_DATABASE=SP Controls
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
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
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
OUI:70B3D58C3*
ID_OUI_FROM_DATABASE=Wyebot, Inc.
+OUI:70B3D58C4*
+ ID_OUI_FROM_DATABASE=APE GmbH
+
OUI:70B3D58C5*
ID_OUI_FROM_DATABASE=HMicro Inc
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
OUI:70B3D58EC*
ID_OUI_FROM_DATABASE=Rudy Tellert
+OUI:70B3D58ED*
+ ID_OUI_FROM_DATABASE=NanoSense
+
OUI:70B3D58EE*
ID_OUI_FROM_DATABASE=Network Additions
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
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.
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
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
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.
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
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.
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.
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
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
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.
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
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.
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
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
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
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.
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
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.
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
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
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
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
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
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.
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
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.
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
OUI:70B3D5E0F*
ID_OUI_FROM_DATABASE=Vtron Pty Ltd
+OUI:70B3D5E14*
+ ID_OUI_FROM_DATABASE=Automata Spa
+
OUI:70B3D5E15*
ID_OUI_FROM_DATABASE=Benetel
OUI:70B3D5E1C*
ID_OUI_FROM_DATABASE=Xcenter AS
+OUI:70B3D5E1E*
+ ID_OUI_FROM_DATABASE=Umano Medical Inc.
+
OUI:70B3D5E1F*
ID_OUI_FROM_DATABASE=THETA432
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.
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.
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
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
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.
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.
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
OUI:70B3D5FB7*
ID_OUI_FROM_DATABASE=SAICE
+OUI:70B3D5FB9*
+ ID_OUI_FROM_DATABASE=EYEDEA
+
OUI:70B3D5FBA*
ID_OUI_FROM_DATABASE=Apogee Applied Research, Inc.
OUI:70B3D5FD4*
ID_OUI_FROM_DATABASE=GETRALINE
+OUI:70B3D5FD5*
+ ID_OUI_FROM_DATABASE=OCEANCCTV LTD
+
OUI:70B3D5FD6*
ID_OUI_FROM_DATABASE=Visual Fan
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
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
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.
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
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
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
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.
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
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
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.
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.
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
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
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
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
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.
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.
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.
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
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
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.
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
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
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.
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
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
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
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.
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.
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
OUI:980D2E*
ID_OUI_FROM_DATABASE=HTC Corporation
+OUI:980D67*
+ ID_OUI_FROM_DATABASE=Zyxel Communications Corporation
+
OUI:980EE4*
ID_OUI_FROM_DATABASE=Private
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
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)
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
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.
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
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
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
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.
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.
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
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
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
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
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)
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.
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
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.
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
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
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
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.
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.
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
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.
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
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.
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
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.
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
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.
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
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
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
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
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
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.
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
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
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
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
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.
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
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
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
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.
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
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
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
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
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
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
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
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
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.
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.
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
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
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
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.
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.
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
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
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
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
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.
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
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
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.
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
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
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
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.
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.
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
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.
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.
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.
# 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
---- 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
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
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)
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)
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]
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)
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]
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)
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)
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)
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]
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
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]
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
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
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
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)
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)
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)
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
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
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
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]
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]
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]
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]
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
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
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
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
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
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
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
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)
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
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
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
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]
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
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
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
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
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
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)
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)
pci:v00001BF4d00000001*
ID_MODEL_FROM_DATABASE=SentinelEX
+pci:v00001BF4d00007011*
+ ID_MODEL_FROM_DATABASE=RX0xxx
+
pci:v00001BFD*
ID_VENDOR_FROM_DATABASE=EeeTOP
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
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.
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.
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.
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.
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)
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
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))
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
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)
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
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)
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)
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)
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
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
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))
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
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
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
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)
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
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
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)
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)
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)
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)
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)
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
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
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)
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)
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
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
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
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
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
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)
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)
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
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
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
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
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
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
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
usb:v0424p274D*
ID_MODEL_FROM_DATABASE=HTC Hub Controller
+usb:v0424p2807*
+ ID_MODEL_FROM_DATABASE=Hub
+
usb:v0424p3FCC*
ID_MODEL_FROM_DATABASE=RME MADIface
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
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
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
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
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.
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
usb:v04B0p042A*
ID_MODEL_FROM_DATABASE=D800 (ptp)
+usb:v04B0p0430*
+ ID_MODEL_FROM_DATABASE=D7100
+
usb:v04B0p043F*
ID_MODEL_FROM_DATABASE=D5600
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
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
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)
usb:v04E8p7081*
ID_MODEL_FROM_DATABASE=Human Interface Device
+usb:v04E8p7301*
+ ID_MODEL_FROM_DATABASE=Fingerprint Device
+
usb:v04E8p8001*
ID_MODEL_FROM_DATABASE=Handheld
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.
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
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
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
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]
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
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
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
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
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
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
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)
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.
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
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
#########################################
# 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
###########################################################
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnAlienware*:pn*
+ KEYBOARD_KEY_81=f21 # Touchpad toggle
KEYBOARD_KEY_8a=ejectcd
# Alienware/Dell reserves these keys; safe to apply on all their devices
evdev: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
###########################################################
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
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
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
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)
#########################################
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
#########################################
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
#########################################
# 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:
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
+
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)
from pyparsing import (Word, White, Literal, Regex,
LineEnd, SkipTo,
ZeroOrMore, OneOrMore, Combine, Optional, Suppress,
+ Group,
stringEnd, pythonStyleComment)
EOL = LineEnd().suppress()
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
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()
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()
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()
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
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
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:
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)
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:
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:
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:
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:
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
\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
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
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
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
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
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
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
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
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
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
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
#
# 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
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
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
# 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
<?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">
<?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>
<?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
<?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
<?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">
<?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">
<?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
<?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
<?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">
<?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+
<?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>
<?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">
<?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>
<?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">
<?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>
<?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">
<!--
<?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">
<?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
<?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">
<?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>
<?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>
<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>
<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>
<?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>
<?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>
<?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">
<?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'
<?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>
<?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">
<?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>
<?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">
<?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">
<?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>
<?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>
<?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">
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
<?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">
<?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>
<?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">
<!--
<?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'>
<?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'>
<?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'>
<?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'>
<?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>
<?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'>
<?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'
<?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">
<?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">
''],
['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',
<?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"
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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+
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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>
<?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" />
<?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">
<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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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>
<?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>
<?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>
-<!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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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">
<?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" />
<?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" />
<?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 > 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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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+ -->
<?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" />
<?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" />
<?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" />
<?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+ -->
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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>
<?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" />
<?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" />
<?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" />
<?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" />
<?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>
<?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" />
<?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" />
<?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" />
<?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" />
<?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">
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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" />
<?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">
<?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">
<?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" />
<?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" />
<?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" />
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<!--
<?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">
<?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">
<?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">
<?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">
<?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>
<?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">
<?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">
<?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">
<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" />
<?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" />
<?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">
<?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>
<?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" />
<?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" />
<?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" />
<?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">
<?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>
<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
<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
<?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'>
<?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">
--- /dev/null
+<?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>
<?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>
<?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">> 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">> 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&
+</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]
# /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 <==
+[Socket]
+ListenStream=100
+==> ./b.socket <==
+[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>
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" />
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 <==
-[Socket]
-ListenStream=100
-
-==> ./b.socket <==
-[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>
<?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>
<?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">
<?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>
<?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">
<?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>
<?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">
<?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">
<?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>
<?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">
<?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">
<?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">
<?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">
<?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>
<?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>
<?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>
<?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">
<?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>
<?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>
<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>
<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>
<?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">
<?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">
<?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>
<?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>
<?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>
<?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>,
<?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">
<?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>
<?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>
<?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'>
<?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">
<?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+ -->
<?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'>
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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'>
<?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'>
<?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+
<?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">
<?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'>
<?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>
<?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>
<?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>,
<?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>
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>
<?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'>
<?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">
<?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>
<?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">
<?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'>
<?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>
<?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>
<?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>
<?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>
<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>
<?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>
<?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>
<?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>
<?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>
<?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">
<?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">
<?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">
<?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">
<?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">
<?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>
<?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">
<?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">
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>
<?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>
<?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'>
<?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'>
<?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'>
<?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">
<?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">
<?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">
<?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>
<?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>
<?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>
<?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>
<?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>
<?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>
<?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>
<?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>
<?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>
<?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>
<?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">
<?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>
<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>
<refsect1>
<title>Mandatory Access Control</title>
+
+ <xi:include href="system-only.xml" xpointer="plural"/>
+
<variablelist class='unit-directives'>
<varlistentry>
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>
<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>
</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>
<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>
<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>
<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>
<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>
<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>
<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>
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>
<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>
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>
</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
<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>
<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>
<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>
</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
<?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>
<?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">
<?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>
<?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
<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]
[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>
<?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>
<?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
<?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
<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>
<?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>
<?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>
<?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>
<?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>
<?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>
<?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>
<?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>
<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>
<?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>
<?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>
<?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>,
<?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">
<?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">
<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
<?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>
<?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">
<?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.
<?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><</literal>,
- <literal><=</literal>, <literal>=</literal>, <literal>>=</literal>, <literal>></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><</literal>, <literal><=</literal>, <literal>=</literal>,
+ <literal>!=</literal>, <literal>>=</literal>, <literal>></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><</literal>, <literal><=</literal>, <literal>=</literal>,
+ <literal>!=</literal>, <literal>>=</literal>, <literal>></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><</literal>, <literal><=</literal>, <literal>=</literal>, <literal>!=</literal>,
+ <literal>>=</literal>, <literal>></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).
<?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">
<?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">
<?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">
<?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>
<?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">
<?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">
<?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+
<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
(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>
<?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">
<?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.
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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">
<?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>
<?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'>
<?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">
<?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>
# SPDX-License-Identifier: LGPL-2.1+
project('systemd', 'c',
- version : '241',
+ version : '242',
license : 'LGPLv2+',
default_options: [
'c_std=gnu99',
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
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
#####################################################################
# 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
if rootprefixdir == ''
rootprefixdir = rootprefix_default
endif
+rootprefixdir_noslash = rootprefixdir == '/' ? '' : rootprefixdir
sysvinit_path = get_option('sysvinit-path')
sysvrcnd_path = get_option('sysvrcnd-path')
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')
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')
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)
'-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',
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')
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',
]
#####################################################################
-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()]
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')
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)
'src/udev',
'src/libudev',
'src/core',
+ 'src/shutdown',
'src/libsystemd/sd-bus',
'src/libsystemd/sd-device',
'src/libsystemd/sd-event',
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,
subdir('src/libudev')
subdir('src/shared')
subdir('src/core')
+subdir('src/shutdown')
subdir('src/udev')
subdir('src/network')
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,
# 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,
include_directories : includes,
link_with : [libcore,
libshared],
- dependencies : [threads,
+ dependencies : [versiondep,
+ threads,
librt,
libseccomp,
libselinux,
include_directories : includes,
link_with : [libcore,
libshared],
- dependencies : [threads,
+ dependencies : [versiondep,
+ threads,
librt,
libseccomp,
libselinux,
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)
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,
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,
systemd_pull_sources,
include_directories : includes,
link_with : [libshared],
- dependencies : [libcurl,
+ dependencies : [versiondep,
+ libcurl,
libz,
libbzip2,
libxz,
systemd_journal_upload_sources,
include_directories : includes,
link_with : [libshared],
- dependencies : [threads,
+ dependencies : [versiondep,
+ threads,
libcurl,
libgnutls,
libxz,
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)
'src/stdio-bridge/stdio-bridge.c',
include_directories : includes,
link_with : [libshared],
+ dependencies : [versiondep],
install_rpath : rootlibexecdir,
install : true)
public_programs += exe
link_with : [libudev_core,
libsystemd_network,
libudev_static],
- dependencies : [threads,
+ dependencies : [versiondep,
+ threads,
libkmod,
libidn,
libacl,
link_with : [libudev_core,
libsystemd_network,
libudev_static],
- dependencies : [threads,
+ dependencies : [versiondep,
+ threads,
libkmod,
libidn,
libacl,
executable('systemd-shutdown',
systemd_shutdown_sources,
include_directories : includes,
- link_with : [libshared],
+ link_with : [libcore_shared,
+ libshared],
dependencies : [libmount],
install_rpath : rootlibexecdir,
install : true,
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
'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)
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,
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
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())
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()
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'])
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',
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')
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
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+
%{_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}
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"
"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 ""
"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."
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"
#: 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"
#: 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"
#: 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"
#: 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"
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"
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"
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"
#: 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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
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"
#: 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 "全ユーザへのメッセージを設定するには認証が必要です。"
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"
"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)'のプロパティを設定するには認証が必要です。"
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"
"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."
"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ę"
"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ę."
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"
"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."
"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"
"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)'."
"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)”."
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"
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"
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 ]
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
-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
--json)
comps=$( busctl --json=help 2>/dev/null )
;;
+ --destination)
+ comps=$( __get_busnames $mode )
+ ;;
esac
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
return 0
[BUSNAME]='status monitor capture tree'
[OBJECT]='introspect'
[METHOD]='call'
+ [EMIT]='emit'
[PROPERTY_GET]='get-property'
[PROPERTY_SET]='set-property'
)
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)
__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)
-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)
;;
--field|-F)
comps=$(journalctl --fields | sort 2>/dev/null)
- ;;
+ ;;
--machine|-M)
comps=$( __get_machines )
;;
__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 () {
--- /dev/null
+# 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
{-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]' \
{-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' \
#include "sd-daemon.h"
#include "alloc-util.h"
+#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "log.h"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
+#include "util.h"
static char** arg_listen = NULL;
static bool arg_accept = false;
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
_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);
#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"
bool memory_deny_write_execute;
bool no_new_privileges;
char *notify_access;
+ bool protect_hostname;
bool private_devices;
bool private_mounts;
uint64_t restrict_namespaces;
bool restrict_realtime;
+ bool restrict_suid_sgid;
char *root_directory;
char *root_image;
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;
.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,
.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",
{ "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) },
{ "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) },
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));
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
+#include <unistd.h>
#include "sd-bus.h"
#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"
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);
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. */
}
static void free_host_info(struct host_info *hi) {
-
if (!hi)
return;
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);
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);
}
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;
}
(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;
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);
}
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;
/* 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;
/* 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);
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');
" 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"
ARG_NO_PAGER,
ARG_MAN,
ARG_GENERATORS,
+ ARG_ITERATIONS,
};
static const struct option options[] = {
{ "generators", optional_argument, NULL, ARG_GENERATORS },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
+ { "iterations", required_argument, NULL, ARG_ITERATIONS },
{}
};
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;
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.");
/* 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"
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
const char *value;
if (validate_device(device) == 0) {
- unlink(saved);
+ (void) unlink(saved);
return 0;
}
/* 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;
/* 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;
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;
}
#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
(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
#include <unistd.h>
#include "async.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "log.h"
#include "macro.h"
} 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;
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) {
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;
}
/* 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;
}
}
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;
}
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");
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");
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))
/* 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)
}
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) {
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;
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;
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;
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;
}
}
- 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) {
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;
}
}
#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);
_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);
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 */
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;
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",
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);
/* 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);
#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,
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;
int flags,
mode_t mode,
unsigned chattr_flags,
+ unsigned chattr_mask,
CopyFlags copy_flags,
copy_progress_bytes_t progress_bytes,
void *userdata) {
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) {
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;
const char *to,
mode_t mode,
unsigned chattr_flags,
+ unsigned chattr_mask,
CopyFlags copy_flags,
copy_progress_bytes_t progress_bytes,
void *userdata) {
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)
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);
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;
}
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);
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);
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);
/* 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)
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)
r = -errno;
}
- unlink(p);
+ (void) unlink(p);
return r;
}
--- /dev/null
+/* 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);
+}
#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);
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;
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);
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
+#include "hexdecoct.h"
#include "log.h"
#include "macro.h"
#include "missing.h"
int read_one_line_file(const char *fn, char **line) {
_cleanup_fclose_ FILE *f = NULL;
- int r;
assert(fn);
assert(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) {
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)) {
* 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;
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) {
* 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;
*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) {
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;
+}
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
+#include <sys/stat.h>
#include <sys/types.h>
#include "macro.h"
} 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);
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);
}
int safe_fgetc(FILE *f, char *ret);
+
+int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line);
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <linux/falloc.h>
#include <linux/magic.h>
#include <time.h>
#include <unistd.h>
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;
}
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);
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);
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;
/* 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);
#include <sys/types.h>
#include <unistd.h>
+#include "errno-util.h"
#include "time-util.h"
-#include "util.h"
int unlink_noerrno(const char *path);
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);
#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 */
#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"
#include "fileio.h"
#include "hashmap.h"
#include "macro.h"
+#include "memory-util.h"
#include "mempool.h"
#include "process-util.h"
#include "random-util.h"
#include "siphash24.h"
#include "string-util.h"
#include "strv.h"
-#include "util.h"
#if ENABLE_DEBUG_HASHMAP
#include <pthread.h>
}
unsigned internal_hashmap_size(HashmapBase *h) {
-
if (!h)
return 0;
}
unsigned internal_hashmap_buckets(HashmapBase *h) {
-
if (!h)
return 0;
if (cache) {
free(cache->keys.ptr);
free(cache->values.ptr);
- free(cache);
}
- return NULL;
+ return mfree(cache);
}
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)
#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);
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;
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) {
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);
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;
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 */
*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) {
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);
#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) {
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);
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);
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);
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:
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);
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
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;
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;
#include "sd-messages.h"
#include "alloc-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "format-util.h"
#include "io-util.h"
#include "terminal-util.h"
#include "time-util.h"
#include "utf8.h"
-#include "util.h"
#define SNDBUF_SIZE (8*1024*1024)
return r;
}
-_printf_(10,0)
-static int log_object_internalv(
+int log_object_internalv(
int level,
int error,
const char *file,
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);
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(
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,
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) \
--- /dev/null
+#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
--- /dev/null
+/* 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));
+}
#include "env-util.h"
#include "macro.h"
+#include "memory-util.h"
#include "mempool.h"
#include "process-util.h"
#include "util.h"
env-util.h
errno-list.c
errno-list.h
+ errno-util.h
escape.c
escape.h
ether-addr-util.c
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
macro.h
memfd-util.c
memfd-util.h
+ memory-util.c
+ memory-util.h
mempool.c
mempool.h
missing.h
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
ratelimit.h
raw-clone.h
raw-reboot.h
- refcnt.h
replace-var.c
replace-var.h
rlimit-util.c
socket-label.c
socket-util.c
socket-util.h
+ sort-util.c
+ sort-util.h
sparse-endian.h
special.h
stat-util.c
#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
#define SO_PEERGROUPS 59
#endif
+#ifndef SO_BINDTOIFINDEX
+#define SO_BINDTOIFINDEX 62
+#endif
+
#ifndef SOL_NETLINK
#define SOL_NETLINK 270
#endif
#include <sys/stat.h>
#include "alloc-util.h"
+#include "format-util.h"
#include "fs-util.h"
#include "macro.h"
#include "mkdir.h"
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include "fileio.h"
#include "ordered-set.h"
#include "strv.h"
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);
+}
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include <stdio.h>
+
#include "hashmap.h"
typedef struct OrderedSet OrderedSet;
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)); )
#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"
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;
}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
#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"
#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;
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 */
log_close();
/* Make sure nobody waits for us on a socket anymore */
- close_all_fds(NULL, 0);
+ (void) close_all_fds(NULL, 0);
sync();
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",
#include <sys/resource.h>
#include <sys/types.h>
+#include "alloc-util.h"
#include "format-util.h"
#include "ioprio.h"
#include "macro.h"
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);
(pid) = 0; \
_pid_; \
})
+
+int cpus_in_affinity_mask(void);
# 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__)
"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;
+++ /dev/null
-/* 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);
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. */
#include <sys/stat.h>
-#include "util.h"
+#include "errno-util.h"
typedef enum RemoveFlags {
REMOVE_ONLY_DIRECTORIES = 1 << 0,
/* 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>
#endif
#include "alloc-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "log.h"
#include "macro.h"
#include "selinux-util.h"
#include "stdio-util.h"
#include "time-util.h"
-#include "util.h"
#if HAVE_SELINUX
DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon);
#include <sys/mman.h>
#include "macro.h"
+#include "memory-util.h"
#include "sigbus.h"
-#include "util.h"
#define SIGBUS_QUEUE_MAX 64
}
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);
#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"
#include "strv.h"
#include "user-util.h"
#include "utf8.h"
-#include "util.h"
#if ENABLE_IDN
# define IDN_FLAGS NI_IDN
}
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;
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);
}
}
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);
+}
return 0;
}
+
+int socket_bind_to_ifname(int fd, const char *ifname);
+int socket_bind_to_ifindex(int fd, int ifindex);
--- /dev/null
+#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;
+}
--- /dev/null
+/* 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); \
+ })
/* 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"
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;
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
+#include <fcntl.h>
#include <stdbool.h>
#include <stddef.h>
#include <sys/stat.h>
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
#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))
#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
#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; \
#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) {
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);
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;
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;
/* 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);
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);
#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;
#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_;
#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"
}
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;
}
}
free(c);
+
+ if (l > SIZE_MAX / 2)
+ return -ENOMEM;
+
l *= 2;
}
}
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;
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;
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);
char *getusername_malloc(void) {
const char *e;
- e = getenv("USER");
+ e = secure_getenv("USER");
if (e)
return strdup(e);
}
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;
if (r != ERANGE)
break;
+ if (bufsize > LONG_MAX/2) /* overflow check */
+ return NULL;
+
bufsize *= 2;
}
}
if (r != ERANGE)
break;
+ if (bufsize > LONG_MAX/2) /* overflow check */
+ return NULL;
+
bufsize *= 2;
}
}
/* 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;
}
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;
}
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;
}
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;
}
}
/* 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)
assert(str);
- len = utf8_encoded_expected_len(str);
+ len = utf8_encoded_expected_len(str[0]);
switch (len) {
case 1:
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 ||
while (*p) {
int len;
- len = utf8_encoded_valid_unichar(p);
+ len = utf8_encoded_valid_unichar(p, (size_t) -1);
if (len < 0)
return NULL;
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;
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);
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;
}
/* 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;
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;
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) {
#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"
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;
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;
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);
/* 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";
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_;
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;
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);
/* https://wiki.freebsd.org/bhyve */
{ "bhyve bhyve ", VIRTUALIZATION_BHYVE },
{ "QNXQVMBSQG", VIRTUALIZATION_QNX },
+ /* https://projectacrn.org */
+ { "ACRNACRNACRN", VIRTUALIZATION_ACRN },
};
uint32_t eax, ebx, ecx, edx;
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()
{ "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;
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. */
/* 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. */
[VIRTUALIZATION_PARALLELS] = "parallels",
[VIRTUALIZATION_BHYVE] = "bhyve",
[VIRTUALIZATION_QNX] = "qnx",
+ [VIRTUALIZATION_ACRN] = "acrn",
[VIRTUALIZATION_VM_OTHER] = "vm-other",
[VIRTUALIZATION_SYSTEMD_NSPAWN] = "systemd-nspawn",
[VIRTUALIZATION_OPENVZ] = "openvz",
[VIRTUALIZATION_DOCKER] = "docker",
[VIRTUALIZATION_RKT] = "rkt",
+ [VIRTUALIZATION_WSL] = "wsl",
[VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
};
VIRTUALIZATION_PARALLELS,
VIRTUALIZATION_BHYVE,
VIRTUALIZATION_QNX,
+ VIRTUALIZATION_ACRN,
VIRTUALIZATION_VM_OTHER,
VIRTUALIZATION_VM_LAST = VIRTUALIZATION_VM_OTHER,
VIRTUALIZATION_OPENVZ,
VIRTUALIZATION_DOCKER,
VIRTUALIZATION_RKT,
+ VIRTUALIZATION_WSL,
VIRTUALIZATION_CONTAINER_OTHER,
VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER,
}
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;
#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"
#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;
#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) {
"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"
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;
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;
}
}
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);
if (r < 0)
return r;
- r = acquire_esp();
+ r = acquire_path();
if (r < 0)
return r;
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);
if (r < 0)
return r;
- r = acquire_esp();
+ r = acquire_path();
if (r < 0)
return r;
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;
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:
#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,
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 */
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;
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;
}
}
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);
}
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;
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++;
}
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) {
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);
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;
"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;
}
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);
}
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);
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;
_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"))
}
/* extend array */
- t = realloc(order, (n + 1) * sizeof(uint16_t));
+ t = reallocarray(order, n + 1, sizeof(uint16_t));
if (!t)
return -ENOMEM;
order = t;
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);
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;
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;
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;
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);
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 },
{}
};
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:
}
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 */
} 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;
}
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;
}
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.");
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;
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);
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;
}
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;
/* 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"
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;
/* 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);
}
}
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;
}
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;
}
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;
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;
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;
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, ©, &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,
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;
}
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);
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);
}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
#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;
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;
}
/* 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);
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 = '''
boot.c
console.c
shim.c
+ crc32.c
'''.split()
stub_sources = '''
#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);
}
/* 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);
}
/* 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);
}
/* 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)
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);
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;
}
EFI_STATUS err;
err = efivar_get(name, &val);
- if (!EFI_ERROR(err))
+ if (!EFI_ERROR(err) && i)
*i = Atoi(val);
return err;
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;
}
#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";
}
#define UINTN_MAX (~(UINTN)0)
#define INTN_MAX ((INTN)(UINTN_MAX>>1))
+
+#define TAKE_PTR(ptr) \
+ ({ \
+ typeof(ptr) _ptr_ = (ptr); \
+ (ptr) = NULL; \
+ _ptr_; \
+ })
/* 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"
#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 {
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;
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;
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;
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;
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;
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)
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) {
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;
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)
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"
" 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
ARG_AUGMENT_CREDS,
ARG_WATCH_BIND,
ARG_JSON,
+ ARG_DESTINATION,
ARG_PID,
ARG_SENDER_PID,
ARG_RECEIVER_PID,
{ "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},
arg_well_known_names = parse_boolean(optarg);
break;
+ case ARG_DESTINATION:
+ arg_destination = optarg;
+ break;
+
case '?':
return -EINVAL;
{ "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 },
" --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"
#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 {
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)) {
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)
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)
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) {
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;
static int automount_start(Unit *u) {
Automount *a = AUTOMOUNT(u);
- Unit *trigger;
int r;
assert(a);
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;
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;
#include "bpf-program.h"
#include "fd-util.h"
#include "ip-address-access.h"
+#include "memory-util.h"
#include "missing_syscall.h"
#include "unit.h"
#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"
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;
_exit(ret);
}
- r = unit_watch_pid(UNIT(n), pid);
+ r = unit_watch_pid(UNIT(n), pid, true);
if (r < 0)
goto fail;
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;
}
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;
#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"
#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
.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,
CGroupDeviceAllow *a;
IPAddressAccessItem *iaai;
char u[FORMAT_TIMESPAN_MAX];
+ char v[FORMAT_TIMESPAN_MAX];
assert(c);
assert(f);
"%sCPUShares=%" PRIu64 "\n"
"%sStartupCPUShares=%" PRIu64 "\n"
"%sCPUQuotaPerSecSec=%s\n"
+ "%sCPUQuotaPeriodSec=%s\n"
"%sIOWeight=%" PRIu64 "\n"
"%sStartupIOWeight=%" PRIu64 "\n"
"%sBlockIOWeight=%" PRIu64 "\n"
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,
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];
(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);
}
(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");
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;
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);
}
}
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);
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)
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;
}
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;
/* Common */
uint64_t tasks_max;
-
- bool delegate;
- CGroupMask delegate_controllers;
-
- CGroupMask disable_controllers;
};
/* Used when querying IP accounting data */
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);
#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;
* 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;
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)
}
}
- 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;
(!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 */
}
#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);
#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);
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),
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)
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;
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),
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);
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);
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;
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)) {
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;
}
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;
}
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
_cleanup_free_ char *joined = NULL;
- bool invert = !whitelist;
char **s;
if (strv_isempty(l)) {
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;
}
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)
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;
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;
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) {
}
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;
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;
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) {
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;
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) {
}
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(
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) {
}
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;
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;
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),
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;
}
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <stdio_ext.h>
+#include <fcntl.h>
#include "alloc-util.h"
#include "async.h"
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;
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;
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),
UnitWriteFlags flags,
sd_bus_error *error) {
- const int *status, *signal;
+ const int32_t *status, *signal;
size_t sz_status, sz_signal, i;
int r;
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);
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;
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),
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;
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);
}
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);
}
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);
}
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);
}
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,
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);
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);
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) {
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;
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),
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);
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)
(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;
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(
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)
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);
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);
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;
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;
}
#include "stat-util.h"
#include "string-util.h"
#include "swap.h"
+#include "udev-util.h"
#include "unit-name.h"
#include "unit.h"
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));
}
}
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
assert(dev);
+ if (device_is_renaming(dev) > 0)
+ return false;
+
if (sd_device_get_property_value(dev, "SYSTEMD_READY", &ready) < 0)
return true;
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);
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");
#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"
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;
* 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. */
"%s: %s", message, reason);
}
-int emergency_action(
+void emergency_action(
Manager *m,
EmergencyAction action,
EmergencyActionFlags options,
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);
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;
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;
}
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:
default:
assert_not_reached("Unknown emergency action");
}
-
- return -ECANCELED;
}
static const char* const emergency_action_table[_EMERGENCY_ACTION_MAX] = {
#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_;
#include "log.h"
#include "macro.h"
#include "manager.h"
+#include "memory-util.h"
#include "missing.h"
#include "mkdir.h"
#include "namespace.h"
#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)
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
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);
x = strappend("HOME=", home);
if (!x)
return -ENOMEM;
+
+ path_simplify(x + 5, true);
our_env[n_env++] = x;
}
x = strappend("SHELL=", shell);
if (!x)
return -ENOMEM;
+
+ path_simplify(x + 6, true);
our_env[n_env++] = x;
}
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))
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;
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
* 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;
if (r < 0)
goto fail;
- pp = strjoin(private_root, "/", *rt);
+ pp = path_join(private_root, *rt);
if (!pp) {
r = -ENOMEM;
goto fail;
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;
}
.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,
};
.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,
};
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,
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;
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 */
}
}
+ 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;
USER_PROCESS,
username);
- if (context->user) {
+ if (uid_is_valid(uid)) {
r = chown_terminal(STDIN_FILENO, uid);
if (r < 0) {
*exit_status = EXIT_STDIN;
}
}
- 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.");
}
}
}
+ 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);
}
if (needs_setuid) {
- if (context->user) {
+ if (uid_is_valid(uid)) {
r = enforce_user(context, uid);
if (r < 0) {
*exit_status = EXIT_USER;
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;
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;
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) {
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);
}
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));
}
"%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 : "/",
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);
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;
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) {
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);
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) {
}
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;
}
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);
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) {
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;
}
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;
}
#include "missing_resource.h"
#include "namespace.h"
#include "nsflags.h"
+#include "time-util.h"
#define EXEC_STDIN_DATA_MAX (64U*1024U*1024U)
/* 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 */
};
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. */
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;
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];
nsec_t timer_slack_nsec;
- bool stdio_as_fds;
-
char *tty_path;
bool tty_reset;
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
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;
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;
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 */
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) {
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);
***/
#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include "alloc-util.h"
#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"
#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"
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
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 {
$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute)
$1.RestrictNamespaces, config_parse_restrict_namespaces, 0, offsetof($1, exec_context)
$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime)
+$1.RestrictSUIDSGID, config_parse_bool, 0, offsetof($1, exec_context.restrict_suid_sgid)
$1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)
$1.LockPersonality, config_parse_bool, 0, offsetof($1, exec_context.lock_personality)',
`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictNamespaces, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictRealtime, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
+$1.RestrictSUIDSGID, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.LockPersonality, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
$1.LimitCPU, config_parse_rlimit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
$1.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)
$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')
$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)
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)
#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"
#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) {
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;
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;
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)
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
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)))
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);
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);
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);
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;
}
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;
}
_cleanup_free_ char *k = NULL, *n = NULL;
Unit *u = userdata;
char **s = data;
- const char *e;
int r;
assert(filename);
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;
}
#include "loopback-setup.h"
#include "missing.h"
#include "netlink-util.h"
+#include "time-util.h"
#define LOOPBACK_SETUP_TIMEOUT_USEC (5 * USEC_PER_SEC)
#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"
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}
# 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}
# %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 \
# %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}
#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"
_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) {
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;
*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;
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));
(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);
#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"
#include "umask-util.h"
#include "unit-name.h"
#include "user-util.h"
-#include "util.h"
#include "virt.h"
#include "watchdog.h"
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;
}
"MAINPID",
"MANAGERPID",
"NOTIFY_SOCKET",
+ "PIDFILE",
"REMOTE_ADDR",
"REMOTE_PORT",
"SERVICE_RESULT",
}
/* 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));
}
/* 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) {
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);
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));
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;
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;
"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;
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;
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;
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));
/* 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;
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;
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));
}
}
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;
}
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");
}
(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);
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;
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;
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",
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",
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,
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;
}
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;
* 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)
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);
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);
# 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
job.h
kill.c
kill.h
- killall.c
- killall.h
kmod-setup.c
kmod-setup.h
load-dropin.c
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
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,
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],
#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 {
#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"
#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,
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;
}
static int mount_add_device_dependencies(Mount *m) {
- bool device_wants_mount;
UnitDependencyMask mask;
MountParameters *p;
UnitDependency dep;
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
/* 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;
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;
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;
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;
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);
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;
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) {
#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)
READONLY,
READWRITE,
TMPFS,
+ READWRITE_IMPLICIT, /* Should have the lowest priority. */
+ _MOUNT_MODE_MAX,
} MountMode;
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 */
/* 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 */
* 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);
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;
.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,
};
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;
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;
/* 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;
}
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;
}
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;
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;
}
(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);
}
_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;
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;
*(m++) = (MountEntry) {
.path_const = "/dev",
.mode = PRIVATE_DEV,
+ .flags = DEV_MOUNT_OPTIONS,
};
}
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 */
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.
}
/* 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;
for (m = mounts; m < mounts + n_mounts; m++)
mount_entry_done(m);
+ free(mounts);
+
return r;
}
.source = TAKE_PTR(s),
.destination = TAKE_PTR(d),
.read_only = item->read_only,
+ .nosuid = item->nosuid,
.recursive = item->recursive,
.ignore_enoent = item->ignore_enoent,
};
char *t;
t = strjoina(a, "/tmp");
- rmdir(t);
- rmdir(a);
+ (void) rmdir(t);
+ (void) rmdir(a);
free(a);
return r;
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) {
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;
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;
};
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_;
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;
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;
(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;
}
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;
}
#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"
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;
}
}
#include "selinux-setup.h"
#include "selinux-util.h"
#include "string-util.h"
+#include "time-util.h"
#include "util.h"
#if HAVE_SELINUX
#include <errno.h>
#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include "sd-messages.h"
}
static int service_set_main_pid(Service *s, pid_t pid) {
- pid_t ppid;
-
assert(s);
if (pid <= 1)
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;
}
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);
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);
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;
}
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;
}
if (r < 0)
return r;
- our_env = new0(char*, 9);
+ our_env = new0(char*, 10);
if (!our_env)
return -ENOMEM;
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);
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;
if (s->pid_file)
(void) unlink(s->pid_file);
+ /* Reset TTY ownership if necessary */
+ exec_context_revert_tty(&s->exec_context);
+
return;
fail:
}
}
+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;
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;
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;
* 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;
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;
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;
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;
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) {
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);
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);
}
}
}
/* 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 */
unsigned n_restarts;
bool flush_n_restarts;
- bool exec_fd_hot;
};
extern const UnitVTable service_vtable;
/* 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"
#include <stdio_ext.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "dirent-util.h"
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,
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");
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");
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);
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;
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;
_exit(EXIT_SUCCESS);
}
- r = unit_watch_pid(UNIT(s), pid);
+ r = unit_watch_pid(UNIT(s), pid, true);
if (r < 0)
goto fail;
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;
}
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. */
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;
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;
}
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);
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");
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");
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
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;
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;
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;
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;
# (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@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
#include <errno.h>
#include "alloc-util.h"
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;
}
"%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) {
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
}
}
- 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;
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;
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;
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) {
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] = {
bool persistent;
bool wake_system;
bool remain_after_elapse;
+ bool on_clock_change;
+ bool on_timezone_change;
char *stamp_path;
};
}
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) {
}
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) {
}
}
-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;
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;
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;
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");
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);
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);
REENABLE_WARNING;
}
-int unit_start_limit_test(Unit *u) {
+int unit_test_start_limit(Unit *u) {
const char *reason;
assert(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) {
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;
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;
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);
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.");
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));
}
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) {
/* 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) {
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));
}
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);
/* 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;
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",
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;
}
}
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);
/* 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) {
if (!p)
return -ENOMEM;
- path = path_simplify(p, false);
+ path = path_simplify(p, true);
if (!path_is_normalized(path))
return -EPERM;
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) {
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",
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;
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);
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);
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);
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, ...) \
/* 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 */
#include "log.h"
#include "macro.h"
#include "main-func.h"
+#include "memory-util.h"
#include "missing.h"
#include "mkdir.h"
#include "parse-util.h"
#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))
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)
error:
if (temp) {
- unlink(temp);
+ (void) unlink(temp);
log_debug("Removed temporary file %s", temp);
}
return r;
if (unlink_path) {
log_debug("Removed temporary file %s", path);
- unlink(path);
+ (void) unlink(path);
}
return r;
#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"
/* 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"
"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),
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);
#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"
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
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"))
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 {
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;
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;
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"
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <unistd.h>
+
#include "alloc-util.h"
#include "generator.h"
#include "mkdir.h"
#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;
#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"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
-#include "util.h"
static const char prefixes[] =
"/etc\0"
_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;
#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"
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);
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);
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;
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);
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);
"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
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)
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"))
}
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) {
}
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);
/* 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);
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
/* 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"
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size > 65536)
+ return 0;
+
/* This triggers client_receive_advertise */
fuzz_client(data, size, false);
--- /dev/null
+[libfuzzer]
+max_len = 65536
/* 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) {
--- /dev/null
+/* 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;
+}
--- /dev/null
+[libfuzzer]
+max_len = 65535
--- /dev/null
+/* 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;
+}
#include <linux/sockios.h>
#include <sys/ioctl.h>
+#include <unistd.h>
#include "fd-util.h"
#include "fuzz.h"
StdoutStream *stream;
int v;
- if (size == 0)
+ if (size == 0 || size > 65536)
return 0;
if (!getenv("SYSTEMD_LOG_LEVEL"))
--- /dev/null
+[libfuzzer]
+max_len = 65536
_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);
--- /dev/null
+[libfuzzer]
+max_len = 2048
_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);
--- /dev/null
+[libfuzzer]
+max_len = 2048
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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;
+}
assert_se(g);
unit_dump(u, g, "");
+ manager_dump(m, g, ">>>");
return 0;
}
libshared],
[]],
+ [['src/fuzz/fuzz-udev-database.c'],
+ [libshared],
+ []],
+
[['src/fuzz/fuzz-udev-rules.c'],
[libudev_core,
libudev_static,
[['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],
+ []],
]
#include "efivars.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "fstab-util.h"
#include "generator.h"
#include "gpt.h"
return generator_add_symlink(arg_dest, SPECIAL_SWAP_TARGET, "wants", name);
}
-#if ENABLE_EFI
static int add_automount(
const char *id,
const char *what,
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);
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;
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",
120 * USEC_PER_SEC);
}
#else
-static int add_esp(DissectedPartition *p) {
+static int add_esp(DissectedPartition *p, bool has_xbootldr) {
return 0;
}
#endif
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);
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;
_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;
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;
}
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",
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.");
}
}
#include <errno.h>
#include <stdio.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "fstab-util.h"
#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;
#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"
#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"
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"
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <fcntl.h>
+
#include "alloc-util.h"
#include "build.h"
#include "curl-util.h"
#include "sd-event.h"
#include "hashmap.h"
+#include "time-util.h"
typedef struct CurlGlue CurlGlue;
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);
}
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <getopt.h>
+#include <locale.h>
#include "sd-event.h"
#include "sd-id128.h"
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);
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);
#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"
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;
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;
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);
}
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;
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;
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);
}
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <getopt.h>
+#include <locale.h>
#include "alloc-util.h"
#include "btrfs-util.h"
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)) {
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");
}
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);
}
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <getopt.h>
+#include <locale.h>
#include "sd-event.h"
#include "sd-id128.h"
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);
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);
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <fcntl.h>
+#include <sys/stat.h>
#include <sys/xattr.h>
#include "alloc-util.h"
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");
}
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)
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);
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;
}
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)
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <getopt.h>
+#include <locale.h>
#include "sd-event.h"
#include "sd-id128.h"
local = l;
}
- if (isempty(local) || streq(local, "-"))
- local = NULL;
+ local = empty_or_dash_to_null(local);
if (local) {
r = tar_strip_suffixes(local, &ll);
local = l;
}
- if (isempty(local) || streq(local, "-"))
- local = NULL;
+ local = empty_or_dash_to_null(local);
if (local) {
r = raw_strip_suffixes(local, &ll);
/* 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;
#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"
#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))
#include <microhttpd.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include "sd-bus.h"
const char *header;
int r, code, fd;
_cleanup_free_ char *hostname = NULL;
+ bool chunked = false;
size_t len;
assert(connection);
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;
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;
int writer_write(Writer *w,
struct iovec_wrapper *iovw,
dual_timestamp *ts,
+ sd_id128_t *boot_id,
bool compress,
bool seal) {
int r;
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) {
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)
int writer_write(Writer *s,
struct iovec_wrapper *iovw,
dual_timestamp *ts,
+ sd_id128_t *boot_id,
bool compress,
bool seal);
#include "alloc-util.h"
#include "def.h"
+#include "errno-util.h"
#include "escape.h"
#include "fd-util.h"
#include "journal-file.h"
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:
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,
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 = {
char *hostname = NULL;
fd2 = accept_connection("raw", fd, &addr, &hostname);
+ if (fd2 == -EAGAIN)
+ return 0;
if (fd2 < 0)
return fd2;
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;
}
#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/",
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" */
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;
}
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;
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);
}
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);
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;
#pragma once
#include <stdbool.h>
+#include <stdio.h>
#include "sd-id128.h"
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <unistd.h>
#if HAVE_XZ
#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));
#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;
#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"
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)
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);
#pragma once
#include <inttypes.h>
+#include <sys/uio.h>
#if HAVE_GCRYPT
# include <gcrypt.h>
#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" */
#include "sd-journal.h"
#include "alloc-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "io-util.h"
#include "memfd-util.h"
#include "stdio-util.h"
#include "string-util.h"
#include "tmpfile-util.h"
-#include "util.h"
#define SNDBUF_SIZE (8*1024*1024)
#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 {
* 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;
#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"
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;
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);
if (offset)
*offset = off;
- return 0;
+ return 1;
}
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"
ARG_VERIFY_KEY,
ARG_DISK_USAGE,
ARG_AFTER_CURSOR,
+ ARG_CURSOR_FILE,
ARG_SHOW_CURSOR,
ARG_USER_UNIT,
ARG_LIST_CATALOG,
{ "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' },
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:
arg_cursor = optarg;
break;
+ case ARG_CURSOR_FILE:
+ arg_cursor_file = optarg;
+ break;
+
case ARG_AFTER_CURSOR:
arg_after_cursor = optarg;
break;
safe_close(fd);
if (k) {
- unlink(k);
+ (void) unlink(k);
free(k);
}
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;
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");
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) {
/* 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)
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;
}
}
- 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;
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;
#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"
#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"
#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
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-#include "util.h"
+#include "time-util.h"
typedef struct JournalRateLimit JournalRateLimit;
#include "journald-stream.h"
#include "list.h"
#include "prioq.h"
+#include "time-util.h"
typedef enum Storage {
STORAGE_AUTO,
#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"
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)
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");
/* 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);
#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;
#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"
#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);
/* 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
/* 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"
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);
#include "sd-journal.h"
+#include "chattr-util.h"
#include "log.h"
#include "parse-util.h"
#include "rm-rf.h"
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);
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);
#include "sd-journal.h"
#include "alloc-util.h"
+#include "chattr-util.h"
#include "io-util.h"
#include "journal-file.h"
#include "journal-vacuum.h"
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();
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);
#include "sd-journal.h"
#include "alloc-util.h"
+#include "chattr-util.h"
#include "journal-file.h"
#include "journal-internal.h"
#include "log.h"
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;
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);
#include <stdio.h>
#include <unistd.h>
+#include "chattr-util.h"
#include "fd-util.h"
#include "io-util.h"
#include "journal-file.h"
}
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];
assert_se(mkdtemp(t));
assert_se(chdir(t) >= 0);
+ (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL);
log_info("Generating...");
#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;
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);
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);
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;
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);
--- /dev/null
+#!/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
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
COMMAND="$1"
KERNEL_VERSION="$2"
-BOOT_DIR_ABS="$3"
+ENTRY_DIR_ABS="$3"
KERNEL_IMAGE="$4"
INITRD_OPTIONS_START="5"
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"
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
}
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
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" || {
#
# 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
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
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
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
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
;;
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
fi
done
- rm -rf "$BOOT_DIR_ABS"
+ [ "$KERNEL_INSTALL_VERBOSE" -gt 0 ] && \
+ echo "Removing $ENTRY_DIR_ABS"
+
+ rm -rf "$ENTRY_DIR_ABS"
((ret+=$?))
;;
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)
#include "siphash24.h"
#include "sparse-endian.h"
#include "stdio-util.h"
+#include "udev-util.h"
#include "virt.h"
#define SYSTEMD_PEN 43793
/* 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);
}
}
/* each 0 if unset */
be32_t address;
be32_t server_address;
- be32_t router;
be32_t next_server;
bool have_subnet_mask;
bool have_broadcast;
be32_t broadcast;
+ struct in_addr *router;
+ size_t router_size;
+
struct in_addr *dns;
size_t dns_size;
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(ð_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 */
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 */
.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);
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) {
#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) {
#include "dhcp-internal.h"
#include "hashmap.h"
#include "log.h"
-#include "util.h"
+#include "time-util.h"
typedef struct DHCPClientId {
size_t length;
#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;
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);
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;
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);
}
#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);
***/
#include "log.h"
+#include "time-util.h"
#include "sd-ndisc.h"
#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"
#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"
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;
}
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;
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;
}
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) {
size++;
}
- *ret = TAKE_PTR(addresses);
+ *ret = size > 0 ? TAKE_PTR(addresses) : NULL;
return size;
}
fprintf(f, "%s=", key);
for (i = 0; i < size; i++) {
+ char sbuf[INET_ADDRSTRLEN];
struct in_addr dest, gw;
uint8_t length;
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);
#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
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);
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);
/* 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"))
#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)
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;
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;
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,
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) {
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;
}
assert(client);
buflen = next_datagram_size_fd(fd);
+ if (buflen == -ENETDOWN)
+ return 0;
if (buflen < 0)
return buflen;
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,
#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"
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) {
}
free(lease->root_path);
+ free(lease->router);
free(lease->timezone);
free(lease->hostname);
free(lease->domainname);
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);
if (!addresses)
return -ENOMEM;
- filter_bogus_addresses(addresses, &n_addresses);
-
free(*ret);
*ret = addresses;
*n_ret = n_addresses;
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:
if (!lease)
return -ENOMEM;
- lease->router = INADDR_ANY;
lease->n_ref = 1;
*ret = lease;
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;
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)
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);
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);
}
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) {
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;
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");
#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)
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);
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);
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;
}
#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
#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)
#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;
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);
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");
#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];
#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 = {
#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"
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);
#include <netinet/icmp6.h>
#include <arpa/inet.h>
+#include <unistd.h>
#include "sd-radv.h"
#include <netinet/icmp6.h>
#include <arpa/inet.h>
+#include <unistd.h>
#include "sd-ndisc.h"
#include "bus-internal.h"
#include "bus-socket.h"
#include "fd-util.h"
+#include "namespace-util.h"
#include "process-util.h"
#include "util.h"
}
}
- bus->rqueue[bus->rqueue_size++] = m;
+ bus->rqueue[bus->rqueue_size++] = bus_message_ref_queued(m, bus);
if (ret_slot)
*ret_slot = s;
"s",
e);
}
+
int bus_add_match_internal_async(
sd_bus *bus,
sd_bus_slot **ret_slot,
/* 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"
#include "alloc-util.h"
#include "bus-error.h"
#include "errno-list.h"
+#include "errno-util.h"
#include "string-util.h"
#include "util.h"
if (slash)
return false;
- return true;
+ return (q - p) <= BUS_PATH_SIZE_MAX;
}
char* object_path_startswith(const char *a, const char *b) {
dot = false;
}
- if (q - p > 255)
+ if (q - p > SD_BUS_MAXIMUM_NAME_LENGTH)
return false;
if (dot)
dot = false;
}
- if (q - p > 255)
+ if (q - p > SD_BUS_MAXIMUM_NAME_LENGTH)
return false;
if (dot)
return false;
}
- if (q - p > 255)
+ if (q - p > SD_BUS_MAXIMUM_NAME_LENGTH)
return false;
return true;
#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;
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);
};
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);
};
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
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);
};
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;
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;
union sockaddr_union sockaddr;
socklen_t sockaddr_size;
- char *kernel;
- char *machine;
pid_t nspid;
+ char *machine;
+
+ char *kernel;
sd_id128_t server_id;
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;
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
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;
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;
#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
#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);
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 (;;) {
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
}
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
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;
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;
#include "string-util.h"
#include "strv.h"
#include "user-util.h"
-#include "util.h"
+#include "memory-util.h"
#pragma GCC diagnostic ignored "-Wformat"
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;
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;
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;
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;
#include "fd-util.h"
#include "fileio.h"
#include "hexdecoct.h"
+#include "sort-util.h"
#include "string-util.h"
#include "strv.h"
#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);
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);
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;
/* 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" */
if (!m)
return -ENOMEM;
- m->n_ref = 1;
m->sealed = true;
m->header = header;
m->header_accessible = header_accessible;
m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
}
+ m->n_ref = 1;
m->bus = sd_bus_ref(bus);
+
*ret = TAKE_PTR(m);
return 0;
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;
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;
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);
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;
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);
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);
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);
return -EBADMSG;
if (*p == 0) {
- char *k;
+ _cleanup_free_ char *k = NULL;
size_t l;
/* We found the beginning of the signature
if (!k)
return -ENOMEM;
+ if (!signature_is_valid(k, true))
+ return -EBADMSG;
+
free_and_replace(m->root_container.signature, k);
break;
}
};
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;
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);
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;
const char *path,
sd_bus_error *error) {
- char *prefix;
+ _cleanup_free_ char *prefix = NULL;
+ size_t pl;
int r;
assert(bus);
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)
}
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;
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);
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)
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,
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);
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") &&
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;
}
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;
* 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;
} 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;
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);
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;
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)
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);
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)
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);
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)
const char *path,
const char *interface) {
- char *prefix;
+ _cleanup_free_ char *prefix = NULL;
+ size_t pl;
int r;
assert(bus);
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)
#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);
p += t;
}
- return p - s <= 255;
+ return p - s <= SD_BUS_MAXIMUM_SIGNATURE_LENGTH;
}
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) {
#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"
#include "string-util.h"
#include "user-util.h"
#include "utf8.h"
-#include "util.h"
#define SNDBUF_SIZE (8*1024*1024)
}
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;
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;
b->server_id = peer;
- /* And possibly check the second line, too */
+ /* And possibly check the third line, too */
if (f)
b->can_fds =
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"))
}
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);
}
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;
}
#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 { \
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;
return -ENOMEM;
*b = (sd_bus) {
- .n_ref = REFCNT_INIT,
+ .n_ref = 1,
.input_fd = -1,
.output_fd = -1,
.inotify_fd = -1,
.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;
}
/* 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;
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);
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;
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) {
* 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;
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;
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;
}
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;
}
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;
}
* 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;
}
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:
_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);
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;
}
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;
}
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;
}
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;
}
SD_BUS_ERROR_UNKNOWN_METHOD,
"Unknown method '%s' on interface '%s'.", m->member, m->interface);
}
-
if (r < 0)
return r;
return r;
*ret = TAKE_PTR(m);
-
return 1;
}
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)
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;
}
#include "log.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
static void test_one_address(sd_bus *b,
const char *host,
-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]",
}
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);
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <sys/wait.h>
+#include <unistd.h>
#include "sd-bus.h"
#include "bus-internal.h"
#include "bus-message.h"
#include "bus-util.h"
-#include "refcnt.h"
#include "tests.h"
static bool use_system_bus = false;
_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) {
}
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;
}
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) {
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) {
#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;
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);
#include "bus-util.h"
#include "log.h"
#include "macro.h"
+#include "memory-util.h"
#include "tests.h"
static bool mask[32];
--- /dev/null
+/* 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);
#include "bus-util.h"
#include "log.h"
#include "macro.h"
-#include "util.h"
+#include "memory-util.h"
struct context {
int fds[2];
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),
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 = {};
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);
#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.");
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. */
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);
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <fcntl.h>
+#include <unistd.h>
+
#include "sd-device.h"
#include "alloc-util.h"
#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
Hashmap *match_property;
Set *match_sysname;
Set *match_tag;
- sd_device *match_parent;
+ Set *match_parent;
bool match_allow_uninitialized;
};
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);
}
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);
}
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) {
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;
}
#include "sd-device.h"
+#include "device-private.h"
#include "hashmap.h"
#include "set.h"
#include "time-util.h"
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 */
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);
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_;
#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"
#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;
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;
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;
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;
assert(key);
assert(_major);
assert(_minor);
- assert(_seqnum);
- assert(_action);
value = strchr(key, '=');
if (!value) {
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;
if (minor != 0)
*_minor = minor;
- if (action != _DEVICE_ACTION_INVALID)
- *_action = action;
-
- if (seqnum > 0)
- *_seqnum = seqnum;
-
return 0;
}
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;
}
_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);
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;
}
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;
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;
}
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;
}
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;
if (r < 0)
return r;
- r = device_add_property_internal(ret, "ACTION", action);
+ r = device_set_action(ret, action);
if (r < 0)
return r;
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);
#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);
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);
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_;
.devmode = (mode_t) -1,
.devuid = (uid_t) -1,
.devgid = (gid_t) -1,
+ .action = _DEVICE_ACTION_INVALID,
};
*ret = device;
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);
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);
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) {
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 {
} 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 */
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;
#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;
#include "hashmap.h"
#include "list.h"
#include "macro.h"
+#include "memory-util.h"
#include "missing.h"
#include "prioq.h"
#include "process-util.h"
#include "string-table.h"
#include "string-util.h"
#include "time-util.h"
-#include "util.h"
#define DEFAULT_ACCURACY_USEC (250 * USEC_PER_MSEC)
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;
#include <ctype.h>
#include <stdio.h>
+#include <sys/stat.h>
#include "alloc-util.h"
#include "conf-files.h"
#include "label.h"
#include "mkdir.h"
#include "path-util.h"
+#include "sort-util.h"
#include "strbuf.h"
#include "string-util.h"
#include "strv.h"
error_fclose:
r = -errno;
fclose(t.f);
- unlink(filename_tmp);
+ (void) unlink(filename_tmp);
return r;
}
#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;
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)
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;
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;
}
static int get_invocation_from_keyring(sd_id128_t *ret) {
-
_cleanup_free_ char *description = NULL;
char *d, *p, *g, *u, *e;
unsigned long perms;
if (key == -1) {
/* Keyring support not available? No invocation key stored? */
if (IN_SET(errno, ENOSYS, ENOKEY))
- return 0;
+ return -ENXIO;
return -errno;
}
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) {
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;
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;
#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) {
} 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) {
#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;
#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))
};
struct sd_netlink {
- RefCount n_ref;
+ unsigned n_ref;
int fd;
};
struct sd_netlink_message {
- RefCount n_ref;
+ unsigned n_ref;
sd_netlink *rtnl;
#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;
if (!m)
return -ENOMEM;
- m->n_ref = REFCNT_INIT;
+ m->n_ref = 1;
m->protocol = rtnl->protocol;
m->sealed = false;
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);
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);
}
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;
#include "netlink-internal.h"
#include "netlink-types.h"
#include "netlink-util.h"
-#include "refcnt.h"
#include "socket-util.h"
#include "util.h"
#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>
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 */
[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 },
.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 = {
};
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) },
};
assert(ifindex > 0);
assert(name);
+ if (!ifname_valid(name))
+ return -EINVAL;
+
if (!*rtnl) {
r = sd_netlink_open(rtnl);
if (r < 0)
#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);
(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);
#include "netlink-internal.h"
#include "netlink-types.h"
#include "netlink-util.h"
-#include "refcnt.h"
#include "socket-util.h"
#include "util.h"
return -ENOMEM;
*rtnl = (sd_netlink) {
- .n_ref = REFCNT_INIT,
+ .n_ref = 1,
.fd = -1,
.sockaddr.nl.nl_family = AF_NETLINK,
.original_pid = getpid_cached(),
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);
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <stdio.h>
+
#include "af-list.h"
#include "alloc-util.h"
#include "in-addr-util.h"
#include "alloc-util.h"
#include "fd-util.h"
#include "network-util.h"
+#include "string-table.h"
#include "strv.h"
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);
#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_;
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);
}
#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
*
* 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;
}
/**
* 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);
}
/**
* 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) {
#include "alloc-util.h"
#include "libudev-list-internal.h"
-#include "util.h"
+#include "memory-util.h"
/**
* SECTION:libudev-list
}
/* 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;
#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"
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;
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;
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;
#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"
#include <errno.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#if HAVE_XKBCOMMON
#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;
}
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();
# 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"''
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"
# 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
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 */
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);
#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"
#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"
#include "terminal-util.h"
#include "unit-name.h"
#include "user-util.h"
-#include "util.h"
#include "verbs.h"
static char **arg_property = NULL;
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;
"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;
#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) {
}
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);
}
int manager_process_button_device(Manager *m, sd_device *d) {
- const char *action, *sysname;
+ const char *sysname;
Button *b;
int r;
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)
#include <errno.h>
#include <pwd.h>
#include <string.h>
+#include <sys/stat.h>
#include <unistd.h>
#include "sd-device.h"
#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"
#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) {
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) {
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;
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,
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);
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;
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))
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))
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)) {
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");
}
}
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
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)) {
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;
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)
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;
/* 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);
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(¶meter);
+ 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,
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);
}
void *userdata,
sd_bus_error *error) {
- int b, r;
Manager *m = userdata;
+ bool use_efi;
+ int b, r;
assert(message);
assert(m);
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",
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(
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,
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);
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),
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),
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);
}
&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))
#include <errno.h>
#include <fcntl.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include "alloc-util.h"
free(i->why);
if (i->state_file) {
- unlink(i->state_file);
+ (void) unlink(i->state_file);
free(i->state_file);
}
inhibit_mode_to_string(i->mode));
if (i->state_file)
- unlink(i->state_file);
+ (void) unlink(i->state_file);
i->started = false;
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);
}
}
#include <fcntl.h>
#include <stdio_ext.h>
#include <string.h>
+#include <sys/stat.h>
#include <unistd.h>
#include "sd-messages.h"
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);
#include <stdio_ext.h>
#include <string.h>
#include <sys/ioctl.h>
+#include <sys/stat.h>
#include <unistd.h>
#include "sd-messages.h"
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;
}
#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"
if (!u->home)
return -ENOMEM;
+ path_simplify(u->home, true);
+
if (asprintf(&u->state_file, "/run/systemd/users/"UID_FMT, uid) < 0)
return -ENOMEM;
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) {
#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);
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;
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;
}
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);
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;
#include "hashmap.h"
#include "list.h"
#include "set.h"
+#include "time-util.h"
typedef struct Manager Manager;
<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"
</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>
#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"
#include "stdio-util.h"
#include "strv.h"
#include "terminal-util.h"
-#include "util.h"
static int parse_argv(
pam_handle_t *handle,
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;
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;
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <unistd.h>
+#include <fcntl.h>
#include "sd-bus.h"
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) {
#include "bus-error.h"
#include "fs-util.h"
+#include "format-util.h"
#include "label.h"
#include "main-func.h"
#include "mkdir.h"
#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"
#include <string.h>
#include <unistd.h>
#include <stdio_ext.h>
+#include <sys/stat.h>
#include "sd-messages.h"
#include "list.h"
#include "machined.h"
#include "operation.h"
+#include "time-util.h"
typedef enum MachineState {
MACHINE_OPENING, /* Machine is being registered */
#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"
#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"
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;
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)
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)
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)
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);
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);
local = l;
}
- if (isempty(local) || streq(local, "-"))
- local = NULL;
+ local = empty_or_dash_to_null(local);
if (local) {
r = tar_strip_suffixes(local, &ll);
local = l;
}
- if (isempty(local) || streq(local, "-"))
- local = NULL;
+ local = empty_or_dash_to_null(local);
if (local) {
r = raw_strip_suffixes(local, &ll);
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++;
}
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;
}
#include <errno.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include "sd-daemon.h"
#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,
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;
_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);
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;
--- /dev/null
+[libfuzzer]
+max_len = 65535
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
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",
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");
}
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");
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;
#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"
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);
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");
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;
}
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;
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);
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");
--- /dev/null
+/* 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,
+};
--- /dev/null
+/* 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);
#include "netdev/vxcan.h"
#include "netdev/wireguard.h"
#include "netdev/fou-tunnel.h"
+#include "netdev/l2tp-tunnel.h"
#include "vlan-util.h"
%}
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)
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)
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
#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,
[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] = {
[NETDEV_KIND_NETDEVSIM] = "netdevsim",
[NETDEV_KIND_FOU] = "fou",
[NETDEV_KIND_ERSPAN] = "erspan",
+ [NETDEV_KIND_L2TP] = "l2tp",
};
DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
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
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;
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)
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");
}
};
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);
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;
}
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);
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);
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;
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) {
case NETDEV_KIND_IP6TNL:
independent = IP6TNL(netdev)->independent;
break;
+ case NETDEV_KIND_ERSPAN:
+ independent = ERSPAN(netdev)->independent;
+ break;
default:
break;
}
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;
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;
NETDEV_CREATE_INDEPENDENT,
NETDEV_CREATE_MASTER,
NETDEV_CREATE_STACKED,
+ NETDEV_CREATE_AFTER_CONFIGURED,
_NETDEV_CREATE_MAX,
_NETDEV_CREATE_INVALID = -1,
} NetDevCreateType;
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;
/* 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);
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 */
#include "conf-parser.h"
#include "missing.h"
+#include "netlink-util.h"
#include "networkd-link.h"
#include "netdev/tunnel.h"
#include "parse-util.h"
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);
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");
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);
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)
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;
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;
}
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;
}
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)
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);
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;
}
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) {
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;
}
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;
}
* 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;
}
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;
}
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) {
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);
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,
};
.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,
};
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,
};
int family;
int ipv6_flowlabel;
int allow_localremote;
- int erspan_sequence;
+ int gre_erspan_sequence;
int isatap;
unsigned ttl;
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");
}
#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) {
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;
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);
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;
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);
* 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;
.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) {
/* 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;
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;
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);
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;
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;
}
Wireguard *w;
assert(netdev);
-
w = WIREGUARD(netdev);
-
assert(w);
w->flags = WGDEVICE_F_REPLACE_PEERS;
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 = {
.init = wireguard_init,
.done = wireguard_done,
.create_type = NETDEV_CREATE_INDEPENDENT,
+ .config_verify = wireguard_verify,
};
#include "netdev.h"
#include "socket-util.h"
-#ifndef IFNAMSIZ
-#define IFNAMSIZ 16
-#endif
-
typedef struct WireguardIPmask {
uint16_t family;
union in_addr_union ip;
} 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);
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);
#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"
#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"
#include "strv.h"
#include "strxcpyx.h"
#include "terminal-util.h"
-#include "util.h"
#include "verbs.h"
static PagerFlags arg_pager_flags = 0;
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")) {
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);
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;
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 &&
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;
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)
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",
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);
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;
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;
" --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
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;
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;
#include "networkd-link.h"
#include "networkd-network.h"
+#include "networkd-util.h"
typedef struct Network Network;
typedef struct Link Link;
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);
#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,
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;
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);
#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"
#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
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;
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;
}
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;
}
address->scope = scope;
address->cinfo = *cinfo;
- link_update_operstate(address->link);
+ link_update_operstate(address->link, true);
link_check_ready(address->link);
if (!ready &&
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);
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);
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);
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 ... */
/* 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,
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;
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);
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;
void *userdata) {
Network *network = userdata;
- _cleanup_(address_freep) Address *n = NULL;
+ _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
int r;
assert(filename);
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;
}
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;
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;
void *data,
void *userdata) {
- _cleanup_(address_freep) Address *n = NULL;
+ _cleanup_(address_free_or_set_invalidp) Address *n = NULL;
Network *network = userdata;
int r;
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;
}
return log_oom();
n = NULL;
-
return 0;
}
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;
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;
}
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);
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;
}
n->prefix_route = r;
else if (streq(lvalue, "AutoJoin"))
n->autojoin = r;
+ else
+ assert_not_reached("Invalid address flag type.");
+ n = NULL;
return 0;
}
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);
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;
}
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;
+}
#include "networkd-link.h"
#include "networkd-network.h"
+#include "networkd-util.h"
#define CACHE_INFO_INFINITY_LIFE_TIME 0xFFFFFFFFU
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);
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);
#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"
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;
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)
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)
* 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;
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;
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;
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;
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);
}
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");
}
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;
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),
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);
}
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) {
}
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);
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);
#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,
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);
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);
#include "conf-parser.h"
#include "list.h"
#include "macro.h"
+#include "networkd-util.h"
typedef struct Network Network;
typedef struct FdbEntry 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);
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;
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;
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;
}
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;
}
#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);
}
static int ipv6_proxy_ndp_set(Link *link) {
- const char *p = NULL;
- int r, v;
+ bool v;
+ int r;
assert(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);
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;
}
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);
#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;
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;
}
if (!link->network)
return false;
+ if (link->network->bond)
+ return false;
+
return link->network->dhcp & ADDRESS_FAMILY_IPV4;
}
if (!link->network)
return false;
+ if (link->network->bond)
+ return false;
+
return link->network->dhcp_server;
}
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;
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;
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. */
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;
}
}
static int link_enable_ipv6(Link *link) {
- const char *p = NULL;
bool disabled;
int r;
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);
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)
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) {
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) \
link->flags = flags;
link->kernel_operstate = operstate;
- link_update_operstate(link);
+ link_update_operstate(link, true);
return 0;
}
}
static Link *link_free(Link *link) {
+ Link *carrier, *master;
Address *address;
- Link *carrier;
Route *route;
Iterator i;
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);
}
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);
link_set_state(link, LINK_STATE_CONFIGURED);
+ (void) link_join_netdevs_after_configured(link);
+
link_dirty(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);
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) {
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];
}
}
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) {
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];
}
}
}
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");
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;
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);
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
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)
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;
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");
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;
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;
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)
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");
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 &&
assert(link);
assert(link->network);
+ assert(link->enslaving > 0);
+ assert(!link->enslaved_raw);
link->enslaving--;
} else
log_link_debug(link, "Joined netdev");
- if (link->enslaving <= 0)
+ if (link->enslaving == 0) {
+ link->enslaved_raw = true;
link_joined(link);
+ }
return 1;
}
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 &&
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,
link_enter_failed(link);
return r;
}
-
- link->enslaving++;
}
if (link->network->bridge) {
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,
link_enter_failed(link);
return r;
}
-
- link->enslaving++;
}
if (link->network->vrf) {
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,
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,
link_enter_failed(link);
return r;
}
-
- link->enslaving++;
}
+ if (link->enslaving == 0)
+ return link_joined(link);
+
return 0;
}
* 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");
* 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");
}
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");
}
static int link_set_ipv6_accept_ra(Link *link) {
- const char *p = NULL;
int r;
/* Make this a NOP if IPv6 is not available */
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");
}
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 */
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");
}
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 */
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");
}
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 */
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");
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);
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;
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. */
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);
assert(link->manager);
if (link->state == LINK_STATE_LINGER) {
- unlink(link->state_file);
+ (void) unlink(link->state_file);
return 0;
}
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)
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) {
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) {
(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;
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;
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);
}
"DHCP_LEASE=%s\n",
link->lease_file);
} else
- unlink(link->lease_file);
+ (void) unlink(link->lease_file);
if (link->ipv4ll) {
struct in_addr address;
r = sd_ipv4ll_get_address(link->ipv4ll, &address);
if (r >= 0) {
fputs("IPV4LL_ADDRESS=", f);
- serialize_in_addrs(f, &address, 1);
+ serialize_in_addrs(f, &address, 1, false, NULL);
fputc('\n', f);
}
}
};
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);
#include "sd-netlink.h"
#include "list.h"
+#include "log-link.h"
+#include "network-util.h"
#include "set.h"
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;
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;
Hashmap *bound_by_links;
Hashmap *bound_to_links;
+ Hashmap *slaves;
} Link;
typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
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);
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);
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, \
#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;
/* 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;
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;
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;
}
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)
(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) {
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;
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;
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;
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)
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)
"# 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)
if (!m->state_file)
return -ENOMEM;
+ m->sysctl_ipv6_enabled = -1;
+
r = sd_event_default(&m->event);
if (r < 0)
return r;
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);
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);
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)
}
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) {
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;
+}
#include "networkd-link.h"
#include "networkd-network.h"
-extern const char* const network_dirs[];
-
struct Manager {
sd_netlink *rtnl;
/* lazy initialized */
Set *rules;
Set *rules_foreign;
Set *rules_saved;
+
+ int sysctl_ipv6_enabled;
};
extern const sd_bus_vtable manager_vtable[];
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);
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;
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;
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;
}
}
-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);
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) {
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;
r = sd_ndisc_router_option_next(rt);
}
+
+ return 0;
}
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;
}
#pragma once
#include "networkd-link.h"
+#include "time-util.h"
typedef struct NDiscRDNSS {
usec_t valid_until;
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);
void *userdata) {
Network *network = userdata;
- _cleanup_(neighbor_freep) Neighbor *n = NULL;
+ _cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
int r;
assert(filename);
void *userdata) {
Network *network = userdata;
- _cleanup_(neighbor_freep) Neighbor *n = NULL;
+ _cleanup_(neighbor_free_or_set_invalidp) Neighbor *n = NULL;
int r;
assert(filename);
#include "networkd-link.h"
#include "networkd-network.h"
+#include "networkd-util.h"
struct Neighbor {
Network *network;
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);
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)
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
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
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)
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
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)
#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) {
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;
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,
.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,
.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,
.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"
"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)
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;
}
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");
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);
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))
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);
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);
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);
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;
}
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;
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,
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;
}
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;
}
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)
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;
}
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;
};
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,
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;
}
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;
}
}
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;
}
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;
}
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;
}
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)
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;
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)
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;
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;
}
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)
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;
}
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)
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;
}
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)
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;
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;
}
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;
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",
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;
+}
#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
_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 {
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;
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;
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 */
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;
size_t can_bitrate;
unsigned can_sample_point;
usec_t can_restart_us;
+ int can_triple_sampling;
AddressFamilyBoolean ip_forward;
bool ip_masquerade;
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 */
/* 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;
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);
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);
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);
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;
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;
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);
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;
}
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;
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);
}
#include "conf-parser.h"
#include "networkd-address.h"
#include "networkd-link.h"
+#include "networkd-util.h"
typedef struct Prefix 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);
.table = RT_TABLE_MAIN,
.lifetime = USEC_INFINITY,
.quickack = -1,
+ .gateway_onlink = -1,
};
*ret = TAKE_PTR(route);
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;
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);
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);
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;
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);
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,
void *userdata) {
Network *network = userdata;
- _cleanup_(route_freep) Route *n = NULL;
+ _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
int r;
assert(filename);
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;
}
void *userdata) {
Network *network = userdata;
- _cleanup_(route_freep) Route *n = NULL;
+ _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
int r;
assert(filename);
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;
}
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;
} 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;
}
void *userdata) {
Network *network = userdata;
- _cleanup_(route_freep) Route *n = NULL;
+ _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
int r;
assert(filename);
void *userdata) {
Network *network = userdata;
- _cleanup_(route_freep) Route *n = NULL;
+ _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
int r;
assert(filename);
void *data,
void *userdata) {
- _cleanup_(route_freep) Route *n = NULL;
+ _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
Network *network = userdata;
int r;
void *userdata) {
Network *network = userdata;
- _cleanup_(route_freep) Route *n = NULL;
+ _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
int r;
assert(filename);
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;
}
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);
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);
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;
}
}
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);
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;
}
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;
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;
}
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;
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;
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;
}
void *userdata) {
Network *network = userdata;
- _cleanup_(route_freep) Route *n = NULL;
+ _cleanup_(route_free_or_set_invalidp) Route *n = NULL;
int r;
assert(filename);
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;
+}
typedef struct NetworkConfigSection NetworkConfigSection;
#include "networkd-network.h"
+#include "networkd-util.h"
struct Route {
Network *network;
uint32_t initrwnd;
unsigned char pref;
unsigned flags;
+ int gateway_onlink;
union in_addr_union gw;
union in_addr_union dst;
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);
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);
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");
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");
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");
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");
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;
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;
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;
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;
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;
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;
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;
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;
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;
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;
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);
}
}
#include "networkd-link.h"
#include "networkd-network.h"
+#include "networkd-util.h"
typedef struct Network Network;
typedef struct Link Link;
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);
}
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);
+}
#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);
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);
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sys/stat.h>
+#include <sys/types.h>
+
#include "sd-daemon.h"
#include "sd-event.h"
_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);
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);
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;
}
hashmap_remove(l->manager->links_by_name, l->ifname);
}
+ free(l->state);
free(l->ifname);
return mfree(l);
}
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)
}
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;
}
#include "sd-netlink.h"
+#include "log-link.h"
+#include "network-util.h"
+
typedef struct Link Link;
typedef struct Manager Manager;
unsigned flags;
bool required_for_online;
- char *operational_state;
+ LinkOperationalState required_operstate;
+ LinkOperationalState operational_state;
char *state;
};
#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);
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)
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;
}
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);
}
if (r < 0)
return r;
- if (manager_all_configured(m))
+ if (manager_configured(m))
sd_event_exit(m->event, 0);
return 1;
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;
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)
#include "sd-network.h"
#include "hashmap.h"
+#include "network-util.h"
+#include "time-util.h"
typedef struct Manager Manager;
typedef struct Link Link;
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;
};
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);
/* 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) {
" -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
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 },
{}
};
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) {
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:
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 '?':
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"
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
#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"
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... */
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)
#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;
}
strv_free(m->lower);
+ free(m->type_argument);
}
free(l);
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) {
}
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;
}
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)
/* 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;
return -EINVAL;
}
+ if (empty_or_root(destination))
+ return -EINVAL;
+
m = custom_mount_add(l, n, CUSTOM_MOUNT_OVERLAY);
if (!m)
return -ENOMEM;
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,
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 */
/* 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. */
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 },
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,
#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);
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))
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) {
}
r = mount_verbose(fatal ? LOG_ERR : LOG_DEBUG,
- what,
+ mount_table[k].what,
where,
mount_table[k].type,
mount_table[k].flags,
}
static int mount_bind(const char *dest, CustomMount *m) {
-
_cleanup_free_ char *where = NULL;
struct stat source_st, dest_st;
int r;
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);
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");
}
}
static int mount_overlay(const char *dest, CustomMount *m) {
-
_cleanup_free_ char *lower = NULL, *where = NULL, *escaped_source = NULL;
const char *options;
int r;
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;
for (i = 0; i < n; i++) {
CustomMount *m = mounts + i;
+ if (m->in_userns != in_userns)
+ continue;
+
switch (m->type) {
case CUSTOM_MOUNT_BIND:
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");
}
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) {
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);
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) {
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");
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;
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;
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;
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;
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);
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);
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include "nspawn-settings.h"
+
+int oci_load(FILE *f, const char *path, Settings **ret);
/* 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;
}
#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"
unsigned n_mounts,
int kill_signal,
char **properties,
+ sd_bus_message *properties_message,
bool keep_unit,
const char *service) {
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;
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;
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,
#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);
#include <errno.h>
#include <linux/netlink.h>
#include <sys/capability.h>
+#include <sys/socket.h>
#include <sys/types.h>
#if HAVE_SECCOMP
#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;
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"
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;
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);
}
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(
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,
#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 */
_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,
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;
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;
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);
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);
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);
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <fcntl.h>
#include <grp.h>
#include <sys/types.h>
#include <unistd.h>
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();
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;
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");
}
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);
/* 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);
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,
#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"
#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"
#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;
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;
(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;
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;
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;
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"
" 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;
}
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) {
/* 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)
ARG_TMPFS,
ARG_OVERLAY,
ARG_OVERLAY_RO,
+ ARG_INACCESSIBLE,
ARG_SHARE_SYSTEM,
ARG_REGISTER,
ARG_KEEP_UNIT,
ARG_CPU_AFFINITY,
ARG_RESOLV_CONF,
ARG_TIMEZONE,
+ ARG_CONSOLE,
+ ARG_PIPE,
+ ARG_OCI_BUNDLE,
+ ARG_NO_PAGER,
};
static const struct option options[] = {
{ "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' },
{ "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 },
{}
};
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':
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':
if (r < 0)
return r;
+ arg_settings_mask |= SETTING_NETWORK;
break;
case 'b':
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':
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;
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;
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;
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);
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;
* --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)
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. */
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.");
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.");
"/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;
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
*/
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
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);
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;
}
/* 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.
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");
"tty\0"
"net/tun\0";
+ _cleanup_umask_ mode_t u;
const char *d;
int r = 0;
- _cleanup_umask_ mode_t u;
assert(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;
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");
_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");
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;
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) {
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) {
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;
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,
};
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,
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 */
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");
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)
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) {
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");
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));
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. */
const char *directory,
const char *console,
DissectedImage *dissected_image,
- bool interactive,
bool secondary,
int pid_socket,
int uuid_socket,
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,
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");
"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,
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.
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");
}
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)
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;
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;
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));
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;
}
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);
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)
} 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 &&
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);
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);
}
}
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 ++) {
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;
}
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)
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,
_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;
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);
arg_directory,
console,
dissected_image,
- interactive,
secondary,
pid_socket_pair[1],
uuid_socket_pair[1],
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]);
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
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.");
}
}
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. */
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);
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)
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);
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)
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;
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");
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) {
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;
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;
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;
if (r < 0)
goto finish;
+ r = load_oci_bundle();
+ if (r < 0)
+ goto finish;
+
r = determine_names();
if (r < 0)
goto finish;
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");
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;
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)
}
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);
(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);
#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
} 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";
}
/* 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)
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(
} 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";
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)
errnop, h_errnop,
ttlp,
canonp);
+
+not_found:
+ *h_errnop = HOST_NOT_FOUND;
+ return NSS_STATUS_NOTFOUND;
}
enum nss_status _nss_myhostname_gethostbyaddr2_r(
#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);
fail:
UNPROTECT_ERRNO;
*errnop = -r;
- *h_errnop = NO_DATA;
+ *h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
fail:
UNPROTECT_ERRNO;
*errnop = -r;
- *h_errnop = NO_DATA;
+ *h_errnop = NO_RECOVERY;
return NSS_STATUS_UNAVAIL;
}
#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);
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) {
_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;
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,
UNPROTECT_ERRNO;
*errnop = -r;
*h_errnop = NO_RECOVERY;
- return ret;
+ return NSS_STATUS_UNAVAIL;
not_found:
*h_errnop = HOST_NOT_FOUND;
_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;
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;
UNPROTECT_ERRNO;
*errnop = -r;
*h_errnop = NO_RECOVERY;
- return ret;
+ return NSS_STATUS_UNAVAIL;
not_found:
*h_errnop = HOST_NOT_FOUND;
_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;
}
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()) {
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;
r = sd_bus_message_rewind(reply, false);
if (r < 0)
- return r;
+ goto fail;
if (c <= 0)
goto not_found;
UNPROTECT_ERRNO;
*errnop = -r;
*h_errnop = NO_RECOVERY;
- return ret;
+ return NSS_STATUS_UNAVAIL;
not_found:
*h_errnop = HOST_NOT_FOUND;
#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"
#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;
<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"
#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"
#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"
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);
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),
/* 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"
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),
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sys/stat.h>
+#include <sys/types.h>
+
#include "sd-bus.h"
#include "sd-daemon.h"
#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"
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");
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;
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
* 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;
#include "fileio.h"
#include "log.h"
#include "macro.h"
+#include "memory-util.h"
#include "socket-util.h"
#include "string-util.h"
#include "util.h"
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <getopt.h>
+#include <locale.h>
#include <net/if.h>
#include "sd-bus.h"
}
}
- 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);
#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"
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <stdio.h>
+
#include "alloc-util.h"
#include "dns-domain.h"
#include "resolved-dns-answer.h"
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);
#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
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)
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) {
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;
+ }
}
}
#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"
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;
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;
}
* 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;
}
/* 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;
}
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);
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);
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;
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) {
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);
((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;
}
}
+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;
case DNS_TYPE_DNSKEY: {
_cleanup_free_ char *alg = NULL;
char *ss;
- int n;
uint16_t key_tag;
key_tag = dnssec_keytag(rr, true);
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)
_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);
/* 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,
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)
}
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)
#include "in-addr-util.h"
#include "list.h"
#include "string-util.h"
+#include "time-util.h"
typedef struct DnsResourceKey DnsResourceKey;
typedef struct DnsResourceRecord DnsResourceRecord;
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);
#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);
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
_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) {
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);
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) {
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)) {
}
}
- 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;
}
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
int dns_stream_new(
Manager *m,
DnsStream **ret,
+ DnsStreamType type,
DnsProtocol protocol,
int fd,
const union sockaddr_union *tfo_address) {
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);
(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;
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"
Manager *manager;
unsigned n_ref;
+ DnsStreamType type;
DnsProtocol protocol;
int fd;
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;
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
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include "errno-util.h"
#include "fd-util.h"
#include "missing_network.h"
#include "resolved-dns-stub.h"
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;
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;
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,
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;
}
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.");
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);
return;
fail:
- if (s && DNS_STREAM_QUEUED(s))
- dns_stub_detach_stream(s);
-
dns_query_free(q);
}
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;
} 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;
}
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;
}
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;
#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"
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;
}
}
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);
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:
fd = dns_scope_socket_tcp(t->scope, family, &address, NULL, LLMNR_PORT, &sa);
}
+ type = DNS_STREAM_LLMNR_SEND;
break;
default:
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;
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;
#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"
+/* 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)
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);
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");
/* 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"
#include <netinet/in.h>
#include <resolv.h>
+#include "errno-util.h"
#include "fd-util.h"
#include "resolved-llmnr.h"
#include "resolved-manager.h"
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;
}
/* 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>
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);
#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))
#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"
/* 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"
#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) {
}
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();
#include "log.h"
#include "resolved-dns-packet.h"
+#include "tests.h"
static void test_dns_packet_new(void) {
size_t i;
}
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();
/* 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"
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)
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <unistd.h>
+
#include "alloc-util.h"
#include "escape.h"
#include "fd-util.h"
#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"
#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"
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;
" --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
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,
{ "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 },
if (r < 0)
return r;
- with_timer = true;
+ arg_with_timer = true;
break;
case ARG_ON_BOOT:
if (r < 0)
return r;
- with_timer = true;
+ arg_with_timer = true;
break;
case ARG_ON_STARTUP:
if (r < 0)
return r;
- with_timer = true;
+ arg_with_timer = true;
break;
case ARG_ON_UNIT_ACTIVE:
if (r < 0)
return r;
- with_timer = true;
+ arg_with_timer = true;
break;
case ARG_ON_UNIT_INACTIVE:
if (r < 0)
return r;
- with_timer = true;
+ arg_with_timer = true;
break;
case ARG_ON_CALENDAR:
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:
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=",
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.");
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.");
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);
#include <errno.h>
#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include "acl-util.h"
#include "alloc-util.h"
#include "io-util.h"
#include "log.h"
#include "macro.h"
+#include "memory-util.h"
#include "missing.h"
#include "mkdir.h"
#include "process-util.h"
#include "tmpfile-util.h"
#include "umask-util.h"
#include "utf8.h"
-#include "util.h"
#define KEYRING_TIMEOUT_USEC ((5 * USEC_PER_MINUTE) / 2)
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);
};
for (;;) {
+ _cleanup_(erase_char) char c;
int sleep_for = -1, k;
ssize_t n;
- char c;
if (until > 0) {
usec_t y;
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;
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);
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);
#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;
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)
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();
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)
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) {
#include "bitmap.h"
#include "hashmap.h"
#include "macro.h"
+#include "memory-util.h"
struct Bitmap {
uint64_t *bitmaps;
#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) {
free(entry->id);
free(entry->path);
+ free(entry->root);
free(entry->title);
free(entry->show_title);
free(entry->version);
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);
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)
free(config->editor);
free(config->auto_entries);
free(config->auto_firmware);
+ free(config->console_mode);
free(config->entry_oneshot);
free(config->entry_default);
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)
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(§ions[i].PointerToRawData);
+ size = unaligned_read_le32(§ions[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;
}
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--)
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)
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);
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.");
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.");
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)
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,
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);
#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;
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_;
#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;
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
/* 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);
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))
"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);
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);
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;
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;
/* 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 {
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);
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);
}
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;
/* 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;
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;
}
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;
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);
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;
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;
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) ||
(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;
}
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;
}
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;
}
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;
}
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;
}
#include "hashmap.h"
#include "macro.h"
#include "string-util.h"
+#include "time-util.h"
typedef enum BusTransport {
BUS_TRANSPORT_LOCAL,
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);
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
#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"
* linked compenents anyway. */
#define CALENDARSPEC_COMPONENTS_MAX 240
-static void free_chain(CalendarComponent *c) {
+static void chain_free(CalendarComponent *c) {
CalendarComponent *n;
while (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);
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;
}
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;
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;
}
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;
}
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);
}
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);
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;
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;
/* 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;
if (!c->timezone)
return -ENOMEM;
- p = strndupa(p, last_space - p);
+ p = p_tmp = strndup(p, last_space - p);
+ if (!p)
+ return -ENOMEM;
}
}
}
#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"
#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;
#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;
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) {
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;
[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;
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);
[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);
[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);
CONDITION_SECURITY,
CONDITION_CAPABILITY,
CONDITION_AC_POWER,
+ CONDITION_MEMORY,
+ CONDITION_CPUS,
CONDITION_NEEDS_UPDATE,
CONDITION_FIRST_BOOT,
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));
#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"
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,
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);
#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);
#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[] =
#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"
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;
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)) {
} 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;
+ }}
}
}
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);
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;
}
[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",
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 */
#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
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;
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;
#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;
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
#endif
+bool efi_loader_entry_name_valid(const char *s);
+
char *efi_tilt_backslashes(char *s);
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();
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);
+ }
}
}
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;
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));
* 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;
_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];
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;
}
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)))
#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"
#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;
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;
}
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)
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);
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 {
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)
"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);
"# 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"
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();
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,
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. */
#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)
#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;
#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"
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",
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;
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;
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;
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
+#include <locale.h>
#include <math.h>
#include <stdarg.h>
#include <stdio_ext.h>
#include "sd-messages.h"
#include "alloc-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "fileio.h"
#include "float.h"
#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"
assert(s || n == 0);
while (n > 0) {
-
if (*s == '\n') {
(*line)++;
*column = 1;
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 */
continue;
}
- len = utf8_encoded_valid_unichar(c);
+ len = utf8_encoded_valid_unichar(c, (size_t) -1);
if (len < 0)
return len;
free(stack);
- va_end(ap);
-
return r;
}
"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(
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;
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;
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;
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;
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;
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;
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)
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)
#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
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))
--- /dev/null
+/* 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);
--- /dev/null
+/* 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
#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"
#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"
#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] = {
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) {
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:
}
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) {
}
int image_name_lock(const char *name, int operation, LockFile *ret) {
- const char *p;
-
assert(name);
assert(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);
}
#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; \
}
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
json-internal.h
json.c
json.h
+ libmount-util.h
linux/auto_dev-ioctl.h
linux/bpf.h
linux/bpf_common.h
linux/netdevice.h
lockfile-util.c
lockfile-util.h
+ log-link.h
logs-show.c
logs-show.h
loop-util.c
pager.h
path-lookup.c
path-lookup.h
+ pe-header.h
pretty-print.c
pretty-print.h
ptyfwd.c
#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
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;
} while (again);
- return r ? r : n;
+ return r < 0 ? r : n;
}
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;
(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;
}
(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);
}
}
-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");
(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) {
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);
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
+#include "util.h"
static pid_t pager_pid = 0;
--- /dev/null
+#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_;
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 */
#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;
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;
/* 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 */
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);
/* 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[] = {
"pause\0"
"prlimit64\0"
"restart_syscall\0"
+ "rseq\0"
"rt_sigreturn\0"
"sched_yield\0"
"set_robust_list\0"
return 0;
}
-int seccomp_parse_syscall_filter_full(
+int seccomp_parse_syscall_filter(
const char *name,
int errno_num,
Hashmap *filter,
* 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;
}
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;
case SCMP_ARCH_X86:
filter_syscall = SCMP_SYS(mmap2);
block_syscall = SCMP_SYS(mmap);
+ shmat_syscall = SCMP_SYS(shmat);
break;
case SCMP_ARCH_PPC:
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));
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;
+}
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);
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[];
#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);
***/
#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>
#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"
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");
#include "sd-id128.h"
#include "alloc-util.h"
+#include "format-util.h"
#include "fs-util.h"
#include "hostname-util.h"
#include "macro.h"
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;
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;
+}
/* 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);
/* 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");
*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;
+}
#include "sd-device.h"
+#include "device-private.h"
#include "time-util.h"
typedef enum ResolveNameTiming {
}
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);
#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);
#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) {
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);
VOLATILE_NO,
VOLATILE_YES,
VOLATILE_STATE,
+ VOLATILE_OVERLAY,
_VOLATILE_MODE_MAX,
_VOLATILE_MODE_INVALID = -1
} VolatileMode;
--- /dev/null
+systemd_shutdown_sources = files('''
+ shutdown.c
+ umount.c
+ umount.h
+'''.split())
* 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)
val += ull;
}
- r = *prev_dirty > val;
-
+ ret = *prev_dirty > val;
*prev_dirty = val;
-
- return r;
+ return ret;
}
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");
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.");
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();
#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"
#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"
#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);
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)
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),
* 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
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;
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)
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;
***/
#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"
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,
"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;
}
#include "sd-resolve.h"
#include "alloc-util.h"
+#include "errno-util.h"
#include "fd-util.h"
#include "log.h"
#include "main-func.h"
#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 {
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))
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))
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);
#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"
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);
} 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 &&
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);
{
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);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include "conf-files.h"
#include "def.h"
#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;
#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;
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;
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,
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);
*_machines = NULL;
*_unit_infos = TAKE_PTR(unit_infos);
-
*_replies = TAKE_PTR(replies);
return c;
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;
}
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))
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 {
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,
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
const char *path;
+ bool done = false;
int r;
assert(method);
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);
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) {
}
*ret = TAKE_PTR(mangled);
-
return 0;
}
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" },
};
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 */
action = verb_to_action(argv[0]);
if (action != _ACTION_INVALID) {
+ /* A command in style "systemctl reboot", "systemctl poweroff", … */
method = "StartUnit";
+ job_type = "start";
mode = action_table[action].mode;
one_name = action_table[action].target;
} else {
if (streq(argv[0], "isolate")) {
+ /* A "systemctl isolate <unit1> <unit2> …" command */
method = "StartUnit";
+ job_type = "start";
mode = "isolate";
-
suffix = ".target";
} else {
+ /* A command in style of "systemctl start <unit1> <unit2> …", "sysemctl stop <unit1> <unit2> …" and so on */
method = verb_to_method(argv[0]);
+ job_type = verb_to_job_type(argv[0]);
mode = arg_job_mode;
}
one_name = NULL;
}
} else {
+ /* A SysV legacy command such as "halt", "reboot", "poweroff", … */
assert(arg_action >= 0 && arg_action < _ACTION_MAX);
assert(action_table[arg_action].target);
assert(action_table[arg_action].mode);
method = "StartUnit";
+ job_type = "start";
mode = action_table[arg_action].mode;
one_name = action_table[arg_action].target;
}
}
if (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,
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");
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);
}
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;
}
#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;
"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
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,
#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;
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;
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();
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) {
"--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;
}
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;
while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, ¶m, &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;
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")) {
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;
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;
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;
}
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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;
}
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)
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)
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];
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)
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;
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;
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;
assert(f > 0);
f--;
assert(args[f] == name);
- strv_remove(args, name);
+ strv_remove(args + f, name);
}
#endif
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);
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)
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);
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"
" 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"
" 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"
" 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"
" 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"
" 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;
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,
ARG_JOB_MODE,
ARG_PRESET_MODE,
ARG_FIRMWARE_SETUP,
+ ARG_BOOT_LOADER_MENU,
+ ARG_BOOT_LOADER_ENTRY,
ARG_NOW,
ARG_MESSAGE,
ARG_WAIT,
{ "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);
/* 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) {
return version();
case 't': {
+ const char *p;
+
if (isempty(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"--type= requires arguments.");
}
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;
}
* 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;
}
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;
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
arg_all = true;
break;
- }
case 'a':
arg_all = true;
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.");
return 0;
}
- if (strv_push(&arg_states, s) < 0)
+ if (strv_consume(&arg_states, TAKE_PTR(s)) < 0)
return log_oom();
-
- s = NULL;
}
break;
}
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);
}
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)
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,
};
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 },
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.");
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
}
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();
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;
}
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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,
+};
#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 */
union {
struct {
size_t element_size;
+ uint64_t features;
} start;
struct {
const char *member;
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;
.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, \
.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, \
.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) \
{ \
#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;
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);
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;
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 */
* -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:
return 0;
fail:
- unlink(temp);
+ (void) unlink(temp);
return r;
}
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], '+', '-'))
* 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], '+', '-'))
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)
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)
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)
*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;
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;
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)
}
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)
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)
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);
[],
[]],
+ [['src/test/test-libmount.c'],
+ [],
+ [threads,
+ libmount]],
+
[['src/test/test-mount-util.c'],
[],
[]],
[],
[]],
+ [['src/test/test-ordered-set.c'],
+ [],
+ []],
+
[['src/test/test-set-disable-mempool.c'],
[],
[threads]],
[],
'', 'manual'],
+ [['src/test/test-cgroup-cpu.c'],
+ [libcore,
+ libshared],
+ []],
+
[['src/test/test-cgroup-mask.c',
'src/test/test-helper.c'],
[libcore,
'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'],
[],
[threads]],
+ [['src/libsystemd/sd-bus/test-bus-queue-ref-cycle.c'],
+ [],
+ [threads]],
+
[['src/libsystemd/sd-bus/test-bus-watch-bind.c'],
[],
[threads], '', 'timeout=120'],
#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] = { };
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;
int main(int argc, char *argv[]) {
test_alloca();
+ test_GREEDY_REALLOC();
test_memdup_multiply_and_greedy_realloc();
test_bool_assign();
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <fcntl.h>
#include <unistd.h>
#include "async.h"
#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
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sys/types.h>
+#include <unistd.h>
+
#include "acpi-fpdt.h"
#include "boot-timestamps.h"
#include "efivars.h"
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <stdio.h>
#include <sys/prctl.h>
#include "alloc-util.h"
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();
--- /dev/null
+/* 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;
+}
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <sys/xattr.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "chown-recursive.h"
_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);
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");
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");
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");
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");
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 */
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);
#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) {
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);
test_condition_test_user();
test_condition_test_group();
test_condition_test_control_group_controller();
+ test_condition_test_cpus();
+ test_condition_test_memory();
return 0;
}
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"));
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[]) {
#include "parse-util.h"
#include "strv.h"
+#include "time-util.h"
int main(int argc, char *argv[]) {
_cleanup_strv_free_ char **l = NULL;
#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;
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);
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");
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");
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));
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);
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"));
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);
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)
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)
(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);
test_execution_order();
test_stdout_gathering();
test_environment_gathering();
+ test_error_catching();
return 0;
}
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;
}
}
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) {
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);
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) {
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");
}
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 */
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) {
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) {
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) {
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) {
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) {
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
}
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
}
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
}
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__);
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__);
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__);
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);
}
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) {
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");
}
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__);
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) {
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) {
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__);
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) {
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;
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;
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;
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);
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
#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"
#include "string-util.h"
#include "tests.h"
#include "tmpfile-util.h"
-#include "util.h"
static void test_close_many(void) {
int fds[3];
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;
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]);
assert_se(safe_fgetc(f, &c) == 0);
}
+#pragma GCC diagnostic pop
+
static const char buffer[] =
"Some test data\n"
"루Non-ascii chars: ąę„”\n"
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);
}
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);
/* 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,
#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);
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <unistd.h>
+
#include "alloc-util.h"
#include "fileio.h"
#include "hostname-util.h"
/* 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"
/* 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,
}
}
+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;
}
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <unistd.h>
+
#include "alloc-util.h"
#include "fileio.h"
#include "install.h"
#include "json.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "util.h"
static void test_tokenizer(const char *data, ...) {
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);
}
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);
--- /dev/null
+/* 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;
+}
#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;
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);
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);
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;
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) {
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;
.data.fd = STDIN_FILENO,
};
+ log_info("/* %s */", __func__);
+
fd_ep = epoll_create1(EPOLL_CLOEXEC);
assert_se(fd_ep >= 0);
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");
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");
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'");
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'");
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'");
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'");
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'");
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;
}
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));
}
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");
}
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);
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' },
{ "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);
test_list();
- return EXIT_SUCCESS;
+ return 0;
}
+
+DEFINE_MAIN_FUNCTION(run);
/* 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;
"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);
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <sys/mount.h>
+#include <unistd.h>
#include "alloc-util.h"
#include "def.h"
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;
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);
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) {
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <sys/socket.h>
+#include <sys/stat.h>
#include "alloc-util.h"
#include "fd-util.h"
#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) {
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;
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) {
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);
--- /dev/null
+/* 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;
+}
}
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;
/* 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"
#include "prioq.h"
#include "set.h"
#include "siphash24.h"
-#include "util.h"
+#include "sort-util.h"
#define SET_SIZE 1024*4
_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);
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);
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,
"idontexist", &value2,
"zumm", &value4,
"SPACE", &value5,
- "doubleticks", &value6) == 4);
+ "doubleticks", &value6,
+ "zummm", &value7) == 5);
+
assert_se(streq_ptr(value1, "quux"));
assert_se(!value2);
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) {
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;
/* 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, ">>>");
#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;
#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__)
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;
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);
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);
test_restrict_archs();
test_load_syscall_filter_set_raw();
test_lock_personality();
+ test_restrict_suid_sgid();
return 0;
}
/* 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;
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[]) {
/* 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;
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include "memory-util.h"
#include "siphash24.h"
-#include "util.h"
#define ITERATIONS 10000000ULL
/* 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"
/* 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"
#include "string-util.h"
#include "tests.h"
#include "tmpfile-util.h"
-#include "util.h"
static void test_ifname_valid(void) {
log_info("/* %s */", __func__);
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);
}
#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"
#include "strv.h"
#include "tests.h"
#include "utf8.h"
+#include "util.h"
static void test_string_erase(void) {
char *x;
#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[] = {
#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"
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);
/* 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"
#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"));
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);
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[]) {
test_default_term_for_tty();
test_read_one_char();
+ test_getttyname_malloc();
return 0;
}
#include "serialize.h"
#include "string-util.h"
#include "strv.h"
+#include "tests.h"
#include "time-util.h"
static void test_parse_sec(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;
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) {
}
int main(int argc, char *argv[]) {
- uintmax_t x;
+ test_setup_logging(LOG_INFO);
log_info("realtime=" USEC_FMT "\n"
"monotonic=" USEC_FMT "\n"
test_parse_sec();
test_parse_sec_fix_0();
+ test_parse_sec_def_infinity();
test_parse_time();
test_parse_nsec();
test_format_timespan(1);
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);
/* 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,
#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"
#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"
#include "tests.h"
#include "tmpfile-util.h"
#include "user-util.h"
-#include "util.h"
static int test_unit_file_get_set(void) {
int r;
#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"
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");
/* 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;
}
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) {
#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"
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <getopt.h>
+
#include "macro.h"
#include "strv.h"
#include "verbs.h"
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);
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;
}
#include <errno.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#include "sd-bus.h"
#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"
#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"
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;
#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"
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <sys/stat.h>
+#include <sys/types.h>
+
#include "sd-daemon.h"
#include "sd-event.h"
#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"
#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
bool keep_this_level) {
struct dirent *dent;
- struct timespec times[2];
bool deleted = false;
int r = 0;
}
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;
}
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;
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;
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;
}
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;
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);
"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);
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 {
{ '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 {
}
if (mode == MODE_SET)
- mask |= ATTRIBUTES_ALL;
+ mask |= CHATTR_ALL_FL;
assert(mask != 0);
_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",
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;
return -EIO;
}
- if (!isempty(buffer) && !streq(buffer, "-")) {
+ if (!empty_or_dash(buffer)) {
i.argument = strdup(buffer);
if (!i.argument)
return log_oom();
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);
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);
i.gid_set = true;
}
- if (!isempty(mode) && !streq(mode, "-")) {
+ if (!empty_or_dash(mode)) {
const char *mm = mode;
unsigned m;
} 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 == '~') {
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)
#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"
#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
-#include "util.h"
#include "utmp-wtmp.h"
static enum {
}
/*
- * 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;
}
}
}
-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;
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;
/*
* Spawn a separate process for each console device.
*/
- return ask_on_consoles(argc, argv);
+ return ask_on_consoles(argv);
if (arg_device) {
/*
#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)
#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;
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",
prog,
include_directories : includes,
c_args : ['-DLOG_REALM=LOG_REALM_UDEV'],
+ dependencies : [versiondep],
link_with : [libudev_static],
install_rpath : udev_rpath,
install : true,
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]]
+ ]
#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",
return i;
}
- return -1;
+ return -ENODATA;
}
int ethtool_set_features(int *fd, const char *ifname, int *features) {
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;
}
--- /dev/null
+/* 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;
+}
--- /dev/null
+[libfuzzer]
+max_len = 65535
%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
#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"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
-#include "util.h"
struct link_config_ctx {
LIST_HEAD(link_config, links);
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;
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);
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;
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;
}
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;
}
}
/* 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) {
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'",
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);
/* 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,
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)) {
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)
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] = {
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,
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;
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);
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);
#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
#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;
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 &&
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)
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
#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
};
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)
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,
.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);
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);
}
/* 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);
#include "strxcpyx.h"
#include "udev-builtin.h"
#include "udev-node.h"
+#include "udev-util.h"
#include "udev-watch.h"
#include "udev.h"
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);
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;
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:
int i;
if (!event->program_result)
- return 0;
+ goto null_terminate;
/* get part of the result string */
i = 0;
(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)
}
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:
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");
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:
}
return s - dest;
+
+null_terminate:
+ *s = '\0';
+ return 0;
}
ssize_t udev_event_apply_format(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)
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);
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;
}
}
- 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);
}
(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;
}
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);
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];
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;
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")) {
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;
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);
#include "alloc-util.h"
#include "conf-files.h"
+#include "def.h"
#include "device-private.h"
#include "device-util.h"
#include "dirent-util.h"
#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;
};
};
-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) {
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",
}
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",
}
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",
}
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,
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;
}
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)
}
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)
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)
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] == ',')
/* 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] == '=')
while (isspace(linepos[0]))
linepos++;
if (linepos[0] == '\0')
- return -1;
+ return -EINVAL;
/* get operation type */
if (linepos[0] == '=' && linepos[1] == '=') {
*op = OP_ASSIGN_FINAL;
linepos += 2;
} else
- return -1;
+ return -EINVAL;
/* terminate key */
temp[0] = '\0';
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 */
break;
if (linepos[i] == '\0')
- return -1;
+ return -EINVAL;
/* double quotes can be escaped */
if (linepos[i] == '\\')
}
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++) {
}
/* 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 */
#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) {
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(). */
else {
if (STR_IN_SET(attr,
"ACTION",
+ "SEQNUM",
"SUBSYSTEM",
"DEVTYPE",
"MAJOR",
} 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);
} 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)
} 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);
} 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)
/* 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) {
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)
};
/* 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;
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");
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 */
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);
if (match)
break;
} else {
- match = (streq(s, val));
+ match = streq(s, val);
break;
}
s = &next[1];
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;
_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 */
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));
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: {
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;
}
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: {
val = NULL;
}
- if (match_key(rules, cur, strempty(val)))
+ if (!match_key(rules, cur, strempty(val)))
goto nomatch;
break;
}
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: {
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;
}
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: {
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];
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;
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;
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:
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",
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));
_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();
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();
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;
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;
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;
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);
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;
}
#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,
"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) {
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': {
#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"
#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;
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);
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;
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");
}
}
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)
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);
#include "sd-event.h"
#include "device-enumerator-private.h"
+#include "device-private.h"
#include "fd-util.h"
#include "fileio.h"
#include "path-util.h"
}
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;
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))
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);
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;
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;
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++) {
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]);
}
#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" },
#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"
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;
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);
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]);
udev_builtin_exit();
+ if (manager->pid == getpid_cached())
+ udev_ctrl_cleanup(manager->ctrl);
+
manager_clear_for_worker(manager);
sd_netlink_unref(manager->rtnl);
* 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);
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)
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;
}
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;
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;
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;
}
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 */
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);
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) {
"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 */
}
/* 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;
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;
.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)
}
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);
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");
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);
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");
}
/* 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" \
#include <errno.h>
#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
#if HAVE_AUDIT
/* 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"
#include "log.h"
#include "selinux-util.h"
#include "string-util.h"
-#include "util.h"
static int run(int argc, char *argv[]) {
int r, k;
#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"
#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"
_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)
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;
}
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) {
}
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);
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();
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)
"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);
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)
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
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
! 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
cat >$initdir/etc/systemd/system/fail-on-restart.service <<EOF
[Unit]
Description=Fail on restart
+StartLimitIntervalSec=1m
+StartLimitBurst=3
[Service]
Type=simple
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 $$
# 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
--- /dev/null
+#! /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
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
! 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
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
#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
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
c
EOF
-systemd-analyze set-log-level info
+systemd-analyze log-level info
echo OK > /testok
--- /dev/null
+../TEST-01-BASIC/Makefile
\ No newline at end of file
--- /dev/null
+#!/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 "$@"
--- /dev/null
+#!/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
--- /dev/null
+../TEST-01-BASIC/Makefile
\ No newline at end of file
--- /dev/null
+#!/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 "$@"
--- /dev/null
+#!/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
--- /dev/null
+../TEST-01-BASIC/Makefile
\ No newline at end of file
--- /dev/null
+#!/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 "$@"
--- /dev/null
+#!/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
--- /dev/null
+@67767992554749550
\ No newline at end of file
--- /dev/null
+VARIABLE="value"
+OPTION="--option=1234"
+NUMBER=1
+EMPTY=""
+PATH=/var/lib/xxx
--- /dev/null
+# 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
--- /dev/null
+[Link]
+Advertise=hoge foo
--- /dev/null
+[Match]
+OriginalName=eth0
+Host=hogehoge
+Virtualization=qemu
+KernelCommandLine=aaa
+KernelVersion=4.20.3
+Architecture=x86-64
--- /dev/null
+[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=
--- /dev/null
+[Match]
+KernelVersion=t
+Virtualization=q
+KernelVersion=
\ No newline at end of file
[WireGuard]
ListenPort=
PrivateKey=
+PrivateKeyFile=
FwMark=
[MACVTAP]
Mode=
[WireGuardPeer]
Endpoint=
PresharedKey=
+PresharedKeyFile=
PersistentKeepalive=
PublicKey=
AllowedIPs=
MTUBytes=
Description=
Name=
+[L2TP]
+TunnelId=
+PeerTunnelId=
+UDPSourcePort=
+UDPDestinationPort=
+Local=
+Remote=
+EncapsulationType=
+UDPCheckSum=
+UDP6CheckSumRx=
+UDP6CheckSumTx=
+[L2TPSession]
+SessionId=
+PeerSessionId=
+Layer2SpecificHeader=
+Name=
--- /dev/null
+[NetDev]
+Name=w
+Kind=wireguard
+[WireGuardPeer]
+Endpoint=:0
+Endpoint=:8
\ No newline at end of file
--- /dev/null
+[NetDev]
+Name=w
+Kind=wireguard
+[WireGuardPeer]
+PublicKey=e
\ No newline at end of file
--- /dev/null
+[NetDev]
+Name=w
+Kind=wireguard
+[WireGuard]
+PrivateKey=E
\ No newline at end of file
Priority=
AllowPortToBeRoot=
MulticastToUnicast=
+MulticastFlood=
+NeighborSuppression=
+Learning=
[Match]
KernelVersion=
Type=
Table=
Gateway=
InitialAdvertisedReceiveWindow=
+GatewayOnLink=
GatewayOnlink=
Type=
InitialCongestionWindow=
IPv6Token=
Description=
VXLAN=
+L2TP=
LinkLocalAddressing=
ConfigureWithoutCarrier=
NTP=
DHCPServer=
BindCarrier=
VRF=
+IgnoreCarrierLoss=
[IPv6Prefix]
Prefix=
OnLink=
SamplePoint=
BitRate=
RestartSec=
+TripleSampling=
[Address]
DuplicateAddressDetection=
AutoJoin=
UseDomains=
RouteTable=
UseDNS=
+UseAutonomousPrefix=
+UseOnLinkPrefix=
[DHCPServer]
EmitNTP=
PoolSize=
--- /dev/null
+{
+ "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"
+ }
+}
--- /dev/null
+{"ociVersion": "1.0.0",
+"linux": {"devices": [ { "access": "mmmw;r"}
+] }, "e": "}e"
+ }
+
\ No newline at end of file
--- /dev/null
+{
+ "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"
+ }
+}
--- /dev/null
+[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
--- /dev/null
+[Files]
+Overlay=/::
\ No newline at end of file
--- /dev/null
+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
FwMark=
GVRP=
Gateway=
-GatewayOnlink=
+GatewayOnLink=
GenericReceiveOffload=
GenericSegmentationOffload=
GratuitousARP=
RestrictAddressFamilies=
RestrictNamespaces=
RestrictRealtime=
+RestrictSUIDSGID=
RuntimeDirectory=
RuntimeDirectoryMode=
RuntimeDirectoryPreserve=
--- /dev/null
+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
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
# 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=
'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',
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 = []
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
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
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
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'
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'
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={}
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',
[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()
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()
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'])
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'])
'''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()
[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:
[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:
[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)
--- /dev/null
+[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"
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
--- /dev/null
+[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"'
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"
# 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
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
if [[ "$LOOKS_LIKE_SUSE" ]]; then
PARAMS+="rd.hostonly=0"
+elif [[ "$LOOKS_LIKE_ARCH" ]]; then
+ PARAMS+="rw"
else
PARAMS+="ro"
fi
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
[ -b "$LOOPDEV" ] || return 1
echo "LOOPDEV=$LOOPDEV" >> $STATEFILE
sfdisk "$LOOPDEV" <<EOF
-,$((_size-10))M
+,$((_size-50))M
,
EOF
"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))
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() {
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 \
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
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
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+IPv6AcceptRA=no
--- /dev/null
+[NetDev]
+Name=dropin-test
+Kind=dummy
+MACAddress=00:50:56:c0:00:38
[NetDev]
Name=macvlan99
Kind=macvlan
+MTUBytes=2000
--- /dev/null
+[Match]
+Name=test1
--- /dev/null
+[Network]
+VLAN=vlan99
+Address=192.168.24.5/24
+Address=192.168.25.5/24
+IPv6AcceptRA=false
+[NetDev]
+MTUBytes=2000
+
[VLAN]
Id=99
GVRP=true
[Match]
-Name=test1
+Name=vlan99
+
+[Network]
+IPv6AcceptRA=false
+Address=192.168.23.5/24
+++ /dev/null
-[Network]
-VLAN=vlan99
--- /dev/null
+[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
+++ /dev/null
-[Match]
-Name=dummy98
-
-[Address]
-Address=10.2.3.4/16
-PreferredLifetime=0
-Scope=link
-
-[Address]
-Address=2001:0db8:0:f101::1/64
+++ /dev/null
-[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
--- /dev/null
+[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
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+BindCarrier=dummy99 dummy98
+Address=192.168.10.30/24
+Gateway=192.168.10.1
+IPv6AcceptRA=no
--- /dev/null
+[Match]
+Name=bridge99
+
+[Network]
+IPv6AcceptRA=no
--- /dev/null
+[NetDev]
+Name=erspan98
+Kind=erspan
+
+[Tunnel]
+ERSPANIndex=124
+Local = any
+Remote = 172.16.1.100
+Key=102
+SerializeTunneledPackets=true
[NetDev]
-Name=erspan-test
+Name=erspan99
Kind=erspan
[Tunnel]
-Independent=true
ERSPANIndex=123
Local = 172.16.1.200
Remote = 172.16.1.100
--- /dev/null
+[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
--- /dev/null
+[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
--- /dev/null
+[NetDev]
+Name=ipiptun96
+Kind=ipip
+MTUBytes=1480
+
+[Tunnel]
+Local=192.168.223.238
+Remote=192.169.224.239
+Independent=true
+
+FooOverUDP=yes
+FOUDestinationPort=55555
--- /dev/null
+[NetDev]
+Name=fou98
+Kind=fou
+
+[FooOverUDP]
+Encapsulation=FooOverUDP
+Port=55556
+Protocol=GRE
--- /dev/null
+[NetDev]
+Name=fou99
+Kind=fou
+
+[FooOverUDP]
+Encapsulation=FooOverUDP
+Port=55555
+Protocol=ipip
--- /dev/null
+[NetDev]
+Name=sittun96
+Kind=sit
+
+[Tunnel]
+Local=10.65.223.238
+Remote=10.65.223.239
+Independent=true
+
+FooOverUDP=yes
+FOUDestinationPort=55555
--- /dev/null
+[NetDev]
+Name=gretun98
+Kind=gre
+
+[Tunnel]
+Local=any
+Remote=10.65.223.239
+Key=104
+SerializeTunneledPackets=false
--- /dev/null
+[NetDev]
+Name=gretun97
+Kind=gre
+
+[Tunnel]
+Local=10.65.223.238
+Remote=any
+Key=105
+SerializeTunneledPackets=false
[Tunnel]
Local=10.65.223.238
Remote=10.65.223.239
+InputKey=1.2.3.103
+OutputKey=1.2.4.103
+SerializeTunneledPackets=true
--- /dev/null
+[NetDev]
+Name=gretap98
+Kind=gretap
+
+[Tunnel]
+Local=any
+Remote=10.65.223.239
+Key=107
+SerializeTunneledPackets=true
[Tunnel]
Local=10.65.223.238
Remote=10.65.223.239
+Key=106
+SerializeTunneledPackets=true
--- /dev/null
+[NetDev]
+Name=ip6gretun98
+Kind=ip6gre
+
+[Tunnel]
+Local=any
+Remote=2001:473:fece:cafe::5179
--- /dev/null
+[NetDev]
+Name=ip6gretun97
+Kind=ip6gre
+
+[Tunnel]
+Local=2a00:ffde:4567:edde::4987
+Remote=any
[NetDev]
-Name=ip6gretap99
-Kind=ip6gretap
+Name=ip6gretun99
+Kind=ip6gre
[Tunnel]
Local=2a00:ffde:4567:edde::4987
--- /dev/null
+[NetDev]
+Name=ip6gretap98
+Kind=ip6gretap
+
+[Tunnel]
+Local=any
+Remote=2001:473:fece:cafe::5179
--- /dev/null
+[NetDev]
+Name=ip6gretap99
+Kind=ip6gretap
+
+[Tunnel]
+Local=2a00:ffde:4567:edde::4987
+Remote=2001:473:fece:cafe::5179
--- /dev/null
+[NetDev]
+Name=ip6tnl98
+Kind=ip6tnl
+
+[Tunnel]
+Mode=ip6ip6
+Local=any
+Remote=2001:473:fece:cafe::5179
--- /dev/null
+[NetDev]
+Name=ip6tnl97
+Kind=ip6tnl
+
+[Tunnel]
+Mode=ip6ip6
+Local=2a00:ffde:4567:edde::4987
+Remote=any
--- /dev/null
+[NetDev]
+Name=ipiptun98
+Kind=ipip
+MTUBytes=1480
+
+[Tunnel]
+Local=any
+Remote=192.169.224.239
--- /dev/null
+[NetDev]
+Name=ipiptun97
+Kind=ipip
+MTUBytes=1480
+
+[Tunnel]
+Local=192.168.223.238
+Remote=any
--- /dev/null
+[Match]
+Name=test1
+
+[Network]
+Address=192.168.30.100/24
+IPv6AcceptRA=false
+L2TP=l2tp99
--- /dev/null
+[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
--- /dev/null
+[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
[Network]
LinkLocalAddressing=yes
+IPv6AcceptRA=no
+++ /dev/null
-[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
+++ /dev/null
-# 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
+++ /dev/null
-[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
+++ /dev/null
-[Match]
-Name=dummy98
-
-[Network]
-Address=192.168.0.15/24
-
-[Route]
-Gateway=192.168.0.1
--- /dev/null
+[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
+++ /dev/null
-[Match]
-Name=test1
-
-[Route]
-Destination=192.168.1.1
-InitialCongestionWindow=20
-
-[Route]
-Destination=192.168.1.2
-InitialAdvertisedReceiveWindow=30
+++ /dev/null
-[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
--- /dev/null
+[NetDev]
+Name=sittun98
+Kind=sit
+
+[Tunnel]
+Local=any
+Remote=10.65.223.239
--- /dev/null
+[NetDev]
+Name=sittun97
+Kind=sit
+
+[Tunnel]
+Local=10.65.223.238
+Remote=any
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+IPv6AcceptRA=no
+Address=10.2.3.4/16
IPv6HopLimit=5
IPv4ProxyARP=true
IPv6ProxyNDP=true
+IPv6AcceptRA=no
--- /dev/null
+[Match]
+Name=vrf99
--- /dev/null
+[NetDev]
+Name=vtitun98
+Kind=vti
+
+[Tunnel]
+Local=remote
+Remote=10.65.223.239
--- /dev/null
+[NetDev]
+Name=vtitun97
+Kind=vti
+
+[Tunnel]
+Local=10.65.223.238
+Remote=any
--- /dev/null
+[NetDev]
+Name=vti6tun98
+Kind=vti6
+
+[Tunnel]
+Local=any
+Remote=2001:473:fece:cafe::5179
--- /dev/null
+[NetDev]
+Name=vti6tun97
+Kind=vti6
+
+[Tunnel]
+Local=2a00:ffde:4567:edde::4987
+Remote=any
[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]
--- /dev/null
+cPLOy1YUrEI0EM
+ MIycPJmOo0aTu3RZnw8bL5
+ meVD6m0=
--- /dev/null
+CJQUtcS9emY2fLY
+ qDlpSZiE/QJyHkP
+ Wr+WHtZ
+
+
+LZ90FU=
--- /dev/null
+[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
--- /dev/null
+[Match]
+Name=wg99
HairPin = true
FastLeave = true
UnicastFlood = true
+MulticastFlood = false
MulticastToUnicast = true
+NeighborSuppression = true
+Learning = false
--- /dev/null
+[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
--- /dev/null
+[Match]
+Name=bond99
+
+[Network]
+IPv6AcceptRA=no
+Address=192.168.123.45/24
--- /dev/null
+[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
[Network]
Address=192.168.0.15/24
Gateway=192.168.0.1
+IPv6AcceptRA=no
--- /dev/null
+[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
Hostname=test-hostname
ClientIdentifier=mac
VendorClassIdentifier=SusantVendorTest
+RouteTable=211
--- /dev/null
+[Match]
+Name=veth99
+
+[Network]
+DHCP=yes
+IPv6AcceptRA=yes
+LinkLocalAddressing=yes
+VRF=vrf99
[Network]
Address=192.168.5.1/24
+IPv6AcceptRA=false
DHCPServer=yes
[DHCPServer]
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=erspan99
+Tunnel=erspan98
[Network]
Tunnel=gretap99
+Tunnel=gretap98
[Network]
Tunnel=gretun99
+Tunnel=gretun98
+Tunnel=gretun97
[Network]
Tunnel=ip6gretap99
+Tunnel=ip6gretap98
--- /dev/null
+[Match]
+Name=dummy98
+
+[Network]
+Tunnel=ip6gretun99
+Tunnel=ip6gretun98
+Tunnel=ip6gretun97
[Network]
Tunnel=ip6tnl99
+Tunnel=ip6tnl98
+Tunnel=ip6tnl97
[Network]
Tunnel=ipiptun99
+Tunnel=ipiptun98
+Tunnel=ipiptun97
--- /dev/null
+[Match]
+Name=dummy98
+
+[RoutingPolicyRule]
+TypeOfService=0x08
+Table=8
+From= 192.168.101.18
+Priority=112
+IncomingInterface=dummy98
+OutgoingInterface=dummy98
[Network]
Tunnel=sittun99
+Tunnel=sittun98
+Tunnel=sittun97
+++ /dev/null
-[Match]
-Name=dummy98
-
-[Network]
-Address=192.168.0.15/24
-Gateway=192.168.0.1
--- /dev/null
+[NetDev]
+Name=vlan6
+Kind=vlan
+MTUBytes=1500
+
+[VLAN]
+Id=6
--- /dev/null
+[Match]
+Name=vlan6
+
+[Network]
+IPv6AcceptRA=false
+Address=100.100.100.2/24
[Network]
Tunnel=vtitun99
+Tunnel=vtitun98
+Tunnel=vtitun97
[Network]
Tunnel=vti6tun99
+Tunnel=vti6tun98
+Tunnel=vti6tun97
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)
return f
def setUpModule():
-
os.makedirs(network_unit_file_path, exist_ok=True)
os.makedirs(networkd_ci_path, exist_ok=True)
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()
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()
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'))):
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):
'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',
'veth99',
'vlan99',
'vrf99',
+ 'vti6tun97',
+ 'vti6tun98',
'vti6tun99',
+ 'vtitun97',
+ 'vtitun98',
'vtitun99',
'vxlan99',
'wg98',
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',
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()
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')
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')
@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')
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')
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')
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'))
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',
'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)
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'))
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'))
@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'))
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
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')
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'))
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',
'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):
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']
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',
'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',
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'))
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))
$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
#
{
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"
{
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"
{
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"
{
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
{
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"
{
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"
{
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"
{
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
{
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"
{
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"
{
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"
{
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
{
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"
{
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"
{
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
{
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"
{
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"
{
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
#
{
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
{
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
{
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
{
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"
{
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"
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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
{
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"
{
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"
{
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"
{
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"
{
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"
{
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
{
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"
{
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"
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
devpath => "/devices/virtual/misc/misc-fake1",
exp_name => "node",
exp_majorminor => "4095:1",
- rules => <<EOF
+ rules => <<EOF
KERNEL=="misc-fake1", SYMLINK+="node"
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
{
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
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
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
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"
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 {
}}' "$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
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
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
What=mqueue
Where=/dev/mqueue
Type=mqueue
+Options=nosuid,nodev,noexec
['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', ''],
['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', ''],
['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', ''],
'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'],
'sockets.target.wants/'],
['systemd-udevd-kernel.socket', '',
'sockets.target.wants/'],
+ ['time-set.target', ''],
['time-sync.target', ''],
['timers.target', ''],
['umount.target', ''],
'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', '',
'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',
['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/'],
What=binfmt_misc
Where=/proc/sys/fs/binfmt_misc
Type=binfmt_misc
+Options=nosuid,nodev,noexec
What=fusectl
Where=/sys/fs/fuse/connections
Type=fusectl
+Options=nosuid,nodev,noexec
What=configfs
Where=/sys/kernel/config
Type=configfs
+Options=nosuid,nodev,noexec
What=debugfs
Where=/sys/kernel/debug
Type=debugfs
+Options=nosuid,nodev,noexec
[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
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
RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
+RestrictSUIDSGID=yes
SmackProcessLabel=System
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
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
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
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
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
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
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
PrivateTmp=yes
ProtectControlGroups=yes
ProtectHome=yes
+ProtectHostname=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectSystem=strict
RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
+RestrictSUIDSGID=yes
SmackProcessLabel=System
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
[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
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes
+ProtectHostname=yes
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
RestrictRealtime=yes
SmackProcessLabel=System
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6 AF_PACKET
RestrictNamespaces=yes
RestrictRealtime=yes
+RestrictSUIDSGID=yes
RuntimeDirectory=systemd/netif
RuntimeDirectoryPreserve=yes
SystemCallArchitectures=native
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
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
RestrictAddressFamilies=AF_UNIX AF_NETLINK AF_INET AF_INET6
RestrictNamespaces=yes
RestrictRealtime=yes
+RestrictSUIDSGID=yes
RuntimeDirectory=systemd/resolve
RuntimeDirectoryPreserve=yes
SystemCallArchitectures=native
PrivateTmp=yes
ProtectControlGroups=yes
ProtectHome=yes
+ProtectHostname=yes
ProtectKernelModules=yes
ProtectKernelTunables=yes
ProtectSystem=strict
RestrictAddressFamilies=AF_UNIX
RestrictNamespaces=yes
RestrictRealtime=yes
+RestrictSUIDSGID=yes
SystemCallArchitectures=native
SystemCallErrorNumber=EPERM
SystemCallFilter=@system-service @clock
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
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
RuntimeDirectory=systemd/timesync
StateDirectory=systemd/timesync
SystemCallArchitectures=native
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]
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
--- /dev/null
+# 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
Description=System Time Synchronized
Documentation=man:systemd.special(7)
RefuseManualStart=yes
+After=time-set.target
+Wants=time-set.target
[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
--- /dev/null
+# 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)
# (at your option) any later version.
[Unit]
-Description=Default
+Description=Main User Target
Documentation=man:systemd.special(7)
Requires=basic.target
After=basic.target
SecureBits=keep-caps
TimeoutStartSec=infinity
TimeoutStopSec=120s
+KeyringMode=inherit